SuperCollider-Source/000755 000765 000024 00000000000 13007315613 015654 5ustar00crucialstaff000000 000000 SuperCollider-Source/.editorconfig000644 000765 000024 00000001024 12766171707 020345 0ustar00crucialstaff000000 000000 # EditorConfig is awesome: http://EditorConfig.org # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true [*.{h,hpp,cpp}] indent_style = space indent_size = 4 [lang/**.cpp] indent_style = tab indent_size = 4 # Tab indentation [*.{sc,schelp}] indent_style = tab indent_size = 4 [CMakeLists.txt] indent_style = tab indent_size = 4 # Matches the exact files either .travis.yml [*.{yml,yaml,json,js}}] indent_style = space indent_size = 2 SuperCollider-Source/.travis/000755 000765 000024 00000000000 13007315612 017241 5ustar00crucialstaff000000 000000 SuperCollider-Source/.travis.yml000644 000765 000024 00000007716 12766171707 020017 0ustar00crucialstaff000000 000000 compiler: - gcc os: - linux - osx sudo: required dist: trusty osx_image: xcode7.3 cache: - apt - bundler before_install: - ifmac () { if [[ $TRAVIS_OS_NAME == osx ]]; then eval $@; fi; } - iflin () { if [[ $TRAVIS_OS_NAME == linux ]]; then eval $@; fi; } - ifmac brew update - ifmac brew tap homebrew/versions - ifmac brew outdated cmake || brew upgrade cmake - ifmac brew install qt55 libsndfile python || true - ifmac brew link qt55 --force - iflin npm install -g lintspaces-cli - iflin sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test - iflin sudo add-apt-repository --yes ppa:beineri/opt-qt551-trusty - iflin sudo apt-get update - iflin sudo apt-get install --yes build-essential gcc-4.9 g++-4.9 cmake pkg-config qt55base qt55location qt55declarative qt55sensors qt55tools qt55webengine qt55webchannel qt55webkit qt55xmlpatterns libjack-jackd2-dev libsndfile1-dev libasound2-dev libavahi-client-dev libreadline6-dev libfftw3-dev libicu-dev libxt-dev libudev-dev - iflin sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.9 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.9 - iflin sudo update-alternatives --auto gcc before_script: - iflin $TRAVIS_BUILD_DIR/.travis/lint.sh $TRAVIS_BUILD_DIR - iflin source /opt/qt55/bin/qt55-env.sh - mkdir BUILD - cd BUILD - export QT_PREFIX=$HOME/qt/gcc_64 - export QT_PLUGIN_PATH=$QT_PREFIX/plugins - export COMMIT_NAME=$TRAVIS_COMMIT - ifmac cmake -G"Xcode" -DCMAKE_PREFIX_PATH=`brew --prefix qt55` -DCMAKE_OSX_DEPLOYMENT_TARGET=10.7 .. --debug-output - iflin cmake -DSC_EL=no -DCMAKE_INSTALL_PREFIX:PATH=$PWD/Install -DCMAKE_BUILD_TYPE=Release .. --debug-output # some paths - ifmac export SCLANG=$TRAVIS_BUILD_DIR/BUILD/Install/SuperCollider/SuperCollider.app/Contents/MacOS/sclang - iflin export SCLANG=$TRAVIS_BUILD_DIR/BUILD/Install/bin/sclang # prep for testing - sudo pip install git+https://github.com/scztt/qpm.git@qpm-unit - qpm quark checkout CommonTests CommonTestsGUI --location $HOME/Quarks - cp ../travis_test_run_proto.json ./travis_test_run.json script: # build - iflin sudo make install - ifmac cmake --build . --config Release --target install # test - $TRAVIS_BUILD_DIR/testsuite/sclang/launch_test.py $SCLANG - qpm test.run -l ./travis_test_run.json --path $SCLANG --include $HOME/Quarks # package - ifmac mkdir -p $HOME/artifacts - (ifmac cd Install; ifmac zip -q -r $HOME/artifacts/SC-$COMMIT_NAME.zip SuperCollider) before_deploy: # required for github releases - git fetch --tags - export BUILD_PREFIX=$TRAVIS_REPO_SLUG/$TRAVIS_OS_NAME - export S3_BUILDS_LOCATION=builds/$BUILD_PREFIX - export S3_URL=https://supercollider.s3.amazonaws.com/$S3_BUILDS_LOCATION/SC-$COMMIT_NAME.zip - export FWD_HTML='' # put everything to be archived in artifacts/ - mkdir -p "$HOME/artifacts/${TRAVIS_BRANCH%/*}" - mkdir -p "$HOME/artifacts/${TRAVIS_TAG%/*}" - echo $FWD_HTML > $HOME/artifacts/$TRAVIS_BRANCH-latest.html - 'if [[ $TRAVIS_TAG != "head" ]]; then echo $FWD_HTML > $HOME/artifacts/$TRAVIS_TAG.html; fi;' deploy: # s3 upload - every commit - provider: s3 access_key_id: $AWS_KEY secret_access_key: $AWS_SECRET bucket: supercollider local-dir: $HOME/artifacts upload-dir: $S3_BUILDS_LOCATION region: us-west-2 skip_cleanup: true endpoint: s3-us-west-2.amazonaws.com acl: public_read on: condition: $TRAVIS_OS_NAME = osx && ! -z $AWS_KEY && ! -z $AWS_SECRET all_branches: true # github releases - only tags - provider: releases api_key: $GITHUB_KEY file: $HOME/artifacts/SC-$COMMIT_NAME.zip prerelease: true skip_cleanup: true on: condition: $TRAVIS_OS_NAME = osx && ! -z $GITHUB_KEY tags: true all_branches: true after-deploy: - "echo S3 Build Location: $S3_URL" notifications: on_success: change on_failure: change webhooks: urls: - https://webhooks.gitter.im/e/51b9b53ca50a7bfca97d on_success: change on_failure: always SuperCollider-Source/AUTHORS000644 000765 000024 00000013274 12756531744 016752 0ustar00crucialstaff000000 000000 8c6794b6 <8c6794b6 att gmail.com> Abel Abraham Camarillo Ojeda Alberto J. Gomez Alberto de Campo Alex Norman Anders Vinjar Andrew Smith Arnaldo Russo Axel Balley BS Collist Batuhan Bozkurt Benjamin Golinvaux Bruno Ruviaro Carlo Capocasa Charles Picasso Chris Sattinger Christopher Frauenberger Dan Buch Dan Stowell Daniel M Karlsson Dave Watson David Granstrom David Runge Eirik Arthur Blekesaune Fredrik Olofsson Georg Bernhard Glen Fraser Graeme Urquhart Guaka Hanspeter Portner Holger Ballweg Ioannis Zannos Jakob Leben James Harkins James McCartney Jan Trutzschler v. Falkenstein John Glover Jonas Bernoulli Jonatan Liljedahl Jonathan Wakely Josh Davison Joshua Parmenter Jost Muxfeldt Juan A. Romero Julian Rohrhuber LFSaw Louis-Guillaume Gagnon Lucas Cornelisse Lucas Samaruga Marije Baalman Mario Lang Mark Polishook Marmaduke Woodman Martin Victory Maurizio Umberto Puxeddu Michael Zacherl Miguel Negrão Nick Collins Patrick Beard Peter Vasil Raffael Seyfried Rainer Schütz Rohan Drape Ron Kuivila Ronald Kuivila Ross Bencina Ryan Brown Sam Aaron Scott Scott Carver Scott Wilson Sean Lee Seth Nickell Stefan Kersten Stefan Nussbaumer Stuart Popejoy Thor Magnusson Till Bovermann Tim Blechmann Tim Walters Tristan Strange Victor Bombi Vincent Donnefort Wouter Snoei Yvan Volochine ZLB a pieper adc afischli andersvi andrea valle artfwo attejensen backseatviolist bagong bion blackrain blacksound cfrb christian a. hresko christophe costigan crucialfelix danstowell dlm gerard roma groma hems henrique matias jamshark70 jpburstrom jrhb lijon marierm mcGitGo miczac mike whyte mohayonao muellmusik newton armstrong nusss ogbornd att mcmaster.ca olafklingt patrickdupuis porres redFrik rs sciss scott sensestage steim uid91958 vanhuman ventosus vividsnow wanninger SuperCollider-Source/build_sclang.cfg.in000644 000765 000024 00000000031 12321461510 021356 0ustar00crucialstaff000000 000000 @BUILD_CLASSLIBRARYPATH@ SuperCollider-Source/ChangeLog000644 000765 000024 00000174063 12756531744 017460 0ustar00crucialstaff000000 000000 See the full CHANGELOG.md for recent releases SuperCollider v3.6.5, released 2013-04 ====================================== Jakob Leben (10): sc class library: fix regression in Server:-scope scide: add "reset font size" action to post window and help browser scide: autocompletion: order methods by class hierarchy when class is known documentation: improve info on logical time, clocks and threads documentation: more info on threads, clocks and time sclang: PyrThread: ensure slot type safety documentation: clarify the functioning of Thread and Routine streamline README.txt documentation: improve thisFunction and thisFunctionDef Julian Rohrhuber (3): sc class library: replacing the source of a node proxy led to hanging patterns sc class library: NodeProxy:cleanNodeMapnow works even if no settings are present fix typo / removing the implication that ansi-C isn't appropriate Michael Zacherl (5): In.schelp: replaced AudioIn w/ SoundIn in reference, added loudness warning in example section Knob.schelp: repositioned text in mouseOverAction example Klang.schelp: changed 'filter' to 'oscillator' in methods section DynKlang.schelp: changed 'filter' to 'oscillator' in methods section README.txt: reworked and simplified with focus on SC IDE and version 3.6 vividsnow (2): scdoc: Pseg: duration pattern in beats not seconds scdoc: add thisFunctionDef/thisFunction SuperCollider v3.6.4, released 2013-04 ====================================== Dan Stowell (1): SinOsc and Osc: note phase issue beyond +-8pi. Fixes #815 Jakob Leben (34): sclang: fix Char:-isUpper/isLower qtcollider: add QListView:-selectionAction qtcollider: add QListView:-selection setter scide: remove credits for kiberpipa help: GUI - improve documentation of alignment options help: add guide on creating standalone applications sc ide: show impl/ref lookup dialogs even when no text under cursor sc class library: ClassBrowser: fix search with empty query string sc ide: interpreter: post notification on quit or crash qtcollider: pass exit code up to SC_TerminalClient sc ide: fix and improve region detection sc ide: sc editor: add action to select pair of brackets enclosing cursor sc ide: sc editor: update bracket match highlight after applying settings qtcollider: QTextView: increase 'selectedString' compatibility, fix docs qtcollider: envelope view: fix drawing of quadratic and cubic curves sc ide: help browser: delegate docklet focus to webpage view sc ide: docklet: when focusing, also activate window sc ide: fix auto-indenting closing brackets on certain locales sc ide: ensure dock widgets within screen bounds when first undocked qtcollider: QTextView: set 'enterInterpretsSelection' to true by default scide: config dialog: preserve font when toggling "show only monospaced" scide: select line in code on triple click scide: ensure last active window activated after open/save file dialog scide: on startup, remove invalid file paths from "recent documents" list scide: improve default paths in open/save dialogs scide: save document dialog: always allow saving with any extension scide: editor: highlight unmatched brackets just like mismatched ones qtcollider: StackLayout: fix crash when removing contained widget qtcollider: do not allow reparenting layouts, to avoid crashing scide: fix closing tool panels on Escape scide: impl/ref lookup: close dialog when opening documentation for class Revert "Revert "scide: on Mac, make one global menu to share by all windows"" scide: prevent erroneous overriding of shortcuts on Mac OS James Harkins (2): Library: Bugfix for PmonoArtic inside other patterns w/cleanup Library: Fix Pfset passing child cleanups up to its parent(s) Tim Blechmann (10): Help: fix rlpf help file plugins: DemandEnv - fix shape polling plugins: GrainBuf - catch both inf and NaN phase arguments scsynth: prevent possible buffer overflow cmake build system: fix x11 include paths class library: Bus - fix get method for multi-channel busses class library: Server.scope - remove limitation to 16 channels plugins: LocalOut - don't crash server if LocalIn is missing sclang: prevent buffer overflow scide: link with librt Victor Bombi (1): supernova: CMakeLists.txt must set include dirs for fftw3f attejensen (1): Update MIDI.schelp SuperCollider v3.6.3, released 2013-02 ====================================== Dan Stowell (2): Add cmake option NO_GPL3 to simplify building of GPL2 binaries SCDoc: generalise licensing from GPL3+ to GPL2+ Graeme Urquhart (2): Issue #702 fix: sendSelection receives NSString String:Help of split method matches implementation Jakob Leben (24): qtcollider: relicense to GPL version 2 sclang: terminal client - fix and simplify request handling qtcollider: support String:-speak when Speech class is available cmake: set LIBSCSYNTH=ON by default on Windows qtcollider: QView - do not block beginDrag if currentDrag is already set qtcollider: QKnob - let 'background' affect knob color sc ide: improve server boot/quit actions sc ide: improve interpreter start/stop actions sc ide: improve default server booting shortcuts qtcollider: sf view: fix loading non-power-of-two floating point files sc ide: disable zooming by mouse wheel (scrolling) sc ide: editor - set Qt::WA_MacNoClickThrough on viewport help: improve the SC IDE guide qtcollider: implement QtGUI:*cursorPosition class library: Platform - redirect getMouseCoords to GUI sc ide: post window - disable click-through on Mac OS X sc ide: add Help menu action to open the SuperCollider IDE guide help: SC IDE guide - show scaled screenshot, with a link to unscaled one sc ide: docklets - fix geometry after undocking sc ide: change default shortcuts for Go To Next/Previous Region sc ide: make cmd-period silent sc ide: improve status box context menu interaction sc ide: add context menu to interpreter status box James Harkins (4): Fix title:: tags in the practical guide: user-friendly titles vs. filenames Add Practical Guide Cookbook entry on swing rhythms PG_Cookbook_08: Fix an omitted copy/paste Fix typo in analysis example: BufWr.ar on a kr signal is bad Tim Blechmann (22): supernova: fix crash on /quit with portaudio class library: PlusFreqScope - survive server actions scide: remove ctrl-b shortcut class library: FreqScope - fix for starting scope after booting common: introduce new autogenerated SC_Version.hpp header class library: fix Array-unlace supernova: plugin interface - guard access to rt-pool plugins: IOUgens - prevent buffer overflow Help: BrownNoise - use a convention of -20db supernova: sized array - assert boundaries supernova: sndfile backend - correctly use correct blocksize for temp buffer supernova: jack backend - avoid uninitialized value supernova: nrt engine - nicer formatting of message log plugins: ui ugens - initialize libx11 for threading supernova: start dsp threads from run methods sclang: library config - correcty handle library config command line argument server plugins: RecordBuf - fix multichannel corruption and buffer overrun fftlib: for now we avoid intptr_t server plugins: fix div_ka plugins: osc ugens - fix GET_TABLE macro plugins: OscUGens - ensure buffer initialization scide: add menu item to open the user application support directory Victor Bombi (2): common: win32 - avoid integer truncation supernova: correctly print synthdef path SuperCollider v3.6.2, released 2012-12 ====================================== BS Collist (1): qtcollider: QEnvelopeView - add method to return all selected indexes Jakob Leben (32): common (windows): unify access to known folder paths sclang (windows): add primitive to access "My Documents" dir cmake: expand the search for libsndfile and libfftw3f cmake (Windows): use CMAKE_LIBRARY_PATH for fixup_bundle() search dirs scide: let cmd-period have an application-wide shortcut context scide: DocumentManager - refresh cached file info before storing save time scide: help browser - support doc/impl/ref lookup for selected text scide: search widget hierarchy upwards for first handler of lookup actions scide: GenericLookupDialog - no need for subclassing QTreeView anymore scide: make doc/impl/ref lookup shortcuts work on detached docklets scide: always pop up lookup dialogs with the active window as the parent scide: update translation sources, add italian qtcollider: start drag within mouse event handler qtcollider: QStethoscope2 - reverse operation of horizontal zoom slider scide: GenericCodeEditor - set Qt::WA_MacNoClickThrough widget attribute scide: SyntaxHighlighter - swap QChar::toAscii() for toLatin1() scide: Document - swap QString::toAscii() for QString::toLatin1() scide: MainWindow - substitute deprecated QFileDialog::setFilter(QString) scide: MainWindow - include QMimeData scide: PostWindow - include QMimeData scide: GenericCodeEditor - include QMimeData qtcollider: QWidgetProxy - include QDrag sclang: SCIpcClient - fix includes cmake: sclang - fix building when SC_IDE=ON and SC_QT=OFF cmake: scide - add QtNetwork to required Qt modules qtcollider: QStethoscope2 - refactor for robustness qtcollider: QListView - add 'selection' method to get all selected indexes help: document new 'selection' methods of EnvelopeView and ListView help: View - improve documentation, fix links help: fix a large amount of broken links due to changes in SCDoc cmake: FindPortmidi - actually implement auto-finding portmidi James Harkins (1): Fix bug introduced by 7f29d322: Don't free the same alloc'ed index twice Tim Blechmann (18): scide: DocumentManager - read files via QTextStream to decode characters supernova: osc handler - fix completion message and done message for /b_close supernova: asynchronous log - fix string splitting supernova: compile fix supernova: send /fail messages on /notify commands supernova: send /fail on buffer commands supernova: fix sndfile error handling win32: ensure stack alignment plugins: fix GrainBuf cleanup Help: SymbolicNotations - replace SCSlider with Slider supernova: plugin interface - protect against multiple done actions Help: remove memStore class library: Buffer - freeMsg should clear all cached information supernova: osc interface - fix bug with node reordering supernova: buffer_read - don't check samplerate when queueing soundfiles class library: fix Function.plot plugins: RecordBuf - fix recordbuf overrun & fix done action handling Help: RecordBuf - RecordBuf is recording, not playing SuperCollider v3.6.1, released 2012-11 ====================================== Dan Stowell (1): SpecFlatness: prevent NaN output for silence (thanks nick collins) Glen Fraser (1): scide: code editor / post window - copy using plain text Jakob Leben (13): update README_WINDOWS.txt for changed application data locations fix compilation with MinGW (broken static initialization) scide: find/replace - use Qt translation system to handle singular/plural cmake: scide - improve handling translations scide: load translations from app resource directory scide: update translation source files scide: change english translation file name to serve as fallback sclang: (Windows) change app support dir from roaming to local scide: load fallback translation in addition to locale translation sclang: add primitive to allow Platform to access user home directory class library: WindowsPlatform - set a user-friendly default recordingsDir readme (windows): add instructions on moving application data Tim Blechmann (1): class library: SynthDef - writeDefFile should use default SynthDef path SuperCollider v3.6.0, released 2012-11 ====================================== Major release with many new features - please see the help doc "News in 3.6" for more information. http://doc.sccode.org/Guides/News-3_6.html SuperCollider v3.5.7, released 2012-11 ====================================== Jakob Leben (6): sclang: (Windows) fix String:-getenv to return variables set with -setenv class library: ServerMeter - fix closing window when server has never run sclang: fix 'gcd' and 'lcm' methods qtcollider: QStethoscope2 - fix width of number boxes qtcollider: fix SoundFileView:-selectAll and -selectNone qtcollider: fix QPen:*matrix setter - combine instead of replace matrix Julian Rohrhuber (1): class library: jitlib - Avoiding sync problems with free/play Tim Blechmann (9): plugins: filters - fix initialization of filter parameters external libraries: nova-simd update external libraries: move nova-simd submodule to github plugins: DelayN - fix initialization code Revert "plugins: DelayN - fix initialization code" common: fftlib - increase size limit for ffts sclang: server shm interface - fix setting of multiple values plugin interface: provide wrapper class for c++-style unit generators SuperCollider v3.5.6, released 2012-10 ====================================== Dan Stowell (2): Improve error messages when cmake can't find optional things Compile fix for Qt widget on arm. Upstreamed from debian-multimedia (thanks Felipe Sateler) James Harkins (1): Fix Spawner bug: cleanup.update is mandatory, including rest events Jonatan Liljedahl (7): Quarks: fix typo and also open old-style helpfiles ending with .htm Include old non-converted helpfiles in SCDoc document index HelpBrowser: also open RTF files with whatever is available Even more support for old help files scdoc: use JS hasOwnProperty instead of testing the property directly HelpBrowser: post javascript errors SCDoc: properly escape keys in generated docmap.js Joshua Parmenter (1): Fix ServerOptions instance var ordering, etc., to make internal server booting use correct number of audio bus channels. Tim Blechmann (4): cmake: provide explicit option to use system-installed boost libraries external libraries - revert submodule updates lang: SerialPort - fix invocation of done action SuperCollider v3.5.5, released 2012-09 ====================================== Dan Stowell (1): Fix bug in Complex:exp James Harkins (1): Convert misleading and confusing OSC-style example into object-style Joshua Parmenter (2): fix IEnvGen kr UGen fix cocoa window alpha setting Tim Blechmann (12): sclang: fix Array:extendWrap for negative size argument sclang: array primitivies - protect all array extend primitives against negative sizes scdoc: fix string comparison in parser supernova: sized_array - don't allocate memory for zero-sized array plugins: GrainBuf - fix crash when using nan as position control scsynth: ensure alignment of wire buffers supernova: catch exceptions when reading synthdefs supernova: free_aligned - fix fallback implementation for null pointers cmake build system: dont compile shared library with -fwhole-program plugins: GrainBuf - allocate grain after reading window plugins: GrainBuf - fix access to default hann window Victor Bombi (1): cpu usage for portaudio_backend.hpp SuperCollider v3.5.4, released 2012-08 ====================================== Dan Stowell (5): Fix typo that causes build fail on big-endian archs, thanks Felipe Sateler fix build on ARM (where qreal==float); thanks Felipe Sateler Strip gremlin characters from JITLib wrapForNodeProxy.sc choose clipping rather than wraparound for writing integer-format audio files (libsndfile setting) arm build fix: another double->qreal in QcMultiSlider James Harkins (1): Improve documentation of GUI kits and kit switching Jonatan Liljedahl (2): SCDoc: Use proper static string constants instead of comparing string literals. Revert "reinstate Mix.arFill and Mix.krFill for backward compatibility reasons" Julian Rohrhuber (2): reinstate Mix.arFill and Mix.krFill for backward compatibility reasons improve string helpfile Tim Blechmann (10): plugins: GrainUGens - handle unallocated window buffers plugins: GrainBuf - reject multi-channel buffers plugins: grain ugens - treat empty window buffers correctly server: provide memory alignment wrappers for msvc server: scsynth - ensure correct deallocation of SndBuffer memory server/language/supernova: automatically clip integer audio files scsynth: correctly free aligned buffers Help: fix OSC function in SendPeakRMS help file package: use alternative implementation of git-archive-all Victor Bombi (1): MSVC fix SuperCollider v3.5.3, released 2012-06 ====================================== Dan Stowell (6): LocalIn helpfile fix, thanks Bruno Ruviaro Fix scvim regsitry file for updated filename (thanks Carlo Capocasa) version number to 3.5.3 Server helpfile: see-also reference docs SCVim.sc should not be executable cmake build system: use system boost libraries if available Jakob Leben (1): cmake: fix Boost Thread linking on Windows James Harkins (10): EnvGen_next_ak_nova: Hardcoded blocksize=64, change to inNumSamples Per Scott W., initSiblings is not needed Reinstate Mix.ar and Mix.kr, with rate checks Fix crossplatform fail: Scale.directory shouldn’t always depend on Document ListPatterns: offset.value omitted (inval) as an argument Fix PbindProxy:storeArgs - should NOT call “source” on keys in the array! Scale:degreeToRatio should handle degrees outside of one octave’s range More meaningful error message for too many selectors Explain the limitation on the number of selectors in one FunctionDef Correct spelling error Jonatan Liljedahl (3): Methods.html: auto-redirect to Search if method not found SCDoc: fix detection of old format class docs Mix.ar was un-deprecated, so remove the deprecated method Joshua Parmenter (2): fix scroll view problem for OS X 10.7.4 update SC_DirUtils to look at the name of the app bundle on osx Julian Rohrhuber (14): fix bugs due to wrong usage of partial application PV_BinShift helpfile improved PV_Diffuser helpfile improved reformat statement for readability (no change of functionality) helpfile improvements improve array helpfile add note to the loop argument of DiskIn (thanks Stefan). improve helpfile some helpfile improvements improve helpfile improve helpfile improve and simplify FFT overview helpfile: fix some errors in examples. improve and simplify IFFT helpfile. improve and simplify FFT helpfile, mention that hopsize must be larger than 0.0 Tim Blechmann (11): external libraries: update nova-tt (gcc 4.7 fix) supernova: correctly implement replace semantics for /s_new Help: Function.scope is not limited to OSX anymore cmake build system: locate server plugins on freebsd server: add support for RF64 cmake build system: ensure boost include path for scsynth cmake build system: set boost library path cmake build system: link scapp with correct version of libboost_thread cmake build system: minor cleanup supernova: fix asynchronous commands for empty reply address common: fix non-apple builds SuperCollider v3.5.2, released 201 ====================================== Dan Stowell (3): Remove outdated Japanese menus Cannot use indentation for CMAKE example - on mac it is rendered as   which then breaks cmake compilation Fix bug in FFT library if winsize != audiosize Jakob Leben (21): qtcollider: fix QTextView:-background and QSoundFileView:-background cmake: improve message if Qt4 or one of its components not found qtcollider: QKnob: fix mouse response when mouseOverAction is set qtcollider: implement missing QPopUpMenu:-background qtcollider: QTextView fixes and improvements help: add missing GUI examples qtcollider: support use of UTF-8 encoded strings qtcollider: QTextView: improve -enterInterpretsSelection qtcollider: QTextField: never propagate Enter to parent qtcollider: QEnvelopeView: improve node selection API and UI help: update EnvelopeView documentation help: fix incorrect info in EnvelopeView documentation qtcollider: QObject:-getProperty: turn an error into a debug warning qtcollider: implement drag-and-drop for data outside SC qtcollider: improve key propagation in QListView and QTreeView qtcollider: optimize view instantiation (take 2) qtcollider: fix mouse wheel event being forwarded to SC for no reason qtcollider: fix potential null pointer dereference qtcollider: optimization - partially revert event handling changes qtcollider: optimization - avoid a signal connection at QObject construction qtcollider: optimization - avoid connecting signals with unnormalized signatures James Harkins (2): Fix Pcollect/select/reject:embedInStream to pass inval to the function setTheme: Inherit colors from parent theme if the user didn't specify Jonatan Liljedahl (41): scdoc: MathJax: don't use fonts installed on users computer New SCDoc parser and renderer. Faster, more stable, less buggy. fix some helpfiles for new scdoc scdoc.css update scdoc: scapp compile fix scdoc: defer indexAllDocuments until first use HelpBrowser tweaks scdoc: warn on additions for non-existent help doc scdoc: fill in argument names for argument:: with no name given SCDocRenderer: warn on broken links scdoc: fix classtree:: rendering bug scdoc: only warn on grouped methods argnames mismatch if argument:: tag is used scdoc: avoid GC error in primitive scdoc: collect metadata also from *.ext.schelp (doc additions) scdoc: warn if argument:: name does not match real method arg scdoc: updated SCDoc related docs scdoc: warn if classdoc title and filename mismatch scdoc: fix varargs name match warning scdoc: render getter/setter combinations as two different methods scdoc: warn if setter methods (trailing underscore) is documented explicitly scdoc: more helpfile fixes scdoc: fix some bugs, handle class docs with missing classes scdoc Search.html: match also on filename for 'title' schelp: fix some broken links scdoc: add clearCache arg to indexAllDocuments, and don't render undocumented classes more than once per session scdoc: updated SCDoc related helpfiles schelp: more doc error fixes scdoc: improve argument:: auto-fill and checks String-warn and -error: don't print newline after WARNING: and ERROR: scdoc: tweak warnings scdoc: fix escaping of :: in metadata parsing and block verbatim schelp: add keywords for scdoc tags in SCDocSyntax.schelp scdoc: allow end-of-file as newline terminator, and improve error messages scdoc: use setter_() syntax if more than one argument scdoc: render method arg defaults as "foo: val" instead of "foo = val" mention new scdoc implementation in News-3_5.schelp scdoc parser: allow empty lines before headertags SCDoc: fix escaping of & < and > SCDoc: fix inf loop at missing :: end-tag in code blocks SCDoc: allow EOF as terminator for private:: and similar tags SCDoc: don't warn on missing trailing mul & add args Miguel Negrão (1): [Class Libray] Quarks GUI - sort quarks by name Tim Blechmann (10): plugins: fix Clip.kr class library: archive TempoClock as compile string cmake build system: restrict win32-specific cflags to win32 external libraries: nova-simd update external libraries: nova-simd compile fix plugins: fix StereoConvolution2L constructor scsynth: use aligned memory allocation functions from supernova external libraries: nova-simd update scsynth: provide zalloc as symbol redFrik (1): scdoc: fixed a bunch of helpfile errors SuperCollider v3.5.1, released 2012-04 ====================================== Jakob Leben (13): windows: properly pass the SC version to NSIS qtcollider: QPopUpMenu: fix action triggering qtcollider: get rid of "X is not implemented" message class library: make Server:-plotTree resilient to GUI kit switching help: improve Stethoscope documentation class library: QStethoscope2: add missing class methods class library: fix UGen scoping on out-of-process servers class library: PlusFreqScope: simplify server checking class library: fix and improve various 'scope' and 'freqscope' methods help: fix Stethoscope:*isValidServer documentation class library: ServerMeter: fix synth startup and cleanup update README_WINDOWS.txt windows: improve building and installation Jonatan Liljedahl (6): lang11d: Fix parse tree generation of expr.(key:value, ...) SC.app: allow saving plain text .schelp files SCDoc: copymethod:: also search *.ext.schelp files Update News for 3.5 doc Fix typo in News-3_5.schelp and improve StartupFile.schelp Update WritingPrimitives.schelp regarding GC safety Joshua Parmenter (1): prevent HID crashes on OS X. Devices still aren't added to the queue though (longs for the locID aren't correctly set up) Scott Wilson (1): Make Unpack1FFT a subclass of UGen, rather than of PV_ChainUGen Tim Blechmann (4): class library: SynthDef - fix uploading of large synthdefs sclang: block evaluation typesafety sclang: signal primitives - fix Signal-fft SuperCollider v3.5.0, released 2012-03 ====================================== Major release with many new features - please see the help doc "News in 3.5" for more information. http://doc.sccode.org/Guides/News-3_5.html SuperCollider v3.4.5, released 2012-01 ====================================== Tim Blechmann (7): class library: FreqScope fix sclang: fix crash of scpacket overflow by using exception handling sclang: pad PyrMethodRaw struct sclang: force size of PyrSlot to 16 byte and fix PyrMethodRaw size server plugins: fix div_ai_nova plugins: Resonz - fix initialization plugins: disable simd-optimization for tanh James Harkins (3): Explicitly show the command to uninstall (for scons idiots like me). (3.4) PathName now sets tmp directory using Platform SimpleController:update would throw error if no actions had been 'put' in Dan Stowell (1): Remove waf file from 3.4.x - was never used, and contains binary code, causing linux packaging problems. See ubuntu bug #529154 for details, and debian bug #529154 for sc-specific Mathieu Trudel-Lapierre (1): Fixup environment variables used for linking against readline, libicu, curl, cwiid. Nick Collins (1): Fix bug in MFCC ugen Noe Rubinstein (1): Fix PMOsc doc: index -> pmindex dmotd (1): Include altivec.h on linux powerpc, fixing FTBFS SuperCollider v3.4.4, released 2011-06 ====================================== Dan Stowell (4): Improve format of copyright/GPL notices (issue raised in debian pkging) Clarify Fontana copyright in MoogFF (and don't use keyword 'copyright' in files where he doesn't have copyright) Update AUTHORS file Remove unneeded PDF (debian raised query over copyright) Nick Collins (1): Initial fix for headphones problem where plugging in or out headphones while using Built-in Output leads to loss of audio on OS X. Aggregate Devices not tackled at this point Tim Blechmann (15): sclang: mathematical operators - clip2 fix plugins: LPF - fix control-rate initialization sclang: wii - don't use address of temporary SCClassLibrary: ScoreStreamPlayer - do not add instances to server list scsynth: apple - set denormal handling flags, if __SSE__ is defined sclang: slotString - crash fix plugins: XLine - correct handling of done actions sclang: gc - introduce LazyCollect to avoid leak of frames and argument lists plugins: Pitch.ar - fix crash for high execution period changelog: fix version number update changelog sclang: parser - support message send syntax for unary operators plugins: delay ugens - rt memory allocation may fail sclang: compile fix SuperCollider v3.4.3 ====================================== Dan Stowell (2): SC 3.4 set correct SOVERSION 1.0.0 for libs, and install more properly. (Changes ported from downstream debian packaging.) lib SOVERSIONs back from 1.0.0 to 1, following debian-multimedia advice James Harkins (8): Fix nowExecutingPath bug in scel (never backported?) fix two bugs in NotificationCenter registerOneShot: fix corner case in ClassBrowser Fix asPseg bug for short curves array (which should wrap, not kill the stream) Clear dataptr when closing a file (so that isClosed answers correctly) Incorrectly used dataptr instead of fileptr in previous commit on this file replace old, unsafe Dictionary test with a safer (but less OOPy) test rats... I missed two others of the same Joshua Parmenter (1): update version number Tim Blechmann (3): scsynth: set ftz flag on osx two commits: (1) simplify access to the superclass tree in Class. (2) when looking for a code file (openCodeFile) or cmd-J, it is now enough to select a full line, instead of havin scons build system: libsclang build fix SuperCollider v3.4.2, released 2011-03 ====================================== Bugfixes: --------- * 2010-06-05 fix Latch first sample output bug: if trigger > 0 initially, latch should not output 0 - jh * 2010-09-04 fix firstArg behavior in BinaryOpUGen by a list-approved hack - jh * 2010-10-01 fix SConstruct so that libscsynth and libsclang get SONAME entries - ds * 2010-11-13 grainBuf: audio-rate trigger fix - tb * 2010-11-15 generate libsclang and libscsynth with .so.1 extension (and soname) on linux - ds * 2010-11-15 scons create symlinks from libX.so to libX.so.1 on linux, and install them - ds * 2010-11-16 added .htm files to SConstruct as approved help file extension - mb * 2010-11-28 compile fix for curl support - tb * 2010-11-28 prevent asBus from breaking when called with no numChannels - jh * 2010-12-03 grain ugens: demand ugen input fix - tb * 2010-12-05 SystemClock and TempoClock sched and schedAbs with inf time doesn't schedule the task in the first place. backported from master - tb * 2010-12-08 prString_FindRegexp fix: match char array was too short to hold null termination - jli * 2010-12-11 fix classbrowser colors bugs. backported from master - tb * 2010-12-12 fixes the bug where installed quark help files would not be detected - tb/ar * 2010-12-13 mark inherited methods in class browser by background colour. backported from master - tb * 2010-12-30 Pipe does not remove closed pipes from openFiles - jh * 2010-12-30 fix String:rotate - pb * 2011-01-02 unit generators: LagControl - fix initialization order - jh * 2011-01-02 unit generators: LagControl - dynamically allocate buffer for filter states - tb * 2011-01-07 fixed iOS compilation and backported changes from master branch - ab * 2011-01-06 array primitives: fix allTuples and unlace - pb * 2011-01-07 sclang: makeIntrinsicClass - correct bounds for memcpy - tb * 2011-01-08 sclang: prString_FindRegexp - fill array after allocating objects - tb * 2011-01-14 sclang: prString_FindRegexp ensure correct size of results array during gc calls - tb * 2011-02-27 sclang: ensure minimum stack size - tb * 2011-03-09 SCVim: avoid generating scvim help cache if not currently in scvim - ds * 2011-03-11 fix the Event type 'note' (fixes rendering patterns to audio files) - rk SuperCollider v3.4.1, released 2010-11 ====================================== * 2010-07-12 remove accidental debug messages from SCView (on mac, posted a lot of info to Console, could affect performance) - ds * 2010-07-11 Collections should behave as reasonably as possible when empty - some fixes to better this - jr * 2010-07-11 SynthDef:add now sends to all running servers if no libname is given. SynthDescs are still added to the global SynthDescLib. If you want to handle multiple SynthDesc libs, you have to add the servers to each of them explicitly - jr * 2010-07-12 PanAz: added support for audio-rate pos arg - lfsaw * 2010-07-18 improved the sclang syntax highlighting parses - Patrick Borgeat * 2010-07-30 Dreset UGen allows to reset the child UGens on its input - jr * 2010-08-05 storeOn / asCompileString now simplifies its output. Default arguments that are given in the *new method anyhow are omitted - jr * 2010-08-06 Dictionary merge and blend methods - jr * 2010-08-09 method overwrite messages not posted by default, rather a message inviting people to run Main:overwriteMsg for the info - ds * 2010-08-13 MethodOverride class to encapsule information on overridden messages, inviting people to run MethodOverride.printAll - jr * 2010-08-13 add size arg to Signal:zeroPad - jr and jh * 2010-08-18 Pevent now uses default event if no event is passed in - jr * 2010-08-18 added a shortcut to the rather tedious .asCompileString method. In analogy to object.postcs, object.cs returns the compile string - jr * 2010-08-20 audio driver for scsynth running on Android (through JNI) - ds * 2010-08-24 un-deprecate scsynth's ability to use internal "green" FFT lib, for embedded devices etc - ds * 2010-08-28 no 'record' button for remote server GUIs, since path not generally known - ds * 2010-09-02 token threading for sclang interpreter - tb * 2010-09-07 when looking for a code file (openCodeFile) or cmd-J, it is now enough to select a full line, instead of having to select both words around the colon - jr * 2010-09-07 added methods for better navigation in the class tree (findOverriddenMethod) - jr * 2010-09-10 add method: Complex:abs to fit common usage - jr * 2010-09-12 added Dwrand UGen - jr * 2010-09-15 SystemClock and TempoClock sched and schedAbs with inf time doesn't schedule the task in the first place - jr * 2010-10-07 change the mac HID error-handler code to output errors to sc post window rather than to mac log; removes a pascal-string issue - ds * 2010-10-19 Ndef now releses its bus when server was quit or just booted - jr * 2010-10-20 retain the path to the file in which an error has occurred and post it - jr Bugfixes: --------- * 2010-07-10 protecting the server against malformatted SynthDef names - jr * 2010-06-28 syntaxColorize fix for double-backslashes, thanks Patrick Borgeat for the patch - ds * 2010-07-24 catch crash in the case that one tries to define a unique method using a return value directly - jr * 2010-09-07 UGen:clip, :wrap, :fold now apply correctly to scalar-rate signals; also methodSelectorForRate tweak for which class is asked - ds * 2010-09-09 fix a bug for trigger signals in Demand.kr that hold longer than one control period - jr * 2010-09-11 bug in audio rate mapping fixed, when new source object was inserted in a mapped node proxy - jr * 2010-09-12 fix bug: 2994009. LFPar and LFCub audio rate modulation frequency argument work now - jr * 2010-09-19 fix to JITGui, when numItems is not supplied - jr * 2010-10-10 remove more crufty NSLog debug messages - ds * 2010-10-13 fix SCUserView:receiveDrag to receive mouse co-ordinates; thanks Daniel van den Eijkel - ds * 2010-10-19 debian-style scvim-check-if-plugin-is-active, brought upstream - ds * 2010-10-19 bug in audio rate mapping fixed, when new source object was inserted in a mapped node proxy - jr * 2010-10-19 partial fix for bugs item #2994009 - seems to fix LFPar but not LFCub. More work needed - ds * 2010-10-19 DC: fix multichannel expansion - tb * 2010-10-19 fix to demand rate unary op ugens, thanks james harkins - tb * 2010-10-19 Ugens: LinLin/LinExp fixes - tb * 2010-10-19 only /clearSched if RT - to fix tracker item #3033454 - tb * 2010-10-19 UGens: binary operators - fix scalar/signal division - tb * 2010-10-19 fix bug 2988525: SynthDef:writeDefFile appends path correctly - tb * 2010-10-19 ProcessOSCPacket: fix possible deadlock - tb * 2010-10-19 fix network address handling - albert graef * 2010-11-05 fix memory issues in regular expressions: correct memory management in prString_FindRegexp - tb * 2010-11-07 sclang: correct symlink handling - tb, ar SuperCollider v3.4, released 2010-07 ==================================== Headlines: ---------- * 2009-09-03 add support for Mac OS 10.5 and greater 64-bit builds of plugins and scsynth * 2009-07-xx iphone support by Axel Balley added - ab * 2009-07-21 EnvirGui added, a gui for livecoding/editing environments - adc * 2009-07-24 Server.plotTree method for visualising the groups and synths on the server - sw * 2009-07-31 mac osx text-completion feature now includes sclang objects - ds * 2009-08-01 sclang now has a flag (Platform.ideName) for which IDE is in use (scapp, scvim, scel, sced, jsceclipse...) so that the same class-library can be used with different IDEs, enabling IDE-specific code as necessary - ds * 2009-08-16 add emergency escape route: if sclang is caught in an infinite loop, send it a USR1 signal to break out of it - ds * 2009-09-12 String:findRegexp and other regular expressions now available on linux as well as mac - mb,ds * 2009-09-18 n_order and Server:reorder allow one to specify chains of nodes - sw * 2009-09-20 simplify the Server recording interface. prepareForRecord is now optional (will be automatically invoked if you don't), and the server gui button is now just two-state "record" "stop" - ds * 2009-10-04 support multichannel indices for Env:at - jr * 2009-10-29 improve OSC message correctness: for convenience, sclang allows command names as symbols with no leading slash e.g. \g_new. To improve compliance with the OSC standard, the leading slash is now added to those symbols before dispatch - ds * 2009-11-07 use nova-simd framework for performance improvements of unit generators - tb * 2009-11-21 Event type \note supports polyphonic sustain, lag and timingOffset, and responds correctly to free and release. Add \grain event type. - jr * 2009-11-28 windows: system "application support path", previously hardcoded as C:\SuperCollider, now settable by environment variable SC_SYSAPPSUP_PATH. Default setting for that env var (when using official wix bundle) will be [SC3INSTALLLOCATION] - ds * 2009-12-15 sclang: 64-bit safety - tb * 2009-12-15 sclang: performance improvement of math ops - tb * 2010-01-02 scsynth: use osc-compilant address patterns for server/lang communication - tb * 2010-01-24 add readline interface to sclang command-line. This is used by default when invoking "sclang" (to use the non-readline interface set the "-i" option to something other than "none") - ds * 2010-01-24 enable GPL3 code by default - this 'upgrades' the overall binary license from GPL2+ to GPL3+, and allows supercollider to benefit from GPL3+ libraries such as libsimdmath and gnu readline - ds * 2010-02-04 Improvements to SC.app editor: Split pane documents, AutoInOutdent - sw * 2010-02-18 scvim: now compatible with gnu screen, opens post window using screen, making it compatible with a pure-CLI environment - ds * 2010-02-xx add the Deployment32-64 build style for building on OS X (10.5 and greater) - jp * 2010-03-10 SynthDef:memStore deprecated in favour of the more coherent and typeable SynthDef:add - jr * 2010-04-11 Moved some more experimental JITLib classes to "JITLib extensions" Quark - jr Bugfixes: --------- * 2009-06-12 fix for level indicator: critical and warning now display based on peak if it is shown rather than on value - sw * 2009-06-18 fix for mouse coordinates bug - sw * 2009-06-22 fix for negative bounds issue in SCUserView - sw * 2009-06-23 avoid memory corruption when unknown OSC type tags are received. Instead forward them to sclang - jr * 2009-06-23 Fix server crash with negative buffer numbers. - jr * 2009-07-20 factors(): no prime factors exist below the first prime - jr * 2009-07-21 Loudness ugen now supports LocalBuf - nc * 2009-07-23 Fix very nasty bug in Pbindf: if a key is an array, new values were written into the incoming event, instead of the outgoing event - jh * 2009-07-28 catch unintialised value in sc_GetUserHomeDirectory(), fixing potential memory corruption if HOME not set - ds * 2009-08-01 SpecCentroid, fix its reaction to silence (output zero instead of NaN) - ds * 2009-08-01 NamedControl: single default value now returns instance, not array, default values are obtained in a consistent way - jr * 2009-08-04 fix the CPU-usage issue when calling plain "./sclang" from the terminal on OSX (seems it was caused by a bug in how OSX handles poll() calls) - ds * 2009-08-15 LinPan2: fix initialisation issue - panning was not correctly applied during the first calc block - ds * 2009-09-28 Workaround for faded colours in HTML docs - sw * 2009-09-13 fix PV_MagShift argument handling, so that the defaults mean no-change, matching the behaviour of PV_BinShift - ds * 2009-09-20 warn about weirdness of Float:switch - ds * 2009-09-30 prevent NaN output from SpecFlatness when input is silence - ds * 2009-10-16 fix cropping issue in printing SuperCollider.app documents - cq * 2009-10-17 many phase-vocoder (PV_) ugens previously didn't handle the DC/nyquist bins as expected. fixed most of these (PV_MagAbove, PV_MagBelow, PV_MagClip, PV_LocalMax, PV_BrickWall, PV_MagSquared, PV_BinWipe, PV_CopyPhase, PV_Max, PV_RandComb) - ds * 2009-11-01 fix audio rate arg problem in PlayBuf - jp * 2009-11-02 fix amplitude-convergence issue in Pan2, Balance2, LinPan2, XFade2, which could sometimes result in sound despite zero amp, as discovered by jh - ds * 2009-11-03 fix unsafe implementation of methods that allow sending collections to buffers - jr * 2009-11-04 fix signalRange for MouseX, MouseY and KeyState, so that the range message works now - jr * 2009-11-19 Fix for PV chains and LocalBuf - sw * 2009-12-14 fix uninitialised variable in Pulse (could sometimes cause small glitch on init), thanks to rhian lloyd - ds * 2010-01-10 Demand ugens can now handle more than 32 channels, thanks Patrick Borgeat for the patch - ds * 2010-02-05 scsynth now respects the -D commandline option when running in NRT mode - ds * 2010-02-11 Fix for nowExecutingPath with Routines - sw * 2010-02-23 Performance fixes for SCUserView - sw * 2010-02-25 Fix interpolation / indexing problem in VDiskIn that caused slight pitch fluctuations - jp * 2010-03-11 SequenceableCollection:reduce no longer returns nil if the collection has only 1 element - ds * 2010-03-28 fix memory leak of empty command line, for interactive sclang mode - tb * 2010-03-29 main menu for Mac lang editor app: correction to key for evaluate selection, used to be return, now return+shift - nc * 2010-04-19 fix missing font issue in Plotter -jr Other additions/improvements: ----------------------------- * 2009-06-11 Evaluate Selection menu command - sw * 2009-06-23 allow remote apps to send type chars - jr * 2009-06-27 build 32bit sclang on x86_64 - tb * 2009-07-xx efficiency improvements on some UGens - tb * 2009-07-xx improve Quarks use of svn for smoother user experience - ds * 2009-07-22 catch the case when a user tries to compile into a synthdef, a unary/binary operator that the server can't apply - jh * 2009-08-29 String:toUpper and String:toLower - ds * 2009-09-06 Boolean:while now throws an informative error, since Boolean:while has no particular use but is often used in error by beginners in code where Function:while is intended - ds * 2009-09-12 method FunctionDef:makeEnvirFromArgs allows to create template events from a function - jr * 2009-09-30 Error is now posted if maxSynthDefs exceeded -sw * 2009-11-03 TwoWayIdentityDictionary has a removeAt method now - jr * 2009-11-04 update of deferredTaskInterval from 0.038 to 0.01667 - fo * 2009-11-07 improved PyrSlot typesafety - tb * 2009-11-23 menu system improvements in Windows IDE - mv * 2009-12-13 tidyups for "sclang when on osx but not in sc.app" - ds * 2009-12-13 added lincurve and curvelin methods for numbers and UGens - jr * 2010-01-01 OSCresponder and OSCresponderNode respond equally to messages with or without preceding slash - jr * 2010-01-04 sclang: deprecated Proutine - switch back to the original Prout * 2010-01-06 UnitTest Quark improved, added script support - jr * 2010-01-23 Improved NodeProxy and ProxySpace helpfiles. Added proxy composition syntax to NodeProxy - jr * 2010-01-30 Make multichannel plotting easier. If no numChannels is given, find out automatically - jr * 2010-01-31 add new LOOP1 macro - tb * 2010-01-31 use c99 log2 functions for sc_log2 - tb * 2010-02-09 rearrangement of supercollider source code tree - ds * 2010-02-11 Server:default_ now assigns to s by default. Settable with flag - sw * 2010-02-27 removed SCAnimationView and added SCUserView:animate_ - fo * 2010-03-10 SCPen:setSmoothing changed to SCPen:smoothing_, harmonised change with swingosc - ds * 2010-03-23 exponentiation for Complex numbers - jr * 2010-xx-xx many helpfiles improved - various authors * 2010-03-30 Image class added, a redirect for SCImage or JSCImage - hr * 2010-03-30 Pitch ugen ability to output clarity measure (by default not activated, for backwards compat) - ds SuperCollider v3.3.1, released 2009-06-19 ========================================= Headlines: ---------- * 2009-05-11 SCWindow additions for visible, visible_, unminimize - cq * 2009-05-17 server guis (on osx) now indicate which one is currently default - adc * 2009-05-18 enabled control rate versions of Ball, TBall and Spring - mb * 2009-05-18 LID support for setting "MSC" state as well as "LED" on devices - ds * 2009-06-19 patched for compatibility with Safari 4, fixing a lockup issue when opening help docs - ar Bugfixes: --------- * 2009-05-11 fix keyword addressing for the order: argument - jmc * 2009-05-15 update libsndfile to 1.0.20 to fix security issues (overflow vulnerabilities) in libsndfile - ds * 2009-05-20 fix bug #2790649, "very large SimpleNumber:series can crash sclang" - ds * 2009-05-25 mac icons for document types .quark .scd .rtfd were omitted from the app bundle, now fixed - ds * 2009-06-02 EnvGen: fix off by one block latency in envelope attacks and releases - jr * 2009-06-12 bug fix for level indicator: critical and warning now display based on peak if it is shown rather than on value - sw * 2009-06-12 mouse coordinates fix, deprecate SCUserView:mousePosition - sw * 2009-06-17 some issues fixed in SCUserView - cq * 2009-06-20 fix redirect for Stethoscope - adc Other additions/improvements: ----------------------------- * 2009-05-05 fixes/improvements to cocoabridge primitives - cq * 2009-05-06 SCImage various minor improvements - cq * 2009-05-16 optimisation for scrollview drawing, remove VIEWHACK - sw * 2009-05-xx various documentation updates - various * 2009-05-xx various improvements to ubuntu-debian packaging scripts - ds, am * 2009-05-20 SynthDef:writeOnce now available as an instance method as well as a class method - ds * 2009-06-11 sc.app gets a menu command for "Evaluate selection" - sw * 2009-06-17 adjusted SCKnob to use relative mouse coordinates - jm * 2009-06-17 small fix to SConstruct to allow for new Debian X11 location when compiling on linux - mb * 2009-06-19 Blip ugen: prevent sound blowup by never letting numharm be less than 1 - fo * 2009-06-20 SCPen: fillStroke changed default from draw(4) to draw(3) - fo * 2009-06-21 Fold, Clip and Wrap can now modulate the low and high inputs. SuperCollider v3.3, released 2009-04-30 ======================================= Headlines: ---------- * 2008-04-08 scvim is now part of the distro - ds * 2008-04-20 improvements to MIDI sysex handling - added sysex parsing directly in source - thanks to charles picasso * 2008-07-12 scsynth on Mac can now use separate devices for audio input vs audio output. Thanks to Axel Balley for much of the work on this, also a bit by ds. * 2008-07-12 PlayBuf, RecordBuf, BufWr, BufRd, ScopeOut - used to be limited to 16-channel audio maximum. Now can handle massively multichannel audio - ds * 2008-07-19 Buffer:normalize method added - ds * 2008-07-23 FFT and IFFT added option for zero-padding, by optional "framesize" argument - ds * 2008-09-03 new VDiskIn ugen - jp * 2008-10-08 SCImage for manipulating bitmap image objects (mac only) - ch * 2008-10-09 LocalBuf system to allow synths to manage their own purely-local buffers - jr * 2008-10-17 Added "-P" option to scsynth (accessible as s.options.restrictedPath) to allow restricting which paths scsynth is allowed to read/write - ds * 2008-10-18 new PartConv ugen, performs efficient frequency-domain convolution - nc * 2008-10-26 support on mac for "modal windows/sheets" (for user dialogs etc) - sw * 2008-xx-xx various behind-the-scenes efficiency improvements, for a sleeker audio server that can do more on a given machine - various contributors * 2008-11-01 add BEQSuite filter UGens (blackrain, jp) * 2008-11-11 add Pfxb pattern - jr * 2008-11-25 new EZPopUpMenu - jm * 2008-11-29 Pitch ugen can now also track the pitch of control-rate signals - mb * 2008-11-30 Drag and drop paths from Finder to Documents and SCViews - sw * 2008-12-03 added PV_Div ugen for complex division - ds * 2008-12-07 added PV_Conj ugen for complex conjugate - ds * 2008-12-15 new ViewRedirect for easier cross-platform gui syntax. e.g. Window now redirects to SCWindow or JWindow. ds & jm * 2008-12-15 revised and updated all SC Gui documentation. New gui introduction. New SCUserView subclassing tutorial. - jm * 2008-12-15 the /done message for Buffer allocation/free/etc now also includes the buffer index - jt * 2008-12-15 added methods to SCFreqScope for "special" SynthDef, and for visualising frequency responses - ds * 2008-12-18 the main windows version of sc is now called "SuperCollider" rather than "PsyCollider" (although psycollider is the name of the code editor). SuperCollider on windows now has a different (better? who knows) installer, uses the main sc3 icon, and has some other tweaks that make it different from version 3.2 - ds * 2008-12-19 new EZListView - jm * 2009-01-02 sced (the gedit sc plugin) is now part of the distro - mb/artem * 2009-01-06 SendReply UGen - jr * 2009-01-06 VDiskIn sends file position to client - jr * 2009-01-12 map audio to SynthDef controls. new OSC messages n_mapa and n_mapan. - jp, jr, rk * 2009-01-13 relativeOrigin=true. SC's coordinate system in container views and user views are now by default relative. * 2009-01-15 SCLevelIndicator view added - sw * 2009-01-16 Scale and Tuning classes added - tw * 2009-01-17 SuperColliderAU (scsynth as a Mac OSX "Audio Unit") added to main distribution - gr * 2009-02-03 EZKnob revised and now part of distro - br, jm * 2009-02-23 SystemActions refactored - jr * 2009-02-23 SCMenuItem, SCMenuGroup, and SCMenuSeparator for user customisable menus - sw * 2009-02-23 LFGauss UGen added - jr * 2009-03-14 Added GeneralHID based patterns PhidKey and PhidSlot - mb Bugfixes: --------- * 2008-05-20 fix for the special case when 0.2.asFraction beachballs the lang (bug id 1856972) - jr * 2008-05-20 fix slight mistake in the defaults printed by scsynth on command-line (bug id 1953392) - ds * 2008-07-24 Routine / AppClock fix setting the clock of the thread (bug id 2023852) - jr * 2008-09-16 stability fixes to FFT and IFFT - ds * 2008-09-27 fix TExpRand.ar - ds * 2008-11-11 SystemSynthDefs.numChannels can now be set from the startup file - jr * 2008-11-24 avoid FFT failure when buffer not allocated - jr * 2008-11-29 resolved inconsistency in Server:waitForBoot - function is always executed in a Routine, whether or not the server is booted - ds * 2008-12-07 FlowView setting inital margin and gap fixed (bug id 1986059) - jh * 2008-12-07 OSCpathResponder fixed (bug id 2021481) - jh * 2009-01-08 b_readChannel fixed (bug id 1938480) - mb * 2009-01-08 MIDIIn.connect on Linux fixed (bug id 1986850) - mb * 2009-01-09 Tabbing in SCTextView - sw * 2008-08-23 fix for sclang crashing sometimes when compiling erroneous code (bug id 2022297) - rb * 2009-01-18 SCScrollView relativeOrigin glitch fixed (bug id 2508451) - jr, sw * 2009-01-28 Fixed QuartzComposer view bounds bug - sw * 2009-02-21 NodeProxy handles groups more consistently - jr * 2009-04-16 asFraction fix by JMcC - jr Other additions/improvements: ----------------------------- * 2008-03-22 added open Method and link handling to SCTextView - sw * 2008-04-04 SoundFile:toCSV - ds * 2008-04-29 buffer UGens now post a warning (rather than failing silently) if buffer channels doesn't match num ins/outs - ds * 2008-07-14 Deprecated rendezvous in favour of zeroConf - sw * 2008-09-xx various code improvements, including compiling for 64-bit linux - tb * 2008-10-03 improvements to standalone build - jp * 2008-10-03 SCEnvelopeView remembers drawing order. - sw * 2008-10-05 Maintain initial offset when dragging on an Envelope View node. This avoids nodes jumping to a new position on mouse down. - sw * 2008-10-05 Enabled gridOn, gridResolution, gridColor, timeCursorOn, timeCursorPosition, and timeCursorColor for SCSoundFileViews. - sw * 2008-10-31 thisProcess.pid - sclang now can know what its process id is - ds * 2008-11-21 support for LocalBuf in FFT UGens - jr * 2008-11-27 SC3 will ignore ugens/class-files in folders named "ignore". Previously the name has been "test" - ignoring folders named "test" is now deprecated and will be removed - ds * 2008-12-06 Added Main:recompile to allow recompiling from code (SC.app only so far) - sw * 2008-12-08 Added custom drag label for SCView - sw * 2008-12-15 Buffer's done osc reply now includes the bufnum - jt * 2008-12-20 Help tree in help menu (OSX) - sw * 2008-12-24 EZSLider and EZNumber now have an enclosing containers, as well labelPosition =\left, \right, or \stack modes - jm * 2009-01-03 Help browser text is editable/executable (CocoaGUI) - sw * 2009-01-04 Escape exits modal and fullscreen states (OSX) - sw * 2009-01-08 interface change to ProxySpace.stop (now stops all proxies, just like free/end/clear) - jr * 2009-01-08 improved Ndef implementation, stores values in an internal ProxySpace, Ndef takes server names for multiple servers. - jr * 2009-01-08 improved ProxyMixer implementation, added NdefMixer. - adc * 2009-01-11 Added class browser to help menu (OSX) - sw * 2009-01-20 New Cocoa based SCTextField - sw * 2009-01-28 More helpful error string for operation cannot be called from this Process - sw * 2009-02-23 CocoaDialog takes allowsMultiple arg rather than maxItems - sw SuperCollider v3.2, released 2008-02-21 ======================================= Headlines: ---------- * 2007-11-xx new suite of machine listening ugens - Loudness, BeatTrack, Onsets, KeyTrack, SpecCentroid, SpecPcile, SpecFlatness - nc, ds * 2008-01-06 FreeBSD compatibility - hb * 2008-01-10 Quarks updating on OSX should now be easier for first-time users; commands are run in a separate terminal window - ds * 2008-01-15 "Advanced find" in Mac interface - jt * 2008-01-20 Buffer.copy changed to match other .copy methods - now copies language-side object rather than server buffer. Buffer.copyData can be used to copy data from one server buffer to another - jh * 2008-01-20 - add volume controls to the Server and Server guis - jp * 2008-01-xx Pattern library implementation changes, Pfx, Pbus, Pgroup etc. - rk, jr, jh * 2008-01-26 TDuty outputs trigger first, not level. for backwards compatibility TDuty_old - jr * 2008-02-03 moved the search location for "startup.rtf" on Mac - now searches in system, then user, "Application Support/SuperCollider" folders - ds Bugfixes: --------- * 2007-11-16 bug fixes for MIDIIn in connect/disconnect methods. split MIDIOut.sysex into user method and primitive (breaks with previous implementation). default value for uid arg in MIDIOut.new. - mb * 2007-11-18 fixed a bug in prTry / protect - jr * 2007-11-27 lock avoided in nextTimeOnGrid * 2007-12-12 Node-setn fixed when using integers as control indices - jr * 2008-01-16 fixed Pen: bug with fillRect, fillOval and fillColor (bugtracker id 1837775) - jt * 2008-01-20 CheckBadValues rate-checking was too restrictive - ds * 2008-01-20 fix for Saw and Pulse's offset noise on first instantiation, thanks to hisao takagi - ds * 2008-01-26 TDuty / Duty does not drift anymore - jr * 2008-02-07 Fixed hang and incorrect background drawing in Cocoa scrollviews - sw Other additions/improvements: ----------------------------- * 2007-11-16 MIDIOut.connect and disconnect - mb * 2007-11-18 added T2A UGen - jr * 2007-11-18 Refactoring of Document class, including new CocoaDocument class to handle the Cocoa-specific (SuperCollider.app) document management - ds * 2007-11-18 More macros available in the plugin API for UGen programmers: GET_BUF, SIMPLE_GET_BUF, FULLRATE, RGET, RPUT - ds * 2007-11-20 UnixPlatform:arch method - jp * 2007-11-20 FFTTrigger UGen - a ugen to create "fake" (empty) FFT chains - jp * 2007-11-21 StartUp protects its added functions from each other - if one fails this no longer prevents others from running - ds * 2007-11-25 added Pclutch and moved StreamClutch to common - jr * 2007-11-27 Function:inEnvir added - jh * 2007-12-12 added Collection.flatIf - jr * 2007-12-15 added control rate functionality to NumRunningSynths - jr * 2008-01-08 martin rumori's DiskIn bugfix and loop enhancement - jp * 2008-01-10 String:runInTerminal method - ds * 2008-01-11 poll now works for scalar ugens - jr * 2008-01-15 Collection:maxIndex and Collection:minIndex - nc * 2008-01-24 Server.options.rendezvous to (de)activate Rendezvous if desired - ds * 2008-01-24 demand ugens accept audio rate inputs correctly - jr * 2008-01-26 added Dbufwr ugen, for writing to buffers from a demand ugen chain - jr * 2008-01-27 Main:version and associated methods for programmatically determining which version SC is - ds * 2008-02-03 Server:defaultRecDir class variable, to allow user to specify default rec location - ds * 2008-02-07 SCScrollView and SCScrollTopView no longer fire their action when scrolled programatically - sw SuperCollider v3.1.1, released 2007-11-16 ========================================= Bugfixes: --------- * 2007-11-09 re-organized the main help file - rb * 2007-11-14 fix for .asStringPrec, to avoid crashes on intel systems for large precision values - jt Other additions/improvements: ----------------------------- * 2007-11-14 added a preprocessor to the interpreter - jr * 2007-11-14 added a startup message specifying how to get help - rk SuperCollider v3.1, released 2007-10-31 ======================================= (changes below are since 2007-09-22, for first ever point release) Headlines: ---------- * 2007-09-27 SparseArray class added - jr * 2007-09-28 Help.gui added - ds * 2007-10-01 FFT and IFFT rewrite - now using more efficient libs, also allows user to vary the overlap and the window type, also large-sized FFTs are possible - ds * 2007-10-02 UnpackFFT and PackFFT added - these allow for flexible frequency-domain manipulations inside synths - ds * 2007-10-04 Pkey and Pif added - hjh * 2007-10-05 reformed Patterns - all patterns accept patterns as arguments - jr * 2007-10-08 change to UGen plugin loading fixes the audio dropout issue that various users have experienced - rb * 2007-10-08 GeneralHID crossplatform HID wrapper - mb * 2007-xx-xx many improvements to Quarks package-management system. gui improvements, dependency-handling improvements, etc - various * 2007-10-20 added a Glossary file - sw * 2007-10-xx various new help files added, and many help files improved - various * 2007-10-26 changed Cmd-? to Cmd-D in lieu of the default help menu shortcut in Leopard. Also changed Cmd-Shift-K (clear post window) to Cmd-Shift-C to avoid accidental recompiles. - rb Other additions/improvements: --------------------------- * 2007-09-22 change log added, much rejoicing * 2007-09-25 added packagesource.sh script to produce source code bundles - ds * 2007-09-28 IdentityDictionary:doesNotUnderstand now warns if adding a pseudo-method which overrides a real method - jr * 2007-09-28 String:openHTMLFile added - ds * 2007-10-04 Integer:collect and Integer:collectAs methods added - ds/jr * 2007-10-05 Dwhite:new and Dbrown:new have default values for lo and hi - jr * 2007-10-10 SC no longer automatically writes data (synthdefs, archive.scxtar) to the application folder - instead writes to "app support". This fixes problems with running SC using an unprivileged user account - ds * 2007-10-16 SequenceableCollection:median speed improvement, approx ten times faster in many cases - ds * 2007-10-20 Object:deprecated and DeprecatedError added to allow for method deprecation - sw * 2007-10-21 Amplitude : attackTime and releaseTime can be modulated now - jr * 2007-10-25 Collection : histo method improved and moved from mathLib to common - jr * 2007-10-30 improvements to cocoa Gui, including SCUserView improved to support layering and own draw hook - jt, sciss * 2007-10-31 refactored Pbrown, added Pgbrown - jr Bugfixes: --------- * 2007-09-29 takekos bug fixed (obscure issue with garbage collection in arrays) - jm * 2007-10-01 fixed off by one bug in Dswitch and Dswitch1 that caused a server crash - jr * 2007-10-09 fixed deadlock and other problems in NSAttributedStringAdditions.m - rb * 2007-10-11 fixed inaccurate automatic determination of whether SC is running as standalone - ds * 2007-10-14 .quark files now saved correctly as plain-text, not RTF - ds * 2007-10-24 fixed a bug in Pbeta - jp SuperCollider-Source/CHANGELOG.md000644 000765 000024 00001052741 13007204634 017477 0ustar00crucialstaff000000 000000 # Change Log ## [3.8.0](https://github.com/supercollider/supercollider/tree/3.8.0) (2016-09-23) [Full Changelog](https://github.com/supercollider/supercollider/compare/3.7.2...3.8.0) ## API change - Increase the default number of audio buses from 128 to 1024 [#2239](https://github.com/supercollider/supercollider/pull/2239) by [vivid-synth](https://github.com/vivid-synth) - server plugins: Unify panning behavior of granular ugens [#2136](https://github.com/supercollider/supercollider/pull/2136) by [snappizz](https://github.com/snappizz) - scsynth: commandline option (-B) to bind to specific address [#2095](https://github.com/supercollider/supercollider/pull/2095) by [llloret](https://github.com/llloret) - PathName has potentially superfluous methods [#1909](https://github.com/supercollider/supercollider/issues/1909) by [telephon](https://github.com/telephon) - class library: sound file view - rename argument startframe -> startFrame to match convention [#1684](https://github.com/supercollider/supercollider/pull/1684) by [telephon](https://github.com/telephon) ## comp: scsynth - Add commit to version info [#2243](https://github.com/supercollider/supercollider/pull/2243) by [vivid-synth](https://github.com/vivid-synth) - fftlib: remove duplicate defines [#2089](https://github.com/supercollider/supercollider/pull/2089) by [sonoro1234](https://github.com/sonoro1234) - SC_fftlib: allow ensurewindow to be called [#2008](https://github.com/supercollider/supercollider/pull/2008) by [sonoro1234](https://github.com/sonoro1234) - jack: add metadata support [#1951](https://github.com/supercollider/supercollider/pull/1951) by [ventosus](https://github.com/ventosus) - reboot of the internal server crashes interpreter [#1526](https://github.com/supercollider/supercollider/issues/1526) by [ceremona](https://github.com/ceremona) ## comp: server plugins - server plugins: Gendy*: fix initialization bug [#2331](https://github.com/supercollider/supercollider/pull/2331) by [snappizz](https://github.com/snappizz) - Bug 1355 demand env overshoot [#2164](https://github.com/supercollider/supercollider/pull/2164) by [baconpaul](https://github.com/baconpaul) - Allow audio-rate phasein argument to VOsc [#2140](https://github.com/supercollider/supercollider/pull/2140) by [snappizz](https://github.com/snappizz) - PartConv avoid using first ir section twice [#2015](https://github.com/supercollider/supercollider/pull/2015) by [sonoro1234](https://github.com/sonoro1234) - plugins: do not advance stages before env start [#1424](https://github.com/supercollider/supercollider/pull/1424) by [scztt](https://github.com/scztt) ## comp: supernova - Add supernova to some scsynth-specific docs [#2256](https://github.com/supercollider/supercollider/pull/2256) by [vivid-synth](https://github.com/vivid-synth) - build: don't auto-enable supernova if old cmake [#2170](https://github.com/supercollider/supercollider/pull/2170) by [danstowell](https://github.com/danstowell) - supernova: use c++14 move captures and proper move semantics [#2141](https://github.com/supercollider/supercollider/pull/2141) by [timblechmann](https://github.com/timblechmann) - supernova: relax handling of malformed c_set messages [#2113](https://github.com/supercollider/supercollider/pull/2113) by [timblechmann](https://github.com/timblechmann) - supernova: portaudio_backend changed #elif for #else [#1947](https://github.com/supercollider/supercollider/pull/1947) by [sonoro1234](https://github.com/sonoro1234) - supernova: minor improvements [#1908](https://github.com/supercollider/supercollider/pull/1908) by [timblechmann](https://github.com/timblechmann) ## comp: sclang - remove references to CocoaBridge [#2351](https://github.com/supercollider/supercollider/pull/2351) by [snappizz](https://github.com/snappizz) - lang: Remove debug message [#2250](https://github.com/supercollider/supercollider/pull/2250) by [gusano](https://github.com/gusano) - sclang: Ensure git object is defined for checkout [#2216](https://github.com/supercollider/supercollider/pull/2216) by [scztt](https://github.com/scztt) - asStringPerc SCLang Crash [#2168](https://github.com/supercollider/supercollider/pull/2168) by [baconpaul](https://github.com/baconpaul) - Classname as Selector crashes [#2166](https://github.com/supercollider/supercollider/pull/2166) by [baconpaul](https://github.com/baconpaul) - Reimplement match lang ip [#1972](https://github.com/supercollider/supercollider/pull/1972) by [muellmusik](https://github.com/muellmusik) - sclang resolves relative paths in the language configuration file relative to the current working directory [#1927](https://github.com/supercollider/supercollider/issues/1927) by [miguel-negrao](https://github.com/miguel-negrao) - class library: plot does not specify min and max, so add 'plotAudio' method with -1 .. 1 range [#1846](https://github.com/supercollider/supercollider/pull/1846) by [telephon](https://github.com/telephon) - Fix presumed bug in d0f475d (min should be max). Fixes #1842 [#1843](https://github.com/supercollider/supercollider/pull/1843) by [danstowell](https://github.com/danstowell) - parser doesn't catch backward variable definitions [#1514](https://github.com/supercollider/supercollider/issues/1514) by [telephon](https://github.com/telephon) - sclang crashes on 0.exit [#1438](https://github.com/supercollider/supercollider/issues/1438) by [jamshark70](https://github.com/jamshark70) - Crash when using a class name in binop method call syntax [#669](https://github.com/supercollider/supercollider/issues/669) by [jamshark70](https://github.com/jamshark70) ## comp: class library - Fix printing filepath at end of recording [#2435](https://github.com/supercollider/supercollider/pull/2435) by [bagong](https://github.com/bagong) - Add default value to second argument in string replace [#2433](https://github.com/supercollider/supercollider/pull/2433) by [bagong](https://github.com/bagong) - server: don't set client id on failure [#2405](https://github.com/supercollider/supercollider/pull/2405) by [telephon](https://github.com/telephon) - class library: add missing proxy init in Ndef [#2387](https://github.com/supercollider/supercollider/pull/2387) by [telephon](https://github.com/telephon) - EnvirGui calls `this.widgets` but has none [#2371](https://github.com/supercollider/supercollider/issues/2371) by [telephon](https://github.com/telephon) - Topic/deprecating [#2370](https://github.com/supercollider/supercollider/pull/2370) by [crucialfelix](https://github.com/crucialfelix) - Make sure Spec is inited before ControlSpec [#2346](https://github.com/supercollider/supercollider/pull/2346) by [antonhornquist](https://github.com/antonhornquist) - Handle spaces in SCDoc internal links [#2336](https://github.com/supercollider/supercollider/pull/2336) by [crucialfelix](https://github.com/crucialfelix) - Usage of Class.initClassTree(ControlSpec) can remove common mappings [#2318](https://github.com/supercollider/supercollider/issues/2318) by [antonhornquist](https://github.com/antonhornquist) - SoundFileView.schelp wrong argument names [#2311](https://github.com/supercollider/supercollider/issues/2311) by [jamshark70](https://github.com/jamshark70) - Add linting and fix classlib indention [#2298](https://github.com/supercollider/supercollider/pull/2298) by [gusano](https://github.com/gusano) - class library: TreeView: add alias methods addChild, insertChild, childAt [#2260](https://github.com/supercollider/supercollider/pull/2260) by [snappizz](https://github.com/snappizz) - Classlib: Quarks: Fix typo in incompatibility message (SC: camel case… [#2245](https://github.com/supercollider/supercollider/pull/2245) by [jamshark70](https://github.com/jamshark70) - Classlib: GUI: asLayoutElement interface for non-Views that work in layouts [#2234](https://github.com/supercollider/supercollider/pull/2234) by [jamshark70](https://github.com/jamshark70) - ServerStatus - watcher notifies the server [#2226](https://github.com/supercollider/supercollider/pull/2226) by [gusano](https://github.com/gusano) - class library: server gui updates better [#2215](https://github.com/supercollider/supercollider/pull/2215) by [telephon](https://github.com/telephon) - class library: update link when server failed to start [#2209](https://github.com/supercollider/supercollider/pull/2209) by [snappizz](https://github.com/snappizz) - s.makeGui server window broken in master [#2202](https://github.com/supercollider/supercollider/issues/2202) by [jamshark70](https://github.com/jamshark70) - Classlib: GUI: Support "has-a" GUI objects by calling asView within Layouts [#2188](https://github.com/supercollider/supercollider/pull/2188) by [jamshark70](https://github.com/jamshark70) - Move Spec/Warp etc. out of GUI back into Control [#2182](https://github.com/supercollider/supercollider/pull/2182) by [crucialfelix](https://github.com/crucialfelix) - asOSCArgArray : do not expand a string into an array [#2133](https://github.com/supercollider/supercollider/pull/2133) by [telephon](https://github.com/telephon) - class library: implement audio rate lag control [#2127](https://github.com/supercollider/supercollider/pull/2127) by [telephon](https://github.com/telephon) - cmake needs to install HUT directory on OSX [#2116](https://github.com/supercollider/supercollider/issues/2116) by [sensestage](https://github.com/sensestage) - class library: streamArg correctly yields [#2110](https://github.com/supercollider/supercollider/pull/2110) by [telephon](https://github.com/telephon) - class library: move asOSCArgArray out of backwards_compatibility [#2108](https://github.com/supercollider/supercollider/pull/2108) by [telephon](https://github.com/telephon) - class library: fix compatibility of asOSCArgArray [#2097](https://github.com/supercollider/supercollider/pull/2097) by [telephon](https://github.com/telephon) - List can't be used in Synth arg list [#2096](https://github.com/supercollider/supercollider/issues/2096) by [jamshark70](https://github.com/jamshark70) - deprecated-3.7: remove it in master? [#2038](https://github.com/supercollider/supercollider/issues/2038) by [danstowell](https://github.com/danstowell) - Topic/server unresponsive [#1935](https://github.com/supercollider/supercollider/pull/1935) by [crucialfelix](https://github.com/crucialfelix) - clean up PathName code [#1912](https://github.com/supercollider/supercollider/pull/1912) by [telephon](https://github.com/telephon) - returning nil as UGen graph returns uninformative error [#1771](https://github.com/supercollider/supercollider/issues/1771) by [telephon](https://github.com/telephon) - Improve error handling in Server:prepareForRecord [#1580](https://github.com/supercollider/supercollider/issues/1580) by [bagong](https://github.com/bagong) - Fix range in Function:plot [#1454](https://github.com/supercollider/supercollider/pull/1454) by [thormagnusson](https://github.com/thormagnusson) - Move Spec back into Control [#2181](https://github.com/supercollider/supercollider/issues/2181) by [multivac61](https://github.com/multivac61) ## comp: help - add News in 3.8 [#2365](https://github.com/supercollider/supercollider/pull/2365) by [snappizz](https://github.com/snappizz) - help: History: remove use of .speak in examples [#2352](https://github.com/supercollider/supercollider/pull/2352) by [snappizz](https://github.com/snappizz) - help: SoundFileView: fix argument names [#2350](https://github.com/supercollider/supercollider/pull/2350) by [snappizz](https://github.com/snappizz) - Add example to LatoocarfianL [#2335](https://github.com/supercollider/supercollider/pull/2335) by [crucialfelix](https://github.com/crucialfelix) - Update Pitch.schelp [#2334](https://github.com/supercollider/supercollider/pull/2334) by [crucialfelix](https://github.com/crucialfelix) - Revert "Update Ndef.schelp" [#2323](https://github.com/supercollider/supercollider/pull/2323) by [nuss](https://github.com/nuss) - move SVG logo from HelpSource/images to icons [#2312](https://github.com/supercollider/supercollider/pull/2312) by [snappizz](https://github.com/snappizz) - Signal.schelp: small typo fix in play:loop desc [#2308](https://github.com/supercollider/supercollider/pull/2308) by [jaschanarveson](https://github.com/jaschanarveson) - Fix some anchor links in help [#2293](https://github.com/supercollider/supercollider/pull/2293) by [vivid-synth](https://github.com/vivid-synth) - Reference: Server-Command: clarify Wave Fill flags [#2288](https://github.com/supercollider/supercollider/pull/2288) by [jaschanarveson](https://github.com/jaschanarveson) - help: SC3 vs SC2: add historical note [#2287](https://github.com/supercollider/supercollider/pull/2287) by [snappizz](https://github.com/snappizz) - help: create help file for ScIDE [#2285](https://github.com/supercollider/supercollider/pull/2285) by [snappizz](https://github.com/snappizz) - help: VLayout: change QLineLayout to LineLayout [#2283](https://github.com/supercollider/supercollider/pull/2283) by [snappizz](https://github.com/snappizz) - help: Dialog: expand explanation of openPanel and savePanel [#2282](https://github.com/supercollider/supercollider/pull/2282) by [snappizz](https://github.com/snappizz) - Add "(NRT)" to the NRT help file title (searchability) [#2281](https://github.com/supercollider/supercollider/pull/2281) by [vivid-synth](https://github.com/vivid-synth) - Update Ndef.schelp [#2273](https://github.com/supercollider/supercollider/pull/2273) by [tiagmoraismorgado](https://github.com/tiagmoraismorgado) - Update MouseX.schelp [#2272](https://github.com/supercollider/supercollider/pull/2272) by [tiagmoraismorgado](https://github.com/tiagmoraismorgado) - Update MouseButton.schelp [#2271](https://github.com/supercollider/supercollider/pull/2271) by [tiagmoraismorgado](https://github.com/tiagmoraismorgado) - help: Remove some outdated GUI info [#2248](https://github.com/supercollider/supercollider/pull/2248) by [snappizz](https://github.com/snappizz) - Add supernova to the list of components [#2244](https://github.com/supercollider/supercollider/pull/2244) by [vivid-synth](https://github.com/vivid-synth) - help: add SVG logo to images dir [#2235](https://github.com/supercollider/supercollider/pull/2235) by [snappizz](https://github.com/snappizz) - Replace use of .send(s) with .add in class examples. [#2223](https://github.com/supercollider/supercollider/pull/2223) by [kisielk](https://github.com/kisielk) - help: update Document.schelp to match current API [#2219](https://github.com/supercollider/supercollider/pull/2219) by [snappizz](https://github.com/snappizz) - help: RangeSlider: correct dragging instructions [#2210](https://github.com/supercollider/supercollider/pull/2210) by [snappizz](https://github.com/snappizz) - examples: replace .send(s) with .add [#2208](https://github.com/supercollider/supercollider/pull/2208) by [snappizz](https://github.com/snappizz) - PulseDivider.schelp: Fix typo and clarify div [#2199](https://github.com/supercollider/supercollider/pull/2199) by [kisielk](https://github.com/kisielk) - Pmono.schelp: fix duplicate "the" [#2187](https://github.com/supercollider/supercollider/pull/2187) by [kisielk](https://github.com/kisielk) - Fix a typo in SynthDef.schelp [#2186](https://github.com/supercollider/supercollider/pull/2186) by [kisielk](https://github.com/kisielk) - fixing Henon help [#2150](https://github.com/supercollider/supercollider/pull/2150) by [tiagmoraismorgado](https://github.com/tiagmoraismorgado) - document DelTapWr/DelTapRd/MultiTap delay time caveats [#2132](https://github.com/supercollider/supercollider/pull/2132) by [snappizz](https://github.com/snappizz) - help: document range better for LFGauss UGen [#2121](https://github.com/supercollider/supercollider/pull/2121) by [telephon](https://github.com/telephon) - help: hidfunc, clarify nil on usage and usageID [#2104](https://github.com/supercollider/supercollider/pull/2104) by [llloret](https://github.com/llloret) - help fixes for OSCfunc & Env [#2087](https://github.com/supercollider/supercollider/pull/2087) by [miczac](https://github.com/miczac) - RecordBuf.schelp: corrected Synthnames for proper playback, lower volume for overdub [#2071](https://github.com/supercollider/supercollider/pull/2071) by [miczac](https://github.com/miczac) - AudioIn.schelp: tamed feedback in example, removed "patching" example [#2070](https://github.com/supercollider/supercollider/pull/2070) by [miczac](https://github.com/miczac) - Pulse.schelp: added missing .kr method, beautified examples [#2069](https://github.com/supercollider/supercollider/pull/2069) by [miczac](https://github.com/miczac) - Helpfile fixing [#2061](https://github.com/supercollider/supercollider/pull/2061) by [LFSaw](https://github.com/LFSaw) - Helpfile fixing [#2057](https://github.com/supercollider/supercollider/pull/2057) by [jreus](https://github.com/jreus) - Revert "LFSaw.schelp: Note and example for special initial-phase behaviour" [#2056](https://github.com/supercollider/supercollider/pull/2056) by [miczac](https://github.com/miczac) - Klank & DynKlank - better structure for examples [#2055](https://github.com/supercollider/supercollider/pull/2055) by [miczac](https://github.com/miczac) - RLPF.schelp: adjust example to avoid exploding filter due to frequency folding when modulated. [#2053](https://github.com/supercollider/supercollider/pull/2053) by [miczac](https://github.com/miczac) - Helpfile fixing [#2042](https://github.com/supercollider/supercollider/pull/2042) by [adcxyz](https://github.com/adcxyz) - Added closeWhenDone to .cue [#2039](https://github.com/supercollider/supercollider/pull/2039) by [tapage](https://github.com/tapage) - help: minor spell fixes in tutorials area [#2004](https://github.com/supercollider/supercollider/pull/2004) by [llloret](https://github.com/llloret) - help: and some more help typos and spell fixes [#2003](https://github.com/supercollider/supercollider/pull/2003) by [llloret](https://github.com/llloret) - help: fixed some more typos and spelling [#2002](https://github.com/supercollider/supercollider/pull/2002) by [llloret](https://github.com/llloret) - help: Help updates for the Classes directory [#1999](https://github.com/supercollider/supercollider/pull/1999) by [llloret](https://github.com/llloret) - Improve "Writing UGens" documentation [#1997](https://github.com/supercollider/supercollider/pull/1997) by [snappizz](https://github.com/snappizz) - More help documentation updates [#1989](https://github.com/supercollider/supercollider/pull/1989) by [llloret](https://github.com/llloret) - help: fixed some typos and spelling [#1988](https://github.com/supercollider/supercollider/pull/1988) by [llloret](https://github.com/llloret) - link was wrong [#1980](https://github.com/supercollider/supercollider/pull/1980) by [grirgz](https://github.com/grirgz) - Document ServerOptions.*devices as OS X only [#1949](https://github.com/supercollider/supercollider/pull/1949) by [snappizz](https://github.com/snappizz) - Clarified nil argument behavior in OSCdef help [#1940](https://github.com/supercollider/supercollider/pull/1940) by [antonhornquist](https://github.com/antonhornquist) - Change title of main help file from "Help" to "SuperCollider [version]" [#1928](https://github.com/supercollider/supercollider/pull/1928) by [snappizz](https://github.com/snappizz) - MultiTap and DelTapRd/Wr could use a Note in help doc [#1883](https://github.com/supercollider/supercollider/issues/1883) by [mtmccrea](https://github.com/mtmccrea) - CocoaBridge seems dead, but examples and doc are still there [#1629](https://github.com/supercollider/supercollider/issues/1629) by [muellmusik](https://github.com/muellmusik) ## comp: HID - Update pointer to submodule hidapi [#2420](https://github.com/supercollider/supercollider/pull/2420) by [bagong](https://github.com/bagong) - Adjust pointer to hidapi to fix cmp0048 bug breaking build for cmake … [#2342](https://github.com/supercollider/supercollider/pull/2342) by [bagong](https://github.com/bagong) - Update pointer to hidapi submodule [#2330](https://github.com/supercollider/supercollider/pull/2330) by [bagong](https://github.com/bagong) - HID: various small additions to adjust to developments in hid submodule [#2123](https://github.com/supercollider/supercollider/pull/2123) by [bagong](https://github.com/bagong) - Switch to hidapi subomodule in sc org repo [#2111](https://github.com/supercollider/supercollider/pull/2111) by [bagong](https://github.com/bagong) ## comp: Qt GUI - Move Qt primitives out of "common" to fix non-Qt builds [#2299](https://github.com/supercollider/supercollider/pull/2299) by [vivid-synth](https://github.com/vivid-synth) - build: fix qt configuration for case-sensitive OS X [#2262](https://github.com/supercollider/supercollider/pull/2262) by [snappizz](https://github.com/snappizz) - Document Qt >= 5.6 not working in Linux [#2206](https://github.com/supercollider/supercollider/pull/2206) by [snappizz](https://github.com/snappizz) - QPen - add RenderHints to StringInRect [#2019](https://github.com/supercollider/supercollider/pull/2019) by [gusano](https://github.com/gusano) ## comp: SCDoc - Adjust Help title for Windows return value of folder [#2392](https://github.com/supercollider/supercollider/pull/2392) by [bagong](https://github.com/bagong) - fix link to class file source in scdoc header [#2131](https://github.com/supercollider/supercollider/pull/2131) by [snappizz](https://github.com/snappizz) - Change "source" to "helpfile source" in scdoc footer [#2130](https://github.com/supercollider/supercollider/pull/2130) by [snappizz](https://github.com/snappizz) - SCDoc HTML renderer includes literal spaces in links with anchors [#1650](https://github.com/supercollider/supercollider/issues/1650) by [jamshark70](https://github.com/jamshark70) - SCDoc shows getters where there are only setters [#837](https://github.com/supercollider/supercollider/issues/837) by [muellmusik](https://github.com/muellmusik) ## comp: build - Document cmake dependency for supernova [#2207](https://github.com/supercollider/supercollider/pull/2207) by [snappizz](https://github.com/snappizz) - Explain /path/to/qt5 in Linux README [#2205](https://github.com/supercollider/supercollider/pull/2205) by [snappizz](https://github.com/snappizz) - move jackey include dir from server to scsynth [#2179](https://github.com/supercollider/supercollider/pull/2179) by [flv0](https://github.com/flv0) - Fix oscpack build fail on various architectures [#2174](https://github.com/supercollider/supercollider/pull/2174) by [danstowell](https://github.com/danstowell) - Simplify MS Compiler detection to avoid cmake warning [#2120](https://github.com/supercollider/supercollider/pull/2120) by [bagong](https://github.com/bagong) - Travis: Update OSX build system and correct omissions [#2092](https://github.com/supercollider/supercollider/pull/2092) by [bagong](https://github.com/bagong) - sclang: changed some boost code to std [#2091](https://github.com/supercollider/supercollider/pull/2091) by [llloret](https://github.com/llloret) - Switch to portaudio repo in supercollider org [#2088](https://github.com/supercollider/supercollider/pull/2088) by [bagong](https://github.com/bagong) - travis: move git key to env, aws fixes [#1987](https://github.com/supercollider/supercollider/pull/1987) by [scztt](https://github.com/scztt) - Set correct hash for portaudio submodule [#1971](https://github.com/supercollider/supercollider/pull/1971) by [bagong](https://github.com/bagong) - cmake: library locations, hide them from the default listing of user cmake variables [#1968](https://github.com/supercollider/supercollider/pull/1968) by [danstowell](https://github.com/danstowell) - Add cmake options list to READMEs [#1965](https://github.com/supercollider/supercollider/pull/1965) by [vivid-synth](https://github.com/vivid-synth) - Update linux travis recipe [#1932](https://github.com/supercollider/supercollider/pull/1932) by [patrickdupuis](https://github.com/patrickdupuis) - build: bump GCC version requirement up from 4.7 to 4.8 [#1839](https://github.com/supercollider/supercollider/pull/1839) by [danstowell](https://github.com/danstowell) - Building master with gcc 4.7 fails due to 'is_trivially_destructible' in SC_PlugIn.hpp [#1820](https://github.com/supercollider/supercollider/issues/1820) by [danstowell](https://github.com/danstowell) ## env: Qt IDE - IDE: Server status bar should send properly formatted /status message (not 'status') [#2450](https://github.com/supercollider/supercollider/pull/2450) by [jamshark70](https://github.com/jamshark70) - Fix Document path sync problems [#2222](https://github.com/supercollider/supercollider/pull/2222) by [jamshark70](https://github.com/jamshark70) - fix #1985 [#2102](https://github.com/supercollider/supercollider/pull/2102) by [miguel-negrao](https://github.com/miguel-negrao) - scide: update document path also if nil [#2098](https://github.com/supercollider/supercollider/pull/2098) by [telephon](https://github.com/telephon) - sc-ide: fix behaviour of right context button when out of tab [#2085](https://github.com/supercollider/supercollider/pull/2085) by [llloret](https://github.com/llloret) - sc-ide: middle mouse button closes tab [#2083](https://github.com/supercollider/supercollider/pull/2083) by [llloret](https://github.com/llloret) - ide: menu option "Show Quarks" [#1867](https://github.com/supercollider/supercollider/pull/1867) by [miguel-negrao](https://github.com/miguel-negrao) ## env: scel - bug with scide_scel [#2036](https://github.com/supercollider/supercollider/pull/2036) by [simdax](https://github.com/simdax) ## env: scvim - Replace built-in scvim with submodule scvim [#1991](https://github.com/supercollider/supercollider/pull/1991) by [danstowell](https://github.com/danstowell) - Makes Vim support more reliable by sending larger buffers [#1930](https://github.com/supercollider/supercollider/pull/1930) by [mzyzik](https://github.com/mzyzik) - scvim as submodules repo [#1921](https://github.com/supercollider/supercollider/issues/1921) by [blacksound](https://github.com/blacksound) ## os: Linux - Do not allocate all channels reported by Pa_GetDeviceInfo / use memcpy instead of for-loop [#1943](https://github.com/supercollider/supercollider/pull/1943) by [hzulla](https://github.com/hzulla) - Fixes/alsa midi fixes [#1760](https://github.com/supercollider/supercollider/pull/1760) by [timblechmann](https://github.com/timblechmann) - HID final cleanup, and LID adaption to use similar API [#1573](https://github.com/supercollider/supercollider/pull/1573) by [sensestage](https://github.com/sensestage) ## os: Windows - Fix problem with boost interprocess module on Win [#2457](https://github.com/supercollider/supercollider/pull/2457) by [llloret](https://github.com/llloret) - Update Windows Readme [#2419](https://github.com/supercollider/supercollider/pull/2419) by [bagong](https://github.com/bagong) - Exception in World_New: boost::interprocess::intermodule_singleton initialization failed [#2409](https://github.com/supercollider/supercollider/issues/2409) by [brachna](https://github.com/brachna) - Fix QLocalSocket problem under Windows [#2197](https://github.com/supercollider/supercollider/pull/2197) by [llloret](https://github.com/llloret) - Windows exit nicely master [#2107](https://github.com/supercollider/supercollider/pull/2107) by [llloret](https://github.com/llloret) - Make MIDI work on Windows (PR for master) [#2106](https://github.com/supercollider/supercollider/pull/2106) by [llloret](https://github.com/llloret) - nsis windows for master branch [#2103](https://github.com/supercollider/supercollider/pull/2103) by [llloret](https://github.com/llloret) - Make Vista the minimum required Windows version [#2017](https://github.com/supercollider/supercollider/pull/2017) by [llloret](https://github.com/llloret) - Make the required version Windows Vista [#2016](https://github.com/supercollider/supercollider/pull/2016) by [llloret](https://github.com/llloret) - sclang: Fix to get Object: render to work on Windows [#1899](https://github.com/supercollider/supercollider/pull/1899) by [antonhornquist](https://github.com/antonhornquist) - Windows: sclang crashes on executing menu-item "Quit interpreter"/freezes on evaluating 0.exit [#1578](https://github.com/supercollider/supercollider/issues/1578) by [bagong](https://github.com/bagong) - Server not shut down on IDE-close [#1449](https://github.com/supercollider/supercollider/issues/1449) by [bagong](https://github.com/bagong) - MIDI sysex is not implemented for Windows (SC_PortMIDI.cpp) [#1200](https://github.com/supercollider/supercollider/issues/1200) by [sensestage](https://github.com/sensestage) ## qt5 - WIP: ide/qtcollider: prototype port to qwebengine [#1936](https://github.com/supercollider/supercollider/pull/1936) by [timblechmann](https://github.com/timblechmann) ## quarks - quarks: sort list by name [#2214](https://github.com/supercollider/supercollider/pull/2214) by [gusano](https://github.com/gusano) - quarks: throw an error when updating without name [#2183](https://github.com/supercollider/supercollider/pull/2183) by [gusano](https://github.com/gusano) ## architecture: arm - Provide compiler flags for armv6l and armv7l and add a few hints for building on RPi and headless [#2065](https://github.com/supercollider/supercollider/pull/2065) by [bagong](https://github.com/bagong) ## bug - ServerStatus failOSCFunc shouldn't set clientID [#2328](https://github.com/supercollider/supercollider/issues/2328) by [crucialfelix](https://github.com/crucialfelix) - class library: server notify dependants correctly [#2093](https://github.com/supercollider/supercollider/pull/2093) by [telephon](https://github.com/telephon) - Topic fix server notify [#2066](https://github.com/supercollider/supercollider/pull/2066) by [telephon](https://github.com/telephon) - OSC/Trigger functionality broken in master [#2058](https://github.com/supercollider/supercollider/issues/2058) by [miczac](https://github.com/miczac) - Problem with matchLangIP primitive: boost seems to give wrong hostname [#1950](https://github.com/supercollider/supercollider/issues/1950) by [muellmusik](https://github.com/muellmusik) - crash on exit, 3.7b [#1422](https://github.com/supercollider/supercollider/issues/1422) by [chriskiefer](https://github.com/chriskiefer) - DemandEnvGen overshooting at high curve [#1355](https://github.com/supercollider/supercollider/issues/1355) by [eleses](https://github.com/eleses) - scsynth OSC packet size in NRT mode [#61](https://github.com/supercollider/supercollider/issues/61) by [jleben](https://github.com/jleben) ## enhancement - Novacollider/alignment cleanups [#1906](https://github.com/supercollider/supercollider/pull/1906) by [timblechmann](https://github.com/timblechmann) - ide: introspection - use qt's concurrency functionality [#1905](https://github.com/supercollider/supercollider/pull/1905) by [timblechmann](https://github.com/timblechmann) - Novacollider/dll [#1904](https://github.com/supercollider/supercollider/pull/1904) by [timblechmann](https://github.com/timblechmann) - Tab does not work in IDE (on OSX) [#1453](https://github.com/supercollider/supercollider/issues/1453) by [thormagnusson](https://github.com/thormagnusson) - Use reader/writer thread for all disk IO (DiskIn / DiskOut ugens, others if applicable) [#1381](https://github.com/supercollider/supercollider/issues/1381) by [scztt](https://github.com/scztt) ## Miscellaneous - Add missing proxy init 3.8 [#2407](https://github.com/supercollider/supercollider/pull/2407) by [telephon](https://github.com/telephon) - Merge 3.7.2 to master [#2177](https://github.com/supercollider/supercollider/pull/2177) by [crucialfelix](https://github.com/crucialfelix) - Update CombC.schelp [#2157](https://github.com/supercollider/supercollider/pull/2157) by [tiagmoraismorgado](https://github.com/tiagmoraismorgado) - Array2D.schelp: Fix put example [#2154](https://github.com/supercollider/supercollider/pull/2154) by [kisielk](https://github.com/kisielk) - jitlib: better warnings when Server is not available [#2119](https://github.com/supercollider/supercollider/pull/2119) by [telephon](https://github.com/telephon) - Topic/boost 1.61 [#2086](https://github.com/supercollider/supercollider/pull/2086) by [timblechmann](https://github.com/timblechmann) - lang: correctly join resync thread [#2079](https://github.com/supercollider/supercollider/pull/2079) by [timblechmann](https://github.com/timblechmann) - Helpfile-fixing branch, final merge [#2076](https://github.com/supercollider/supercollider/pull/2076) by [LFSaw](https://github.com/LFSaw) - ide: mark scide as able to handle multiple files [#2062](https://github.com/supercollider/supercollider/pull/2062) by [fsateler](https://github.com/fsateler) - removed method::preferencesAction [#2046](https://github.com/supercollider/supercollider/pull/2046) by [tapage](https://github.com/tapage) - fixed naming startframe & aSoundFile [#2045](https://github.com/supercollider/supercollider/pull/2045) by [tapage](https://github.com/tapage) - prReadDirectoryFile private, added done as arg [#2044](https://github.com/supercollider/supercollider/pull/2044) by [tapage](https://github.com/tapage) - added Pmul arguments name & pattern [#2043](https://github.com/supercollider/supercollider/pull/2043) by [tapage](https://github.com/tapage) - LFSaw.schelp: Note and example for special initial-phase behaviour [#2041](https://github.com/supercollider/supercollider/pull/2041) by [miczac](https://github.com/miczac) - Emacs and extBuffer.sc [#2035](https://github.com/supercollider/supercollider/issues/2035) by [simdax](https://github.com/simdax) - Help: Removed double PlayBuf in doneAction help file [#2026](https://github.com/supercollider/supercollider/pull/2026) by [cappelnord](https://github.com/cappelnord) - Classlib: Add NodeProxy:trace [#2020](https://github.com/supercollider/supercollider/pull/2020) by [jamshark70](https://github.com/jamshark70) - PartConv not working (duplicate impulses) [#2014](https://github.com/supercollider/supercollider/issues/2014) by [sonoro1234](https://github.com/sonoro1234) - Server crash when calling play on a not-yet ready Buffer [#2005](https://github.com/supercollider/supercollider/issues/2005) by [patrickdupuis](https://github.com/patrickdupuis) - Make sure NodeProxy generates unique name. [#1994](https://github.com/supercollider/supercollider/pull/1994) by [blacksound](https://github.com/blacksound) - class library: node proxy, improve documentation [#1986](https://github.com/supercollider/supercollider/pull/1986) by [telephon](https://github.com/telephon) - Osc.sc: fix audio rate TChoose [#1979](https://github.com/supercollider/supercollider/pull/1979) by [miczac](https://github.com/miczac) - Osc.sc: fix audio rate TChoose [#1974](https://github.com/supercollider/supercollider/pull/1974) by [miczac](https://github.com/miczac) - Readd wrongly removed part of system-boost fix [#1970](https://github.com/supercollider/supercollider/pull/1970) by [bagong](https://github.com/bagong) - Merge 3.7 into master [#1969](https://github.com/supercollider/supercollider/pull/1969) by [bagong](https://github.com/bagong) - Add CommonTests and CommonTestsGUI to travis [#1967](https://github.com/supercollider/supercollider/pull/1967) by [scztt](https://github.com/scztt) - Fix lines and functions with mixed tabs and spaces [#1963](https://github.com/supercollider/supercollider/pull/1963) by [vivid-synth](https://github.com/vivid-synth) - Remove unused variable [#1960](https://github.com/supercollider/supercollider/pull/1960) by [patrickdupuis](https://github.com/patrickdupuis) - error message: wrong path in unsaved file [#1953](https://github.com/supercollider/supercollider/issues/1953) by [telephon](https://github.com/telephon) - class library: don't declare variables in an if statement, please. [#1925](https://github.com/supercollider/supercollider/pull/1925) by [telephon](https://github.com/telephon) - Add custom.css to help files that don't include it [#1920](https://github.com/supercollider/supercollider/pull/1920) by [snappizz](https://github.com/snappizz) - Document SynthDef.writeOnce as a legacy method [#1918](https://github.com/supercollider/supercollider/pull/1918) by [snappizz](https://github.com/snappizz) - Move internal css to scdoc.css [#1917](https://github.com/supercollider/supercollider/pull/1917) by [rygen](https://github.com/rygen) - Fix Scope Window Error [#1915](https://github.com/supercollider/supercollider/pull/1915) by [patrickdupuis](https://github.com/patrickdupuis) - Quarks: fix save method [#1897](https://github.com/supercollider/supercollider/pull/1897) by [jpburstrom](https://github.com/jpburstrom) - ide: Add standalone option in settings. [#1863](https://github.com/supercollider/supercollider/pull/1863) by [miguel-negrao](https://github.com/miguel-negrao) - sclang: introduce unixCmd for array of arguments [#1856](https://github.com/supercollider/supercollider/pull/1856) by [miguel-negrao](https://github.com/miguel-negrao) - uiugens: correctly terminate input threads [#1855](https://github.com/supercollider/supercollider/pull/1855) by [timblechmann](https://github.com/timblechmann) - supernova: don't delete shared memory data [#1854](https://github.com/supercollider/supercollider/pull/1854) by [timblechmann](https://github.com/timblechmann) - Novacollider/mac [#1853](https://github.com/supercollider/supercollider/pull/1853) by [timblechmann](https://github.com/timblechmann) - class library: HIDMatchers: Add missing if statement [#1851](https://github.com/supercollider/supercollider/pull/1851) by [davidgranstrom](https://github.com/davidgranstrom) - class library: protect MultiOutUGen from void numChannels [#1847](https://github.com/supercollider/supercollider/pull/1847) by [telephon](https://github.com/telephon) - Fixes/for master [#1844](https://github.com/supercollider/supercollider/pull/1844) by [timblechmann](https://github.com/timblechmann) - Topic/rate fallthrough [#1835](https://github.com/supercollider/supercollider/pull/1835) by [telephon](https://github.com/telephon) - Novacollider/cmake modernisation [#1822](https://github.com/supercollider/supercollider/pull/1822) by [timblechmann](https://github.com/timblechmann) - LinXFade2 - fix pos slope [#1798](https://github.com/supercollider/supercollider/pull/1798) by [timblechmann](https://github.com/timblechmann) - ide cleanup [#1715](https://github.com/supercollider/supercollider/pull/1715) by [timblechmann](https://github.com/timblechmann) - MultiOutUGen with numchannels less than 1 return an empty array [#1686](https://github.com/supercollider/supercollider/issues/1686) by [telephon](https://github.com/telephon) - use c++17-style executors to compile class library [#1677](https://github.com/supercollider/supercollider/pull/1677) by [timblechmann](https://github.com/timblechmann) - scide: improve dark color scheme [#1609](https://github.com/supercollider/supercollider/pull/1609) by [timblechmann](https://github.com/timblechmann) - scide: add qt-creator style shortcut sequence to visualise whitespaces [#1607](https://github.com/supercollider/supercollider/pull/1607) by [timblechmann](https://github.com/timblechmann) - Topic/refactor server status [#1547](https://github.com/supercollider/supercollider/pull/1547) by [telephon](https://github.com/telephon) - Enabling multi-touch on Qt widgets (for multi-touch screens) [#1533](https://github.com/supercollider/supercollider/pull/1533) by [scazan](https://github.com/scazan) - import boost-1.58 [#1528](https://github.com/supercollider/supercollider/pull/1528) by [timblechmann](https://github.com/timblechmann) - Scide/line number fix [#1330](https://github.com/supercollider/supercollider/pull/1330) by [vdonnefort](https://github.com/vdonnefort) - Scide/theme mgmt fix [#1297](https://github.com/supercollider/supercollider/pull/1297) by [vdonnefort](https://github.com/vdonnefort) - Made performKeyToDegree much closer to inverse of performDegreeToKey [#1164](https://github.com/supercollider/supercollider/pull/1164) by [triss](https://github.com/triss) ## [3.7.2](https://github.com/supercollider/supercollider/tree/3.7.2) (2016-06-03) [Full Changelog](https://github.com/supercollider/supercollider/compare/Version-3.7.1...Version-3.7.2) This patch release fixes the Windows including MIDI. HID is still not quite working on Windows. Many thanks to: @bagong and @llloret SC VIM is now a git submodule. This affects mainly developers. VIM support can be installed as per the documentation - nothing has changed in how you use it. We changed this in 3.7.2 as well as on master (3.8 development) so that switching back and forth between branches wouldn't be super annoying. **Fixes:** - Midi not working on Windows [\#1922](https://github.com/supercollider/supercollider/issues/1922) - Windows: opening SC via system registered document types faulty [\#2022](https://github.com/supercollider/supercollider/issues/2022) - HIDdef.element forwards arguments incorrectly [\#2090](https://github.com/supercollider/supercollider/issues/2090) **Closed Pull Requests** - midi: make midi work in Windows [\#2009](https://github.com/supercollider/supercollider/pull/2009) ([llloret](https://github.com/llloret)) - Classlib: Fix HIDdef.element arg list passed to super.element [\#2105](https://github.com/supercollider/supercollider/pull/2105) ([jamshark70](https://github.com/jamshark70)) - Fix build on debian, add -fPIC to TLSF target [\#2031](https://github.com/supercollider/supercollider/pull/2031) ([danstowell](https://github.com/danstowell)) - Update linux readme, add missing dependency [\#2030](https://github.com/supercollider/supercollider/pull/2030) ([danstowell](https://github.com/danstowell)) - editor: windows: fix double click when app already open [\#2029](https://github.com/supercollider/supercollider/pull/2029) ([llloret](https://github.com/llloret)) - nsis: windows: add path information [\#2028](https://github.com/supercollider/supercollider/pull/2028) ([llloret](https://github.com/llloret)) - Convert scvim to submodule, on 3.7 branch [\#2025](https://github.com/supercollider/supercollider/pull/2025) ([danstowell](https://github.com/danstowell)) - lang: Not wait for keystroke when exiting [\#2012](https://github.com/supercollider/supercollider/pull/2012) ([llloret](https://github.com/llloret)) - Windows Readme: tiny enhancements [\#2006](https://github.com/supercollider/supercollider/pull/2006) ([bagong](https://github.com/bagong)) - Make sure NodeProxy generates unique name. [\#1998](https://github.com/supercollider/supercollider/pull/1998) ([blacksound](https://github.com/blacksound)) - Cherry pick telefon's nodeproxy documentation enhancements [\#1996](https://github.com/supercollider/supercollider/pull/1996) ([bagong](https://github.com/bagong)) ## [3.7.1](https://github.com/supercollider/supercollider/tree/3.7.1) (2016-04-10) [Full Changelog](https://github.com/supercollider/supercollider/compare/Version-3.7.0...Version-3.7.1) **Enhancements** - Native FLAC support for scsynth on OS X [\#1783](https://github.com/supercollider/supercollider/issues/1783) - Libsndfile: have cmake prefer homebrew install over bundled version [\#1870](https://github.com/supercollider/supercollider/pull/1870) ([bagong](https://github.com/bagong)) - OS X Readme: note that Qt 5.5 is required, not Qt 5.6 [\#1931](https://github.com/supercollider/supercollider/issues/1931) - class library: node proxy: improve shape error post [\#1889](https://github.com/supercollider/supercollider/pull/1889) ([telephon](https://github.com/telephon)) - Server.schelp: fixed description of scsynth method, changed wording, … [\#1894](https://github.com/supercollider/supercollider/pull/1894) ([miczac](https://github.com/miczac)) **Fixes:** - Windows build system [\#1900](https://github.com/supercollider/supercollider/pull/1900) ([bagong](https://github.com/bagong)) - cmake: fix build when using system boost [\#1896](https://github.com/supercollider/supercollider/pull/1896) ([danstowell](https://github.com/danstowell)) - Correct accidental msys leftovers in findPortaudio [\#1941](https://github.com/supercollider/supercollider/pull/1941) ([bagong](https://github.com/bagong)) - Remove -fstrict-aliasing from the MinGW build to allow using MinGW 4.9.2 [\#1923](https://github.com/supercollider/supercollider/pull/1923) ([bagong](https://github.com/bagong)) - Quarks.update\("quarkname"\) does not always update correctly [\#1895](https://github.com/supercollider/supercollider/issues/1895) - fix \#1895 : update Quark by `git pull` and `git checkout master` [\#1954](https://github.com/supercollider/supercollider/pull/1954) ([crucialfelix](https://github.com/crucialfelix)) - Quarks Windows fixes [\#1956](https://github.com/supercollider/supercollider/pull/1956) ([bagong](https://github.com/bagong)) - Errors when closing scope window [\#1878](https://github.com/supercollider/supercollider/issues/1878) ## [3.7.0](https://github.com/supercollider/supercollider/tree/3.7.0) (2016-03-13) [Full Changelog](https://github.com/supercollider/supercollider/compare/Version-3.6.6...Version-3.7.0) **Enhancements** - New Quarks system using Git [\#1800](https://github.com/supercollider/supercollider/issues/1800) - Qt GUI: TextView's enterInterpretsSelection treats line wrapping like a hard line break [\#1637](https://github.com/supercollider/supercollider/issues/1637) - UnitTest missing documentation [\#1610](https://github.com/supercollider/supercollider/issues/1610) - LinLog function? [\#1555](https://github.com/supercollider/supercollider/issues/1555) - sclang and scserver use the same icon [\#1548](https://github.com/supercollider/supercollider/issues/1548) - help: recent changes for 3.7 documentation [\#1516](https://github.com/supercollider/supercollider/issues/1516) - MIDIFunc does not deal with allNotesOff message [\#1485](https://github.com/supercollider/supercollider/issues/1485) - Tab does not work in IDE \(on OSX\) [\#1453](https://github.com/supercollider/supercollider/issues/1453) - Feature: IDE preference to disable displaying help pages in the autocomplete popup [\#1435](https://github.com/supercollider/supercollider/issues/1435) - quarks \(new\) - suggestion - directory.txt use https instead of git protocol. [\#1397](https://github.com/supercollider/supercollider/issues/1397) - quarks \(new\) - Add a way to update quarks \(git pull or delete folder and clone again\) [\#1386](https://github.com/supercollider/supercollider/issues/1386) - Use reader/writer thread for all disk IO \(DiskIn / DiskOut ugens, others if applicable\) [\#1381](https://github.com/supercollider/supercollider/issues/1381) - quarks \(new\) - canceling git checkout [\#1376](https://github.com/supercollider/supercollider/issues/1376) - help: News in 3.7 [\#1347](https://github.com/supercollider/supercollider/issues/1347) - class library: addition of SimpleController::removeAt [\#1328](https://github.com/supercollider/supercollider/issues/1328) - scsynth ought to print the version number when passed the --version flag [\#1310](https://github.com/supercollider/supercollider/issues/1310) - UGen to report node ID [\#1212](https://github.com/supercollider/supercollider/issues/1212) - incomprehenisble error message with Function-play and empty array [\#1128](https://github.com/supercollider/supercollider/issues/1128) - pattern cleanup shouldn't be passed around [\#1049](https://github.com/supercollider/supercollider/issues/1049) - README file and windows build instructions [\#1034](https://github.com/supercollider/supercollider/issues/1034) - Enhance OSX readme for 3.6.6 [\#1001](https://github.com/supercollider/supercollider/issues/1001) - README\_OS\_X.txt is overly complex [\#960](https://github.com/supercollider/supercollider/issues/960) - "Exception when parsing synthdef: corrupted synthdef" - report which synthdef caused the error. [\#904](https://github.com/supercollider/supercollider/issues/904) - "start coding" window title [\#898](https://github.com/supercollider/supercollider/issues/898) - Windows: No 64-bit version [\#853](https://github.com/supercollider/supercollider/issues/853) - toggle dumpOSC via menu entry [\#848](https://github.com/supercollider/supercollider/issues/848) - default file extension missing [\#838](https://github.com/supercollider/supercollider/issues/838) - open file dialog: start in last used directory across sessions [\#805](https://github.com/supercollider/supercollider/issues/805) - recent files: hide no-longer existent files [\#804](https://github.com/supercollider/supercollider/issues/804) - Faint highlighting on the cursor's line [\#793](https://github.com/supercollider/supercollider/issues/793) - display volume in server status bar [\#762](https://github.com/supercollider/supercollider/issues/762) - mouse wheel volume control \(server status bar\) [\#760](https://github.com/supercollider/supercollider/issues/760) - post message in post window when sclang quits/crashes [\#743](https://github.com/supercollider/supercollider/issues/743) - I would like to ask for a ListView.selection\_ method. [\#741](https://github.com/supercollider/supercollider/issues/741) - Autosave [\#725](https://github.com/supercollider/supercollider/issues/725) - NRT message length limit [\#714](https://github.com/supercollider/supercollider/issues/714) - problems with PandaboardES and SC [\#689](https://github.com/supercollider/supercollider/issues/689) - More obvious access to SCIDE help file [\#682](https://github.com/supercollider/supercollider/issues/682) - get rid of jitter for non time stamped bundles [\#648](https://github.com/supercollider/supercollider/issues/648) - Popup Index for class file tabs [\#629](https://github.com/supercollider/supercollider/issues/629) - semicolon ending block evaluation [\#627](https://github.com/supercollider/supercollider/issues/627) - Missing functionality in Qt: QuartzComposer [\#624](https://github.com/supercollider/supercollider/issues/624) - Missing functionality in Qt: Checking whether a window is closed [\#622](https://github.com/supercollider/supercollider/issues/622) - Missing functionality in Qt: SCMenuItem [\#617](https://github.com/supercollider/supercollider/issues/617) - Missing functionality in Qt: SCImage [\#616](https://github.com/supercollider/supercollider/issues/616) - Please make ctrl-return behavior configurable WRT execute region [\#603](https://github.com/supercollider/supercollider/issues/603) - Command like "Balance Parens" from sc.app [\#602](https://github.com/supercollider/supercollider/issues/602) - Soften, or allow customizing, the bracket-mismatch color [\#599](https://github.com/supercollider/supercollider/issues/599) - Tab behaviour [\#593](https://github.com/supercollider/supercollider/issues/593) - scide - help browser window font should be adjustable [\#587](https://github.com/supercollider/supercollider/issues/587) - hide line numbers [\#585](https://github.com/supercollider/supercollider/issues/585) - "Start sclang" should be greyed out when language is running [\#584](https://github.com/supercollider/supercollider/issues/584) - Double-click on a float doesn't select all of it [\#581](https://github.com/supercollider/supercollider/issues/581) - Hitting Cmd/Ctrl while inertial scrolling causes rapid zoom in / out [\#568](https://github.com/supercollider/supercollider/issues/568) - find next / previous key binding [\#555](https://github.com/supercollider/supercollider/issues/555) - If untitled doc from start has not been used close it when first file is opened [\#553](https://github.com/supercollider/supercollider/issues/553) - Undocking widgets and tabs as proper windows [\#550](https://github.com/supercollider/supercollider/issues/550) - Move cursor to end of document on down arrow key in last line. [\#543](https://github.com/supercollider/supercollider/issues/543) - New method to get complete \(multiple\) item selection from QListView and QTreeView [\#535](https://github.com/supercollider/supercollider/issues/535) - Several items in the preferences can be set to the same shortcut [\#516](https://github.com/supercollider/supercollider/issues/516) - language config dialog [\#515](https://github.com/supercollider/supercollider/issues/515) - bracket auto-paring [\#513](https://github.com/supercollider/supercollider/issues/513) - A few basic issues concerning the replacement of SCApp by SCIDE [\#511](https://github.com/supercollider/supercollider/issues/511) - ctrl-click on document icon to open file path [\#510](https://github.com/supercollider/supercollider/issues/510) - support for editing plain-text files [\#495](https://github.com/supercollider/supercollider/issues/495) - Method Call Assist: Handy way to insert an argument name for keyword addressing [\#492](https://github.com/supercollider/supercollider/issues/492) - integrate scdoc into ide [\#471](https://github.com/supercollider/supercollider/issues/471) - Class method autocompletion and method signatures of view redirect classes [\#469](https://github.com/supercollider/supercollider/issues/469) - \(Future\) More sophisticated regexp find/replace [\#464](https://github.com/supercollider/supercollider/issues/464) - Looking up definition from post window [\#461](https://github.com/supercollider/supercollider/issues/461) - Request keyboard shortcut to navigate up/down to the next empty line [\#453](https://github.com/supercollider/supercollider/issues/453) - rtf import of \(erroneous\) weblinks [\#448](https://github.com/supercollider/supercollider/issues/448) - Document open/save dialogs: Keyboard shortcut to navigate to the parent folder [\#445](https://github.com/supercollider/supercollider/issues/445) - Keyboard shortcut to select a code block enclosed in \(\) [\#444](https://github.com/supercollider/supercollider/issues/444) - Dark-on-light color scheme: orange for ~envVars is too bright [\#442](https://github.com/supercollider/supercollider/issues/442) - Shortcuts to add and remove /\* \*/ pairs [\#441](https://github.com/supercollider/supercollider/issues/441) - Add menu command to save all dirty files [\#439](https://github.com/supercollider/supercollider/issues/439) - make post window scrollback configurable [\#430](https://github.com/supercollider/supercollider/issues/430) - switch session dialog [\#429](https://github.com/supercollider/supercollider/issues/429) - case-insensitive search in `open definition' dialog [\#428](https://github.com/supercollider/supercollider/issues/428) - Documentation dock widget [\#420](https://github.com/supercollider/supercollider/issues/420) - SC-IDE: Show full path somewhere [\#413](https://github.com/supercollider/supercollider/issues/413) - autocompletion for literals and brackets [\#410](https://github.com/supercollider/supercollider/issues/410) - insert key should toggle overwrite mode [\#407](https://github.com/supercollider/supercollider/issues/407) - Save dialog should provide options for scd and sc [\#405](https://github.com/supercollider/supercollider/issues/405) - keyboard shortcut for "clear post window" [\#404](https://github.com/supercollider/supercollider/issues/404) - .sc and .scd links in Help should open in scide [\#402](https://github.com/supercollider/supercollider/issues/402) - Quick toggle of spaces/tab indentation [\#400](https://github.com/supercollider/supercollider/issues/400) - Word wrap [\#399](https://github.com/supercollider/supercollider/issues/399) - Show help and definition don't work on post window [\#398](https://github.com/supercollider/supercollider/issues/398) - F1 is an awkward keyboard shortcut for help on Macs [\#397](https://github.com/supercollider/supercollider/issues/397) - Split pane tabs [\#396](https://github.com/supercollider/supercollider/issues/396) - Provide built-in color schemes [\#387](https://github.com/supercollider/supercollider/issues/387) - Preview of color settings [\#386](https://github.com/supercollider/supercollider/issues/386) - show references to symbol [\#384](https://github.com/supercollider/supercollider/issues/384) - drag/drop support for scide [\#383](https://github.com/supercollider/supercollider/issues/383) - popup list view to cycle open documents [\#382](https://github.com/supercollider/supercollider/issues/382) - scide desktop integration [\#381](https://github.com/supercollider/supercollider/issues/381) - key combinations for commenting/uncommenting [\#380](https://github.com/supercollider/supercollider/issues/380) - programmatically resize or set a preferences for IDE window placement [\#376](https://github.com/supercollider/supercollider/issues/376) - server control widget [\#372](https://github.com/supercollider/supercollider/issues/372) - Instance method auto-completion: group offered methods by name [\#371](https://github.com/supercollider/supercollider/issues/371) - Method call aid: highlight proper argument when entered "by name" [\#370](https://github.com/supercollider/supercollider/issues/370) - Integrate help with auto-completion [\#368](https://github.com/supercollider/supercollider/issues/368) - Do not require a keyword to be selected to lookup implementations or help [\#364](https://github.com/supercollider/supercollider/issues/364) - Related to 312 and 313: Completion of instance methods by user selection of class [\#362](https://github.com/supercollider/supercollider/issues/362) - Option to preserve Poll output w/ lower verbosity [\#350](https://github.com/supercollider/supercollider/issues/350) - Support NRT with no output file, for analysis [\#349](https://github.com/supercollider/supercollider/issues/349) - \[SC-IDE\] Document implementation [\#333](https://github.com/supercollider/supercollider/issues/333) - \[SC-IDE\] Make OSX Bundle [\#331](https://github.com/supercollider/supercollider/issues/331) - \[SC-IDE\] Syntax colorize schelp files [\#330](https://github.com/supercollider/supercollider/issues/330) - \[SC-IDE\] Open file by searching for Class or method in a pop up window. [\#329](https://github.com/supercollider/supercollider/issues/329) - \[SC-IDE\] save or discard changes on quit per unsaved document [\#327](https://github.com/supercollider/supercollider/issues/327) - \[SC-IDE\] Update file view if it is updated by another program [\#326](https://github.com/supercollider/supercollider/issues/326) - \[SC-IDE\] Open recent file menu entry. [\#321](https://github.com/supercollider/supercollider/issues/321) - \[SC-IDE\] Open multiple files at the same time [\#318](https://github.com/supercollider/supercollider/issues/318) - \[SC-IDE\] Visual indicator if file is edited or not [\#317](https://github.com/supercollider/supercollider/issues/317) - show search-replace results in realtime [\#316](https://github.com/supercollider/supercollider/issues/316) - Code completion for Class names with hovering dropdown menu. [\#314](https://github.com/supercollider/supercollider/issues/314) - \[SC-IDE\] Code completion for Class methods with hovering drop-down menu. [\#313](https://github.com/supercollider/supercollider/issues/313) - Hovering popup with argument names for class methods [\#312](https://github.com/supercollider/supercollider/issues/312) - \[SC-IDE\] Open definition of method [\#309](https://github.com/supercollider/supercollider/issues/309) - postln with prefix and suffix [\#306](https://github.com/supercollider/supercollider/issues/306) - .data\_ method for QSoundFileView implementation [\#304](https://github.com/supercollider/supercollider/issues/304) - Proposal for Helpbrowser layout [\#300](https://github.com/supercollider/supercollider/issues/300) - \[Cocoa GUI\] allowsReselection flag on SCPopUpMenu [\#299](https://github.com/supercollider/supercollider/issues/299) - allowsReselection for SC- and Q- listviews and popup menus [\#298](https://github.com/supercollider/supercollider/issues/298) - Implement focusGainedAction/focusLostAction for QtGUI [\#295](https://github.com/supercollider/supercollider/issues/295) - HTML doc and web standards [\#294](https://github.com/supercollider/supercollider/issues/294) - Control over the numeric x-labels in plot2 [\#293](https://github.com/supercollider/supercollider/issues/293) - Implement focusGainedAction/focusLostAction for CocoaGUI [\#291](https://github.com/supercollider/supercollider/issues/291) - Dwrand doesn't exist [\#287](https://github.com/supercollider/supercollider/issues/287) - Send to bus without creating new synths [\#286](https://github.com/supercollider/supercollider/issues/286) - BinaryOpUGen optimization needs review [\#284](https://github.com/supercollider/supercollider/issues/284) - Convolution UGens should all use SC\_fftlib [\#276](https://github.com/supercollider/supercollider/issues/276) - Buffer:normalize [\#275](https://github.com/supercollider/supercollider/issues/275) - test 2 [\#274](https://github.com/supercollider/supercollider/issues/274) - test [\#273](https://github.com/supercollider/supercollider/issues/273) - mapping audio buses as synth controls [\#272](https://github.com/supercollider/supercollider/issues/272) - Getting sound card list with \# of ins/outs from scsynth [\#271](https://github.com/supercollider/supercollider/issues/271) - source code [\#270](https://github.com/supercollider/supercollider/issues/270) - Post window should have correct window title [\#269](https://github.com/supercollider/supercollider/issues/269) - Menu Icon request [\#268](https://github.com/supercollider/supercollider/issues/268) - sources tarball [\#267](https://github.com/supercollider/supercollider/issues/267) - Windows Port [\#266](https://github.com/supercollider/supercollider/issues/266) - Topic/release notes 3 7 0 [\#1791](https://github.com/supercollider/supercollider/pull/1791) ([crucialfelix](https://github.com/crucialfelix)) - Topic/select reject indices [\#1591](https://github.com/supercollider/supercollider/pull/1591) ([LFSaw](https://github.com/LFSaw)) - class library: fuzzy equal with relative precision [\#1587](https://github.com/supercollider/supercollider/pull/1587) ([telephon](https://github.com/telephon)) - Fix range in Function:plot [\#1454](https://github.com/supercollider/supercollider/pull/1454) ([thormagnusson](https://github.com/thormagnusson)) **Fixed bugs:** - scel: Directory change of sclang/scsynth in 3.7-beta1 causing error [\#1860](https://github.com/supercollider/supercollider/issues/1860) - interpreter crashes after server boot when very large scd file is currently open [\#1823](https://github.com/supercollider/supercollider/issues/1823) - SC\_SndBuf.h \(in master\) can't compile on ARM because uses \_mm\_pause [\#1819](https://github.com/supercollider/supercollider/issues/1819) - OS X: scsynth icon bounces forever in the dock [\#1804](https://github.com/supercollider/supercollider/issues/1804) - supernova compilation error [\#1794](https://github.com/supercollider/supercollider/issues/1794) - MulAddUGens broken [\#1793](https://github.com/supercollider/supercollider/issues/1793) - Evaluate commands \(Shift-Enter/Return, Ctrl-Enter/Cmd-Return, menus\) work not reliably [\#1786](https://github.com/supercollider/supercollider/issues/1786) - Bad values \(nan\) from underflow with pow\(\) on Server [\#1766](https://github.com/supercollider/supercollider/issues/1766) - setProperties fails for plots of signals [\#1762](https://github.com/supercollider/supercollider/issues/1762) - Quarks: update fail when missing tag or no new version number [\#1735](https://github.com/supercollider/supercollider/issues/1735) - Quarks.update calls wrong git method [\#1734](https://github.com/supercollider/supercollider/issues/1734) - Typo / wrong cmake function name in CMakeLists.txt [\#1705](https://github.com/supercollider/supercollider/issues/1705) - TwoWayIdentityDictionary.asCompileString misses to include key [\#1699](https://github.com/supercollider/supercollider/issues/1699) - error with soundfileview.schelp [\#1682](https://github.com/supercollider/supercollider/issues/1682) - Quarks on Windows: isPath regex is wrong [\#1670](https://github.com/supercollider/supercollider/issues/1670) - Windows File.existsCaseSensitive does not work for directories [\#1668](https://github.com/supercollider/supercollider/issues/1668) - calling ScIDE prSend from a routine makes the ide unreachable [\#1657](https://github.com/supercollider/supercollider/issues/1657) - EnvGen \cub produces NaNs [\#1656](https://github.com/supercollider/supercollider/issues/1656) - Scale.choose throws error [\#1653](https://github.com/supercollider/supercollider/issues/1653) - d\_removed [\#1648](https://github.com/supercollider/supercollider/issues/1648) - Triggering EnvGen with Impulse.ar crashes the server [\#1642](https://github.com/supercollider/supercollider/issues/1642) - DetectSilence won't free if it never encounters nonzero value [\#1639](https://github.com/supercollider/supercollider/issues/1639) - IDE: Colorizer highlights "pi" at the start of a word [\#1613](https://github.com/supercollider/supercollider/issues/1613) - LanguageConfig-includePaths stack overflow [\#1604](https://github.com/supercollider/supercollider/issues/1604) - Removing Application Support/SuperCollider causes SCDoc to crash the interpreter [\#1589](https://github.com/supercollider/supercollider/issues/1589) - supernova tries to set unallocated memory in b\_set and b\_setn [\#1588](https://github.com/supercollider/supercollider/issues/1588) - failed to read Quark directory listing [\#1585](https://github.com/supercollider/supercollider/issues/1585) - Example code in documentation doesn't play for LocalIn function. Missing Out.ar\(0,local\); [\#1563](https://github.com/supercollider/supercollider/issues/1563) - OscUGens.cpp omits the required DefineSimpleUnit call for PSinGrain [\#1556](https://github.com/supercollider/supercollider/issues/1556) - MethodOverride.printAll fails on OSX 10.8 [\#1538](https://github.com/supercollider/supercollider/issues/1538) - NRT realloc failure [\#1537](https://github.com/supercollider/supercollider/issues/1537) - useSystemClock breaks the server [\#1534](https://github.com/supercollider/supercollider/issues/1534) - evaluating code in the help browser evaluates code in the document window instead [\#1532](https://github.com/supercollider/supercollider/issues/1532) - Installing Quark with an invalid refspec should throw an error [\#1531](https://github.com/supercollider/supercollider/issues/1531) - FreqScope doesn't work [\#1527](https://github.com/supercollider/supercollider/issues/1527) - reboot of the internal server crashes interpreter [\#1526](https://github.com/supercollider/supercollider/issues/1526) - Scroll view issue in Qt -- no vertical scroll bar [\#1521](https://github.com/supercollider/supercollider/issues/1521) - \(regression\) Document keyDownActions: discrepancy between global and instance [\#1512](https://github.com/supercollider/supercollider/issues/1512) - Issues with maximized \(fullscreen\) Qt windows on OS X [\#1506](https://github.com/supercollider/supercollider/issues/1506) - WebView auto-closes when used without explicit parent [\#1505](https://github.com/supercollider/supercollider/issues/1505) - LFPulse UGen gives asymmetrical waveform when duty \(width\) is 0.5 [\#1501](https://github.com/supercollider/supercollider/issues/1501) - MIDIdef.mtcQuarterFrame [\#1496](https://github.com/supercollider/supercollider/issues/1496) - WebView closes after displaying scrollbar [\#1489](https://github.com/supercollider/supercollider/issues/1489) - MIDIIn.connectAll connects to wrong ports on Linux [\#1487](https://github.com/supercollider/supercollider/issues/1487) - Sclang client crashes on serial port close from data sender [\#1479](https://github.com/supercollider/supercollider/issues/1479) - Quarks: memory corruption\(s\) [\#1476](https://github.com/supercollider/supercollider/issues/1476) - Windows: New Quarks system: installed Quarks not recognized [\#1475](https://github.com/supercollider/supercollider/issues/1475) - How to complete unload plugins PR? [\#1473](https://github.com/supercollider/supercollider/issues/1473) - Quarks: refix the valueing of isCompatible [\#1463](https://github.com/supercollider/supercollider/issues/1463) - Slider with an increment fires action even when value doesn't change [\#1460](https://github.com/supercollider/supercollider/issues/1460) - Scsynth zombie when quitting scide [\#1456](https://github.com/supercollider/supercollider/issues/1456) - IDE Help popup -\> crash [\#1452](https://github.com/supercollider/supercollider/issues/1452) - Quarks windows path error bug [\#1451](https://github.com/supercollider/supercollider/issues/1451) - Error on interpreter startup [\#1448](https://github.com/supercollider/supercollider/issues/1448) - Font.defaultMonoFace/.defaultSansFace/.defaultSerifFace return the same value [\#1447](https://github.com/supercollider/supercollider/issues/1447) - Switching a session causes the IDE to segfault [\#1430](https://github.com/supercollider/supercollider/issues/1430) - Quarks conflicts with case insensitive file systems [\#1429](https://github.com/supercollider/supercollider/issues/1429) - Using Function-try inside an ArrayedCollection.do loop corrupts interpreter [\#1428](https://github.com/supercollider/supercollider/issues/1428) - MIDIFunc.noteOn does not work with floats when Arrays of numbers are passed [\#1426](https://github.com/supercollider/supercollider/issues/1426) - Sclang keeps crashing on recent build \(Win\) [\#1405](https://github.com/supercollider/supercollider/issues/1405) - Preferences/Editor/Fonts&Colors/Color:Current Line: sample text display doesn't update to the color selected in Text [\#1403](https://github.com/supercollider/supercollider/issues/1403) - icon representation of sclang and scserver: and still jumping [\#1399](https://github.com/supercollider/supercollider/issues/1399) - Blank help window [\#1395](https://github.com/supercollider/supercollider/issues/1395) - ERROR: ScIDE not connected [\#1390](https://github.com/supercollider/supercollider/issues/1390) - scdoc - can't run code from help window. [\#1385](https://github.com/supercollider/supercollider/issues/1385) - GridLayout spanning bug [\#1383](https://github.com/supercollider/supercollider/issues/1383) - Server window should use reasonable default record buffer size [\#1380](https://github.com/supercollider/supercollider/issues/1380) - quarks \(new\) - installing local quark does not install it's dependencies it only links. [\#1378](https://github.com/supercollider/supercollider/issues/1378) - quarks \(new\) - dependencies specified with git url and refspec not working ? [\#1377](https://github.com/supercollider/supercollider/issues/1377) - Server Gui volume bug \(gitreports.com\) [\#1370](https://github.com/supercollider/supercollider/issues/1370) - LanguageConfig.current problems [\#1369](https://github.com/supercollider/supercollider/issues/1369) - same cubic icon with scide and sclang \(OS X\) [\#1367](https://github.com/supercollider/supercollider/issues/1367) - OSX/IDE: default key for "trigger autocomplete" cmd-space conflicts with spotlight [\#1365](https://github.com/supercollider/supercollider/issues/1365) - IDE: Splits & Tool panels: after closing panel with esc keyboard focus will always move to top left split/pane [\#1363](https://github.com/supercollider/supercollider/issues/1363) - New Quarks: if sclang\_config.yaml doesn't exist prior to install of Quark, include-path is not written [\#1362](https://github.com/supercollider/supercollider/issues/1362) - Quarks install on Windows fails in parseQuarkName [\#1346](https://github.com/supercollider/supercollider/issues/1346) - fix travis builds posting to github [\#1339](https://github.com/supercollider/supercollider/issues/1339) - DiskIOUGens zombies [\#1331](https://github.com/supercollider/supercollider/issues/1331) - supernova dont report lateness [\#1323](https://github.com/supercollider/supercollider/issues/1323) - .argumentString fails for Methods with argNames==nil [\#1320](https://github.com/supercollider/supercollider/issues/1320) - Delay1's first output sample is its input, rather than 0 [\#1313](https://github.com/supercollider/supercollider/issues/1313) - Poll ignores initial trigger [\#1312](https://github.com/supercollider/supercollider/issues/1312) - OSCdef:free does not free OSCdef when \(srcID != nil\) [\#1306](https://github.com/supercollider/supercollider/issues/1306) - GeneralHID documentation misleading [\#1303](https://github.com/supercollider/supercollider/issues/1303) - drag and drop files to expand paths broken [\#1295](https://github.com/supercollider/supercollider/issues/1295) - LinXFade2 pans backward in at least some cases [\#1294](https://github.com/supercollider/supercollider/issues/1294) - Disable tokenizing and auto-indent for schelp documents [\#1292](https://github.com/supercollider/supercollider/issues/1292) - \_String\_Format primitive eats backslashes [\#1291](https://github.com/supercollider/supercollider/issues/1291) - argumentString includes 'this' for Method [\#1289](https://github.com/supercollider/supercollider/issues/1289) - ide "Open Recent" doesn't update when loading a new session [\#1287](https://github.com/supercollider/supercollider/issues/1287) - MultiSliderView.action\_ not triggered by value changes via keyboard [\#1285](https://github.com/supercollider/supercollider/issues/1285) - TRand, TExpRand, TIRand are broken for audio-rate inputs [\#1278](https://github.com/supercollider/supercollider/issues/1278) - UserView with drawFunc loops infinitely when resized by code [\#1274](https://github.com/supercollider/supercollider/issues/1274) - HelpSource is not installed on Linux anymore [\#1273](https://github.com/supercollider/supercollider/issues/1273) - MoreDocument: selectionStart doesn't update upon document changes [\#1254](https://github.com/supercollider/supercollider/issues/1254) - cmake version should be over 2.8.11 for 3.7 [\#1247](https://github.com/supercollider/supercollider/issues/1247) - notes may hang in NodeProxy when using synth def names \(symbols\) [\#1246](https://github.com/supercollider/supercollider/issues/1246) - "String".newTextWindow complaints [\#1238](https://github.com/supercollider/supercollider/issues/1238) - Primitive '\_ScIDE\_SetDocSelectionMirror' failed. [\#1228](https://github.com/supercollider/supercollider/issues/1228) - dumpOSC method posts status messages when it shouldn't [\#1227](https://github.com/supercollider/supercollider/issues/1227) - recent build - osx crashes 10.7 [\#1226](https://github.com/supercollider/supercollider/issues/1226) - getting these errors WARNING: Attempted to modify missing Text Mirror for Document [\#1220](https://github.com/supercollider/supercollider/issues/1220) - .post in .onFree\(\) doesn't post. [\#1219](https://github.com/supercollider/supercollider/issues/1219) - help-installation broken - possibly under Linux only [\#1218](https://github.com/supercollider/supercollider/issues/1218) - REPL sometimes doesn't Post [\#1216](https://github.com/supercollider/supercollider/issues/1216) - TGrains & LocalBuf [\#1204](https://github.com/supercollider/supercollider/issues/1204) - linux: MIDI - rescanning MIDI.connectAll does not note new ports without disposing client first [\#1194](https://github.com/supercollider/supercollider/issues/1194) - incorrect plugin directory in cmake: exception in GraphDef\_Recv: UGen 'Control' not installed [\#1181](https://github.com/supercollider/supercollider/issues/1181) - BlockSize UGen not working due to typo Blocksize -\> BlockSize [\#1180](https://github.com/supercollider/supercollider/issues/1180) - fatal error: tlsf.h: No such file or directory [\#1176](https://github.com/supercollider/supercollider/issues/1176) - help not installed properly \(at least under Linux\) [\#1174](https://github.com/supercollider/supercollider/issues/1174) - Keyboard-shortcuts that contain right or left arrow are not persistent across sc restart [\#1170](https://github.com/supercollider/supercollider/issues/1170) - Menu-item 'Show Spaces and Docs' confusing [\#1169](https://github.com/supercollider/supercollider/issues/1169) - Pbindef broken when overloading play key [\#1167](https://github.com/supercollider/supercollider/issues/1167) - DiskIn channel limitation [\#1162](https://github.com/supercollider/supercollider/issues/1162) - Document.globalKeyDownAction doesn't apply to new code windows in the IDE [\#1159](https://github.com/supercollider/supercollider/issues/1159) - synth order shouldn't matter for TrigControl [\#1145](https://github.com/supercollider/supercollider/issues/1145) - two Dictionaries merge to an Event [\#1142](https://github.com/supercollider/supercollider/issues/1142) - Crash after launching sc with floating Doc panel [\#1139](https://github.com/supercollider/supercollider/issues/1139) - Qt5 branch in Ubuntu exhibits some seriously weird behavior [\#1138](https://github.com/supercollider/supercollider/issues/1138) - ide toggle "Dump OSC" sticks when recompiling sclang [\#1136](https://github.com/supercollider/supercollider/issues/1136) - Commit f7b708553 breaks Pan2 where a mono NodeProxy is the source [\#1116](https://github.com/supercollider/supercollider/issues/1116) - JitLib: Ndef.play sending stereo output to bus 0 [\#1114](https://github.com/supercollider/supercollider/issues/1114) - Jitlib: Ndef\(\y\).play\(numChannels:2\) causes error [\#1113](https://github.com/supercollider/supercollider/issues/1113) - scvim doesn't close down properly [\#1111](https://github.com/supercollider/supercollider/issues/1111) - SynthDescLib send can cause recursive sends [\#1110](https://github.com/supercollider/supercollider/issues/1110) - findAllRegexp seems to be broken [\#1108](https://github.com/supercollider/supercollider/issues/1108) - tcp server\<-\>sclang communication is broken in 3.7 [\#1099](https://github.com/supercollider/supercollider/issues/1099) - setting font in TextView fails [\#1097](https://github.com/supercollider/supercollider/issues/1097) - NdefMixer clips output channel to 99 [\#1096](https://github.com/supercollider/supercollider/issues/1096) - Incorrect window position with multiple displays and negative x value [\#1090](https://github.com/supercollider/supercollider/issues/1090) - NdefMixer bug - calling controlspec on EZText [\#1083](https://github.com/supercollider/supercollider/issues/1083) - keyDown in QtGUI doesn't pass char as indicated for non-printing chars [\#1081](https://github.com/supercollider/supercollider/issues/1081) - Plotter doesn't respond to arrays of nil as minval/maxval as expected [\#1078](https://github.com/supercollider/supercollider/issues/1078) - Function-plot scales each channel separately [\#1077](https://github.com/supercollider/supercollider/issues/1077) - server crashes on control rate input to audio rate DelTapWr [\#1065](https://github.com/supercollider/supercollider/issues/1065) - dumpOSC doesn't post array type chars [\#1064](https://github.com/supercollider/supercollider/issues/1064) - EnvGen releases incorrectly for early gate [\#1063](https://github.com/supercollider/supercollider/issues/1063) - switch called with just one function without var declarations crashes sclang [\#1056](https://github.com/supercollider/supercollider/issues/1056) - sclang EXC\_BAD\_ACCESS \(SIGSEGV\) [\#1051](https://github.com/supercollider/supercollider/issues/1051) - Pcollect behaves incorrectly with event as input [\#1048](https://github.com/supercollider/supercollider/issues/1048) - Pcollect behaves incorrectly with event as input [\#1047](https://github.com/supercollider/supercollider/issues/1047) - SplayAz fails when input array has only one element [\#1045](https://github.com/supercollider/supercollider/issues/1045) - SplayAz fails when input is not an array [\#1044](https://github.com/supercollider/supercollider/issues/1044) - multichannel control mapping spill over [\#1037](https://github.com/supercollider/supercollider/issues/1037) - Document title method returns a Symbol - should be a String [\#1031](https://github.com/supercollider/supercollider/issues/1031) - OSX - sclang crashing [\#1030](https://github.com/supercollider/supercollider/issues/1030) - sclang - currently not starting properly on terminal due to new document stuff [\#1026](https://github.com/supercollider/supercollider/issues/1026) - EnvGen releases incorrectly for very very short envelope segments [\#1023](https://github.com/supercollider/supercollider/issues/1023) - 'Host not found' error in 10.9 [\#1016](https://github.com/supercollider/supercollider/issues/1016) - supernova: UIUGens get built but not installed [\#1010](https://github.com/supercollider/supercollider/issues/1010) - Windows - possible fix for if there is no default input or output device on a machine [\#1009](https://github.com/supercollider/supercollider/issues/1009) - dictionary doesn't freeze properly [\#1007](https://github.com/supercollider/supercollider/issues/1007) - .blend outputs array rather than signal in Signal [\#1004](https://github.com/supercollider/supercollider/issues/1004) - long enough function chain causes sclang to output bogus results [\#999](https://github.com/supercollider/supercollider/issues/999) - Cmd-W doesn't close help window when it is detached and front [\#996](https://github.com/supercollider/supercollider/issues/996) - scide: Object::connect: No such slot ScIDE::DocumentManager::updateCurrentDocContents\(int, int, int\) in ../editors/sc-ide/core/doc\_manager.cpp:907 [\#985](https://github.com/supercollider/supercollider/issues/985) - scrolling scide is extremely slow on osx [\#984](https://github.com/supercollider/supercollider/issues/984) - sc does not build against 10.9 sdk [\#982](https://github.com/supercollider/supercollider/issues/982) - sclang consumes high CPU when opening a session with multiple files [\#980](https://github.com/supercollider/supercollider/issues/980) - \[ide\] help-\>"how to use the supercollider ide" detaches help browser [\#976](https://github.com/supercollider/supercollider/issues/976) - NamedControl.new\(\) returns single-element array of Lags when it should return a Lag [\#973](https://github.com/supercollider/supercollider/issues/973) - NdefGUI and related don't show vol labels in IDE [\#965](https://github.com/supercollider/supercollider/issues/965) - Primitive error in \_ScIDE\_SetDocTextMirror called from openDocument [\#964](https://github.com/supercollider/supercollider/issues/964) - ide document: errors when closing document windows during language init [\#961](https://github.com/supercollider/supercollider/issues/961) - SC\_QT=OFF build flag still needs QT on OSX [\#959](https://github.com/supercollider/supercollider/issues/959) - dumpOSC is broken [\#955](https://github.com/supercollider/supercollider/issues/955) - IDE passes wrong Document modifiers to mouseDownAction [\#952](https://github.com/supercollider/supercollider/issues/952) - scope buffer allocation problem [\#937](https://github.com/supercollider/supercollider/issues/937) - Programmatically opening help files bug on linux [\#931](https://github.com/supercollider/supercollider/issues/931) - Sending to a NetAddr with broadcast IP fails [\#930](https://github.com/supercollider/supercollider/issues/930) - Windows - SCIDE: font-size snaps down in editor pane on preferences save/apply [\#928](https://github.com/supercollider/supercollider/issues/928) - QView doesn't receive all key down actions [\#918](https://github.com/supercollider/supercollider/issues/918) - supernova: setting an array onto a control that doesn't exist will set value that does exist [\#916](https://github.com/supercollider/supercollider/issues/916) - Qt menu's with \> 10 items get a scrollbar, and at the same time the view doesn't get wider [\#915](https://github.com/supercollider/supercollider/issues/915) - BinaryOpUGen 'div' operator: off-by-one and not integer division [\#907](https://github.com/supercollider/supercollider/issues/907) - SimpleNumber-curvelin broken for negative numbers [\#902](https://github.com/supercollider/supercollider/issues/902) - switching session: cancel loses unsaved documents and dialog blocks reviewing them [\#899](https://github.com/supercollider/supercollider/issues/899) - Ramp UGen fails in LTI test [\#888](https://github.com/supercollider/supercollider/issues/888) - Pitch UGen fails in unit test [\#884](https://github.com/supercollider/supercollider/issues/884) - prSimpleNumberSeries throws incomprehensible error for bad inputs [\#882](https://github.com/supercollider/supercollider/issues/882) - uiugens: osx uses deprecated API [\#880](https://github.com/supercollider/supercollider/issues/880) - A few UGens failing the unit tests [\#879](https://github.com/supercollider/supercollider/issues/879) - Alias Manager depreated: sc\_ResolveIfAlias will have to be rewritten [\#875](https://github.com/supercollider/supercollider/issues/875) - NodeProxy: multi-channel expansion broken for SynthDefs [\#872](https://github.com/supercollider/supercollider/issues/872) - git clone --recursive is broken [\#866](https://github.com/supercollider/supercollider/issues/866) - Windows: No SCIDE-icon [\#854](https://github.com/supercollider/supercollider/issues/854) - Linux FFT/IFFT: Hann window with hop size 0.25 sounds wrong [\#851](https://github.com/supercollider/supercollider/issues/851) - SendReply kills server [\#850](https://github.com/supercollider/supercollider/issues/850) - SuperCollider can't boot on disabling microphone [\#844](https://github.com/supercollider/supercollider/issues/844) - SendReply.ar crashes the server [\#841](https://github.com/supercollider/supercollider/issues/841) - chained function application giving strange results [\#839](https://github.com/supercollider/supercollider/issues/839) - QListView:items\_ can crash sclang [\#835](https://github.com/supercollider/supercollider/issues/835) - menu items in the title bar vanish when detached window comes in focus [\#829](https://github.com/supercollider/supercollider/issues/829) - ScrollView in Qt - setting visibleOrigin doesn't work unless deferred [\#823](https://github.com/supercollider/supercollider/issues/823) - SinOsc phase argument fails for values outside +-8pi [\#815](https://github.com/supercollider/supercollider/issues/815) - Return key before closing bracket: empty line is not always appropriate [\#814](https://github.com/supercollider/supercollider/issues/814) - Drag-and-drop broken on windows with 'alwaysOnTop' enabled [\#812](https://github.com/supercollider/supercollider/issues/812) - IDE Config \> Editor \> Font Settings: Unsetting "Show only monospaced" doesn't return the previously selected font [\#811](https://github.com/supercollider/supercollider/issues/811) - sclang crashes for some GUI operation involving QTextEngine::itemize\(\) [\#794](https://github.com/supercollider/supercollider/issues/794) - LocalOut without LocalIn crashes the server [\#780](https://github.com/supercollider/supercollider/issues/780) - QWindow crash with wrong argument types [\#770](https://github.com/supercollider/supercollider/issues/770) - s.options.sampleRate\_ setter requires boot then reboot to take effect [\#768](https://github.com/supercollider/supercollider/issues/768) - FreqScope not updating correctly on current development version. [\#767](https://github.com/supercollider/supercollider/issues/767) - Wrongly reported external document changes [\#758](https://github.com/supercollider/supercollider/issues/758) ## [Version-3.6.6](https://github.com/supercollider/supercollider/tree/Version-3.6.6) (2013-11-27) [Full Changelog](https://github.com/supercollider/supercollider/compare/Version-3.6.5...Version-3.6.6) **Enhancements** - Enhance OSX readme for 3.6.6 [\#1001](https://github.com/supercollider/supercollider/issues/1001) - "Exception when parsing synthdef: corrupted synthdef" - report which synthdef caused the error. [\#904](https://github.com/supercollider/supercollider/issues/904) - "start coding" window title [\#898](https://github.com/supercollider/supercollider/issues/898) - default file extension missing [\#838](https://github.com/supercollider/supercollider/issues/838) **Fixed bugs:** - scide: Object::connect: No such slot ScIDE::DocumentManager::updateCurrentDocContents\(int, int, int\) in ../editors/sc-ide/core/doc\_manager.cpp:907 [\#985](https://github.com/supercollider/supercollider/issues/985) - sclang consumes high CPU when opening a session with multiple files [\#980](https://github.com/supercollider/supercollider/issues/980) - \[ide\] help-\>"how to use the supercollider ide" detaches help browser [\#976](https://github.com/supercollider/supercollider/issues/976) - NdefGUI and related don't show vol labels in IDE [\#965](https://github.com/supercollider/supercollider/issues/965) - Primitive error in \_ScIDE\_SetDocTextMirror called from openDocument [\#964](https://github.com/supercollider/supercollider/issues/964) - ide document: errors when closing document windows during language init [\#961](https://github.com/supercollider/supercollider/issues/961) - SC\_QT=OFF build flag still needs QT on OSX [\#959](https://github.com/supercollider/supercollider/issues/959) - Sending to a NetAddr with broadcast IP fails [\#930](https://github.com/supercollider/supercollider/issues/930) - supernova: setting an array onto a control that doesn't exist will set value that does exist [\#916](https://github.com/supercollider/supercollider/issues/916) - BinaryOpUGen 'div' operator: off-by-one and not integer division [\#907](https://github.com/supercollider/supercollider/issues/907) - SimpleNumber-curvelin broken for negative numbers [\#902](https://github.com/supercollider/supercollider/issues/902) - switching session: cancel loses unsaved documents and dialog blocks reviewing them [\#899](https://github.com/supercollider/supercollider/issues/899) - Ramp UGen fails in LTI test [\#888](https://github.com/supercollider/supercollider/issues/888) - prSimpleNumberSeries throws incomprehensible error for bad inputs [\#882](https://github.com/supercollider/supercollider/issues/882) - uiugens: osx uses deprecated API [\#880](https://github.com/supercollider/supercollider/issues/880) - A few UGens failing the unit tests [\#879](https://github.com/supercollider/supercollider/issues/879) - Alias Manager depreated: sc\_ResolveIfAlias will have to be rewritten [\#875](https://github.com/supercollider/supercollider/issues/875) - NodeProxy: multi-channel expansion broken for SynthDefs [\#872](https://github.com/supercollider/supercollider/issues/872) - git clone --recursive is broken [\#866](https://github.com/supercollider/supercollider/issues/866) - Windows: No SCIDE-icon [\#854](https://github.com/supercollider/supercollider/issues/854) - Linux FFT/IFFT: Hann window with hop size 0.25 sounds wrong [\#851](https://github.com/supercollider/supercollider/issues/851) - SendReply kills server [\#850](https://github.com/supercollider/supercollider/issues/850) - SendReply.ar crashes the server [\#841](https://github.com/supercollider/supercollider/issues/841) **Closed issues:** - Error in Help - Getting Started Tutorial Series - Section 2 [\#981](https://github.com/supercollider/supercollider/issues/981) - Crash in creating SynthDef [\#957](https://github.com/supercollider/supercollider/issues/957) - supernova compilation error [\#951](https://github.com/supercollider/supercollider/issues/951) - supercollider-gedit plugin not loading [\#950](https://github.com/supercollider/supercollider/issues/950) - OSCFunc addr.hostname returns nil [\#933](https://github.com/supercollider/supercollider/issues/933) - iOS build, doesn't. [\#927](https://github.com/supercollider/supercollider/issues/927) - Disable mathjax - an unused feature that can cause problems [\#909](https://github.com/supercollider/supercollider/issues/909) - DiskIn channel limitation [\#901](https://github.com/supercollider/supercollider/issues/901) - sclang \(readline\) cannot quit [\#897](https://github.com/supercollider/supercollider/issues/897) - PV\_Copy breaks edge model [\#896](https://github.com/supercollider/supercollider/issues/896) - linux \(debian x64\) compilation error [\#894](https://github.com/supercollider/supercollider/issues/894) - osx/wii uses deprecated/removed API [\#876](https://github.com/supercollider/supercollider/issues/876) - drawFunc drawingEnabled\_\(false\) not respected by refresh [\#869](https://github.com/supercollider/supercollider/issues/869) - file browser lacks default [\#868](https://github.com/supercollider/supercollider/issues/868) - Issue Tracker: user can't enter categories/lables [\#860](https://github.com/supercollider/supercollider/issues/860) - Windows \(installer\): no program shortcuts [\#857](https://github.com/supercollider/supercollider/issues/857) - Windows: installer does not register in system [\#856](https://github.com/supercollider/supercollider/issues/856) - Windows: no file associations [\#855](https://github.com/supercollider/supercollider/issues/855) - Server load percentage on Windows off by factor 100 [\#849](https://github.com/supercollider/supercollider/issues/849) - scsynth sound stops in 3.5 not in 3.4 [\#343](https://github.com/supercollider/supercollider/issues/343) **Merged pull requests:** - class library: pbind midi type - fix for sending sysex [\#947](https://github.com/supercollider/supercollider/pull/947) ([redFrik](https://github.com/redFrik)) - supernova: TCP support [\#757](https://github.com/supercollider/supercollider/issues/757) - sclang crashes when 'connect'ing a NetAddr for TCP [\#755](https://github.com/supercollider/supercollider/issues/755) - EnvGen's gate argument can crash the server [\#753](https://github.com/supercollider/supercollider/issues/753) - s.sync returns too soon after buffer load [\#750](https://github.com/supercollider/supercollider/issues/750) - Broken color dialog [\#749](https://github.com/supercollider/supercollider/issues/749) - Triple-click line selection only works when clicking on strings \[mac\] [\#748](https://github.com/supercollider/supercollider/issues/748) - When undocked, docklets may appear off screen, impossible to move [\#730](https://github.com/supercollider/supercollider/issues/730) - malformed YAML crashes interpreter [\#728](https://github.com/supercollider/supercollider/issues/728) - SequenceableCollection resamp0/1 broken \(e.g. SplayAz\) [\#727](https://github.com/supercollider/supercollider/issues/727) - Shaper should guard against negative buffer numbers [\#722](https://github.com/supercollider/supercollider/issues/722) - wavetable oscillators broken for large wavetables [\#720](https://github.com/supercollider/supercollider/issues/720) - prevent buffer overrun in IO UGens [\#716](https://github.com/supercollider/supercollider/issues/716) - crash report Exception Type: EXC\_BAD\_ACCESS \(SIGSEGV\) [\#715](https://github.com/supercollider/supercollider/issues/715) - Dialog.openPanel hangs on Windows XP [\#707](https://github.com/supercollider/supercollider/issues/707) - SCTextView cmd-d crash [\#702](https://github.com/supercollider/supercollider/issues/702) - cmd+B quite server as default is really unsafe for performance [\#699](https://github.com/supercollider/supercollider/issues/699) - Knob does not allow change of background color [\#697](https://github.com/supercollider/supercollider/issues/697) - Platform.getMouseCoords does not work [\#696](https://github.com/supercollider/supercollider/issues/696) - scope issues: dies with CmdPeriod, not old behaviour [\#695](https://github.com/supercollider/supercollider/issues/695) - Spawner:suspend doesn't execute EventStreamCleanup actions [\#681](https://github.com/supercollider/supercollider/issues/681) - IDE window looses focus when subwindow is closed without action \(OS X\) [\#678](https://github.com/supercollider/supercollider/issues/678) - selected text gets deselected when IDE editor window gets clicked on to get it to front [\#677](https://github.com/supercollider/supercollider/issues/677) - "External-file-change" dialog pops up when saving file in IDE [\#673](https://github.com/supercollider/supercollider/issues/673) - Problems with DragSource [\#671](https://github.com/supercollider/supercollider/issues/671) - Key commands like STOP \(cmd + . \) don't work in Help window when it's detached [\#668](https://github.com/supercollider/supercollider/issues/668) - ndef play producing click when evaluated [\#664](https://github.com/supercollider/supercollider/issues/664) - Ndef channel wrapping broken for many channels [\#658](https://github.com/supercollider/supercollider/issues/658) - Window's "detached" state is not persisted if it was closed before quit [\#655](https://github.com/supercollider/supercollider/issues/655) - Crash when re-opening undocked help window [\#650](https://github.com/supercollider/supercollider/issues/650) - crash on recompile if OSCFunc receiving messages on non-sclang port [\#649](https://github.com/supercollider/supercollider/issues/649) - Array:slide bug [\#645](https://github.com/supercollider/supercollider/issues/645) - got NotYetImplementedError with 3.6beta2 [\#641](https://github.com/supercollider/supercollider/issues/641) - jitlib guis hardly readable [\#637](https://github.com/supercollider/supercollider/issues/637) - Server -O and -I options causes seg fault and crashes sclang [\#636](https://github.com/supercollider/supercollider/issues/636) - crash when closing tab [\#635](https://github.com/supercollider/supercollider/issues/635) - \[SC-IDE\]\[MAC\] cmd+f \(resp. cmd+r\) doesn't work in the IDE [\#634](https://github.com/supercollider/supercollider/issues/634) - Invoking Help does not bring it to front if: \(1\) it is in a hidden tab AND \(2\) the query string is empty [\#631](https://github.com/supercollider/supercollider/issues/631) - command FIFO Full again [\#613](https://github.com/supercollider/supercollider/issues/613) - Scale with scale name doesn't work as described [\#611](https://github.com/supercollider/supercollider/issues/611) - Drag text from document to GUI deletes the text [\#610](https://github.com/supercollider/supercollider/issues/610) - Auto-indent doesn't respect string and symbol literals [\#609](https://github.com/supercollider/supercollider/issues/609) - SoundFileView selectNone and selectAll does not work [\#607](https://github.com/supercollider/supercollider/issues/607) - QWindow, QView background color alpha broken on 3.6beta? [\#606](https://github.com/supercollider/supercollider/issues/606) - Crash when evaluating code in non-code files [\#605](https://github.com/supercollider/supercollider/issues/605) - 3.5.6 with sc3-plugins: SCDoc.renderAll\(true\) fails [\#604](https://github.com/supercollider/supercollider/issues/604) - Evaluate line doesn't work if text wraps [\#601](https://github.com/supercollider/supercollider/issues/601) - crash in autocompleter [\#600](https://github.com/supercollider/supercollider/issues/600) - inconsistent behavior of Env.duration\_ [\#598](https://github.com/supercollider/supercollider/issues/598) - multichannel Envelope.plot broken [\#592](https://github.com/supercollider/supercollider/issues/592) - Cmd-I doesn't work from the Command line pane [\#588](https://github.com/supercollider/supercollider/issues/588) - The post window seems to use double the tab size of documents [\#586](https://github.com/supercollider/supercollider/issues/586) - Freqscope and Scope can't be used at the same time [\#580](https://github.com/supercollider/supercollider/issues/580) - Shift-up/down at start/end of file cancels the selection [\#579](https://github.com/supercollider/supercollider/issues/579) - Close brace } put at the wrong indent level in new SC IDE editor [\#578](https://github.com/supercollider/supercollider/issues/578) - Can't type \[ \(open bracket\) character with Spanish keyboard [\#577](https://github.com/supercollider/supercollider/issues/577) - Regexp with "^" makes sc-ide hang [\#576](https://github.com/supercollider/supercollider/issues/576) - File extension warning when saving a new file [\#575](https://github.com/supercollider/supercollider/issues/575) - There are problems with copying text from the post window [\#574](https://github.com/supercollider/supercollider/issues/574) - Do not open HelpBrowser on application start if it was closed in the restored window state [\#572](https://github.com/supercollider/supercollider/issues/572) - IDE help browser incorrectly shows "old help" warning [\#571](https://github.com/supercollider/supercollider/issues/571) - Hitting Cmd/Ctrl while inertial scrolling causes rapid zoom in / out [\#568](https://github.com/supercollider/supercollider/issues/568) - Deleting a session will lose unsaved documents w/o warning [\#565](https://github.com/supercollider/supercollider/issues/565) - Save All is useless with one or more read only documents open [\#564](https://github.com/supercollider/supercollider/issues/564) - Inline help: example code cannot be executed with regular keyboard shortcut [\#563](https://github.com/supercollider/supercollider/issues/563) - Document tabs can become unusably small [\#562](https://github.com/supercollider/supercollider/issues/562) - Cmd+Period doesn't work in Qt GUI windows [\#561](https://github.com/supercollider/supercollider/issues/561) - Inaccurate wording in language configuration message box [\#559](https://github.com/supercollider/supercollider/issues/559) - Aggressive method call aid within class method arg lists [\#557](https://github.com/supercollider/supercollider/issues/557) - Mouse pointer vanishes when modifier keys are pressed [\#554](https://github.com/supercollider/supercollider/issues/554) - changing file type should update/reload CodeEditor [\#551](https://github.com/supercollider/supercollider/issues/551) - Win XP only: TempoClock scheduling crashes sclang [\#547](https://github.com/supercollider/supercollider/issues/547) - Help browser: progress indicator stuck when opening links in code editor [\#546](https://github.com/supercollider/supercollider/issues/546) - Help browser: can not evaluate a single line in code examples [\#545](https://github.com/supercollider/supercollider/issues/545) - Help browser: code examples not syntax highlighted [\#544](https://github.com/supercollider/supercollider/issues/544) - Cmd-Period doesn't work with help focussed. [\#541](https://github.com/supercollider/supercollider/issues/541) - Cmd-Return / Shift-Return inconsistency in IDE and lang. [\#540](https://github.com/supercollider/supercollider/issues/540) - IDE hides when another application becomes front [\#539](https://github.com/supercollider/supercollider/issues/539) - Cmd+Alt+\ shortcuts not saved correctly [\#538](https://github.com/supercollider/supercollider/issues/538) - IDE hides when another application becomes front [\#537](https://github.com/supercollider/supercollider/issues/537) - Line numbers don't match lines [\#536](https://github.com/supercollider/supercollider/issues/536) - scapp: library menu crash [\#534](https://github.com/supercollider/supercollider/issues/534) - Superfluous blank lines between postln lines [\#533](https://github.com/supercollider/supercollider/issues/533) - "Save" action for read-only files should trigger "Save as" [\#532](https://github.com/supercollider/supercollider/issues/532) - Ctrl-shift-C doesn't clear the post window in winxp [\#531](https://github.com/supercollider/supercollider/issues/531) - call hints don't scroll [\#529](https://github.com/supercollider/supercollider/issues/529) - wrong font spacing in QT [\#527](https://github.com/supercollider/supercollider/issues/527) - some color configuration items don't show default values [\#526](https://github.com/supercollider/supercollider/issues/526) - nowExecutingPath in a newly saved document [\#523](https://github.com/supercollider/supercollider/issues/523) - Saving as .sc saves as .scd instead [\#518](https://github.com/supercollider/supercollider/issues/518) - Shortcuts reset after quiting [\#517](https://github.com/supercollider/supercollider/issues/517) - server does not boot [\#512](https://github.com/supercollider/supercollider/issues/512) - Wacom Bamboo Pen & Touch crashes [\#509](https://github.com/supercollider/supercollider/issues/509) - "maxval" ignored by Buffer.plot [\#507](https://github.com/supercollider/supercollider/issues/507) - Autocomplete sometimes pops up when I type open-bracket [\#505](https://github.com/supercollider/supercollider/issues/505) - drag/drop a WAV onto scide should not attempt to open it [\#502](https://github.com/supercollider/supercollider/issues/502) - Plugging in headphones crashes scsynth [\#499](https://github.com/supercollider/supercollider/issues/499) - Save All doesn't update all document tabs [\#497](https://github.com/supercollider/supercollider/issues/497) - general text colors are applied everywhere [\#496](https://github.com/supercollider/supercollider/issues/496) - \[supernova\] fix g\_dumpTree [\#494](https://github.com/supercollider/supercollider/issues/494) - "Step forward": Cursor doesn't move if line starts with "\(" and cursor is inside [\#493](https://github.com/supercollider/supercollider/issues/493) - Method Call Assist: infer the class of literal values as receivers [\#490](https://github.com/supercollider/supercollider/issues/490) - Method Call Assist: Alt+Space doesn't trigger [\#489](https://github.com/supercollider/supercollider/issues/489) - \[CRITICAL\] IDE crashes when autocompleting methods of an integer literal [\#488](https://github.com/supercollider/supercollider/issues/488) - Sessions: Document tabs out of order sometimes [\#485](https://github.com/supercollider/supercollider/issues/485) - QEnvelopeView does not support quadratic/cubic shapes [\#483](https://github.com/supercollider/supercollider/issues/483) - SCDoc document browser & search broken [\#482](https://github.com/supercollider/supercollider/issues/482) - Autocompletion box pops up when pasting text -- shouldn't [\#481](https://github.com/supercollider/supercollider/issues/481) - Server control state problem [\#477](https://github.com/supercollider/supercollider/issues/477) - Server-meter window errors [\#476](https://github.com/supercollider/supercollider/issues/476) - evaluate regions when being at opening bracket [\#474](https://github.com/supercollider/supercollider/issues/474) - Up-arrow after RET does not move the insertion point straight up [\#472](https://github.com/supercollider/supercollider/issues/472) - Multichannel Function:plot is broken in master [\#470](https://github.com/supercollider/supercollider/issues/470) - new lines do not scroll anymore [\#467](https://github.com/supercollider/supercollider/issues/467) - line numbers when opening files [\#466](https://github.com/supercollider/supercollider/issues/466) - goto next block broken [\#465](https://github.com/supercollider/supercollider/issues/465) - \[QWebView Windows 2\] Handling of file:// in \ [\#463](https://github.com/supercollider/supercollider/issues/463) - \[QWebView Windows 1\] Handling of file:// links [\#462](https://github.com/supercollider/supercollider/issues/462) - session: save-as glitch [\#458](https://github.com/supercollider/supercollider/issues/458) - Method Call Assist: fix for functional notation [\#457](https://github.com/supercollider/supercollider/issues/457) - "Step forward": Put the cursor at the beginning of the next line [\#454](https://github.com/supercollider/supercollider/issues/454) - ide: ctrl-enter adds strange invisible line breaks [\#451](https://github.com/supercollider/supercollider/issues/451) - Interactive find behavior is... hyperactive [\#437](https://github.com/supercollider/supercollider/issues/437) - Line breaks in the post window, not generated by sc code [\#436](https://github.com/supercollider/supercollider/issues/436) - Cannot dismiss the method signature popup for a "new" class method [\#435](https://github.com/supercollider/supercollider/issues/435) - SerialPort doneAction never called & port not properly closed? [\#434](https://github.com/supercollider/supercollider/issues/434) - SC-ide runs its own server status thread? [\#433](https://github.com/supercollider/supercollider/issues/433) - Questionable, but common, auto indent case [\#432](https://github.com/supercollider/supercollider/issues/432) - Highlighting flash of just-executed code sometimes gets stuck [\#431](https://github.com/supercollider/supercollider/issues/431) - Interpreter \*is\* running but "Interpreter is not running!" [\#425](https://github.com/supercollider/supercollider/issues/425) - SC 3.5.4 crashes with buffers on windows 7 [\#423](https://github.com/supercollider/supercollider/issues/423) - stack smashing crash on certain code [\#422](https://github.com/supercollider/supercollider/issues/422) - set nowExecutingPath from scide [\#418](https://github.com/supercollider/supercollider/issues/418) - running sclang script does not set nowExecutingPath [\#417](https://github.com/supercollider/supercollider/issues/417) - \[SC-IDE\] Ctrl-R replace panel: Replace button doesn't replace [\#416](https://github.com/supercollider/supercollider/issues/416) - \[SC 3.5.4\] GrainBuf SynthDef causes SC to crash [\#415](https://github.com/supercollider/supercollider/issues/415) - Preference pane does not select default font [\#414](https://github.com/supercollider/supercollider/issues/414) - indentation bug [\#409](https://github.com/supercollider/supercollider/issues/409) - ctrl+c after selecting text in post window does not copy [\#408](https://github.com/supercollider/supercollider/issues/408) - Keyboard shortcut for Shrink font in post window says 'Shink' [\#406](https://github.com/supercollider/supercollider/issues/406) - make install fails on verify app sclang.app, and it's not fixed-up correctly [\#401](https://github.com/supercollider/supercollider/issues/401) - Tabs don't overflow correctly [\#395](https://github.com/supercollider/supercollider/issues/395) - Volume initialization bug [\#393](https://github.com/supercollider/supercollider/issues/393) - Multiple clocks after fullscreen [\#390](https://github.com/supercollider/supercollider/issues/390) - double-click behavior [\#388](https://github.com/supercollider/supercollider/issues/388) - Syntax color settings are not saved [\#385](https://github.com/supercollider/supercollider/issues/385) - scide: "Auto Scroll" looks like a button but it can't be clicked off [\#378](https://github.com/supercollider/supercollider/issues/378) - Drag'n'drop in QtGui makes Sc-Client crahs [\#375](https://github.com/supercollider/supercollider/issues/375) - Method call aid popup stays shown when main window minimized/deactivated [\#369](https://github.com/supercollider/supercollider/issues/369) - Language Configuration broken for osx command line sclang [\#366](https://github.com/supercollider/supercollider/issues/366) - Missing boundary check in prArrayWrapExtend [\#360](https://github.com/supercollider/supercollider/issues/360) - MIDI listEndPoints crash [\#353](https://github.com/supercollider/supercollider/issues/353) - GrainBuf crashes server when position = NaN [\#352](https://github.com/supercollider/supercollider/issues/352) - GrainBuf does not check buffer inputs to see if they exist [\#341](https://github.com/supercollider/supercollider/issues/341) - \[SC-IDE\] Preferences -\> Keyboard shortcuts & font issues [\#339](https://github.com/supercollider/supercollider/issues/339) - \[SC-IDE\] Region Detection [\#338](https://github.com/supercollider/supercollider/issues/338) - \[SC-IDE\] Cannot save new file [\#337](https://github.com/supercollider/supercollider/issues/337) - \[SC-IDE\] Open class definition + file already open [\#335](https://github.com/supercollider/supercollider/issues/335) - \[SC-IDE\] Don't open same file twice [\#328](https://github.com/supercollider/supercollider/issues/328) - \[SC-IDE\] Can't copy text from post window [\#322](https://github.com/supercollider/supercollider/issues/322) - \[SC-IDE\] Add .scd file extension [\#320](https://github.com/supercollider/supercollider/issues/320) - SCDoc.rendelAll broken in 3.5 branch [\#265](https://github.com/supercollider/supercollider/issues/265) - Plotter domainSpecs bug [\#264](https://github.com/supercollider/supercollider/issues/264) - \[Qt\] UserView doesn't pass click count for control clicks [\#263](https://github.com/supercollider/supercollider/issues/263) - Sending sysex is broken [\#262](https://github.com/supercollider/supercollider/issues/262) - sc3-plugins [\#261](https://github.com/supercollider/supercollider/issues/261) - WARNING: server 'localhost' not running. nil [\#260](https://github.com/supercollider/supercollider/issues/260) - Server crash on polling phase of DelTapWr [\#258](https://github.com/supercollider/supercollider/issues/258) - opening this file crashes sc.app [\#257](https://github.com/supercollider/supercollider/issues/257) - .add fails with SynthDefs containing \> 255 controls [\#256](https://github.com/supercollider/supercollider/issues/256) - .freqscope not working on OS X 3.5 RC2 and RC3 [\#255](https://github.com/supercollider/supercollider/issues/255) - HrEnvelopeView Crash in Cocoa [\#254](https://github.com/supercollider/supercollider/issues/254) - KeyTrack not working with LocalBuf [\#253](https://github.com/supercollider/supercollider/issues/253) - SCNSObject broken under osx 64bit [\#252](https://github.com/supercollider/supercollider/issues/252) - 3.5.rc1 - -getControlBusValue only supports local servers [\#250](https://github.com/supercollider/supercollider/issues/250) - 0 \> Signal\[0\] causes infinite loop and memory hogging [\#249](https://github.com/supercollider/supercollider/issues/249) - 3.5 beta 3 crash on startup after forced quit [\#247](https://github.com/supercollider/supercollider/issues/247) - same font looks different in qt/cocoa [\#245](https://github.com/supercollider/supercollider/issues/245) - Segault:while loops with Routine in condition + empty bodies [\#244](https://github.com/supercollider/supercollider/issues/244) - draw methods for String [\#242](https://github.com/supercollider/supercollider/issues/242) - Some views does not work inside a Layout [\#240](https://github.com/supercollider/supercollider/issues/240) - escapeWindow crashes app [\#239](https://github.com/supercollider/supercollider/issues/239) - compiling error [\#238](https://github.com/supercollider/supercollider/issues/238) - mouseOverActions trigger normal `action' [\#237](https://github.com/supercollider/supercollider/issues/237) - alsa midi deadlock [\#236](https://github.com/supercollider/supercollider/issues/236) - lib fixup for scsynth and sclang [\#235](https://github.com/supercollider/supercollider/issues/235) - Outdated About dialog [\#234](https://github.com/supercollider/supercollider/issues/234) - Pbind makes no sound when utilized in ProxySpace environment [\#233](https://github.com/supercollider/supercollider/issues/233) - \[win\] UnixFILE GetInt primitives return unsigned [\#231](https://github.com/supercollider/supercollider/issues/231) - Quarks GUI info button doesn't work [\#230](https://github.com/supercollider/supercollider/issues/230) - SCEnvelopeView broken [\#229](https://github.com/supercollider/supercollider/issues/229) - Internal server fails to quit on reboot [\#228](https://github.com/supercollider/supercollider/issues/228) - Segmentation fault \(no X\) [\#227](https://github.com/supercollider/supercollider/issues/227) - scvim: crash on startup [\#226](https://github.com/supercollider/supercollider/issues/226) - DetectSilence initialization [\#225](https://github.com/supercollider/supercollider/issues/225) - scel + qt: Document.open from qt doesn't run the callback [\#224](https://github.com/supercollider/supercollider/issues/224) - QButton doesn't pass in modifier keycode to button action [\#223](https://github.com/supercollider/supercollider/issues/223) - OSX does not resolve symlinks [\#222](https://github.com/supercollider/supercollider/issues/222) - CmdPeriod + Task + AppClock = fail [\#221](https://github.com/supercollider/supercollider/issues/221) - Broken: A sequence of multiple Pfxs with 'isolate' [\#220](https://github.com/supercollider/supercollider/issues/220) - CmdPeriod broken [\#219](https://github.com/supercollider/supercollider/issues/219) - UserView graphics on linux is \*very\* slow [\#218](https://github.com/supercollider/supercollider/issues/218) - \[plot\] superposing envelopes [\#217](https://github.com/supercollider/supercollider/issues/217) - SCDoc search results appear in arbitrary order [\#216](https://github.com/supercollider/supercollider/issues/216) - FreeVerb/2 does not check if inputs are audio rate. [\#214](https://github.com/supercollider/supercollider/issues/214) - randSeed doesn't effect Drand [\#212](https://github.com/supercollider/supercollider/issues/212) - Subsection highlighting css bug [\#211](https://github.com/supercollider/supercollider/issues/211) - cocoa window alpha\_ [\#210](https://github.com/supercollider/supercollider/issues/210) - Minor colorizing bug in scdoc rendering [\#209](https://github.com/supercollider/supercollider/issues/209) - SynthDef add fails silently [\#207](https://github.com/supercollider/supercollider/issues/207) - cmd-f should work on OSX to search in helpbrowser [\#206](https://github.com/supercollider/supercollider/issues/206) - cmd-d should open links in new Window if selected [\#205](https://github.com/supercollider/supercollider/issues/205) - Proposal for Helpbrowser layout [\#204](https://github.com/supercollider/supercollider/issues/204) - a nonpositive number in a Dser ends the server: [\#203](https://github.com/supercollider/supercollider/issues/203) - b\_allocReadChannel reads only 1024 samples [\#202](https://github.com/supercollider/supercollider/issues/202) - \[linux\] internal server doesn't receive OSC - unresponsive [\#201](https://github.com/supercollider/supercollider/issues/201) - Internal server \(sometimes?\) fails to connect to CoreAudio [\#200](https://github.com/supercollider/supercollider/issues/200) - Peak broken on OS X 64-bit [\#199](https://github.com/supercollider/supercollider/issues/199) - b\_allocReadChannel crashes supernova [\#198](https://github.com/supercollider/supercollider/issues/198) - LFPar and LFCub return silence with ar rate as input [\#197](https://github.com/supercollider/supercollider/issues/197) - pow wierdness [\#196](https://github.com/supercollider/supercollider/issues/196) - DragSink [\#194](https://github.com/supercollider/supercollider/issues/194) - GEdit plugin doesn't work in GEdit 3 [\#193](https://github.com/supercollider/supercollider/issues/193) - Inappropriate writing inside "Program Files" causes problems [\#192](https://github.com/supercollider/supercollider/issues/192) - Strange behaviour with Demand ugen at kr [\#191](https://github.com/supercollider/supercollider/issues/191) - Dswitch repeats source patterns' ending values [\#190](https://github.com/supercollider/supercollider/issues/190) - \[SC.app\] DeferredDelete events are not processed [\#188](https://github.com/supercollider/supercollider/issues/188) - Error with help system using Gedit \(help doc cache issue\) [\#187](https://github.com/supercollider/supercollider/issues/187) - yNjV79 \midjepicgais\, [\#185](https://github.com/supercollider/supercollider/issues/185) - QSoundFileView read family: missing arguments [\#184](https://github.com/supercollider/supercollider/issues/184) - Class browser crashes sc [\#183](https://github.com/supercollider/supercollider/issues/183) - \[OS X\] QView, QWindow: .remove resp. .close don't work [\#182](https://github.com/supercollider/supercollider/issues/182) - HelpBrowser find-box does not work correctly [\#180](https://github.com/supercollider/supercollider/issues/180) - Help browser line execution doesn't always work [\#179](https://github.com/supercollider/supercollider/issues/179) - Find field is misleading [\#178](https://github.com/supercollider/supercollider/issues/178) - s.meter is broken after reboot [\#177](https://github.com/supercollider/supercollider/issues/177) - QFont size does not allow floats [\#176](https://github.com/supercollider/supercollider/issues/176) - \[OS X\] setting QtGUI.style does not work first time [\#175](https://github.com/supercollider/supercollider/issues/175) - Selection of code within brackets [\#174](https://github.com/supercollider/supercollider/issues/174) - QWebView - process selection before eval [\#173](https://github.com/supercollider/supercollider/issues/173) - SCWebView - process selection before eval [\#172](https://github.com/supercollider/supercollider/issues/172) - SCDoc - convert remaining helpfiles [\#171](https://github.com/supercollider/supercollider/issues/171) - SCWebView copy plain text [\#170](https://github.com/supercollider/supercollider/issues/170) - some shortcuts does not work in SCWebView [\#169](https://github.com/supercollider/supercollider/issues/169) - Qt linking [\#168](https://github.com/supercollider/supercollider/issues/168) - \[OS X\] HelpBrowser with Qt doesn't display text [\#167](https://github.com/supercollider/supercollider/issues/167) - SC.app: Qt vs Cocoa windows Z order [\#166](https://github.com/supercollider/supercollider/issues/166) - SC.app: class-lib recompilation leaves unresponsive windows [\#165](https://github.com/supercollider/supercollider/issues/165) - SC.app: QWebView bug on false URL [\#164](https://github.com/supercollider/supercollider/issues/164) - Dictionary putPairs [\#163](https://github.com/supercollider/supercollider/issues/163) - right-click in Qt-help-browser crashes SC.app \(OSX only?\) [\#162](https://github.com/supercollider/supercollider/issues/162) - GeneralHID is still broken on osx 10.6.7 [\#161](https://github.com/supercollider/supercollider/issues/161) - Resonz after DiskOut = big BIG distortion [\#160](https://github.com/supercollider/supercollider/issues/160) - SC.app crash when scrolling QListView [\#159](https://github.com/supercollider/supercollider/issues/159) - PopUpMenu problems in QtCollider under OSX [\#158](https://github.com/supercollider/supercollider/issues/158) - QWebView a:hover underlined [\#157](https://github.com/supercollider/supercollider/issues/157) - sclang does not start without X [\#156](https://github.com/supercollider/supercollider/issues/156) - .wrap2 behavior [\#155](https://github.com/supercollider/supercollider/issues/155) - SC.app hang in drawHook or drawFunc [\#154](https://github.com/supercollider/supercollider/issues/154) - SC.app hangs when closing a Dialog [\#153](https://github.com/supercollider/supercollider/issues/153) - \[Mac OS\] Button hit are too small [\#152](https://github.com/supercollider/supercollider/issues/152) - SC.app crashes due to cmake's fixup\_bundle [\#151](https://github.com/supercollider/supercollider/issues/151) - Strange display behavior in Help.gui [\#150](https://github.com/supercollider/supercollider/issues/150) - Float error with QtCollider [\#149](https://github.com/supercollider/supercollider/issues/149) - Semaphore does not work propery [\#148](https://github.com/supercollider/supercollider/issues/148) - Help files not found with prefix=/usr [\#145](https://github.com/supercollider/supercollider/issues/145) - String.powerset dosent throw error and causes SC to crash [\#144](https://github.com/supercollider/supercollider/issues/144) - Review patterns for old early termination [\#143](https://github.com/supercollider/supercollider/issues/143) - DetectSilence may never detect silence [\#142](https://github.com/supercollider/supercollider/issues/142) - Patch for minor 'links' bug in scvim\_make\_help [\#141](https://github.com/supercollider/supercollider/issues/141) - scheduling infinite duration freezes SClang [\#140](https://github.com/supercollider/supercollider/issues/140) - sc3-plugins-src archive is out of date on the website [\#139](https://github.com/supercollider/supercollider/issues/139) - Demand ugens broken [\#138](https://github.com/supercollider/supercollider/issues/138) - Demand broken for infinite-length input sequences [\#137](https://github.com/supercollider/supercollider/issues/137) - /clearSched causes NRT Crash [\#136](https://github.com/supercollider/supercollider/issues/136) - DemandEnvGen curve=0 is wrong [\#135](https://github.com/supercollider/supercollider/issues/135) - Cocoa SCEnvelopeView crashes SC app. [\#134](https://github.com/supercollider/supercollider/issues/134) - On the new 3.4RC [\#133](https://github.com/supercollider/supercollider/issues/133) - loadRelative breaks on linux [\#131](https://github.com/supercollider/supercollider/issues/131) - sclang parsing does not take bracket sematics into account [\#130](https://github.com/supercollider/supercollider/issues/130) - sclang crashes routinely in prGetBackTrace -\> MakeDebugFrame [\#129](https://github.com/supercollider/supercollider/issues/129) - Demand plugins built by scons on osx: bad repeats/le [\#128](https://github.com/supercollider/supercollider/issues/128) - LFPar and LFCub audio rate modulation frequency argument bug [\#127](https://github.com/supercollider/supercollider/issues/127) - Error in method .set 's "initAction" of EZSlider [\#126](https://github.com/supercollider/supercollider/issues/126) - SimpleNumber:frac wrong for negative numbers [\#125](https://github.com/supercollider/supercollider/issues/125) - SynthDef:writeDefFile dir-name trailing slash [\#124](https://github.com/supercollider/supercollider/issues/124) - SoundFile.cue cuts off low-sample-rate sounds early [\#123](https://github.com/supercollider/supercollider/issues/123) - Scroll View with Drawhook drawing errors [\#122](https://github.com/supercollider/supercollider/issues/122) - Signal fft crash [\#121](https://github.com/supercollider/supercollider/issues/121) - WaveTerrain Crash [\#120](https://github.com/supercollider/supercollider/issues/120) - drawAtPoint primitive fails if Font not installed [\#119](https://github.com/supercollider/supercollider/issues/119) - Some methods SimpleNumber now fail with floats [\#118](https://github.com/supercollider/supercollider/issues/118) - BeatTrack2 unsafety [\#117](https://github.com/supercollider/supercollider/issues/117) - SCUserView relativeOrigin = true is inefficient [\#116](https://github.com/supercollider/supercollider/issues/116) - SCPen.fillRadialGradient is faulty [\#115](https://github.com/supercollider/supercollider/issues/115) - Compilation failure on PPC/Linux [\#114](https://github.com/supercollider/supercollider/issues/114) - OSCpathResponder broken, needs fix like OSCresponderNode [\#113](https://github.com/supercollider/supercollider/issues/113) - TCP broken in sclang \(rev 9591 onwards?\) [\#112](https://github.com/supercollider/supercollider/issues/112) - Buffer cueSoundFile does not update path var [\#111](https://github.com/supercollider/supercollider/issues/111) - Incoming OSC messages are dropped when VM is busy [\#110](https://github.com/supercollider/supercollider/issues/110) - Setting Document default font causes crashes [\#109](https://github.com/supercollider/supercollider/issues/109) - SCUserView relativeOrigin=true outputs bitmap [\#108](https://github.com/supercollider/supercollider/issues/108) - Stuck synths using Pdef and Pmono [\#107](https://github.com/supercollider/supercollider/issues/107) - SuperCollider.app v3.3.1 crashes on launch \(OS X 10.6.2\) [\#106](https://github.com/supercollider/supercollider/issues/106) - is /b\_gen asynchronous? [\#105](https://github.com/supercollider/supercollider/issues/105) - /b\_zero crashes for illegal bufnum [\#104](https://github.com/supercollider/supercollider/issues/104) - BufDelayN produces "clicks" if buffer size is not power of 2 [\#103](https://github.com/supercollider/supercollider/issues/103) - Buffer docs:bad par. name for asWavetable \[3.3.1\] [\#102](https://github.com/supercollider/supercollider/issues/102) - Bug o f SuperCollider 3.3 on windows [\#100](https://github.com/supercollider/supercollider/issues/100) - Bug o f SupperCollider 3.3 on windows [\#99](https://github.com/supercollider/supercollider/issues/99) - Printing Bug [\#98](https://github.com/supercollider/supercollider/issues/98) - SuperCollider 3.3 win alpha6 sur Windows XP [\#97](https://github.com/supercollider/supercollider/issues/97) - SuperCollider 3.3 win alpha6 sur Windows XP [\#96](https://github.com/supercollider/supercollider/issues/96) - Memory leak in Convolution2 [\#95](https://github.com/supercollider/supercollider/issues/95) - bug on Max os X tiger intel [\#94](https://github.com/supercollider/supercollider/issues/94) - source-with-extras bundle: instructions don't work [\#93](https://github.com/supercollider/supercollider/issues/93) - fullscreen windows draw in front of PopUpMenu [\#92](https://github.com/supercollider/supercollider/issues/92) - Loudness doesn't understand LocalBuf [\#91](https://github.com/supercollider/supercollider/issues/91) - Build fails [\#89](https://github.com/supercollider/supercollider/issues/89) - scvim tries to install in absolute path [\#88](https://github.com/supercollider/supercollider/issues/88) - SuperCollider Crash with Safari4 [\#87](https://github.com/supercollider/supercollider/issues/87) - very large SimpleNumber:series can crash sclang [\#86](https://github.com/supercollider/supercollider/issues/86) - OSCresponderNode SCUserView refresh crashes [\#85](https://github.com/supercollider/supercollider/issues/85) - Cmd-R does not update the cmdLine before interpreting [\#83](https://github.com/supercollider/supercollider/issues/83) - doneAction in RecordBuf doesn't work [\#82](https://github.com/supercollider/supercollider/issues/82) - findHelpFile sometimes returns an empty string on Linux [\#81](https://github.com/supercollider/supercollider/issues/81) - ServerBoot and ServerQuit are called at wrong time [\#80](https://github.com/supercollider/supercollider/issues/80) - 3.3beta: MFCC fails to init outputs in ctor \(fix attached\) [\#79](https://github.com/supercollider/supercollider/issues/79) - LocalBuf and {}.plot are incompatible \(3.3.beta\) [\#78](https://github.com/supercollider/supercollider/issues/78) - OSC-dumping crashes sound [\#76](https://github.com/supercollider/supercollider/issues/76) - SCScrollView relativeOrigin glitch [\#75](https://github.com/supercollider/supercollider/issues/75) - allTuple returns out of bounds memory results sometimes [\#74](https://github.com/supercollider/supercollider/issues/74) - SCRangeSlider bg draws wrong in relative origin parent [\#72](https://github.com/supercollider/supercollider/issues/72) - Pen clipping bug [\#71](https://github.com/supercollider/supercollider/issues/71) - Document.listener.alwaysOnTop\_\(true\) survives recompilation [\#70](https://github.com/supercollider/supercollider/issues/70) - Routine / AppClock broken [\#68](https://github.com/supercollider/supercollider/issues/68) - sclang crashes when compiling errorneous code [\#67](https://github.com/supercollider/supercollider/issues/67) - OSCpathResponder is broken [\#66](https://github.com/supercollider/supercollider/issues/66) - test [\#65](https://github.com/supercollider/supercollider/issues/65) - MIDIIn.connect no longer works on Linux [\#64](https://github.com/supercollider/supercollider/issues/64) - FlowView setting inital margin and gap broken [\#63](https://github.com/supercollider/supercollider/issues/63) - findRegExp sometimes crashes SC - probable GC corruption [\#62](https://github.com/supercollider/supercollider/issues/62) - Condition.wait breaks any AppClock routine [\#60](https://github.com/supercollider/supercollider/issues/60) - Reproducable unmotivated sclang crash [\#59](https://github.com/supercollider/supercollider/issues/59) - view.remove only works one at a time [\#58](https://github.com/supercollider/supercollider/issues/58) - scsynth terminal printout rendezvous default [\#57](https://github.com/supercollider/supercollider/issues/57) - b\_readChannel broken [\#56](https://github.com/supercollider/supercollider/issues/56) - infinities sometimes render compilestrings wrong in Windows [\#55](https://github.com/supercollider/supercollider/issues/55) - clip2 on Signal [\#54](https://github.com/supercollider/supercollider/issues/54) - Advanced Find/Replace Syntax Highlight Issue [\#53](https://github.com/supercollider/supercollider/issues/53) - OSX double-click bracket matching fails in Windows files [\#51](https://github.com/supercollider/supercollider/issues/51) - Collection:removeAll does not catch repeated items [\#50](https://github.com/supercollider/supercollider/issues/50) - \_BasicClipPut primitive doesn't work [\#49](https://github.com/supercollider/supercollider/issues/49) - Fix takeAt documentation [\#48](https://github.com/supercollider/supercollider/issues/48) - \[post-3.2\] Incomplete compilation warning posted [\#47](https://github.com/supercollider/supercollider/issues/47) - String literals in functiondefs can get corrupted [\#46](https://github.com/supercollider/supercollider/issues/46) - Midi SysEx Message Bug [\#45](https://github.com/supercollider/supercollider/issues/45) - Timestamped OSC messages don't work in Psycollider 3.2b1 [\#44](https://github.com/supercollider/supercollider/issues/44) - GrainBuf bug [\#43](https://github.com/supercollider/supercollider/issues/43) - SC2DSlider problem in an absolute-bound compositeview [\#42](https://github.com/supercollider/supercollider/issues/42) - Make non-timestamped messages execute on control block bound [\#41](https://github.com/supercollider/supercollider/issues/41) - Document.new returns nil if SC is not the active application [\#40](https://github.com/supercollider/supercollider/issues/40) - \[windows\] SoundFile info is wrong after openRead'ing a file [\#39](https://github.com/supercollider/supercollider/issues/39) - \[windows\] buffer reading seems not to work in win2k [\#38](https://github.com/supercollider/supercollider/issues/38) - SC\_SYNTHDEF\_DIR environment variable incorrectly read, win32 [\#37](https://github.com/supercollider/supercollider/issues/37) - Pen: strokeOval ignores pen width [\#34](https://github.com/supercollider/supercollider/issues/34) - fixing deprecated use of string constants [\#33](https://github.com/supercollider/supercollider/issues/33) - scsynth.exe crashes upon quit after timestamped messages [\#32](https://github.com/supercollider/supercollider/issues/32) - Pitch crashes with too high a median length [\#31](https://github.com/supercollider/supercollider/issues/31) - Some array primitives crash the VM if fed an empty array [\#30](https://github.com/supercollider/supercollider/issues/30) - 0.2.asFraction beachballs the lang [\#29](https://github.com/supercollider/supercollider/issues/29) - Server.bootSync optional argument [\#28](https://github.com/supercollider/supercollider/issues/28) - sclang crash on invalid code [\#27](https://github.com/supercollider/supercollider/issues/27) - Pen: bug with fillRect, fillOval and fillColor [\#26](https://github.com/supercollider/supercollider/issues/26) - n\_free can crash the server [\#25](https://github.com/supercollider/supercollider/issues/25) - SCTestView editable\_ [\#24](https://github.com/supercollider/supercollider/issues/24) - Instr path variable is not populated [\#23](https://github.com/supercollider/supercollider/issues/23) - Incorrect input/output device display on bootup [\#22](https://github.com/supercollider/supercollider/issues/22) - .quark files saved as RTF? [\#21](https://github.com/supercollider/supercollider/issues/21) - sclang memory usage [\#20](https://github.com/supercollider/supercollider/issues/20) - Please ignore \(test 2\) [\#19](https://github.com/supercollider/supercollider/issues/19) - Please ignore \(test item\) [\#18](https://github.com/supercollider/supercollider/issues/18) - Audio dropout if starting UGens not used yet in session\(OSX\) [\#17](https://github.com/supercollider/supercollider/issues/17) - Trouble finding libs when using PREFIX [\#16](https://github.com/supercollider/supercollider/issues/16) - tiny doc bug [\#15](https://github.com/supercollider/supercollider/issues/15) - server will not boot [\#14](https://github.com/supercollider/supercollider/issues/14) - s\_new and synthdef names with hyphen under linux not working [\#13](https://github.com/supercollider/supercollider/issues/13) - LPF fails due to NaN error when cutoff==0 [\#12](https://github.com/supercollider/supercollider/issues/12) - exponentiation bug [\#11](https://github.com/supercollider/supercollider/issues/11) - permission problem in synthdef [\#10](https://github.com/supercollider/supercollider/issues/10) - SC folder rename introspection errors [\#9](https://github.com/supercollider/supercollider/issues/9) - linux build error [\#8](https://github.com/supercollider/supercollider/issues/8) - cannot build sc3 on linux [\#7](https://github.com/supercollider/supercollider/issues/7) - cmd-line build fails \(needs -faltivec?\) [\#6](https://github.com/supercollider/supercollider/issues/6) - views invisible on refresh if window too small [\#5](https://github.com/supercollider/supercollider/issues/5) - SCSliderBase, knobColor bug [\#4](https://github.com/supercollider/supercollider/issues/4) - SCRangeSlider dragging bug [\#3](https://github.com/supercollider/supercollider/issues/3) - SCView.sc [\#2](https://github.com/supercollider/supercollider/issues/2) - SCRangeSlider [\#1](https://github.com/supercollider/supercollider/issues/1) - ide: fix issue with large documents [\#1849](https://github.com/supercollider/supercollider/pull/1849) ([miguel-negrao](https://github.com/miguel-negrao)) - Classlib: Update PauseStream stream's clock upon play [\#1711](https://github.com/supercollider/supercollider/pull/1711) ([jamshark70](https://github.com/jamshark70)) - Plugins: Clip NOVA functions should update unit-\> variables [\#1702](https://github.com/supercollider/supercollider/pull/1702) ([jamshark70](https://github.com/jamshark70)) **Closed issues:** - copyRange vs. bracket ranges [\#1876](https://github.com/supercollider/supercollider/issues/1876) - FloatArray prevents rounding [\#1873](https://github.com/supercollider/supercollider/issues/1873) - Quark not properly checked-out and/or updated [\#1864](https://github.com/supercollider/supercollider/issues/1864) - ScopeView broken in SuperCollider 3.7.0-beta1? [\#1862](https://github.com/supercollider/supercollider/issues/1862) - sclang in master freezes on arm \(due to PR \#1677 / commit d0f475d\) [\#1842](https://github.com/supercollider/supercollider/issues/1842) - Multiple schelp syntax errors [\#1837](https://github.com/supercollider/supercollider/issues/1837) - scsynth: verbosity -1 & -2 not recognised - scsynth won't start [\#1825](https://github.com/supercollider/supercollider/issues/1825) - Building master with gcc 4.7 fails due to 'is\_trivially\_destructible' in SC\_PlugIn.hpp [\#1820](https://github.com/supercollider/supercollider/issues/1820) - compilation error on slackware linux [\#1814](https://github.com/supercollider/supercollider/issues/1814) - The Font help file has a syntax error [\#1811](https://github.com/supercollider/supercollider/issues/1811) - Github's source code bundles are unhelpful for SuperCollider because submodules missing [\#1807](https://github.com/supercollider/supercollider/issues/1807) - Error when saving with 3.7.0 beta1 [\#1806](https://github.com/supercollider/supercollider/issues/1806) - cmake: if on ARM, automatically disable SSE and SSE2 flags [\#1802](https://github.com/supercollider/supercollider/issues/1802) - sclang compilation error in Linux [\#1797](https://github.com/supercollider/supercollider/issues/1797) - Confusing terminology in "02. First Steps" of Tutorial "Getting Started With SuperCollider" [\#1781](https://github.com/supercollider/supercollider/issues/1781) - if duplicate quark folders exist in extensions ... [\#1767](https://github.com/supercollider/supercollider/issues/1767) - Need updated Windows build instructions [\#1763](https://github.com/supercollider/supercollider/issues/1763) - build: LFUGens.cpp requires nova\_simd code even if NOVA\_SIMD=off [\#1751](https://github.com/supercollider/supercollider/issues/1751) - StkInst overloaded new and delete waiting supernova [\#1747](https://github.com/supercollider/supercollider/issues/1747) - install instructions for ubuntu are out of date [\#1723](https://github.com/supercollider/supercollider/issues/1723) - NodeProxy fails to detect containing audiorate \(irregularly\) [\#1672](https://github.com/supercollider/supercollider/issues/1672) - Issues running with Portaudio \(without jack\) on linux [\#1658](https://github.com/supercollider/supercollider/issues/1658) - OSCFunc with special recvPort can't be freed [\#1654](https://github.com/supercollider/supercollider/issues/1654) - Pipe breaks if it receives lines longer than 1024 characters [\#1593](https://github.com/supercollider/supercollider/issues/1593) - Multichannel recording does not work in Windows 7 [\#1560](https://github.com/supercollider/supercollider/issues/1560) - concatenating large strings causes memory corruption [\#1543](https://github.com/supercollider/supercollider/issues/1543) - Seems like interpreter \(or servers\) are not tracking osc messages to server correctly [\#1524](https://github.com/supercollider/supercollider/issues/1524) - help: TempoClock set beats example is incorrect [\#1518](https://github.com/supercollider/supercollider/issues/1518) - supernova was left out of the -v -V transition [\#1468](https://github.com/supercollider/supercollider/issues/1468) - findRegexp does not compile escaped character sequences correctly [\#1411](https://github.com/supercollider/supercollider/issues/1411) - blocksize and latency in scsynth and supernova [\#1314](https://github.com/supercollider/supercollider/issues/1314) - EnvelopeView gridOn\_ doesn't work \(in Qt on MS Windows anyway\) [\#1284](https://github.com/supercollider/supercollider/issues/1284) - minor bug in an IEnvGen example [\#1276](https://github.com/supercollider/supercollider/issues/1276) - Signal.waveFill function parameters \(3\) don't match documentation \(2\) [\#1259](https://github.com/supercollider/supercollider/issues/1259) - Env.step example is confusing [\#1143](https://github.com/supercollider/supercollider/issues/1143) - \(unnecessary?\) warning "The HID scheme 'nil' is not installed" [\#1120](https://github.com/supercollider/supercollider/issues/1120) - AudioStreamAddPropertyListener deprecated warning [\#1117](https://github.com/supercollider/supercollider/issues/1117) - counter intuitive behaviour when embedding events/dictionaries in streams directly [\#1107](https://github.com/supercollider/supercollider/issues/1107) - No implementation of "Preferences" in Cocoa application [\#1098](https://github.com/supercollider/supercollider/issues/1098) - SplayAz behaviour doesn't match documentation [\#1059](https://github.com/supercollider/supercollider/issues/1059) - Error in Help - Getting Started Tutorial Series - Section 2 [\#981](https://github.com/supercollider/supercollider/issues/981) - SuperCollider won't build with Xcode 5 [\#958](https://github.com/supercollider/supercollider/issues/958) - Crash in creating SynthDef [\#957](https://github.com/supercollider/supercollider/issues/957) - supernova compilation error [\#951](https://github.com/supercollider/supercollider/issues/951) - supercollider-gedit plugin not loading [\#950](https://github.com/supercollider/supercollider/issues/950) - OSCFunc addr.hostname returns nil [\#933](https://github.com/supercollider/supercollider/issues/933) - iOS build, doesn't. [\#927](https://github.com/supercollider/supercollider/issues/927) - Disable mathjax - an unused feature that can cause problems [\#909](https://github.com/supercollider/supercollider/issues/909) - DiskIn channel limitation [\#901](https://github.com/supercollider/supercollider/issues/901) - sclang \(readline\) cannot quit [\#897](https://github.com/supercollider/supercollider/issues/897) - PV\_Copy breaks edge model [\#896](https://github.com/supercollider/supercollider/issues/896) - linux \(debian x64\) compilation error [\#894](https://github.com/supercollider/supercollider/issues/894) - osx/wii uses deprecated/removed API [\#876](https://github.com/supercollider/supercollider/issues/876) - drawFunc drawingEnabled\_\(false\) not respected by refresh [\#869](https://github.com/supercollider/supercollider/issues/869) - file browser lacks default [\#868](https://github.com/supercollider/supercollider/issues/868) - SerialPort Cleanup error [\#862](https://github.com/supercollider/supercollider/issues/862) - Windows: preferably use native file selector on document open etc. [\#861](https://github.com/supercollider/supercollider/issues/861) - Issue Tracker: user can't enter categories/lables [\#860](https://github.com/supercollider/supercollider/issues/860) - Windows: curl support doesn't work and no alternative available [\#859](https://github.com/supercollider/supercollider/issues/859) - Windows \(installer\): no program shortcuts [\#857](https://github.com/supercollider/supercollider/issues/857) - Windows: installer does not register in system [\#856](https://github.com/supercollider/supercollider/issues/856) - Windows: no file associations [\#855](https://github.com/supercollider/supercollider/issues/855) - Server load percentage on Windows off by factor 100 [\#849](https://github.com/supercollider/supercollider/issues/849) - SC IDE: Custom Shortcut ctrl-alt-\ for Move Line Up/Down gets lost after quitting SC [\#836](https://github.com/supercollider/supercollider/issues/836) - searched word is highlighted even after edit [\#833](https://github.com/supercollider/supercollider/issues/833) - server-scope: zoom default value not set on SC 3.6.4 [\#825](https://github.com/supercollider/supercollider/issues/825) - build error [\#816](https://github.com/supercollider/supercollider/issues/816) - Missing "\)" in HelpSource / Guides / MIDI.schelp [\#802](https://github.com/supercollider/supercollider/issues/802) - Up-arrow after hitting return wrongly goes to the end of the previous line [\#800](https://github.com/supercollider/supercollider/issues/800) - \[linux, gnome\] Tab-navigation in find/replace panel is invisible [\#797](https://github.com/supercollider/supercollider/issues/797) - EnvelopeView and exponential, cubed and squared curves. [\#784](https://github.com/supercollider/supercollider/issues/784) - Bug in Bus:get when using multichannel busses [\#778](https://github.com/supercollider/supercollider/issues/778) - Scope won't show a channel count higher than 16 upon initialization [\#769](https://github.com/supercollider/supercollider/issues/769) - FreqScope not updating correctly [\#764](https://github.com/supercollider/supercollider/issues/764) - Supernova does not load UGens from ~/.local [\#763](https://github.com/supercollider/supercollider/issues/763) - Convolution2: frameSize = 2\*\*15 \(32768\) fails [\#738](https://github.com/supercollider/supercollider/issues/738) - Convolution2: kernel size is truncated to fftsize [\#737](https://github.com/supercollider/supercollider/issues/737) - Convolution2: failure if frameSize \> numFrames, in some cases! [\#736](https://github.com/supercollider/supercollider/issues/736) - sclang crash on quit - assertion failure [\#726](https://github.com/supercollider/supercollider/issues/726) - Wrong results from something.kr / something.ar [\#721](https://github.com/supercollider/supercollider/issues/721) - TreeView.clear works in IDE, but doesn't work in Standalone [\#719](https://github.com/supercollider/supercollider/issues/719) - X11 crashes: \[xcb\] Unknown request in queue while dequeuing [\#717](https://github.com/supercollider/supercollider/issues/717) - sclang -l configuration fails \(no warnings, no errors\) [\#713](https://github.com/supercollider/supercollider/issues/713) - scsynth stops when running with RME Fireface UCX [\#701](https://github.com/supercollider/supercollider/issues/701) - plot on a signal does not work \(3.6.1\) [\#698](https://github.com/supercollider/supercollider/issues/698) - Document browser's "Tutorial" subsection should list all tutorials [\#693](https://github.com/supercollider/supercollider/issues/693) - OpenBSD, runtime error: gNumClasses 'discrepancy' [\#684](https://github.com/supercollider/supercollider/issues/684) - cmd-d in help document does not work [\#667](https://github.com/supercollider/supercollider/issues/667) - SC 3.6beta3 - help docs don't compile [\#666](https://github.com/supercollider/supercollider/issues/666) - 3.6.3 STANDARD plugin API mismatch [\#660](https://github.com/supercollider/supercollider/issues/660) - Copy/paste from SC IDE to Mail loses formatting & tabs \(OS X\) [\#657](https://github.com/supercollider/supercollider/issues/657) - scide: Ctrl+P does not focus Post Window [\#654](https://github.com/supercollider/supercollider/issues/654) - Single channel NamedControl returns default values as one-item-array [\#652](https://github.com/supercollider/supercollider/issues/652) - Cannot create new .sc class definition file from SC IDE [\#651](https://github.com/supercollider/supercollider/issues/651) - \[SCIDE 3.6 beta 2\] Help pane browser pops up annoyingly on load [\#643](https://github.com/supercollider/supercollider/issues/643) - Env/event documentation error [\#638](https://github.com/supercollider/supercollider/issues/638) - crash when evaluating exprand [\#632](https://github.com/supercollider/supercollider/issues/632) - \[SC-IDE\] save/save as dialog extensions [\#615](https://github.com/supercollider/supercollider/issues/615) - \[SC-IDE\] hang when trying to stop sclang [\#614](https://github.com/supercollider/supercollider/issues/614) - Ndef clear/play sequence problem [\#612](https://github.com/supercollider/supercollider/issues/612) - File-changed behavior is triggered while file is opened \(and closed\) in other applications [\#595](https://github.com/supercollider/supercollider/issues/595) - Tab widths are radically different between post window and [\#594](https://github.com/supercollider/supercollider/issues/594) - Number views on Stethoscope are too narrow to be readable on OSX [\#583](https://github.com/supercollider/supercollider/issues/583) - Line numbers do not sync for some fonts [\#567](https://github.com/supercollider/supercollider/issues/567) - Duplicate keyboard shortcuts can be set, causing undefined behavior [\#566](https://github.com/supercollider/supercollider/issues/566) - indent line or region sometimes doesn't work [\#528](https://github.com/supercollider/supercollider/issues/528) - server meter menu option always localhost [\#525](https://github.com/supercollider/supercollider/issues/525) - No sound after stopping and running Main again [\#520](https://github.com/supercollider/supercollider/issues/520) - \[sc-ide\] Saving as .sc saves as .scd instead [\#519](https://github.com/supercollider/supercollider/issues/519) - ~tildestuff is not treated as a unit for selection [\#508](https://github.com/supercollider/supercollider/issues/508) - SCDoc: right-click on a link offers non-working "Open in new window" [\#504](https://github.com/supercollider/supercollider/issues/504) - pressing ctrl+D with cursor just before bracket in "Latch\)" searches for bracket not Latch [\#503](https://github.com/supercollider/supercollider/issues/503) - Cmd-Delete to have similar functionality to other OSX windows [\#501](https://github.com/supercollider/supercollider/issues/501) - Ctrl-shift-I/U should not be separated from Ctrl-I/U in the menus [\#498](https://github.com/supercollider/supercollider/issues/498) - Can't connect to and play sounds on already running scsynth [\#487](https://github.com/supercollider/supercollider/issues/487) - Ctrl+. in helpfile doesn't stop it [\#480](https://github.com/supercollider/supercollider/issues/480) - SC-IDE under Mac OSX: Open Class/Method Definition not working [\#479](https://github.com/supercollider/supercollider/issues/479) - SC-IDE under Mac OSX: Open Class/Method Definition not working [\#478](https://github.com/supercollider/supercollider/issues/478) - SuperCollider is renamed SuperColliderCocoa [\#473](https://github.com/supercollider/supercollider/issues/473) - ide: simplifying find/replace? [\#468](https://github.com/supercollider/supercollider/issues/468) - Copying from post window widget [\#460](https://github.com/supercollider/supercollider/issues/460) - Enable word wrap in the post window [\#459](https://github.com/supercollider/supercollider/issues/459) - keyboard shortcut for copy is disabled in post window [\#452](https://github.com/supercollider/supercollider/issues/452) - Switching applications [\#449](https://github.com/supercollider/supercollider/issues/449) - serialPort doneAction never called & port not properly closed? [\#438](https://github.com/supercollider/supercollider/issues/438) - SC 3.5.4 crashes with buffers on windows 7 [\#424](https://github.com/supercollider/supercollider/issues/424) - default for freqscope [\#421](https://github.com/supercollider/supercollider/issues/421) - \[SC-IDE\] Evaluate a line within a region \(with the same shortcut\) [\#403](https://github.com/supercollider/supercollider/issues/403) - Introspection thread safety [\#394](https://github.com/supercollider/supercollider/issues/394) - Import RTF files [\#392](https://github.com/supercollider/supercollider/issues/392) - Custom OSC Message processing section in OSC Communication doc's is incorrect [\#389](https://github.com/supercollider/supercollider/issues/389) - font scaling behavior [\#379](https://github.com/supercollider/supercollider/issues/379) - scide: arg tooltip for floats, display 1 not 1.000000 [\#377](https://github.com/supercollider/supercollider/issues/377) - \[Qt IDE\] Tab not working [\#374](https://github.com/supercollider/supercollider/issues/374) - sclang menu bar vs ide [\#367](https://github.com/supercollider/supercollider/issues/367) - Buffer.free on 3.5.3 crash scsynth [\#359](https://github.com/supercollider/supercollider/issues/359) - \[SC-IDE\] server status bar [\#348](https://github.com/supercollider/supercollider/issues/348) - Can SFC\_SET\_CLIPPING fix the wrapped vs. clipped int-format recording problem? [\#345](https://github.com/supercollider/supercollider/issues/345) - SynthDef compiler in Lua [\#344](https://github.com/supercollider/supercollider/issues/344) - scsynth sound stops in 3.5 not in 3.4 [\#343](https://github.com/supercollider/supercollider/issues/343) - Pseg duration in secs or beats? [\#340](https://github.com/supercollider/supercollider/issues/340) - MIDIFunc.noteOn does not work with floats [\#325](https://github.com/supercollider/supercollider/issues/325) **Merged pull requests:** - fix: typo in CHANGELOG.md [\#1888](https://github.com/supercollider/supercollider/pull/1888) ([crucialfelix](https://github.com/crucialfelix)) - build: copy CHANGELOG.md not the old ChangeLog [\#1887](https://github.com/supercollider/supercollider/pull/1887) ([crucialfelix](https://github.com/crucialfelix)) - class library: poll treats numbers as signals [\#1885](https://github.com/supercollider/supercollider/pull/1885) ([telephon](https://github.com/telephon)) - class library display path in quark gui [\#1882](https://github.com/supercollider/supercollider/pull/1882) ([telephon](https://github.com/telephon)) - Topic/osx move scsynth [\#1881](https://github.com/supercollider/supercollider/pull/1881) ([crucialfelix](https://github.com/crucialfelix)) - fix \#1864 Quarks Git not detecting latest she correctly [\#1880](https://github.com/supercollider/supercollider/pull/1880) ([crucialfelix](https://github.com/crucialfelix)) - build: use direct test to decide if SSE available [\#1879](https://github.com/supercollider/supercollider/pull/1879) ([danstowell](https://github.com/danstowell)) - Improved documentation for copyRange and copySeries [\#1877](https://github.com/supercollider/supercollider/pull/1877) ([snappizz](https://github.com/snappizz)) - sclang: add explanation of standalone mode. [\#1872](https://github.com/supercollider/supercollider/pull/1872) ([miguel-negrao](https://github.com/miguel-negrao)) - Avoid misleading message for Xcode and Visual Studio [\#1871](https://github.com/supercollider/supercollider/pull/1871) ([bagong](https://github.com/bagong)) - ide: menu option "Show Quarks" [\#1867](https://github.com/supercollider/supercollider/pull/1867) ([miguel-negrao](https://github.com/miguel-negrao)) - ide: Add standalone option in settings. [\#1863](https://github.com/supercollider/supercollider/pull/1863) ([miguel-negrao](https://github.com/miguel-negrao)) - ide: fix memory leak [\#1859](https://github.com/supercollider/supercollider/pull/1859) ([miguel-negrao](https://github.com/miguel-negrao)) - plugins: allow Vibrato to be triggered [\#1858](https://github.com/supercollider/supercollider/pull/1858) ([sonoro1234](https://github.com/sonoro1234)) - 3.7win without IPC fix [\#1852](https://github.com/supercollider/supercollider/pull/1852) ([bagong](https://github.com/bagong)) - Topic fix allocations [\#1845](https://github.com/supercollider/supercollider/pull/1845) ([telephon](https://github.com/telephon)) - Fixes/for master [\#1844](https://github.com/supercollider/supercollider/pull/1844) ([timblechmann](https://github.com/timblechmann)) - build: bump GCC version requirement up from 4.7 to 4.8 [\#1839](https://github.com/supercollider/supercollider/pull/1839) ([danstowell](https://github.com/danstowell)) - Help source syntax fix [\#1838](https://github.com/supercollider/supercollider/pull/1838) ([gusano](https://github.com/gusano)) - build: fix PanUGens to build when NOVA\_SIMD=OFF [\#1834](https://github.com/supercollider/supercollider/pull/1834) ([danstowell](https://github.com/danstowell)) - Fix error message [\#1828](https://github.com/supercollider/supercollider/pull/1828) ([carlocapocasa](https://github.com/carlocapocasa)) - Server.sc: option for scsynth's verbosity now is "V" not "v". [\#1826](https://github.com/supercollider/supercollider/pull/1826) ([miczac](https://github.com/miczac)) - build: fix non-SSE2 compile of SC\_SndBuf.h \(Fixes \#1819\) [\#1821](https://github.com/supercollider/supercollider/pull/1821) ([danstowell](https://github.com/danstowell)) - cmake: disable SSE on ARM [\#1817](https://github.com/supercollider/supercollider/pull/1817) ([danstowell](https://github.com/danstowell)) - QView.sc: removes residue OS X Space after closing a fullscreen window. [\#1816](https://github.com/supercollider/supercollider/pull/1816) ([miczac](https://github.com/miczac)) - build: fix an integer type mismatch that caused build fail for some [\#1815](https://github.com/supercollider/supercollider/pull/1815) ([danstowell](https://github.com/danstowell)) - fixes \#1811, also, allowing for more space for the last two examples [\#1813](https://github.com/supercollider/supercollider/pull/1813) ([miczac](https://github.com/miczac)) - cmake: avoid confusing "FATAL" messages if not a git checkout [\#1809](https://github.com/supercollider/supercollider/pull/1809) ([crucialfelix](https://github.com/crucialfelix)) - cmake: disable SSE on ARM [\#1803](https://github.com/supercollider/supercollider/pull/1803) ([danstowell](https://github.com/danstowell)) - plugins: fix plugin registration for sum3/sum4 [\#1799](https://github.com/supercollider/supercollider/pull/1799) ([timblechmann](https://github.com/timblechmann)) - Revert "subproject commit" which mistakenly downgraded nova dependencies [\#1795](https://github.com/supercollider/supercollider/pull/1795) ([danstowell](https://github.com/danstowell)) - class library: moved Model.sc out of GUI directory [\#1792](https://github.com/supercollider/supercollider/pull/1792) ([redFrik](https://github.com/redFrik)) - help guides: fix typo [\#1790](https://github.com/supercollider/supercollider/pull/1790) ([gusano](https://github.com/gusano)) - Incorporate these tutorial corrections [\#1787](https://github.com/supercollider/supercollider/pull/1787) ([afischli](https://github.com/afischli)) - FIx typo in tutorial on shortcut explanation to clear the post window [\#1784](https://github.com/supercollider/supercollider/pull/1784) ([afischli](https://github.com/afischli)) - scide: don't sync documents if language was not compiled [\#1780](https://github.com/supercollider/supercollider/pull/1780) ([gusano](https://github.com/gusano)) - Novacollider/cleanups [\#1779](https://github.com/supercollider/supercollider/pull/1779) ([timblechmann](https://github.com/timblechmann)) - supernova: tests - use thread and chrono [\#1778](https://github.com/supercollider/supercollider/pull/1778) ([timblechmann](https://github.com/timblechmann)) - Correcting a spelling of "Buffer" in Getting Started 13 [\#1777](https://github.com/supercollider/supercollider/pull/1777) ([meatballhat](https://github.com/meatballhat)) - plugin interface: avoid dependency on nova-tt [\#1776](https://github.com/supercollider/supercollider/pull/1776) ([timblechmann](https://github.com/timblechmann)) - Novacollider/cleanups [\#1775](https://github.com/supercollider/supercollider/pull/1775) ([timblechmann](https://github.com/timblechmann)) - nova-simd: fix lower boundary of exp approximation [\#1774](https://github.com/supercollider/supercollider/pull/1774) ([timblechmann](https://github.com/timblechmann)) - cmake: refuse to build if unrecognised AUDIOAPI [\#1773](https://github.com/supercollider/supercollider/pull/1773) ([danstowell](https://github.com/danstowell)) - jack audio driver: remove old unused codepath for jack\<0.100 [\#1772](https://github.com/supercollider/supercollider/pull/1772) ([danstowell](https://github.com/danstowell)) - Topic/boost 1.60 [\#1770](https://github.com/supercollider/supercollider/pull/1770) ([timblechmann](https://github.com/timblechmann)) - Novacollider/supernova refactoring [\#1769](https://github.com/supercollider/supercollider/pull/1769) ([timblechmann](https://github.com/timblechmann)) - external libraries: nova-simd [\#1768](https://github.com/supercollider/supercollider/pull/1768) ([timblechmann](https://github.com/timblechmann)) - supernova: tcp - catch exceptions when sending replies via tcp [\#1765](https://github.com/supercollider/supercollider/pull/1765) ([timblechmann](https://github.com/timblechmann)) - Refactor EnvirGui [\#1761](https://github.com/supercollider/supercollider/pull/1761) ([adcxyz](https://github.com/adcxyz)) - Fix string find [\#1759](https://github.com/supercollider/supercollider/pull/1759) ([muellmusik](https://github.com/muellmusik)) - scdoc: typo in Working\_with\_HID.schelp [\#1756](https://github.com/supercollider/supercollider/pull/1756) ([redFrik](https://github.com/redFrik)) - scdoc: typo in LID\_permissions.schelp [\#1755](https://github.com/supercollider/supercollider/pull/1755) ([redFrik](https://github.com/redFrik)) - scdoc: typo in HID\_permissions.schelp [\#1754](https://github.com/supercollider/supercollider/pull/1754) ([redFrik](https://github.com/redFrik)) - c++ interface: introduce templated registerUnit [\#1753](https://github.com/supercollider/supercollider/pull/1753) ([timblechmann](https://github.com/timblechmann)) - Topic/quarks git fixes [\#1752](https://github.com/supercollider/supercollider/pull/1752) ([crucialfelix](https://github.com/crucialfelix)) - Fixes/supernova unload plugins [\#1748](https://github.com/supercollider/supercollider/pull/1748) ([timblechmann](https://github.com/timblechmann)) - Novacollider/supernova refactoring [\#1745](https://github.com/supercollider/supercollider/pull/1745) ([timblechmann](https://github.com/timblechmann)) - Novacollider/prevent bad optimization [\#1744](https://github.com/supercollider/supercollider/pull/1744) ([timblechmann](https://github.com/timblechmann)) - plugin interface: provide numInputs/numOutputs as interface functions [\#1743](https://github.com/supercollider/supercollider/pull/1743) ([timblechmann](https://github.com/timblechmann)) - cleanup: detect apple via \_\_APPLE\_\_ [\#1741](https://github.com/supercollider/supercollider/pull/1741) ([timblechmann](https://github.com/timblechmann)) - build: modify trunc\(\) calls to compile on gcc 4.8.4 [\#1740](https://github.com/supercollider/supercollider/pull/1740) ([danstowell](https://github.com/danstowell)) - supernova: received\_packet - make implementation more robust [\#1739](https://github.com/supercollider/supercollider/pull/1739) ([timblechmann](https://github.com/timblechmann)) - Fixes/supernova handle out of memory [\#1733](https://github.com/supercollider/supercollider/pull/1733) ([timblechmann](https://github.com/timblechmann)) - Fix avoid calling nonexisting cleanup event type [\#1731](https://github.com/supercollider/supercollider/pull/1731) ([blacksound](https://github.com/blacksound)) - Fix obsolete server method call [\#1730](https://github.com/supercollider/supercollider/pull/1730) ([blacksound](https://github.com/blacksound)) - Consistent use of Event in example. [\#1729](https://github.com/supercollider/supercollider/pull/1729) ([blacksound](https://github.com/blacksound)) - example & help files: cleanup and streamlining of server handling [\#1728](https://github.com/supercollider/supercollider/pull/1728) ([miczac](https://github.com/miczac)) - example & help files: fix reference to default server [\#1727](https://github.com/supercollider/supercollider/pull/1727) ([miczac](https://github.com/miczac)) - Simplify pspawner example [\#1726](https://github.com/supercollider/supercollider/pull/1726) ([blacksound](https://github.com/blacksound)) - typofix - make description match example code [\#1725](https://github.com/supercollider/supercollider/pull/1725) ([blacksound](https://github.com/blacksound)) - UGen-scope.sc: fixes method to determine default server [\#1724](https://github.com/supercollider/supercollider/pull/1724) ([miczac](https://github.com/miczac)) - Fix typo in NodeProxy roles help file [\#1722](https://github.com/supercollider/supercollider/pull/1722) ([blacksound](https://github.com/blacksound)) - ass Filters: warning in help-docs about filter frequencies close to zero [\#1721](https://github.com/supercollider/supercollider/pull/1721) ([miczac](https://github.com/miczac)) - Clean up classlib: consistent tabs and Egyptian braces [\#1714](https://github.com/supercollider/supercollider/pull/1714) ([crucialfelix](https://github.com/crucialfelix)) - fix \#1668 - make existsCaseSensitive work for directories [\#1713](https://github.com/supercollider/supercollider/pull/1713) ([crucialfelix](https://github.com/crucialfelix)) - fix \#1670 isPath and isAbsolutePath regexp for windows [\#1712](https://github.com/supercollider/supercollider/pull/1712) ([crucialfelix](https://github.com/crucialfelix)) - fixes for master [\#1710](https://github.com/supercollider/supercollider/pull/1710) ([timblechmann](https://github.com/timblechmann)) - supernova: silence clang warning [\#1709](https://github.com/supercollider/supercollider/pull/1709) ([timblechmann](https://github.com/timblechmann)) - sclang: file prim - remove unused carbon code [\#1708](https://github.com/supercollider/supercollider/pull/1708) ([timblechmann](https://github.com/timblechmann)) - fix issues found by clang's static analyzer [\#1707](https://github.com/supercollider/supercollider/pull/1707) ([timblechmann](https://github.com/timblechmann)) - class library: store floats with full precision [\#1701](https://github.com/supercollider/supercollider/pull/1701) ([telephon](https://github.com/telephon)) - docs: minor typo adjustment in Getting Started 11 [\#1698](https://github.com/supercollider/supercollider/pull/1698) ([meatballhat](https://github.com/meatballhat)) - modernize supernova [\#1697](https://github.com/supercollider/supercollider/pull/1697) ([timblechmann](https://github.com/timblechmann)) - docs: minor typo correction in Getting Started 10 [\#1694](https://github.com/supercollider/supercollider/pull/1694) ([meatballhat](https://github.com/meatballhat)) - sclang: slot - improve architecture detection [\#1693](https://github.com/supercollider/supercollider/pull/1693) ([timblechmann](https://github.com/timblechmann)) - scdoc/sclang lexers: use intptr\_t tof compatibility with LLP64 archtectures [\#1692](https://github.com/supercollider/supercollider/pull/1692) ([timblechmann](https://github.com/timblechmann)) - refactoring [\#1691](https://github.com/supercollider/supercollider/pull/1691) ([timblechmann](https://github.com/timblechmann)) - fix lost keyevents [\#1690](https://github.com/supercollider/supercollider/pull/1690) ([timblechmann](https://github.com/timblechmann)) - install help sources on linux [\#1689](https://github.com/supercollider/supercollider/pull/1689) ([timblechmann](https://github.com/timblechmann)) - cmake fixes [\#1688](https://github.com/supercollider/supercollider/pull/1688) ([timblechmann](https://github.com/timblechmann)) - class library: make control set atomic [\#1687](https://github.com/supercollider/supercollider/pull/1687) ([LFSaw](https://github.com/LFSaw)) - Primitive related cleanups [\#1683](https://github.com/supercollider/supercollider/pull/1683) ([muellmusik](https://github.com/muellmusik)) - fixed one broken link [\#1680](https://github.com/supercollider/supercollider/pull/1680) ([redFrik](https://github.com/redFrik)) - fixed two broken links [\#1679](https://github.com/supercollider/supercollider/pull/1679) ([redFrik](https://github.com/redFrik)) - scel: Fix mode-line update [\#1678](https://github.com/supercollider/supercollider/pull/1678) ([ptrv](https://github.com/ptrv)) - use c++17-style executors to compile class library [\#1677](https://github.com/supercollider/supercollider/pull/1677) ([timblechmann](https://github.com/timblechmann)) - supernova: guard gcc version check [\#1675](https://github.com/supercollider/supercollider/pull/1675) ([timblechmann](https://github.com/timblechmann)) - fixed two broken links [\#1673](https://github.com/supercollider/supercollider/pull/1673) ([redFrik](https://github.com/redFrik)) - Update 03-Start-Your-Engines.schelp [\#1667](https://github.com/supercollider/supercollider/pull/1667) ([danielmkarlsson](https://github.com/danielmkarlsson)) - Update 02-First-Steps.schelp [\#1666](https://github.com/supercollider/supercollider/pull/1666) ([danielmkarlsson](https://github.com/danielmkarlsson)) - Update 01-Introductory-Remarks.schelp [\#1665](https://github.com/supercollider/supercollider/pull/1665) ([danielmkarlsson](https://github.com/danielmkarlsson)) - Subclass searches [\#1663](https://github.com/supercollider/supercollider/pull/1663) ([jamshark70](https://github.com/jamshark70)) - scsynth: sends d\_removed from the right thread [\#1662](https://github.com/supercollider/supercollider/pull/1662) ([sonoro1234](https://github.com/sonoro1234)) - class library: defer calls to ide [\#1661](https://github.com/supercollider/supercollider/pull/1661) ([telephon](https://github.com/telephon)) - EnvGen: fix cub nans [\#1660](https://github.com/supercollider/supercollider/pull/1660) ([sonoro1234](https://github.com/sonoro1234)) - scsynth: denormal handling in PortAudio and Jack [\#1659](https://github.com/supercollider/supercollider/pull/1659) ([sonoro1234](https://github.com/sonoro1234)) - QtCollider: TextView: Get code for enterInterpretsSelection from block\(\) [\#1652](https://github.com/supercollider/supercollider/pull/1652) ([jamshark70](https://github.com/jamshark70)) - some buildsystem fixes [\#1649](https://github.com/supercollider/supercollider/pull/1649) ([timblechmann](https://github.com/timblechmann)) - supernova: cpu\_time\_info compile fix [\#1647](https://github.com/supercollider/supercollider/pull/1647) ([timblechmann](https://github.com/timblechmann)) - scsynth:SC\_GraphDef.cpp correct d\_removed packet definition [\#1646](https://github.com/supercollider/supercollider/pull/1646) ([sonoro1234](https://github.com/sonoro1234)) - lang: prevent Signal.chebyFill from returning nan [\#1645](https://github.com/supercollider/supercollider/pull/1645) ([totalgee](https://github.com/totalgee)) - SequenceableCollection help: fix some erroneous links [\#1641](https://github.com/supercollider/supercollider/pull/1641) ([nuss](https://github.com/nuss)) - disallow newCopyArgs in Boolean [\#1638](https://github.com/supercollider/supercollider/pull/1638) ([miguel-negrao](https://github.com/miguel-negrao)) - Novacollider/freelist updates [\#1636](https://github.com/supercollider/supercollider/pull/1636) ([timblechmann](https://github.com/timblechmann)) - Non-characters pass ASCII code 0 to key actions [\#1632](https://github.com/supercollider/supercollider/pull/1632) ([jamshark70](https://github.com/jamshark70)) - plugin interface: fix compile failure with gcc-4.9 [\#1628](https://github.com/supercollider/supercollider/pull/1628) ([timblechmann](https://github.com/timblechmann)) - Classlib: SystemSynthDefs: Clean up temp defs properly on all platforms [\#1627](https://github.com/supercollider/supercollider/pull/1627) ([jamshark70](https://github.com/jamshark70)) - Gc fixes and doc final [\#1624](https://github.com/supercollider/supercollider/pull/1624) ([muellmusik](https://github.com/muellmusik)) - common: oscutils - correct printf format specifier for \(u\)int64\_t [\#1620](https://github.com/supercollider/supercollider/pull/1620) ([timblechmann](https://github.com/timblechmann)) - scide: fix float regexp [\#1619](https://github.com/supercollider/supercollider/pull/1619) ([timblechmann](https://github.com/timblechmann)) - supernova: some refactoring [\#1614](https://github.com/supercollider/supercollider/pull/1614) ([timblechmann](https://github.com/timblechmann)) - server: Assume requested SR was successfully set [\#1612](https://github.com/supercollider/supercollider/pull/1612) ([scztt](https://github.com/scztt)) - cmake: copy targets to ide app bundle in post-build steps [\#1608](https://github.com/supercollider/supercollider/pull/1608) ([timblechmann](https://github.com/timblechmann)) - Misc Quarks fixes [\#1606](https://github.com/supercollider/supercollider/pull/1606) ([crucialfelix](https://github.com/crucialfelix)) - sclang: fix gc-related bug [\#1605](https://github.com/supercollider/supercollider/pull/1605) ([timblechmann](https://github.com/timblechmann)) - Quarks: avoid a stack overflow from LanguageConfig.includePaths [\#1603](https://github.com/supercollider/supercollider/pull/1603) ([crucialfelix](https://github.com/crucialfelix)) - fix: Quarks.load quark set [\#1602](https://github.com/supercollider/supercollider/pull/1602) ([crucialfelix](https://github.com/crucialfelix)) - Topic/ide fixes for master [\#1601](https://github.com/supercollider/supercollider/pull/1601) ([timblechmann](https://github.com/timblechmann)) - Topic/ide keyevent fixes [\#1598](https://github.com/supercollider/supercollider/pull/1598) ([timblechmann](https://github.com/timblechmann)) - scide: preferences dialog - fix width of icon list widget [\#1597](https://github.com/supercollider/supercollider/pull/1597) ([timblechmann](https://github.com/timblechmann)) - Topic/fixes for master [\#1595](https://github.com/supercollider/supercollider/pull/1595) ([timblechmann](https://github.com/timblechmann)) - qtcollider/sc-ide: make use of QStringLiteral [\#1594](https://github.com/supercollider/supercollider/pull/1594) ([timblechmann](https://github.com/timblechmann)) - Topic/fixes for master [\#1592](https://github.com/supercollider/supercollider/pull/1592) ([timblechmann](https://github.com/timblechmann)) - Fix: \#1475 absolute path detection and conversion for windows [\#1590](https://github.com/supercollider/supercollider/pull/1590) ([crucialfelix](https://github.com/crucialfelix)) - Adding a note about W64, CAF and WAV support as proposed by @scztt [\#1584](https://github.com/supercollider/supercollider/pull/1584) ([gogobd](https://github.com/gogobd)) - Topic/fixes for master [\#1583](https://github.com/supercollider/supercollider/pull/1583) ([timblechmann](https://github.com/timblechmann)) - Classlib: Event: Add missing ~latency into ~schedBundleArray calls [\#1582](https://github.com/supercollider/supercollider/pull/1582) ([jamshark70](https://github.com/jamshark70)) - OSX: Allow cmake install prefix to be overridden [\#1576](https://github.com/supercollider/supercollider/pull/1576) ([bagong](https://github.com/bagong)) - HID final cleanup, and LID adaption to use similar API [\#1573](https://github.com/supercollider/supercollider/pull/1573) ([sensestage](https://github.com/sensestage)) - Midi connect all [\#1571](https://github.com/supercollider/supercollider/pull/1571) ([sensestage](https://github.com/sensestage)) - OSX: return to old default cmake install location ./Install [\#1569](https://github.com/supercollider/supercollider/pull/1569) ([bagong](https://github.com/bagong)) - class library: HID: fix else statement in findAvailable [\#1567](https://github.com/supercollider/supercollider/pull/1567) ([sensestage](https://github.com/sensestage)) - fix scope on internal, solves \#1527 [\#1552](https://github.com/supercollider/supercollider/pull/1552) ([adcxyz](https://github.com/adcxyz)) - add valueActionIfChanged to fix issue\#1460 [\#1551](https://github.com/supercollider/supercollider/pull/1551) ([adcxyz](https://github.com/adcxyz)) - scsynth: alow using malloc, realloc, free [\#1549](https://github.com/supercollider/supercollider/pull/1549) ([sonoro1234](https://github.com/sonoro1234)) - fix \#1476 stack corruption triggered by calling a git unixCmd [\#1542](https://github.com/supercollider/supercollider/pull/1542) ([crucialfelix](https://github.com/crucialfelix)) - quarks: protect during eval of isCompatible fix \#1463 [\#1541](https://github.com/supercollider/supercollider/pull/1541) ([crucialfelix](https://github.com/crucialfelix)) - validate that a refspec refers to an existing tag [\#1540](https://github.com/supercollider/supercollider/pull/1540) ([crucialfelix](https://github.com/crucialfelix)) - ide: Switch focus to help docklet on help request [\#1529](https://github.com/supercollider/supercollider/pull/1529) ([scztt](https://github.com/scztt)) - import boost-1.58 [\#1528](https://github.com/supercollider/supercollider/pull/1528) ([timblechmann](https://github.com/timblechmann)) - build: switch to alpha1 [\#1525](https://github.com/supercollider/supercollider/pull/1525) ([scztt](https://github.com/scztt)) - Topic/fix scrollbar hiding osx [\#1523](https://github.com/supercollider/supercollider/pull/1523) ([scztt](https://github.com/scztt)) - sclang: fix default fonts [\#1522](https://github.com/supercollider/supercollider/pull/1522) ([scztt](https://github.com/scztt)) - Chebyshev: zero-offset default change plus documentation updates [\#1520](https://github.com/supercollider/supercollider/pull/1520) ([totalgee](https://github.com/totalgee)) - Fix MIDIIn.connectAll on Linux to only connect to external sources and not internal ones [\#1517](https://github.com/supercollider/supercollider/pull/1517) ([sensestage](https://github.com/sensestage)) - sclang: Fix incorrect modifiers [\#1513](https://github.com/supercollider/supercollider/pull/1513) ([scztt](https://github.com/scztt)) - Update Ringz.schelp [\#1511](https://github.com/supercollider/supercollider/pull/1511) ([porres](https://github.com/porres)) - Update LFPar.schelp [\#1510](https://github.com/supercollider/supercollider/pull/1510) ([porres](https://github.com/porres)) - Update Resonz.schelp [\#1509](https://github.com/supercollider/supercollider/pull/1509) ([porres](https://github.com/porres)) - Update Ringz.schelp [\#1508](https://github.com/supercollider/supercollider/pull/1508) ([porres](https://github.com/porres)) - Update LFPar.schelp [\#1507](https://github.com/supercollider/supercollider/pull/1507) ([porres](https://github.com/porres)) - Chebyshev polynomials: various fixes \(issue \#1500\) [\#1504](https://github.com/supercollider/supercollider/pull/1504) ([totalgee](https://github.com/totalgee)) - plugins/LFUGens: generate symmetrical waveforms in LFPulse [\#1503](https://github.com/supercollider/supercollider/pull/1503) ([totalgee](https://github.com/totalgee)) - Timedll for supernova [\#1497](https://github.com/supercollider/supercollider/pull/1497) ([sonoro1234](https://github.com/sonoro1234)) - ide: Workaround for completion help view crash [\#1495](https://github.com/supercollider/supercollider/pull/1495) ([scztt](https://github.com/scztt)) - sclang: fix crash during SerialPort cleanup [\#1494](https://github.com/supercollider/supercollider/pull/1494) ([scztt](https://github.com/scztt)) - sclang: workaround webkit scrollbar hiding bug [\#1493](https://github.com/supercollider/supercollider/pull/1493) ([scztt](https://github.com/scztt)) - classlib: Don't pass unprintables in key events [\#1492](https://github.com/supercollider/supercollider/pull/1492) ([scztt](https://github.com/scztt)) - sclang: set max scroll according to req'd value [\#1491](https://github.com/supercollider/supercollider/pull/1491) ([scztt](https://github.com/scztt)) - ide: better newline behavior within brackets [\#1490](https://github.com/supercollider/supercollider/pull/1490) ([scztt](https://github.com/scztt)) - MIDI: make interpreting noteOnZeroAsNoteOff an option rather than a h… [\#1488](https://github.com/supercollider/supercollider/pull/1488) ([sensestage](https://github.com/sensestage)) - classlib: Use correct spec for x coord of edits [\#1486](https://github.com/supercollider/supercollider/pull/1486) ([scztt](https://github.com/scztt)) - Add two qt5 packages to dependencies list [\#1481](https://github.com/supercollider/supercollider/pull/1481) ([bagong](https://github.com/bagong)) - supernova: print version with -v and use -V for verbose [\#1470](https://github.com/supercollider/supercollider/pull/1470) ([sonoro1234](https://github.com/sonoro1234)) - Help: WritingClasses: Extension methods are like obj-c categories [\#1469](https://github.com/supercollider/supercollider/pull/1469) ([jamshark70](https://github.com/jamshark70)) - Pluginsunload2 [\#1467](https://github.com/supercollider/supercollider/pull/1467) ([sonoro1234](https://github.com/sonoro1234)) - remove obsolete Document autocomplete extensions [\#1461](https://github.com/supercollider/supercollider/pull/1461) ([crucialfelix](https://github.com/crucialfelix)) - Sclang: print version with -v [\#1459](https://github.com/supercollider/supercollider/pull/1459) ([gusano](https://github.com/gusano)) - Scsynth: print version with -v [\#1458](https://github.com/supercollider/supercollider/pull/1458) ([gusano](https://github.com/gusano)) - Topic/quarks window is path [\#1457](https://github.com/supercollider/supercollider/pull/1457) ([crucialfelix](https://github.com/crucialfelix)) - Classlib: lincurve: Prevent incorrect range clipping when curve ~= 0 [\#1441](https://github.com/supercollider/supercollider/pull/1441) ([jamshark70](https://github.com/jamshark70)) - lang: NetAddr: correctly disconnect tcp socket [\#1440](https://github.com/supercollider/supercollider/pull/1440) ([miguel-negrao](https://github.com/miguel-negrao)) - protect NetAddr-disconnectAll from failing during shutdown [\#1439](https://github.com/supercollider/supercollider/pull/1439) ([crucialfelix](https://github.com/crucialfelix)) - classlib: translate modifier keys on mac [\#1434](https://github.com/supercollider/supercollider/pull/1434) ([scztt](https://github.com/scztt)) - ide: fix crash on session switch [\#1433](https://github.com/supercollider/supercollider/pull/1433) ([scztt](https://github.com/scztt)) - classlib: Convert note/cc nums in array case [\#1432](https://github.com/supercollider/supercollider/pull/1432) ([scztt](https://github.com/scztt)) - qtcollider: defer setPropery if called inside drawFunc [\#1431](https://github.com/supercollider/supercollider/pull/1431) ([scztt](https://github.com/scztt)) - Fix: Install quark dependencies with refspecs [\#1427](https://github.com/supercollider/supercollider/pull/1427) ([crucialfelix](https://github.com/crucialfelix)) - classlib: note nums / cc channels must be integers [\#1425](https://github.com/supercollider/supercollider/pull/1425) ([scztt](https://github.com/scztt)) - FreqScope.sc: adapt to new fill property of scope. [\#1419](https://github.com/supercollider/supercollider/pull/1419) ([miczac](https://github.com/miczac)) - ide: hide toolbox after changing box focus [\#1418](https://github.com/supercollider/supercollider/pull/1418) ([scztt](https://github.com/scztt)) - lang: don't drop backslashes [\#1417](https://github.com/supercollider/supercollider/pull/1417) ([scztt](https://github.com/scztt)) - ide: track files opened in a session switch in the recent documents menu [\#1416](https://github.com/supercollider/supercollider/pull/1416) ([scztt](https://github.com/scztt)) - ide: do not save format settings for controls that are disabled. [\#1415](https://github.com/supercollider/supercollider/pull/1415) ([scztt](https://github.com/scztt)) - Quarks GUI tiny improvements [\#1414](https://github.com/supercollider/supercollider/pull/1414) ([gusano](https://github.com/gusano)) - scide: theme: introducing built-in "dark" theme [\#1410](https://github.com/supercollider/supercollider/pull/1410) ([vdonnefort](https://github.com/vdonnefort)) - \[Help\] add words "Fast Fourier Transform" to guide [\#1407](https://github.com/supercollider/supercollider/pull/1407) ([patrickdupuis](https://github.com/patrickdupuis)) - Topic/quarks gui enhancements [\#1394](https://github.com/supercollider/supercollider/pull/1394) ([crucialfelix](https://github.com/crucialfelix)) - Pattern.record method doesn't stop recording [\#1392](https://github.com/supercollider/supercollider/pull/1392) ([gurk](https://github.com/gurk)) - fixes \#1369 LanguageConfig.current returns "", should return nil [\#1388](https://github.com/supercollider/supercollider/pull/1388) ([crucialfelix](https://github.com/crucialfelix)) - class library: GridLayout - fix position when using spanning [\#1384](https://github.com/supercollider/supercollider/pull/1384) ([gusano](https://github.com/gusano)) - fix-DiskOut [\#1382](https://github.com/supercollider/supercollider/pull/1382) ([muellmusik](https://github.com/muellmusik)) - server GUI: fix initial volume button value [\#1372](https://github.com/supercollider/supercollider/pull/1372) ([gusano](https://github.com/gusano)) - ide: Fix triggering of doc modified signal [\#1371](https://github.com/supercollider/supercollider/pull/1371) ([scztt](https://github.com/scztt)) - Date.schelp: corrected peculiar format example [\#1368](https://github.com/supercollider/supercollider/pull/1368) ([miczac](https://github.com/miczac)) - Fix broken link in Ndef help file [\#1366](https://github.com/supercollider/supercollider/pull/1366) ([albertojgomez](https://github.com/albertojgomez)) - class library: collectCopy method implementation [\#1357](https://github.com/supercollider/supercollider/pull/1357) ([telephon](https://github.com/telephon)) - Revert "scide: DocumentSelectPopUp - convert to Popup to fix lost KeyRel... [\#1354](https://github.com/supercollider/supercollider/pull/1354) ([telephon](https://github.com/telephon)) - scide: DocumentSelectPopUp - convert to Popup to fix lost KeyRelease event [\#1352](https://github.com/supercollider/supercollider/pull/1352) ([timblechmann](https://github.com/timblechmann)) - cmake: use bundled yaml-cpp by default [\#1351](https://github.com/supercollider/supercollider/pull/1351) ([timblechmann](https://github.com/timblechmann)) - Topic/improve doc readability [\#1349](https://github.com/supercollider/supercollider/pull/1349) ([telephon](https://github.com/telephon)) - Classlib: Complex: Fix bugs in 'pow' method [\#1348](https://github.com/supercollider/supercollider/pull/1348) ([jamshark70](https://github.com/jamshark70)) - Topic/simplify gui documentation [\#1345](https://github.com/supercollider/supercollider/pull/1345) ([telephon](https://github.com/telephon)) - Tiny enhancements to README\_OSX.md [\#1344](https://github.com/supercollider/supercollider/pull/1344) ([bagong](https://github.com/bagong)) - Topic nodeproxy gui for numbers [\#1343](https://github.com/supercollider/supercollider/pull/1343) ([telephon](https://github.com/telephon)) - class library: FunctionList copies before iterating. [\#1341](https://github.com/supercollider/supercollider/pull/1341) ([telephon](https://github.com/telephon)) - Topic/level indicator [\#1338](https://github.com/supercollider/supercollider/pull/1338) ([scztt](https://github.com/scztt)) - Topic/ogl filled scope [\#1337](https://github.com/supercollider/supercollider/pull/1337) ([scztt](https://github.com/scztt)) - Topic/source preview [\#1336](https://github.com/supercollider/supercollider/pull/1336) ([scztt](https://github.com/scztt)) - Topic/qt5 tim all and cosmetics [\#1334](https://github.com/supercollider/supercollider/pull/1334) ([scztt](https://github.com/scztt)) - Scide/autocomplete help [\#1333](https://github.com/supercollider/supercollider/pull/1333) ([vdonnefort](https://github.com/vdonnefort)) - Topic language config current path [\#1327](https://github.com/supercollider/supercollider/pull/1327) ([telephon](https://github.com/telephon)) - supernova: fix endpoint handling for asynchronous commands [\#1326](https://github.com/supercollider/supercollider/pull/1326) ([timblechmann](https://github.com/timblechmann)) - qtcollider: avoid un-safe printf by using qWarning\(\) instead [\#1325](https://github.com/supercollider/supercollider/pull/1325) ([timblechmann](https://github.com/timblechmann)) - Sclang/print version [\#1324](https://github.com/supercollider/supercollider/pull/1324) ([blacksound](https://github.com/blacksound)) - scsynth: print version and exit with option -V [\#1322](https://github.com/supercollider/supercollider/pull/1322) ([blacksound](https://github.com/blacksound)) - supernova: use -Z in portaudio 0 hight \(negative\) low others desired har... [\#1318](https://github.com/supercollider/supercollider/pull/1318) ([sonoro1234](https://github.com/sonoro1234)) - server: GraphDef\_ReadVer1 now reads via ParamSpec\_ReadVer1 [\#1317](https://github.com/supercollider/supercollider/pull/1317) ([telephon](https://github.com/telephon)) - plugins: fix 10 trigger UGens that did not initialize ZOUT correcly [\#1311](https://github.com/supercollider/supercollider/pull/1311) ([jamshark70](https://github.com/jamshark70)) - Plugins: Demand: Add Dconst UGen, with schelp [\#1305](https://github.com/supercollider/supercollider/pull/1305) ([jamshark70](https://github.com/jamshark70)) - Scide/line number [\#1302](https://github.com/supercollider/supercollider/pull/1302) ([vdonnefort](https://github.com/vdonnefort)) - Topic/linxfade fix [\#1301](https://github.com/supercollider/supercollider/pull/1301) ([timblechmann](https://github.com/timblechmann)) - class library\(GUI\): rename arguments - \*new [\#1288](https://github.com/supercollider/supercollider/pull/1288) ([gurk](https://github.com/gurk)) - Topic/timing cleanup [\#1286](https://github.com/supercollider/supercollider/pull/1286) ([muellmusik](https://github.com/muellmusik)) - Topic/operators [\#1282](https://github.com/supercollider/supercollider/pull/1282) ([telephon](https://github.com/telephon)) - scide: add OSX delete word ctrl+w shortcut [\#1272](https://github.com/supercollider/supercollider/pull/1272) ([vdonnefort](https://github.com/vdonnefort)) - Topic/bounded controls: cleaned up branch ready. [\#1270](https://github.com/supercollider/supercollider/pull/1270) ([telephon](https://github.com/telephon)) - string: regex: rename firstRegexp [\#1269](https://github.com/supercollider/supercollider/pull/1269) ([sofakid](https://github.com/sofakid)) - scide: introducing restore function [\#1267](https://github.com/supercollider/supercollider/pull/1267) ([vdonnefort](https://github.com/vdonnefort)) - plugins: EnvGen - fix initialization of hold segment [\#1265](https://github.com/supercollider/supercollider/pull/1265) ([timblechmann](https://github.com/timblechmann)) - scide: add save-as-extension functionality [\#1264](https://github.com/supercollider/supercollider/pull/1264) ([timblechmann](https://github.com/timblechmann)) - cmake: externals - don't scare users about auto\_ptr [\#1263](https://github.com/supercollider/supercollider/pull/1263) ([timblechmann](https://github.com/timblechmann)) - Update Tdef.schelp [\#1262](https://github.com/supercollider/supercollider/pull/1262) ([vividsnow](https://github.com/vividsnow)) - class library: translations between key value pairs, asscociations, and dictionaries [\#1260](https://github.com/supercollider/supercollider/pull/1260) ([telephon](https://github.com/telephon)) - Apple build: Prevent supernova from being installed twice [\#1256](https://github.com/supercollider/supercollider/pull/1256) ([bagong](https://github.com/bagong)) - plugins: Linen checks for prehistoric release message [\#1255](https://github.com/supercollider/supercollider/pull/1255) ([telephon](https://github.com/telephon)) - Topic/boost 1.57 [\#1249](https://github.com/supercollider/supercollider/pull/1249) ([timblechmann](https://github.com/timblechmann)) - string: Fix regex cache init, implement firstRegex [\#1248](https://github.com/supercollider/supercollider/pull/1248) ([sofakid](https://github.com/sofakid)) - Orthographical adjustment to win installer script [\#1244](https://github.com/supercollider/supercollider/pull/1244) ([bagong](https://github.com/bagong)) - IFFT.schelp: fix example [\#1243](https://github.com/supercollider/supercollider/pull/1243) ([miczac](https://github.com/miczac)) - sclang: hidapi - fix gc corruption bug [\#1242](https://github.com/supercollider/supercollider/pull/1242) ([timblechmann](https://github.com/timblechmann)) - Classlib: Pstep: Fix unnecessary creation of an array on every iteration [\#1236](https://github.com/supercollider/supercollider/pull/1236) ([jamshark70](https://github.com/jamshark70)) - Classlib: QPenPrinter: Add 'bounds' method [\#1235](https://github.com/supercollider/supercollider/pull/1235) ([jamshark70](https://github.com/jamshark70)) - Classlib: Pfuncn: Like Pfunc, this should call processRest before yield [\#1234](https://github.com/supercollider/supercollider/pull/1234) ([jamshark70](https://github.com/jamshark70)) - Classlib: Rest: Add 'value' method to simplify mixing rests and numbers [\#1233](https://github.com/supercollider/supercollider/pull/1233) ([jamshark70](https://github.com/jamshark70)) - Topic/qt5 win [\#1229](https://github.com/supercollider/supercollider/pull/1229) ([timblechmann](https://github.com/timblechmann)) - cmake: fix & clean up xcode project [\#1225](https://github.com/supercollider/supercollider/pull/1225) ([timblechmann](https://github.com/timblechmann)) - Fix "QNetworkRequest header not found". [\#1223](https://github.com/supercollider/supercollider/pull/1223) ([ventosus](https://github.com/ventosus)) - fix help installation [\#1222](https://github.com/supercollider/supercollider/pull/1222) ([nuss](https://github.com/nuss)) - supernova: /notify - return client id [\#1221](https://github.com/supercollider/supercollider/pull/1221) ([timblechmann](https://github.com/timblechmann)) - tcp server, retry a couple of times until getting a tcp connection [\#1215](https://github.com/supercollider/supercollider/pull/1215) ([miguel-negrao](https://github.com/miguel-negrao)) - lang: Fix TCP bugs [\#1214](https://github.com/supercollider/supercollider/pull/1214) ([muellmusik](https://github.com/muellmusik)) - More document stuff [\#1213](https://github.com/supercollider/supercollider/pull/1213) ([muellmusik](https://github.com/muellmusik)) - rd/tgrains \(& localbuf\) [\#1207](https://github.com/supercollider/supercollider/pull/1207) ([rd--](https://github.com/rd--)) - Blocksize-\>BlockSize [\#1206](https://github.com/supercollider/supercollider/pull/1206) ([rd--](https://github.com/rd--)) - scel: highlight uppercase symbols in emacs [\#1205](https://github.com/supercollider/supercollider/pull/1205) ([bion](https://github.com/bion)) - HID\_API fix: initClass -\> initClassTree [\#1203](https://github.com/supercollider/supercollider/pull/1203) ([andersvi](https://github.com/andersvi)) - Adding drawImage example to Pen.schelp [\#1197](https://github.com/supercollider/supercollider/pull/1197) ([thormagnusson](https://github.com/thormagnusson)) - Create Image.schelp [\#1195](https://github.com/supercollider/supercollider/pull/1195) ([thormagnusson](https://github.com/thormagnusson)) - Update win32\_api.hpp [\#1192](https://github.com/supercollider/supercollider/pull/1192) ([bagong](https://github.com/bagong)) - Topic/boost updates [\#1191](https://github.com/supercollider/supercollider/pull/1191) ([timblechmann](https://github.com/timblechmann)) - cmake/apple: compile targets directly into the app bundle [\#1189](https://github.com/supercollider/supercollider/pull/1189) ([timblechmann](https://github.com/timblechmann)) - supernova: don't scare osx users by consumer-os [\#1187](https://github.com/supercollider/supercollider/pull/1187) ([timblechmann](https://github.com/timblechmann)) - fix assign path [\#1186](https://github.com/supercollider/supercollider/pull/1186) ([carlocapocasa](https://github.com/carlocapocasa)) - scide: mark current session in dialogs [\#1184](https://github.com/supercollider/supercollider/pull/1184) ([timblechmann](https://github.com/timblechmann)) - scide: fix preferences action name shortcut for osx menu placement [\#1183](https://github.com/supercollider/supercollider/pull/1183) ([timblechmann](https://github.com/timblechmann)) - cmake: fix typo [\#1182](https://github.com/supercollider/supercollider/pull/1182) ([timblechmann](https://github.com/timblechmann)) - scide: key up after line evaluation should go to original position [\#1178](https://github.com/supercollider/supercollider/pull/1178) ([timblechmann](https://github.com/timblechmann)) - cmake: link sclang with tlsf [\#1177](https://github.com/supercollider/supercollider/pull/1177) ([timblechmann](https://github.com/timblechmann)) - cmake: install help on non-apple systems [\#1175](https://github.com/supercollider/supercollider/pull/1175) ([timblechmann](https://github.com/timblechmann)) - Topic/scide enhancements [\#1172](https://github.com/supercollider/supercollider/pull/1172) ([timblechmann](https://github.com/timblechmann)) - boost updates & cmake modernization [\#1166](https://github.com/supercollider/supercollider/pull/1166) ([timblechmann](https://github.com/timblechmann)) - Fix Scale.newFromKey with tuning argument [\#1161](https://github.com/supercollider/supercollider/pull/1161) ([slpopejoy](https://github.com/slpopejoy)) - Update Date.schelp [\#1151](https://github.com/supercollider/supercollider/pull/1151) ([thormagnusson](https://github.com/thormagnusson)) - ide: introducing themes management [\#1150](https://github.com/supercollider/supercollider/pull/1150) ([vdonnefort](https://github.com/vdonnefort)) - help: chaotic generators warnings removed [\#1149](https://github.com/supercollider/supercollider/pull/1149) ([smrg-lm](https://github.com/smrg-lm)) - Topic/coremidi crash fix [\#1147](https://github.com/supercollider/supercollider/pull/1147) ([scztt](https://github.com/scztt)) - plugins: TrigControl behaves like Control. Fixes \#1145 [\#1146](https://github.com/supercollider/supercollider/pull/1146) ([telephon](https://github.com/telephon)) - Classlib: PlotView: Don't post spec in calcSpecs [\#1135](https://github.com/supercollider/supercollider/pull/1135) ([jamshark70](https://github.com/jamshark70)) - mergeCharFormat instead of setCharFormat, so existing format info isn't ... [\#1134](https://github.com/supercollider/supercollider/pull/1134) ([scztt](https://github.com/scztt)) - Colorize lines in the post window. [\#1131](https://github.com/supercollider/supercollider/pull/1131) ([scztt](https://github.com/scztt)) - Allow the addReplace action to replace existing nodes while keeping the ... [\#1130](https://github.com/supercollider/supercollider/pull/1130) ([scztt](https://github.com/scztt)) - Show line number \(v3\) [\#1129](https://github.com/supercollider/supercollider/pull/1129) ([vdonnefort](https://github.com/vdonnefort)) - supernova: ensure that daz/ftz are set in all audio threads [\#1127](https://github.com/supercollider/supercollider/pull/1127) ([timblechmann](https://github.com/timblechmann)) - File.schelp: changed pathnames to fully qualified [\#1126](https://github.com/supercollider/supercollider/pull/1126) ([miczac](https://github.com/miczac)) - some supernova fixes [\#1123](https://github.com/supercollider/supercollider/pull/1123) ([timblechmann](https://github.com/timblechmann)) - ide: add show/hide line number feature [\#1121](https://github.com/supercollider/supercollider/pull/1121) ([vdonnefort](https://github.com/vdonnefort)) - scsynth coreaudio fixes [\#1118](https://github.com/supercollider/supercollider/pull/1118) ([gurk](https://github.com/gurk)) - Topic/supernova tcp [\#1109](https://github.com/supercollider/supercollider/pull/1109) ([timblechmann](https://github.com/timblechmann)) - sclang: fix accidental number literal [\#1105](https://github.com/supercollider/supercollider/pull/1105) ([mohayonao](https://github.com/mohayonao)) - sclang: fix float radix with pi [\#1104](https://github.com/supercollider/supercollider/pull/1104) ([mohayonao](https://github.com/mohayonao)) - server: mapped audio bus for /g\_queryTree.reply [\#1103](https://github.com/supercollider/supercollider/pull/1103) ([8c6794b6](https://github.com/8c6794b6)) - Initialize openPorts variable before startup.scd file is executed. [\#1102](https://github.com/supercollider/supercollider/pull/1102) ([marierm](https://github.com/marierm)) - Fix ctrl-w [\#1101](https://github.com/supercollider/supercollider/pull/1101) ([muellmusik](https://github.com/muellmusik)) - supernova: protect synth controls [\#1095](https://github.com/supercollider/supercollider/pull/1095) ([timblechmann](https://github.com/timblechmann)) - update readline version from homebrew in os x readme [\#1093](https://github.com/supercollider/supercollider/pull/1093) ([seansay](https://github.com/seansay)) - HID fix cleaned up [\#1092](https://github.com/supercollider/supercollider/pull/1092) ([sensestage](https://github.com/sensestage)) - ClassLib: SimpleNumber: biexp return calculated value [\#1089](https://github.com/supercollider/supercollider/pull/1089) ([mohayonao](https://github.com/mohayonao)) - Netbsd compatibility [\#1088](https://github.com/supercollider/supercollider/pull/1088) ([danstowell](https://github.com/danstowell)) - Tiny correction [\#1080](https://github.com/supercollider/supercollider/pull/1080) ([arnaldorusso](https://github.com/arnaldorusso)) - Classlib: SystemSynthDefs: Remove postln that shouldn't have been committed [\#1076](https://github.com/supercollider/supercollider/pull/1076) ([jamshark70](https://github.com/jamshark70)) - Classlib: Server.sc: Prevent an inadvertent "non-inlined function" warning [\#1075](https://github.com/supercollider/supercollider/pull/1075) ([jamshark70](https://github.com/jamshark70)) - cmake: disable some msvc warnings [\#1074](https://github.com/supercollider/supercollider/pull/1074) ([timblechmann](https://github.com/timblechmann)) - Classlib: GUI: Reinstate proper functioning of ObjectGui system [\#1073](https://github.com/supercollider/supercollider/pull/1073) ([marierm](https://github.com/marierm)) - lang: include missing header [\#1072](https://github.com/supercollider/supercollider/pull/1072) ([timblechmann](https://github.com/timblechmann)) - class library: single lag value in NamedControl shouldn't result in an a... [\#1071](https://github.com/supercollider/supercollider/pull/1071) ([miguel-negrao](https://github.com/miguel-negrao)) - sclang: deepfreeze - do not freeze immutable / permanent objects [\#1069](https://github.com/supercollider/supercollider/pull/1069) ([timblechmann](https://github.com/timblechmann)) - DreamHouse.scd: replaced code on request by author [\#1067](https://github.com/supercollider/supercollider/pull/1067) ([miczac](https://github.com/miczac)) - supernova: make apple clang happy [\#1066](https://github.com/supercollider/supercollider/pull/1066) ([timblechmann](https://github.com/timblechmann)) - Help: Fix envelope handling in a pattern-cookbook example [\#1061](https://github.com/supercollider/supercollider/pull/1061) ([jamshark70](https://github.com/jamshark70)) - Fix NRT file paths [\#1060](https://github.com/supercollider/supercollider/pull/1060) ([jamshark70](https://github.com/jamshark70)) - lang: Fix memory corruption bug introduced in commit ac613331d5062bcd1ae... [\#1054](https://github.com/supercollider/supercollider/pull/1054) ([muellmusik](https://github.com/muellmusik)) - syntax highlight and allow running code from schelp files [\#1052](https://github.com/supercollider/supercollider/pull/1052) ([miguel-negrao](https://github.com/miguel-negrao)) - Classlib: fixed PatternProxy constrainStream so defaultQuant works [\#1043](https://github.com/supercollider/supercollider/pull/1043) ([d0kt0r0](https://github.com/d0kt0r0)) - Classlib: Change NetAddr's default port to nil [\#1040](https://github.com/supercollider/supercollider/pull/1040) ([jamshark70](https://github.com/jamshark70)) - class library: Env\#\*step easier creation of step envelopes [\#1039](https://github.com/supercollider/supercollider/pull/1039) ([miguel-negrao](https://github.com/miguel-negrao)) - sclang: Fixed bug where osc bundles were being chooped midway [\#1038](https://github.com/supercollider/supercollider/pull/1038) ([miguel-negrao](https://github.com/miguel-negrao)) - Small tweaks required for building libscsynth for Win 64-bit [\#1035](https://github.com/supercollider/supercollider/pull/1035) ([maedoc](https://github.com/maedoc)) - lang: capture elapsedTime\(\) when a packet is received, rather than just ... [\#1032](https://github.com/supercollider/supercollider/pull/1032) ([muellmusik](https://github.com/muellmusik)) - plugins: EnvGen - initialize level of initial \hold segments [\#1028](https://github.com/supercollider/supercollider/pull/1028) ([timblechmann](https://github.com/timblechmann)) - Update INSTALL [\#1025](https://github.com/supercollider/supercollider/pull/1025) ([jwakely](https://github.com/jwakely)) - plugins: EnvGen - update number of produced samples on audio-rate gates [\#1024](https://github.com/supercollider/supercollider/pull/1024) ([timblechmann](https://github.com/timblechmann)) - sclang: add terminal standalone option [\#1021](https://github.com/supercollider/supercollider/pull/1021) ([miguel-negrao](https://github.com/miguel-negrao)) - Server multi client [\#1019](https://github.com/supercollider/supercollider/pull/1019) ([muellmusik](https://github.com/muellmusik)) - sc class library: events: allocWrite type [\#1017](https://github.com/supercollider/supercollider/pull/1017) ([vividsnow](https://github.com/vividsnow)) - fix filepath typo in os x readme file [\#1015](https://github.com/supercollider/supercollider/pull/1015) ([seansay](https://github.com/seansay)) - sclang/identDictput: test if object is mutable before changing [\#1012](https://github.com/supercollider/supercollider/pull/1012) ([mortuosplango](https://github.com/mortuosplango)) - Disable AppNap in QtCollider, sclang, and scsynth [\#1011](https://github.com/supercollider/supercollider/pull/1011) ([snickell](https://github.com/snickell)) - Minor enhancements after first rewrite [\#1003](https://github.com/supercollider/supercollider/pull/1003) ([bagong](https://github.com/bagong)) - scdoc: minor correction to Dshuf new argument - should be repeats and no... [\#1002](https://github.com/supercollider/supercollider/pull/1002) ([redFrik](https://github.com/redFrik)) - Rework OSX Readme [\#1000](https://github.com/supercollider/supercollider/pull/1000) ([bagong](https://github.com/bagong)) - Add matchLangIP method and primitive [\#998](https://github.com/supercollider/supercollider/pull/998) ([muellmusik](https://github.com/muellmusik)) - Fix open document [\#997](https://github.com/supercollider/supercollider/pull/997) ([muellmusik](https://github.com/muellmusik)) - Mac OS 10.9 SDK compatibility [\#994](https://github.com/supercollider/supercollider/pull/994) ([mortuosplango](https://github.com/mortuosplango)) - update to boost-1.55 [\#993](https://github.com/supercollider/supercollider/pull/993) ([timblechmann](https://github.com/timblechmann)) - scvim: Adding tmux support, fixing screen support, fixing sclang restart/start/kill \(also in terminal multiplexers\) [\#990](https://github.com/supercollider/supercollider/pull/990) ([dvzrv](https://github.com/dvzrv)) - boost: fix build error with recent versions of glibc [\#988](https://github.com/supercollider/supercollider/pull/988) ([gusano](https://github.com/gusano)) - cmake: disable SC\_WII by default [\#987](https://github.com/supercollider/supercollider/pull/987) ([gusano](https://github.com/gusano)) - external libs: bump nova-tt [\#983](https://github.com/supercollider/supercollider/pull/983) ([timblechmann](https://github.com/timblechmann)) - help: update phasor [\#978](https://github.com/supercollider/supercollider/pull/978) ([miguel-negrao](https://github.com/miguel-negrao)) - Topic/env step2 [\#975](https://github.com/supercollider/supercollider/pull/975) ([timblechmann](https://github.com/timblechmann)) - class library: allow NamedControl.new\(\) to return non-arrayed Lag \(fixing issue 973\) [\#974](https://github.com/supercollider/supercollider/pull/974) ([totalgee](https://github.com/totalgee)) - Topic/for master [\#971](https://github.com/supercollider/supercollider/pull/971) ([timblechmann](https://github.com/timblechmann)) - Ide editor improvements improvements [\#970](https://github.com/supercollider/supercollider/pull/970) ([muellmusik](https://github.com/muellmusik)) - lang: Add editable property to QWebView [\#969](https://github.com/supercollider/supercollider/pull/969) ([muellmusik](https://github.com/muellmusik)) - Topic/for master [\#963](https://github.com/supercollider/supercollider/pull/963) ([timblechmann](https://github.com/timblechmann)) - class library: speed improvements in a few places where bit operations are used. [\#962](https://github.com/supercollider/supercollider/pull/962) ([redFrik](https://github.com/redFrik)) - Topic/for master [\#953](https://github.com/supercollider/supercollider/pull/953) ([timblechmann](https://github.com/timblechmann)) - Scide document rework text mirror [\#948](https://github.com/supercollider/supercollider/pull/948) ([muellmusik](https://github.com/muellmusik)) - class library: pbind midi type - fix for sending sysex [\#947](https://github.com/supercollider/supercollider/pull/947) ([redFrik](https://github.com/redFrik)) - help: changed .send\(s\) for .add in SynthDef example [\#946](https://github.com/supercollider/supercollider/pull/946) ([brunoruviaro](https://github.com/brunoruviaro)) - Classlib: Fix 2 issues regarding Rest and patterns [\#941](https://github.com/supercollider/supercollider/pull/941) ([jamshark70](https://github.com/jamshark70)) - Topic/asio appclock [\#940](https://github.com/supercollider/supercollider/pull/940) ([timblechmann](https://github.com/timblechmann)) - class library: NamedControl - avoid lags if possible [\#938](https://github.com/supercollider/supercollider/pull/938) ([timblechmann](https://github.com/timblechmann)) - Documentation: Escape char in string literals, and thisProcess.nowExecutingPath [\#935](https://github.com/supercollider/supercollider/pull/935) ([jamshark70](https://github.com/jamshark70)) - Filter Help Docs: Warning about frequencies close to 0 [\#934](https://github.com/supercollider/supercollider/pull/934) ([miczac](https://github.com/miczac)) - Simplify and enhance Windows installer [\#929](https://github.com/supercollider/supercollider/pull/929) ([bagong](https://github.com/bagong)) - Library: Prevent inline-function warning in FFTUnpacking.sc [\#922](https://github.com/supercollider/supercollider/pull/922) ([jamshark70](https://github.com/jamshark70)) - Class Library: Object - performance improvements for Object.dup [\#921](https://github.com/supercollider/supercollider/pull/921) ([thormagnusson](https://github.com/thormagnusson)) - linux readme: qt5 limitation [\#917](https://github.com/supercollider/supercollider/pull/917) ([miguel-negrao](https://github.com/miguel-negrao)) - scsynth: support for receiving nested OSC bundles. [\#914](https://github.com/supercollider/supercollider/pull/914) ([ventosus](https://github.com/ventosus)) - supernova: synthdef corruption - added synthef path to error message [\#912](https://github.com/supercollider/supercollider/pull/912) ([miguel-negrao](https://github.com/miguel-negrao)) - SCDoc: remove MathJax support [\#910](https://github.com/supercollider/supercollider/pull/910) ([gusano](https://github.com/gusano)) - implement sclang sockets via boost.asio & move ReplyAddress out of the public interface [\#903](https://github.com/supercollider/supercollider/pull/903) ([timblechmann](https://github.com/timblechmann)) - HelpSource: MIDIFunc: show how to free a MIDIFunc [\#900](https://github.com/supercollider/supercollider/pull/900) ([gusano](https://github.com/gusano)) - make sure GUI.skins is not nil in ProxyMixerOld [\#893](https://github.com/supercollider/supercollider/pull/893) ([redFrik](https://github.com/redFrik)) - scide: sc\_editor: include parenthesis in regionAroundCursor\(\) [\#892](https://github.com/supercollider/supercollider/pull/892) ([gusano](https://github.com/gusano)) - Pproto minor typo fix [\#891](https://github.com/supercollider/supercollider/pull/891) ([blacksound](https://github.com/blacksound)) - Topic/markdown for readme files [\#890](https://github.com/supercollider/supercollider/pull/890) ([gusano](https://github.com/gusano)) - sclang: support for receiving nested OSC bundles. [\#881](https://github.com/supercollider/supercollider/pull/881) ([ventosus](https://github.com/ventosus)) - sclang: support for more non-standard OSC types [\#878](https://github.com/supercollider/supercollider/pull/878) ([ventosus](https://github.com/ventosus)) - sclang bugfix: proper handling of Open Sound Control Blob Arguments [\#877](https://github.com/supercollider/supercollider/pull/877) ([ventosus](https://github.com/ventosus)) - Quarks: use new sf.net repo url [\#873](https://github.com/supercollider/supercollider/pull/873) ([gusano](https://github.com/gusano)) - classlib \(quarks\): Defer svn path checking until needed; try{} the check [\#865](https://github.com/supercollider/supercollider/pull/865) ([jamshark70](https://github.com/jamshark70)) - Ndef.schelp, Shaper.schelp, Wavetable.schelp [\#846](https://github.com/supercollider/supercollider/pull/846) ([miczac](https://github.com/miczac)) - Server : pings before considered dead [\#842](https://github.com/supercollider/supercollider/pull/842) ([miguel-negrao](https://github.com/miguel-negrao)) - remove bundled elisp library tree-widget.el [\#840](https://github.com/supercollider/supercollider/pull/840) ([tarsius](https://github.com/tarsius)) - scdoc: Pseg: duration pattern in beats not seconds [\#827](https://github.com/supercollider/supercollider/pull/827) ([vividsnow](https://github.com/vividsnow)) - new version of README.txt, corrections to help docs [\#822](https://github.com/supercollider/supercollider/pull/822) ([miczac](https://github.com/miczac)) - examples: ASA - simplify and cleanup [\#819](https://github.com/supercollider/supercollider/pull/819) ([gusano](https://github.com/gusano)) - updated README.txt [\#818](https://github.com/supercollider/supercollider/pull/818) ([miczac](https://github.com/miczac)) - thisFunction/thisFunctionDef keywords in help [\#809](https://github.com/supercollider/supercollider/pull/809) ([vividsnow](https://github.com/vividsnow)) - Update the description of LinPan2. [\#808](https://github.com/supercollider/supercollider/pull/808) ([vanhuman](https://github.com/vanhuman)) - Updates the description. [\#807](https://github.com/supercollider/supercollider/pull/807) ([vanhuman](https://github.com/vanhuman)) - Changed the description of Balance2 into something a bit more explanatory. [\#806](https://github.com/supercollider/supercollider/pull/806) ([vanhuman](https://github.com/vanhuman)) - Added missing closing "\)" in MIDI input example. [\#803](https://github.com/supercollider/supercollider/pull/803) ([attejensen](https://github.com/attejensen)) - sc ide: settings editor: move insertMatchingTokens setting [\#796](https://github.com/supercollider/supercollider/pull/796) ([gusano](https://github.com/gusano)) - Update GUI-Layout-Management.schelp [\#795](https://github.com/supercollider/supercollider/pull/795) ([olafklingt](https://github.com/olafklingt)) - sc ide: sc editor: slight improvement of matching token insertion [\#792](https://github.com/supercollider/supercollider/pull/792) ([gusano](https://github.com/gusano)) - sc ide: settings editor: move insertMatchingTokens setting [\#791](https://github.com/supercollider/supercollider/pull/791) ([gusano](https://github.com/gusano)) - class library: UGen - provide bilin [\#781](https://github.com/supercollider/supercollider/pull/781) ([timblechmann](https://github.com/timblechmann)) - scide: left|right arrow keys disable completion [\#773](https://github.com/supercollider/supercollider/pull/773) ([gusano](https://github.com/gusano)) - removed superfluous links under related [\#766](https://github.com/supercollider/supercollider/pull/766) ([redFrik](https://github.com/redFrik)) - added related link to SendReply [\#765](https://github.com/supercollider/supercollider/pull/765) ([redFrik](https://github.com/redFrik)) - Update Warp1.schelp [\#759](https://github.com/supercollider/supercollider/pull/759) ([redFrik](https://github.com/redFrik)) - fix git recursive flag command [\#747](https://github.com/supercollider/supercollider/pull/747) ([hems](https://github.com/hems)) - Adding "Contributing with the documentation" to "Writing Help.schelp" file [\#746](https://github.com/supercollider/supercollider/pull/746) ([hems](https://github.com/hems)) - cmake: link pthreads libraries [\#742](https://github.com/supercollider/supercollider/pull/742) ([gusano](https://github.com/gusano)) - Topic/simplify cpu dispatching [\#732](https://github.com/supercollider/supercollider/pull/732) ([timblechmann](https://github.com/timblechmann)) - Multichannel envelope fixes [\#718](https://github.com/supercollider/supercollider/pull/718) ([timblechmann](https://github.com/timblechmann)) - Topic/ide cmdline [\#711](https://github.com/supercollider/supercollider/pull/711) ([timblechmann](https://github.com/timblechmann)) - out-comment s\_tick [\#709](https://github.com/supercollider/supercollider/pull/709) ([2mc](https://github.com/2mc)) - include: split public and private headers & prototype libsclang interface [\#703](https://github.com/supercollider/supercollider/pull/703) ([timblechmann](https://github.com/timblechmann)) - in OpenBSD search for classes using cmake configuration [\#685](https://github.com/supercollider/supercollider/pull/685) ([acamari](https://github.com/acamari)) - ports supercollider to OpenBSD [\#683](https://github.com/supercollider/supercollider/pull/683) ([acamari](https://github.com/acamari)) - scide: code editor - insert path when dropping unknown files [\#663](https://github.com/supercollider/supercollider/pull/663) ([totalgee](https://github.com/totalgee)) - asSynthDef and SynthDef.name should return symbols [\#661](https://github.com/supercollider/supercollider/pull/661) ([timblechmann](https://github.com/timblechmann)) - Fix for \#657; copy/paste to OS X Mail loses tabs [\#659](https://github.com/supercollider/supercollider/pull/659) ([totalgee](https://github.com/totalgee)) - Main:startup: initialize openPorts before StartUp.run to enable OSCFunc ... [\#647](https://github.com/supercollider/supercollider/pull/647) ([iani](https://github.com/iani)) - Properly initialize mSaveTime on document open and save. [\#597](https://github.com/supercollider/supercollider/pull/597) ([scztt](https://github.com/scztt)) - Corrected some typos and errors in the help docs [\#506](https://github.com/supercollider/supercollider/pull/506) ([andrewcsmith](https://github.com/andrewcsmith)) - Fixed two typos in the update news [\#500](https://github.com/supercollider/supercollider/pull/500) ([andrewcsmith](https://github.com/andrewcsmith)) - class library: fix server meter initialization [\#484](https://github.com/supercollider/supercollider/pull/484) ([timblechmann](https://github.com/timblechmann)) - Refer to TChoose from the TIRand help file [\#355](https://github.com/supercollider/supercollider/pull/355) ([rukano](https://github.com/rukano)) - Typo in PparGroup's help file example [\#351](https://github.com/supercollider/supercollider/pull/351) ([rukano](https://github.com/rukano)) - corrected pathname for sound file in LevelIndicator.schelp [\#347](https://github.com/supercollider/supercollider/pull/347) ([miczac](https://github.com/miczac)) SuperCollider v3.6.5, released 2013-04 ====================================== Jakob Leben (10): - sc class library: fix regression in Server:-scope - scide: add "reset font size" action to post window and help browser - scide: autocompletion: order methods by class hierarchy when class is known - documentation: improve info on logical time, clocks and threads - documentation: more info on threads, clocks and time - sclang: PyrThread: ensure slot type safety - documentation: clarify the functioning of Thread and Routine - streamline README.txt - documentation: improve thisFunction and thisFunctionDef Julian Rohrhuber (3): - sc class library: replacing the source of a node proxy led to hanging patterns - sc class library: NodeProxy:cleanNodeMapnow works even if no settings are present - fix typo / removing the implication that ansi-C isn't appropriate Michael Zacherl (5): - In.schelp: replaced AudioIn w/ SoundIn in reference, added loudness in example section - Knob.schelp: repositioned text in mouseOverAction example - Klang.schelp: changed 'filter' to 'oscillator' in methods section - DynKlang.schelp: changed 'filter' to 'oscillator' in methods section - README.txt: reworked and simplified with focus on SC IDE and version 3.6 vividsnow (2): - scdoc: Pseg: duration pattern in beats not seconds - scdoc: add thisFunctionDef/thisFunction SuperCollider v3.6.4, released 2013-04 ====================================== Dan Stowell (1): - SinOsc and Osc: note phase issue beyond +-8pi. Fixes #815 Jakob Leben (34): - sclang: fix Char:-isUpper/isLower - qtcollider: add QListView:-selectionAction - qtcollider: add QListView:-selection setter - scide: remove credits for kiberpipa - help: GUI - improve documentation of alignment options - help: add guide on creating standalone applications - sc ide: show impl/ref lookup dialogs even when no text under cursor - sc class library: ClassBrowser: fix search with empty query string - sc ide: interpreter: post notification on quit or crash - qtcollider: pass exit code up to SC_TerminalClient - sc ide: fix and improve region detection - sc ide: sc editor: add action to select pair of brackets enclosing cursor - sc ide: sc editor: update bracket match highlight after applying settings - qtcollider: QTextView: increase 'selectedString' compatibility, fix docs - qtcollider: envelope view: fix drawing of quadratic and cubic curves - sc ide: help browser: delegate docklet focus to webpage view - sc ide: docklet: when focusing, also activate window - sc ide: fix auto-indenting closing brackets on certain locales - sc ide: ensure dock widgets within screen bounds when first undocked - qtcollider: QTextView: set 'enterInterpretsSelection' to true by default - scide: config dialog: preserve font when toggling "show only monospaced" - scide: select line in code on triple click - scide: ensure last active window activated after open/save file dialog - scide: on startup, remove invalid file paths from "recent documents" list - scide: improve default paths in open/save dialogs - scide: save document dialog: always allow saving with any extension - scide: editor: highlight unmatched brackets just like mismatched ones - qtcollider: StackLayout: fix crash when removing contained widget - qtcollider: do not allow reparenting layouts, to avoid crashing - scide: fix closing tool panels on Escape - scide: impl/ref lookup: close dialog when opening documentation for class - Revert "Revert "scide: on Mac, make one global menu to share by all windows"" - scide: prevent erroneous overriding of shortcuts on Mac OS James Harkins (2): - Library: Bugfix for PmonoArtic inside other patterns w/cleanup - Library: Fix Pfset passing child cleanups up to its parent(s) Tim Blechmann (10): - Help: fix rlpf help file - plugins: DemandEnv - fix shape polling - plugins: GrainBuf - catch both inf and NaN phase arguments - scsynth: prevent possible buffer overflow - cmake build system: fix x11 include paths - class library: Bus - fix get method for multi-channel busses - class library: Server.scope - remove limitation to 16 channels - plugins: LocalOut - don't crash server if LocalIn is missing - sclang: prevent buffer overflow - scide: link with librt Victor Bombi (1): - supernova: CMakeLists.txt must set include dirs for fftw3f attejensen (1): - Update MIDI.schelp SuperCollider v3.6.3, released 2013-02 ====================================== Dan Stowell (2): - Add cmake option NO_GPL3 to simplify building of GPL2 binaries - SCDoc: generalise licensing from GPL3+ to GPL2+ Graeme Urquhart (2): - Issue #702 fix: sendSelection receives NSString - String:Help of split method matches implementation Jakob Leben (24): - qtcollider: relicense to GPL version 2 - sclang: terminal client - fix and simplify request handling - qtcollider: support String:-speak when Speech class is available - cmake: set LIBSCSYNTH=ON by default on Windows - qtcollider: QView - do not block beginDrag if currentDrag is already set - qtcollider: QKnob - let 'background' affect knob color - sc ide: improve server boot/quit actions - sc ide: improve interpreter start/stop actions - sc ide: improve default server booting shortcuts - qtcollider: sf view: fix loading non-power-of-two floating point files - sc ide: disable zooming by mouse wheel (scrolling) - sc ide: editor - set Qt::WA_MacNoClickThrough on viewport - help: improve the SC IDE guide - qtcollider: implement QtGUI:*cursorPosition - class library: Platform - redirect getMouseCoords to GUI - sc ide: post window - disable click-through on Mac OS X - sc ide: add Help menu action to open the SuperCollider IDE guide - help: SC IDE guide - show scaled screenshot, with a link to unscaled one - sc ide: docklets - fix geometry after undocking - sc ide: change default shortcuts for Go To Next/Previous Region - sc ide: make cmd-period silent - sc ide: improve status box context menu interaction - sc ide: add context menu to interpreter status box James Harkins (4): - Fix title:: tags in the practical guide: user-friendly titles vs. filenames - Add Practical Guide Cookbook entry on swing rhythms - PG_Cookbook_08: Fix an omitted copy/paste - Fix typo in analysis example: BufWr.ar on a kr signal is bad Tim Blechmann (22): - supernova: fix crash on /quit with portaudio - class library: PlusFreqScope - survive server actions - scide: remove ctrl-b shortcut - class library: FreqScope - fix for starting scope after booting - common: introduce new autogenerated SC_Version.hpp header - class library: fix Array-unlace - supernova: plugin interface - guard access to rt-pool - plugins: IOUgens - prevent buffer overflow - Help: BrownNoise - use a convention of -20db - supernova: sized array - assert boundaries - supernova: sndfile backend - correctly use correct blocksize for temp buffer - supernova: jack backend - avoid uninitialized value - supernova: nrt engine - nicer formatting of message log - plugins: ui ugens - initialize libx11 for threading - supernova: start dsp threads from run methods - sclang: library config - correcty handle library config command line argument - server plugins: RecordBuf - fix multichannel corruption and buffer overrun - fftlib: for now we avoid intptr_t - server plugins: fix div_ka - plugins: osc ugens - fix GET_TABLE macro - plugins: OscUGens - ensure buffer initialization - scide: add menu item to open the user application support directory Victor Bombi (2): - common: win32 - avoid integer truncation - supernova: correctly print synthdef path SuperCollider v3.6.2, released 2012-12 ====================================== BS Collist (1): - qtcollider: QEnvelopeView - add method to return all selected indexes Jakob Leben (32): - common (windows): unify access to known folder paths - sclang (windows): add primitive to access "My Documents" dir - cmake: expand the search for libsndfile and libfftw3f - cmake (Windows): use CMAKE_LIBRARY_PATH for fixup_bundle() search dirs - scide: let cmd-period have an application-wide shortcut context - scide: DocumentManager - refresh cached file info before storing save time - scide: help browser - support doc/impl/ref lookup for selected text - scide: search widget hierarchy upwards for first handler of lookup actions - scide: GenericLookupDialog - no need for subclassing QTreeView anymore - scide: make doc/impl/ref lookup shortcuts work on detached docklets - scide: always pop up lookup dialogs with the active window as the parent - scide: update translation sources, add italian - qtcollider: start drag within mouse event handler - qtcollider: QStethoscope2 - reverse operation of horizontal zoom slider - scide: GenericCodeEditor - set Qt::WA_MacNoClickThrough widget attribute - scide: SyntaxHighlighter - swap QChar::toAscii() for toLatin1() - scide: Document - swap QString::toAscii() for QString::toLatin1() - scide: MainWindow - substitute deprecated QFileDialog::setFilter(QString) - scide: MainWindow - include QMimeData - scide: PostWindow - include QMimeData - scide: GenericCodeEditor - include QMimeData - qtcollider: QWidgetProxy - include QDrag - sclang: SCIpcClient - fix includes - cmake: sclang - fix building when SC_IDE=ON and SC_QT=OFF - cmake: scide - add QtNetwork to required Qt modules - qtcollider: QStethoscope2 - refactor for robustness - qtcollider: QListView - add 'selection' method to get all selected indexes - help: document new 'selection' methods of EnvelopeView and ListView - help: View - improve documentation, fix links - help: fix a large amount of broken links due to changes in SCDoc - cmake: FindPortmidi - actually implement auto-finding portmidi James Harkins (1): - Fix bug introduced by 7f29d322: Don't free the same alloc'ed index twice Tim Blechmann (18): - scide: DocumentManager - read files via QTextStream to decode characters - supernova: osc handler - fix completion message and done message for /b_close - supernova: asynchronous log - fix string splitting - supernova: compile fix - supernova: send /fail messages on /notify commands - supernova: send /fail on buffer commands - supernova: fix sndfile error handling - win32: ensure stack alignment - plugins: fix GrainBuf cleanup - Help: SymbolicNotations - replace SCSlider with Slider - supernova: plugin interface - protect against multiple done actions - Help: remove memStore - class library: Buffer - freeMsg should clear all cached information - supernova: osc interface - fix bug with node reordering - supernova: buffer_read - don't check samplerate when queueing soundfiles - class library: fix Function.plot - plugins: RecordBuf - fix recordbuf overrun & fix done action handling - Help: RecordBuf - RecordBuf is recording, not playing SuperCollider v3.6.1, released 2012-11 ====================================== Dan Stowell (1): - SpecFlatness: prevent NaN output for silence (thanks nick collins) Glen Fraser (1): - scide: code editor / post window - copy using plain text Jakob Leben (13): - update README_WINDOWS.txt for changed application data locations - fix compilation with MinGW (broken static initialization) - scide: find/replace - use Qt translation system to handle singular/plural - cmake: scide - improve handling translations - scide: load translations from app resource directory - scide: update translation source files - scide: change english translation file name to serve as fallback - sclang: (Windows) change app support dir from roaming to local - scide: load fallback translation in addition to locale translation - sclang: add primitive to allow Platform to access user home directory - class library: WindowsPlatform - set a user-friendly default recordingsDir - readme (windows): add instructions on moving application data Tim Blechmann (1): - class library: SynthDef - writeDefFile should use default SynthDef path SuperCollider v3.6.0, released 2012-11 ====================================== Major release with many new features - please see the help doc "News in 3.6" for more information. http://doc.sccode.org/Guides/News-3_6.html SuperCollider v3.5.7, released 2012-11 ====================================== Jakob Leben (6): - sclang: (Windows) fix String:-getenv to return variables set with -setenv - class library: ServerMeter - fix closing window when server has never run - sclang: fix 'gcd' and 'lcm' methods - qtcollider: QStethoscope2 - fix width of number boxes - qtcollider: fix SoundFileView:-selectAll and -selectNone - qtcollider: fix QPen:*matrix setter - combine instead of replace matrix Julian Rohrhuber (1): - class library: jitlib - Avoiding sync problems with free/play Tim Blechmann (9): - plugins: filters - fix initialization of filter parameters - external libraries: nova-simd update - external libraries: move nova-simd submodule to github - plugins: DelayN - fix initialization code - Revert "plugins: DelayN - fix initialization code" - common: fftlib - increase size limit for ffts - sclang: server shm interface - fix setting of multiple values - plugin interface: provide wrapper class for c++-style unit generators SuperCollider v3.5.6, released 2012-10 ====================================== Dan Stowell (2): - Improve error messages when cmake can't find optional things - Compile fix for Qt widget on arm. Upstreamed from debian-multimedia (thanks Felipe Sateler) James Harkins (1): - Fix Spawner bug: cleanup.update is mandatory, including rest events Jonatan Liljedahl (7): - Quarks: fix typo and also open old-style helpfiles ending with .htm - Include old non-converted helpfiles in SCDoc document index - HelpBrowser: also open RTF files with whatever is available - Even more support for old help files - scdoc: use JS hasOwnProperty instead of testing the property directly - HelpBrowser: post javascript errors - SCDoc: properly escape keys in generated docmap.js Joshua Parmenter (1): - Fix ServerOptions instance var ordering, etc., to make internal server booting use correct number of audio bus channels. Tim Blechmann (4): - cmake: provide explicit option to use system-installed boost libraries - external libraries - revert submodule updates - lang: SerialPort - fix invocation of done action SuperCollider v3.5.5, released 2012-09 ====================================== Dan Stowell (1): - Fix bug in Complex:exp James Harkins (1): - Convert misleading and confusing OSC-style example into object-style Joshua Parmenter (2): - fix IEnvGen kr UGen - fix cocoa window alpha setting Tim Blechmann (12): - sclang: fix Array:extendWrap for negative size argument - sclang: array primitivies - protect all array extend primitives against negative sizes - scdoc: fix string comparison in parser - supernova: sized_array - don't allocate memory for zero-sized array - plugins: GrainBuf - fix crash when using nan as position control - scsynth: ensure alignment of wire buffers - supernova: catch exceptions when reading synthdefs - supernova: free_aligned - fix fallback implementation for null pointers - cmake build system: dont compile shared library with -fwhole-program - plugins: GrainBuf - allocate grain after reading window - plugins: GrainBuf - fix access to default hann window Victor Bombi (1): - cpu usage for portaudio_backend.hpp SuperCollider v3.5.4, released 2012-08 ====================================== Dan Stowell (5): - Fix typo that causes build fail on big-endian archs, thanks Felipe Sateler - fix build on ARM (where qreal==float); thanks Felipe Sateler - Strip gremlin characters from JITLib wrapForNodeProxy.sc - choose clipping rather than wraparound for writing integer-format audio files (libsndfile setting) - arm build fix: another double->qreal in QcMultiSlider James Harkins (1): - Improve documentation of GUI kits and kit switching Jonatan Liljedahl (2): - SCDoc: Use proper static string constants instead of comparing string literals. - Revert "reinstate Mix.arFill and Mix.krFill for backward compatibility reasons" Julian Rohrhuber (2): - reinstate Mix.arFill and Mix.krFill for backward compatibility reasons - improve string helpfile Tim Blechmann (10): - plugins: GrainUGens - handle unallocated window buffers - plugins: GrainBuf - reject multi-channel buffers - plugins: grain ugens - treat empty window buffers correctly - server: provide memory alignment wrappers for msvc - server: scsynth - ensure correct deallocation of SndBuffer memory - server/language/supernova: automatically clip integer audio files - scsynth: correctly free aligned buffers - Help: fix OSC function in SendPeakRMS help file - package: use alternative implementation of git-archive-all Victor Bombi (1): - MSVC fix SuperCollider v3.5.3, released 2012-06 ====================================== Dan Stowell (6): - LocalIn helpfile fix, thanks Bruno Ruviaro - Fix scvim regsitry file for updated filename (thanks Carlo Capocasa) - version number to 3.5.3 - Server helpfile: see-also reference docs - SCVim.sc should not be executable - cmake build system: use system boost libraries if available Jakob Leben (1): - cmake: fix Boost Thread linking on Windows James Harkins (10): - EnvGen_next_ak_nova: Hardcoded blocksize=64, change to - inNumSamples - Per Scott W., initSiblings is not needed - Reinstate Mix.ar and Mix.kr, with rate checks - Fix crossplatform fail: Scale.directory shouldn’t always depend - on Document - ListPatterns: offset.value omitted (inval) as an argument - Fix PbindProxy:storeArgs - should NOT call “source” on keys in - the array! - Scale:degreeToRatio should handle degrees outside of one - octave’s range - More meaningful error message for too many selectors - Explain the limitation on the number of selectors in one - FunctionDef - Correct spelling error Jonatan Liljedahl (3): - Methods.html: auto-redirect to Search if method not found - SCDoc: fix detection of old format class docs - Mix.ar was un-deprecated, so remove the deprecated method Joshua Parmenter (2): - fix scroll view problem for OS X 10.7.4 - update SC_DirUtils to look at the name of the app bundle on osx Julian Rohrhuber (14): - fix bugs due to wrong usage of partial application - PV_BinShift helpfile improved - PV_Diffuser helpfile improved - reformat statement for readability (no change of functionality) - helpfile improvements - improve array helpfile - add note to the loop argument of DiskIn (thanks Stefan). - improve helpfile - some helpfile improvements - improve helpfile - improve helpfile - improve and simplify FFT overview helpfile: fix some errors in - examples. - improve and simplify IFFT helpfile. - improve and simplify FFT helpfile, mention that hopsize must be - larger than 0.0 Tim Blechmann (11): - external libraries: update nova-tt (gcc 4.7 fix) - supernova: correctly implement replace semantics for /s_new - Help: Function.scope is not limited to OSX anymore - cmake build system: locate server plugins on freebsd - server: add support for RF64 - cmake build system: ensure boost include path for scsynth - cmake build system: set boost library path - cmake build system: link scapp with correct version of - libboost_thread - cmake build system: minor cleanup - supernova: fix asynchronous commands for empty reply address - common: fix non-apple builds SuperCollider v3.5.2, released 201 ====================================== Dan Stowell (3): - Remove outdated Japanese menus - Cannot use indentation for CMAKE example - on mac it is rendered as   which then breaks cmake compilation - Fix bug in FFT library if winsize != audiosize Jakob Leben (21): - qtcollider: fix QTextView:-background and QSoundFileView:-background - cmake: improve message if Qt4 or one of its components not found - qtcollider: QKnob: fix mouse response when mouseOverAction is set - qtcollider: implement missing QPopUpMenu:-background - qtcollider: QTextView fixes and improvements - help: add missing GUI examples - qtcollider: support use of UTF-8 encoded strings - qtcollider: QTextView: improve -enterInterpretsSelection - qtcollider: QTextField: never propagate Enter to parent - qtcollider: QEnvelopeView: improve node selection API and UI - help: update EnvelopeView documentation - help: fix incorrect info in EnvelopeView documentation - qtcollider: QObject:-getProperty: turn an error into a debug warning - qtcollider: implement drag-and-drop for data outside SC - qtcollider: improve key propagation in QListView and QTreeView - qtcollider: optimize view instantiation (take 2) - qtcollider: fix mouse wheel event being forwarded to SC for no reason - qtcollider: fix potential null pointer dereference - qtcollider: optimization - partially revert event handling changes - qtcollider: optimization - avoid a signal connection at QObject construction - qtcollider: optimization - avoid connecting signals with unnormalized signatures James Harkins (2): - Fix Pcollect/select/reject:embedInStream to pass inval to the function - setTheme: Inherit colors from parent theme if the user didn't specify Jonatan Liljedahl (41): - scdoc: MathJax: don't use fonts installed on users computer - New SCDoc parser and renderer. Faster, more stable, less buggy. - fix some helpfiles for new scdoc - scdoc.css update - scdoc: scapp compile fix - scdoc: defer indexAllDocuments until first use - HelpBrowser tweaks - scdoc: warn on additions for non-existent help doc - scdoc: fill in argument names for argument:: with no name given - SCDocRenderer: warn on broken links - scdoc: fix classtree:: rendering bug - scdoc: only warn on grouped methods argnames mismatch if argument:: tag is used - scdoc: avoid GC error in primitive - scdoc: collect metadata also from *.ext.schelp (doc additions) - scdoc: warn if argument:: name does not match real method arg - scdoc: updated SCDoc related docs - scdoc: warn if classdoc title and filename mismatch - scdoc: fix varargs name match warning - scdoc: render getter/setter combinations as two different methods - scdoc: warn if setter methods (trailing underscore) is documented explicitly - scdoc: more helpfile fixes - scdoc: fix some bugs, handle class docs with missing classes - scdoc Search.html: match also on filename for 'title' - schelp: fix some broken links - scdoc: add clearCache arg to indexAllDocuments, and don't render undocumented classes more than once per session - scdoc: updated SCDoc related helpfiles - schelp: more doc error fixes - scdoc: improve argument:: auto-fill and checks - String-warn and -error: don't print newline after WARNING: and ERROR: - scdoc: tweak warnings - scdoc: fix escaping of :: in metadata parsing and block verbatim - schelp: add keywords for scdoc tags in SCDocSyntax.schelp - scdoc: allow end-of-file as newline terminator, and improve error messages - scdoc: use setter_() syntax if more than one argument - scdoc: render method arg defaults as "foo: val" instead of "foo = val" - mention new scdoc implementation in News-3_5.schelp - scdoc parser: allow empty lines before headertags - SCDoc: fix escaping of & < and > - SCDoc: fix inf loop at missing :: end-tag in code blocks - SCDoc: allow EOF as terminator for private:: and similar tags - SCDoc: don't warn on missing trailing mul & add args Miguel Negrão (1): - [Class Libray] Quarks GUI - sort quarks by name Tim Blechmann (10): - plugins: fix Clip.kr - class library: archive TempoClock as compile string - cmake build system: restrict win32-specific cflags to win32 - external libraries: nova-simd update - external libraries: nova-simd compile fix - plugins: fix StereoConvolution2L constructor - scsynth: use aligned memory allocation functions from supernova - external libraries: nova-simd update - scsynth: provide zalloc as symbol redFrik (1): - scdoc: fixed a bunch of helpfile errors SuperCollider v3.5.1, released 2012-04 ====================================== Jakob Leben (13): - windows: properly pass the SC version to NSIS - qtcollider: QPopUpMenu: fix action triggering - qtcollider: get rid of "X is not implemented" message - class library: make Server:-plotTree resilient to GUI kit switching - help: improve Stethoscope documentation - class library: QStethoscope2: add missing class methods - class library: fix UGen scoping on out-of-process servers - class library: PlusFreqScope: simplify server checking - class library: fix and improve various 'scope' and 'freqscope' methods - help: fix Stethoscope:*isValidServer documentation - class library: ServerMeter: fix synth startup and cleanup - update README_WINDOWS.txt - windows: improve building and installation Jonatan Liljedahl (6): - lang11d: Fix parse tree generation of expr.(key:value, ...) - SC.app: allow saving plain text .schelp files - SCDoc: copymethod:: also search *.ext.schelp files - Update News for 3.5 doc - Fix typo in News-3_5.schelp and improve StartupFile.schelp - Update WritingPrimitives.schelp regarding GC safety Joshua Parmenter (1): - prevent HID crashes on OS X. Devices still aren't added to the queue though (longs for the locID aren't correctly set up) Scott Wilson (1): - Make Unpack1FFT a subclass of UGen, rather than of PV_ChainUGen Tim Blechmann (4): - class library: SynthDef - fix uploading of large synthdefs - sclang: block evaluation typesafety - sclang: signal primitives - fix Signal-fft SuperCollider v3.5.0, released 2012-03 ====================================== Major release with many new features - please see the help doc "News in 3.5" for more information. http://doc.sccode.org/Guides/News-3_5.html SuperCollider v3.4.5, released 2012-01 ====================================== Tim Blechmann (7): - class library: FreqScope fix - sclang: fix crash of scpacket overflow by using exception handling - sclang: pad PyrMethodRaw struct - sclang: force size of PyrSlot to 16 byte and fix PyrMethodRaw size - server plugins: fix div_ai_nova - plugins: Resonz - fix initialization - plugins: disable simd-optimization for tanh James Harkins (3): - Explicitly show the command to uninstall (for scons idiots like me). - (3.4) PathName now sets tmp directory using Platform - SimpleController:update would throw error if no actions had been 'put' in Dan Stowell (1): - Remove waf file from 3.4.x - was never used, and contains binary code, causing linux packaging problems. See ubuntu bug #529154 for details, and debian bug #529154 for sc-specific Mathieu Trudel-Lapierre (1): - Fixup environment variables used for linking against readline, libicu, curl, cwiid. Nick Collins (1): - Fix bug in MFCC ugen Noe Rubinstein (1): - Fix PMOsc doc: index -> pmindex dmotd (1): - Include altivec.h on linux powerpc, fixing FTBFS SuperCollider v3.4.4, released 2011-06 ====================================== Dan Stowell (4): - Improve format of copyright/GPL notices (issue raised in debian pkging) - Clarify Fontana copyright in MoogFF (and don't use keyword 'copyright' in files where he doesn't have copyright) - Update AUTHORS file - Remove unneeded PDF (debian raised query over copyright) Nick Collins (1): - Initial fix for headphones problem where plugging in or out headphones while using Built-in Output leads to loss of audio on OS X. Aggregate Devices not tackled at this point Tim Blechmann (15): - sclang: mathematical operators - clip2 fix - plugins: LPF - fix control-rate initialization - sclang: wii - don't use address of temporary - SCClassLibrary: ScoreStreamPlayer - do not add instances to server list - scsynth: apple - set denormal handling flags, if __SSE__ is defined - sclang: slotString - crash fix - plugins: XLine - correct handling of done actions - sclang: gc - introduce LazyCollect to avoid leak of frames and argument lists - plugins: Pitch.ar - fix crash for high execution period - changelog: fix version number - update changelog - sclang: parser - support message send syntax for unary operators - plugins: delay ugens - rt memory allocation may fail - sclang: compile fix SuperCollider v3.4.3 ====================================== Dan Stowell (2): - SC 3.4 set correct SOVERSION 1.0.0 for libs, and install more properly. (Changes ported from downstream debian packaging.) - lib SOVERSIONs back from 1.0.0 to 1, following debian-multimedia advice James Harkins (8): - Fix nowExecutingPath bug in scel (never backported?) - fix two bugs in NotificationCenter registerOneShot: - fix corner case in ClassBrowser - Fix asPseg bug for short curves array (which should wrap, not kill the stream) - Clear dataptr when closing a file (so that isClosed answers correctly) - Incorrectly used dataptr instead of fileptr in previous commit on this file - replace old, unsafe Dictionary test with a safer (but less OOPy) test - rats... I missed two others of the same Joshua Parmenter (1): - update version number Tim Blechmann (3): - scsynth: set ftz flag on osx - two commits: (1) simplify access to the superclass tree in Class. (2) when looking for a code file (openCodeFile) or cmd-J, it is now enough to select a full line, instead of havin - scons build system: libsclang build fix SuperCollider v3.4.2, released 2011-03 ====================================== Bugfixes: --------- - 2010-06-05 fix Latch first sample output bug: if trigger > 0 initially, latch should not output 0 - jh - 2010-09-04 fix firstArg behavior in BinaryOpUGen by a list-approved hack - jh - 2010-10-01 fix SConstruct so that libscsynth and libsclang get SONAME entries - ds - 2010-11-13 grainBuf: audio-rate trigger fix - tb - 2010-11-15 generate libsclang and libscsynth with .so.1 extension (and soname) on linux - ds - 2010-11-15 scons create symlinks from libX.so to libX.so.1 on linux, and install them - ds - 2010-11-16 added .htm files to SConstruct as approved help file extension - mb - 2010-11-28 compile fix for curl support - tb - 2010-11-28 prevent asBus from breaking when called with no numChannels - jh - 2010-12-03 grain ugens: demand ugen input fix - tb - 2010-12-05 SystemClock and TempoClock sched and schedAbs with inf time doesn't schedule the task in the first place. backported from master - tb - 2010-12-08 prString_FindRegexp fix: match char array was too short to hold null termination - jli - 2010-12-11 fix classbrowser colors bugs. backported from master - tb - 2010-12-12 fixes the bug where installed quark help files would not be detected - tb/ar - 2010-12-13 mark inherited methods in class browser by background colour. backported from master - tb - 2010-12-30 Pipe does not remove closed pipes from openFiles - jh - 2010-12-30 fix String:rotate - pb - 2011-01-02 unit generators: LagControl - fix initialization order - jh - 2011-01-02 unit generators: LagControl - dynamically allocate buffer for filter states - tb - 2011-01-07 fixed iOS compilation and backported changes from master branch - ab - 2011-01-06 array primitives: fix allTuples and unlace - pb - 2011-01-07 sclang: makeIntrinsicClass - correct bounds for memcpy - tb - 2011-01-08 sclang: prString_FindRegexp - fill array after allocating objects - tb - 2011-01-14 sclang: prString_FindRegexp ensure correct size of results array during gc calls - tb - 2011-02-27 sclang: ensure minimum stack size - tb - 2011-03-09 SCVim: avoid generating scvim help cache if not currently in scvim - ds - 2011-03-11 fix the Event type 'note' (fixes rendering patterns to audio files) - rk SuperCollider v3.4.1, released 2010-11 ====================================== - 2010-07-12 remove accidental debug messages from SCView (on mac, posted a lot of info to Console, could affect performance) - ds - 2010-07-11 Collections should behave as reasonably as possible when empty - some fixes to better this - jr - 2010-07-11 SynthDef:add now sends to all running servers if no libname is given. SynthDescs are still added to the global SynthDescLib. If you want to handle multiple SynthDesc libs, you have to add the servers to each of them explicitly - jr - 2010-07-12 PanAz: added support for audio-rate pos arg - lfsaw - 2010-07-18 improved the sclang syntax highlighting parses - Patrick Borgeat - 2010-07-30 Dreset UGen allows to reset the child UGens on its input - jr - 2010-08-05 storeOn / asCompileString now simplifies its output. Default arguments that are given in the *new method anyhow are omitted - jr - 2010-08-06 Dictionary merge and blend methods - jr - 2010-08-09 method overwrite messages not posted by default, rather a message inviting people to run Main:overwriteMsg for the info - ds - 2010-08-13 MethodOverride class to encapsule information on overridden messages, inviting people to run MethodOverride.printAll - jr - 2010-08-13 add size arg to Signal:zeroPad - jr and jh - 2010-08-18 Pevent now uses default event if no event is passed in - jr - 2010-08-18 added a shortcut to the rather tedious .asCompileString method. In analogy to object.postcs, object.cs returns the compile string - jr - 2010-08-20 audio driver for scsynth running on Android (through JNI) - ds - 2010-08-24 un-deprecate scsynth's ability to use internal "green" FFT lib, for embedded devices etc - ds - 2010-08-28 no 'record' button for remote server GUIs, since path not generally known - ds - 2010-09-02 token threading for sclang interpreter - tb - 2010-09-07 when looking for a code file (openCodeFile) or cmd-J, it is now enough to select a full line, instead of having to select both words around the colon - jr - 2010-09-07 added methods for better navigation in the class tree (findOverriddenMethod) - jr - 2010-09-10 add method: Complex:abs to fit common usage - jr - 2010-09-12 added Dwrand UGen - jr - 2010-09-15 SystemClock and TempoClock sched and schedAbs with inf time doesn't schedule the task in the first place - jr - 2010-10-07 change the mac HID error-handler code to output errors to sc post window rather than to mac log; removes a pascal-string issue - ds - 2010-10-19 Ndef now releses its bus when server was quit or just booted - jr - 2010-10-20 retain the path to the file in which an error has occurred and post it - jr Bugfixes: --------- - 2010-07-10 protecting the server against malformatted SynthDef names - jr - 2010-06-28 syntaxColorize fix for double-backslashes, thanks Patrick Borgeat for the patch - ds - 2010-07-24 catch crash in the case that one tries to define a unique method using a return value directly - jr - 2010-09-07 UGen:clip, :wrap, :fold now apply correctly to scalar-rate signals; also methodSelectorForRate tweak for which class is asked - ds - 2010-09-09 fix a bug for trigger signals in Demand.kr that hold longer than one control period - jr - 2010-09-11 bug in audio rate mapping fixed, when new source object was inserted in a mapped node proxy - jr - 2010-09-12 fix bug: 2994009. LFPar and LFCub audio rate modulation frequency argument work now - jr - 2010-09-19 fix to JITGui, when numItems is not supplied - jr - 2010-10-10 remove more crufty NSLog debug messages - ds - 2010-10-13 fix SCUserView:receiveDrag to receive mouse co-ordinates; thanks Daniel van den Eijkel - ds - 2010-10-19 debian-style scvim-check-if-plugin-is-active, brought upstream - ds - 2010-10-19 bug in audio rate mapping fixed, when new source object was inserted in a mapped node proxy - jr - 2010-10-19 partial fix for bugs item #2994009 - seems to fix LFPar but not LFCub. More work needed - ds - 2010-10-19 DC: fix multichannel expansion - tb - 2010-10-19 fix to demand rate unary op ugens, thanks james harkins - tb - 2010-10-19 Ugens: LinLin/LinExp fixes - tb - 2010-10-19 only /clearSched if RT - to fix tracker item #3033454 - tb - 2010-10-19 UGens: binary operators - fix scalar/signal division - tb - 2010-10-19 fix bug 2988525: SynthDef:writeDefFile appends path correctly - tb - 2010-10-19 ProcessOSCPacket: fix possible deadlock - tb - 2010-10-19 fix network address handling - albert graef - 2010-11-05 fix memory issues in regular expressions: correct memory management in prString_FindRegexp - tb - 2010-11-07 sclang: correct symlink handling - tb, ar SuperCollider v3.4, released 2010-07 ==================================== Headlines: ---------- - 2009-09-03 add support for Mac OS 10.5 and greater 64-bit builds of plugins and scsynth - 2009-07-xx iphone support by Axel Balley added - ab - 2009-07-21 EnvirGui added, a gui for livecoding/editing environments - adc - 2009-07-24 Server.plotTree method for visualising the groups and synths on the server - sw - 2009-07-31 mac osx text-completion feature now includes sclang objects - ds - 2009-08-01 sclang now has a flag (Platform.ideName) for which IDE is in use (scapp, scvim, scel, sced, jsceclipse...) so that the same class-library can be used with different IDEs, enabling IDE-specific code as necessary - ds - 2009-08-16 add emergency escape route: if sclang is caught in an infinite loop, send it a USR1 signal to break out of it - ds - 2009-09-12 String:findRegexp and other regular expressions now available on linux as well as mac - mb,ds - 2009-09-18 n_order and Server:reorder allow one to specify chains of nodes - sw - 2009-09-20 simplify the Server recording interface. prepareForRecord is now optional (will be automatically invoked if you don't), and the server gui button is now just two-state "record" "stop" - ds - 2009-10-04 support multichannel indices for Env:at - jr - 2009-10-29 improve OSC message correctness: for convenience, sclang allows command names as symbols with no leading slash e.g. \g_new. To improve compliance with the OSC standard, the leading slash is now added to those symbols before dispatch - ds - 2009-11-07 use nova-simd framework for performance improvements of unit generators - tb - 2009-11-21 Event type \note supports polyphonic sustain, lag and timingOffset, and responds correctly to free and release. Add \grain event type. - jr - 2009-11-28 windows: system "application support path", previously hardcoded as C:\SuperCollider, now settable by environment variable SC_SYSAPPSUP_PATH. Default setting for that env var (when using official wix bundle) will be [SC3INSTALLLOCATION] - ds - 2009-12-15 sclang: 64-bit safety - tb - 2009-12-15 sclang: performance improvement of math ops - tb - 2010-01-02 scsynth: use osc-compilant address patterns for server/lang communication - tb - 2010-01-24 add readline interface to sclang command-line. This is used by default when invoking "sclang" (to use the non-readline interface set the "-i" option to something other than "none") - ds - 2010-01-24 enable GPL3 code by default - this 'upgrades' the overall binary license from GPL2+ to GPL3+, and allows supercollider to benefit from GPL3+ libraries such as libsimdmath and gnu readline - ds - 2010-02-04 Improvements to SC.app editor: Split pane documents, AutoInOutdent - sw - 2010-02-18 scvim: now compatible with gnu screen, opens post window using screen, making it compatible with a pure-CLI environment - ds - 2010-02-xx add the Deployment32-64 build style for building on OS X (10.5 and greater) - jp - 2010-03-10 SynthDef:memStore deprecated in favour of the more coherent and typeable SynthDef:add - jr - 2010-04-11 Moved some more experimental JITLib classes to "JITLib extensions" Quark - jr Bugfixes: --------- - 2009-06-12 fix for level indicator: critical and warning now display based on peak if it is shown rather than on value - sw - 2009-06-18 fix for mouse coordinates bug - sw - 2009-06-22 fix for negative bounds issue in SCUserView - sw - 2009-06-23 avoid memory corruption when unknown OSC type tags are received. Instead forward them to sclang - jr - 2009-06-23 Fix server crash with negative buffer numbers. - jr - 2009-07-20 factors(): no prime factors exist below the first prime - jr - 2009-07-21 Loudness ugen now supports LocalBuf - nc - 2009-07-23 Fix very nasty bug in Pbindf: if a key is an array, new values were written into the incoming event, instead of the outgoing event - jh - 2009-07-28 catch unintialised value in sc_GetUserHomeDirectory(), fixing potential memory corruption if HOME not set - ds - 2009-08-01 SpecCentroid, fix its reaction to silence (output zero instead of NaN) - ds - 2009-08-01 NamedControl: single default value now returns instance, not array, default values are obtained in a consistent way - jr - 2009-08-04 fix the CPU-usage issue when calling plain "./sclang" from the terminal on OSX (seems it was caused by a bug in how OSX handles poll() calls) - ds - 2009-08-15 LinPan2: fix initialisation issue - panning was not correctly applied during the first calc block - ds - 2009-09-28 Workaround for faded colours in HTML docs - sw - 2009-09-13 fix PV_MagShift argument handling, so that the defaults mean no-change, matching the behaviour of PV_BinShift - ds - 2009-09-20 warn about weirdness of Float:switch - ds - 2009-09-30 prevent NaN output from SpecFlatness when input is silence - ds - 2009-10-16 fix cropping issue in printing SuperCollider.app documents - cq - 2009-10-17 many phase-vocoder (PV_) ugens previously didn't handle the DC/nyquist bins as expected. fixed most of these (PV_MagAbove, PV_MagBelow, PV_MagClip, PV_LocalMax, PV_BrickWall, PV_MagSquared, PV_BinWipe, PV_CopyPhase, PV_Max, PV_RandComb) - ds - 2009-11-01 fix audio rate arg problem in PlayBuf - jp - 2009-11-02 fix amplitude-convergence issue in Pan2, Balance2, LinPan2, XFade2, which could sometimes result in sound despite zero amp, as discovered by jh - ds - 2009-11-03 fix unsafe implementation of methods that allow sending collections to buffers - jr - 2009-11-04 fix signalRange for MouseX, MouseY and KeyState, so that the range message works now - jr - 2009-11-19 Fix for PV chains and LocalBuf - sw - 2009-12-14 fix uninitialised variable in Pulse (could sometimes cause small glitch on init), thanks to rhian lloyd - ds - 2010-01-10 Demand ugens can now handle more than 32 channels, thanks Patrick Borgeat for the patch - ds - 2010-02-05 scsynth now respects the -D commandline option when running in NRT mode - ds - 2010-02-11 Fix for nowExecutingPath with Routines - sw - 2010-02-23 Performance fixes for SCUserView - sw - 2010-02-25 Fix interpolation / indexing problem in VDiskIn that caused slight pitch fluctuations - jp - 2010-03-11 SequenceableCollection:reduce no longer returns nil if the collection has only 1 element - ds - 2010-03-28 fix memory leak of empty command line, for interactive sclang mode - tb - 2010-03-29 main menu for Mac lang editor app: correction to key for evaluate selection, used to be return, now return+shift - nc - 2010-04-19 fix missing font issue in Plotter -jr Other additions/improvements: ----------------------------- - 2009-06-11 Evaluate Selection menu command - sw - 2009-06-23 allow remote apps to send type chars - jr - 2009-06-27 build 32bit sclang on x86_64 - tb - 2009-07-xx efficiency improvements on some UGens - tb - 2009-07-xx improve Quarks use of svn for smoother user experience - ds - 2009-07-22 catch the case when a user tries to compile into a synthdef, a unary/binary operator that the server can't apply - jh - 2009-08-29 String:toUpper and String:toLower - ds - 2009-09-06 Boolean:while now throws an informative error, since Boolean:while has no particular use but is often used in error by beginners in code where Function:while is intended - ds - 2009-09-12 method FunctionDef:makeEnvirFromArgs allows to create template events from a function - jr - 2009-09-30 Error is now posted if maxSynthDefs exceeded -sw - 2009-11-03 TwoWayIdentityDictionary has a removeAt method now - jr - 2009-11-04 update of deferredTaskInterval from 0.038 to 0.01667 - fo - 2009-11-07 improved PyrSlot typesafety - tb - 2009-11-23 menu system improvements in Windows IDE - mv - 2009-12-13 tidyups for "sclang when on osx but not in sc.app" - ds - 2009-12-13 added lincurve and curvelin methods for numbers and UGens - jr - 2010-01-01 OSCresponder and OSCresponderNode respond equally to messages with or without preceding slash - jr - 2010-01-04 sclang: deprecated Proutine - switch back to the original Prout - 2010-01-06 UnitTest Quark improved, added script support - jr - 2010-01-23 Improved NodeProxy and ProxySpace helpfiles. Added proxy composition syntax to NodeProxy - jr - 2010-01-30 Make multichannel plotting easier. If no numChannels is given, find out automatically - jr - 2010-01-31 add new LOOP1 macro - tb - 2010-01-31 use c99 log2 functions for sc_log2 - tb - 2010-02-09 rearrangement of supercollider source code tree - ds - 2010-02-11 Server:default_ now assigns to s by default. Settable with flag - sw - 2010-02-27 removed SCAnimationView and added SCUserView:animate_ - fo - 2010-03-10 SCPen:setSmoothing changed to SCPen:smoothing_, harmonised change with swingosc - ds - 2010-03-23 exponentiation for Complex numbers - jr - 2010-xx-xx many helpfiles improved - various authors - 2010-03-30 Image class added, a redirect for SCImage or JSCImage - hr - 2010-03-30 Pitch ugen ability to output clarity measure (by default not activated, for backwards compat) - ds SuperCollider v3.3.1, released 2009-06-19 ========================================= Headlines: ---------- - 2009-05-11 SCWindow additions for visible, visible_, unminimize - cq - 2009-05-17 server guis (on osx) now indicate which one is currently default - adc - 2009-05-18 enabled control rate versions of Ball, TBall and Spring - mb - 2009-05-18 LID support for setting "MSC" state as well as "LED" on devices - ds - 2009-06-19 patched for compatibility with Safari 4, fixing a lockup issue when opening help docs - ar Bugfixes: --------- - 2009-05-11 fix keyword addressing for the order: argument - jmc - 2009-05-15 update libsndfile to 1.0.20 to fix security issues (overflow vulnerabilities) in libsndfile - ds - 2009-05-20 fix bug #2790649, "very large SimpleNumber:series can crash sclang" - ds - 2009-05-25 mac icons for document types .quark .scd .rtfd were omitted from the app bundle, now fixed - ds - 2009-06-02 EnvGen: fix off by one block latency in envelope attacks and releases - jr - 2009-06-12 bug fix for level indicator: critical and warning now display based on peak if it is shown rather than on value - sw - 2009-06-12 mouse coordinates fix, deprecate SCUserView:mousePosition - sw - 2009-06-17 some issues fixed in SCUserView - cq - 2009-06-20 fix redirect for Stethoscope - adc Other additions/improvements: ----------------------------- - 2009-05-05 fixes/improvements to cocoabridge primitives - cq - 2009-05-06 SCImage various minor improvements - cq - 2009-05-16 optimisation for scrollview drawing, remove VIEWHACK - sw - 2009-05-xx various documentation updates - various - 2009-05-xx various improvements to ubuntu-debian packaging scripts - ds, am - 2009-05-20 SynthDef:writeOnce now available as an instance method as well as a class method - ds - 2009-06-11 sc.app gets a menu command for "Evaluate selection" - sw - 2009-06-17 adjusted SCKnob to use relative mouse coordinates - jm - 2009-06-17 small fix to SConstruct to allow for new Debian X11 location when compiling on linux - mb - 2009-06-19 Blip ugen: prevent sound blowup by never letting numharm be less than 1 - fo - 2009-06-20 SCPen: fillStroke changed default from draw(4) to draw(3) - fo - 2009-06-21 Fold, Clip and Wrap can now modulate the low and high inputs. SuperCollider v3.3, released 2009-04-30 ======================================= Headlines: ---------- - 2008-04-08 scvim is now part of the distro - ds - 2008-04-20 improvements to MIDI sysex handling - added sysex parsing directly in source - thanks to charles picasso - 2008-07-12 scsynth on Mac can now use separate devices for audio input vs audio output. Thanks to Axel Balley for much of the work on this, also a bit by ds. - 2008-07-12 PlayBuf, RecordBuf, BufWr, BufRd, ScopeOut - used to be limited to 16-channel audio maximum. Now can handle massively multichannel audio - ds - 2008-07-19 Buffer:normalize method added - ds - 2008-07-23 FFT and IFFT added option for zero-padding, by optional "framesize" argument - ds - 2008-09-03 new VDiskIn ugen - jp - 2008-10-08 SCImage for manipulating bitmap image objects (mac only) - ch - 2008-10-09 LocalBuf system to allow synths to manage their own purely-local buffers - jr - 2008-10-17 Added "-P" option to scsynth (accessible as s.options.restrictedPath) to allow restricting which paths scsynth is allowed to read/write - ds - 2008-10-18 new PartConv ugen, performs efficient frequency-domain convolution - nc - 2008-10-26 support on mac for "modal windows/sheets" (for user dialogs etc) - sw - 2008-xx-xx various behind-the-scenes efficiency improvements, for a sleeker audio server that can do more on a given machine - various contributors - 2008-11-01 add BEQSuite filter UGens (blackrain, jp) - 2008-11-11 add Pfxb pattern - jr - 2008-11-25 new EZPopUpMenu - jm - 2008-11-29 Pitch ugen can now also track the pitch of control-rate signals - mb - 2008-11-30 Drag and drop paths from Finder to Documents and SCViews - sw - 2008-12-03 added PV_Div ugen for complex division - ds - 2008-12-07 added PV_Conj ugen for complex conjugate - ds - 2008-12-15 new ViewRedirect for easier cross-platform gui syntax. e.g. Window now redirects to SCWindow or JWindow. ds & jm - 2008-12-15 revised and updated all SC Gui documentation. New gui introduction. New SCUserView subclassing tutorial. - jm - 2008-12-15 the /done message for Buffer allocation/free/etc now also includes the buffer index - jt - 2008-12-15 added methods to SCFreqScope for "special" SynthDef, and for visualising frequency responses - ds - 2008-12-18 the main windows version of sc is now called "SuperCollider" rather than "PsyCollider" (although psycollider is the name of the code editor). SuperCollider on windows now has a different (better? who knows) installer, uses the main sc3 icon, and has some other tweaks that make it different from version 3.2 - ds - 2008-12-19 new EZListView - jm - 2009-01-02 sced (the gedit sc plugin) is now part of the distro - mb/artem - 2009-01-06 SendReply UGen - jr - 2009-01-06 VDiskIn sends file position to client - jr - 2009-01-12 map audio to SynthDef controls. new OSC messages n_mapa and n_mapan. - jp, jr, rk - 2009-01-13 relativeOrigin=true. SC's coordinate system in container views and user views are now by default relative. - 2009-01-15 SCLevelIndicator view added - sw - 2009-01-16 Scale and Tuning classes added - tw - 2009-01-17 SuperColliderAU (scsynth as a Mac OSX "Audio Unit") added to main distribution - gr - 2009-02-03 EZKnob revised and now part of distro - br, jm - 2009-02-23 SystemActions refactored - jr - 2009-02-23 SCMenuItem, SCMenuGroup, and SCMenuSeparator for user customisable menus - sw - 2009-02-23 LFGauss UGen added - jr - 2009-03-14 Added GeneralHID based patterns PhidKey and PhidSlot - mb Bugfixes: --------- - 2008-05-20 fix for the special case when 0.2.asFraction beachballs the lang (bug id 1856972) - jr - 2008-05-20 fix slight mistake in the defaults printed by scsynth on command-line (bug id 1953392) - ds - 2008-07-24 Routine / AppClock fix setting the clock of the thread (bug id 2023852) - jr - 2008-09-16 stability fixes to FFT and IFFT - ds - 2008-09-27 fix TExpRand.ar - ds - 2008-11-11 SystemSynthDefs.numChannels can now be set from the startup file - jr - 2008-11-24 avoid FFT failure when buffer not allocated - jr - 2008-11-29 resolved inconsistency in Server:waitForBoot - function is always executed in a Routine, whether or not the server is booted - ds - 2008-12-07 FlowView setting inital margin and gap fixed (bug id 1986059) - jh - 2008-12-07 OSCpathResponder fixed (bug id 2021481) - jh - 2009-01-08 b_readChannel fixed (bug id 1938480) - mb - 2009-01-08 MIDIIn.connect on Linux fixed (bug id 1986850) - mb - 2009-01-09 Tabbing in SCTextView - sw - 2008-08-23 fix for sclang crashing sometimes when compiling erroneous code (bug id 2022297) - rb - 2009-01-18 SCScrollView relativeOrigin glitch fixed (bug id 2508451) - jr, sw - 2009-01-28 Fixed QuartzComposer view bounds bug - sw - 2009-02-21 NodeProxy handles groups more consistently - jr - 2009-04-16 asFraction fix by JMcC - jr Other additions/improvements: ----------------------------- - 2008-03-22 added open Method and link handling to SCTextView - sw - 2008-04-04 SoundFile:toCSV - ds - 2008-04-29 buffer UGens now post a warning (rather than failing silently) if buffer channels doesn't match num ins/outs - ds - 2008-07-14 Deprecated rendezvous in favour of zeroConf - sw - 2008-09-xx various code improvements, including compiling for 64-bit linux - tb - 2008-10-03 improvements to standalone build - jp - 2008-10-03 SCEnvelopeView remembers drawing order. - sw - 2008-10-05 Maintain initial offset when dragging on an Envelope View node. This avoids nodes jumping to a new position on mouse down. - sw - 2008-10-05 Enabled gridOn, gridResolution, gridColor, timeCursorOn, timeCursorPosition, and timeCursorColor for SCSoundFileViews. - sw - 2008-10-31 thisProcess.pid - sclang now can know what its process id is - ds - 2008-11-21 support for LocalBuf in FFT UGens - jr - 2008-11-27 SC3 will ignore ugens/class-files in folders named "ignore". Previously the name has been "test" - ignoring folders named "test" is now deprecated and will be removed - ds - 2008-12-06 Added Main:recompile to allow recompiling from code (SC.app only so far) - sw - 2008-12-08 Added custom drag label for SCView - sw - 2008-12-15 Buffer's done osc reply now includes the bufnum - jt - 2008-12-20 Help tree in help menu (OSX) - sw - 2008-12-24 EZSLider and EZNumber now have an enclosing containers, as well labelPosition =\left, \right, or \stack modes - jm - 2009-01-03 Help browser text is editable/executable (CocoaGUI) - sw - 2009-01-04 Escape exits modal and fullscreen states (OSX) - sw - 2009-01-08 interface change to ProxySpace.stop (now stops all proxies, just like free/end/clear) - jr - 2009-01-08 improved Ndef implementation, stores values in an internal ProxySpace, Ndef takes server names for multiple servers. - jr - 2009-01-08 improved ProxyMixer implementation, added NdefMixer. - adc - 2009-01-11 Added class browser to help menu (OSX) - sw - 2009-01-20 New Cocoa based SCTextField - sw - 2009-01-28 More helpful error string for operation cannot be called from this Process - sw - 2009-02-23 CocoaDialog takes allowsMultiple arg rather than maxItems - sw SuperCollider v3.2, released 2008-02-21 ======================================= Headlines: ---------- - 2007-11-xx new suite of machine listening ugens - Loudness, BeatTrack, Onsets, KeyTrack, SpecCentroid, SpecPcile, SpecFlatness - nc, ds - 2008-01-06 FreeBSD compatibility - hb - 2008-01-10 Quarks updating on OSX should now be easier for first-time users; commands are run in a separate terminal window - ds - 2008-01-15 "Advanced find" in Mac interface - jt - 2008-01-20 Buffer.copy changed to match other .copy methods - now copies language-side object rather than server buffer. Buffer.copyData can be used to copy data from one server buffer to another - jh - 2008-01-20 - add volume controls to the Server and Server guis - jp - 2008-01-xx Pattern library implementation changes, Pfx, Pbus, Pgroup etc. - rk, jr, jh - 2008-01-26 TDuty outputs trigger first, not level. for backwards compatibility TDuty_old - jr - 2008-02-03 moved the search location for "startup.rtf" on Mac - now searches in system, then user, "Application Support/SuperCollider" folders - ds Bugfixes: --------- - 2007-11-16 bug fixes for MIDIIn in connect/disconnect methods. split MIDIOut.sysex into user method and primitive (breaks with previous implementation). default value for uid arg in MIDIOut.new. - mb - 2007-11-18 fixed a bug in prTry / protect - jr - 2007-11-27 lock avoided in nextTimeOnGrid - 2007-12-12 Node-setn fixed when using integers as control indices - jr - 2008-01-16 fixed Pen: bug with fillRect, fillOval and fillColor (bugtracker id 1837775) - jt - 2008-01-20 CheckBadValues rate-checking was too restrictive - ds - 2008-01-20 fix for Saw and Pulse's offset noise on first instantiation, thanks to hisao takagi - ds - 2008-01-26 TDuty / Duty does not drift anymore - jr - 2008-02-07 Fixed hang and incorrect background drawing in Cocoa scrollviews - sw Other additions/improvements: ----------------------------- - 2007-11-16 MIDIOut.connect and disconnect - mb - 2007-11-18 added T2A UGen - jr - 2007-11-18 Refactoring of Document class, including new CocoaDocument class to handle the Cocoa-specific (SuperCollider.app) document management - ds - 2007-11-18 More macros available in the plugin API for UGen programmers: GET_BUF, SIMPLE_GET_BUF, FULLRATE, RGET, RPUT - ds - 2007-11-20 UnixPlatform:arch method - jp - 2007-11-20 FFTTrigger UGen - a ugen to create "fake" (empty) FFT chains - jp - 2007-11-21 StartUp protects its added functions from each other - if one fails this no longer prevents others from running - ds - 2007-11-25 added Pclutch and moved StreamClutch to common - jr - 2007-11-27 Function:inEnvir added - jh - 2007-12-12 added Collection.flatIf - jr - 2007-12-15 added control rate functionality to NumRunningSynths - jr - 2008-01-08 martin rumori's DiskIn bugfix and loop enhancement - jp - 2008-01-10 String:runInTerminal method - ds - 2008-01-11 poll now works for scalar ugens - jr - 2008-01-15 Collection:maxIndex and Collection:minIndex - nc - 2008-01-24 Server.options.rendezvous to (de)activate Rendezvous if desired - ds - 2008-01-24 demand ugens accept audio rate inputs correctly - jr - 2008-01-26 added Dbufwr ugen, for writing to buffers from a demand ugen chain - jr - 2008-01-27 Main:version and associated methods for programmatically determining which version SC is - ds - 2008-02-03 Server:defaultRecDir class variable, to allow user to specify default rec location - ds - 2008-02-07 SCScrollView and SCScrollTopView no longer fire their action when scrolled programatically - sw SuperCollider v3.1.1, released 2007-11-16 ========================================= Bugfixes: --------- - 2007-11-09 re-organized the main help file - rb - 2007-11-14 fix for .asStringPrec, to avoid crashes on intel systems for large precision values - jt Other additions/improvements: ----------------------------- - 2007-11-14 added a preprocessor to the interpreter - jr - 2007-11-14 added a startup message specifying how to get help - rk SuperCollider v3.1, released 2007-10-31 ======================================= (changes below are since 2007-09-22, for first ever point release) Headlines: ---------- - 2007-09-27 SparseArray class added - jr - 2007-09-28 Help.gui added - ds - 2007-10-01 FFT and IFFT rewrite - now using more efficient libs, also allows user to vary the overlap and the window type, also large-sized FFTs are possible - ds - 2007-10-02 UnpackFFT and PackFFT added - these allow for flexible frequency-domain manipulations inside synths - ds - 2007-10-04 Pkey and Pif added - hjh - 2007-10-05 reformed Patterns - all patterns accept patterns as arguments - jr - 2007-10-08 change to UGen plugin loading fixes the audio dropout issue that various users have experienced - rb - 2007-10-08 GeneralHID crossplatform HID wrapper - mb - 2007-xx-xx many improvements to Quarks package-management system. gui improvements, dependency-handling improvements, etc - various - 2007-10-20 added a Glossary file - sw - 2007-10-xx various new help files added, and many help files improved - various - 2007-10-26 changed Cmd-? to Cmd-D in lieu of the default help menu shortcut in Leopard. Also changed Cmd-Shift-K (clear post window) to Cmd-Shift-C to avoid accidental recompiles. - rb Other additions/improvements: --------------------------- - 2007-09-22 change log added, much rejoicing - 2007-09-25 added packagesource.sh script to produce source code bundles - ds - 2007-09-28 IdentityDictionary:doesNotUnderstand now warns if adding a pseudo-method which overrides a real method - jr - 2007-09-28 String:openHTMLFile added - ds - 2007-10-04 Integer:collect and Integer:collectAs methods added - ds/jr - 2007-10-05 Dwhite:new and Dbrown:new have default values for lo and hi - jr - 2007-10-10 SC no longer automatically writes data (synthdefs, archive.scxtar) to the application folder - instead writes to "app support". This fixes problems with running SC using an unprivileged user account - ds - 2007-10-16 SequenceableCollection:median speed improvement, approx ten times faster in many cases - ds - 2007-10-20 Object:deprecated and DeprecatedError added to allow for method deprecation - sw - 2007-10-21 Amplitude : attackTime and releaseTime can be modulated now - jr - 2007-10-25 Collection : histo method improved and moved from mathLib to common - jr - 2007-10-30 improvements to cocoa Gui, including SCUserView improved to support layering and own draw hook - jt, sciss - 2007-10-31 refactored Pbrown, added Pgbrown - jr Bugfixes: --------- - 2007-09-29 takekos bug fixed (obscure issue with garbage collection in arrays) - jm - 2007-10-01 fixed off by one bug in Dswitch and Dswitch1 that caused a server crash - jr - 2007-10-09 fixed deadlock and other problems in NSAttributedStringAdditions.m - rb - 2007-10-11 fixed inaccurate automatic determination of whether SC is running as standalone - ds - 2007-10-14 .quark files now saved correctly as plain-text, not RTF - ds - 2007-10-24 fixed a bug in Pbeta - jp \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* SuperCollider-Source/cmake_modules/000755 000765 000024 00000000000 13007315613 020464 5ustar00crucialstaff000000 000000 SuperCollider-Source/CMakeLists.txt000644 000765 000024 00000045407 12766171707 020445 0ustar00crucialstaff000000 000000 project (SuperCollider) if (CMAKE_SYSTEM_NAME MATCHES "Linux") set(LINUX 1) endif() cmake_minimum_required (VERSION 2.8.12) set(SUPERNOVA_CMAKE_MINVERSION 3.1) include("SCVersion.txt") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${PROJECT_VERSION_PATCH}") message(STATUS "SuperCollider Version: ${PROJECT_VERSION}") message(STATUS "Building from branch ${GIT_BRANCH}, commit hash is ${GIT_COMMIT_HASH}") include(CTest) enable_testing() include (cmake_modules/FinalFile.cmake) if(CMAKE_GENERATOR MATCHES "Visual Studio" OR CMAKE_GENERATOR MATCHES "Xcode") message(STATUS "Please specify the build configuration in the next step") else() if (NOT CMAKE_BUILD_TYPE) message(STATUS "Build type defaulting to \"RelWithDebInfo\"") set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif() endif() if (${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) message(WARNING "WARNING: IN-PLACE BUILDS ARE NOT RECOMMENDED - PLEASE USE A BUILD DIRECTORY") endif() set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules ${CMAKE_MODULE_PATH}) CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") # identify target architecture, build portaudio before any SC specific # definitions break the pa-build if(WIN32) SET(SC_WIN_BUNDLE_NAME "SuperCollider" CACHE STRING "Folder name of SC install") if(CMAKE_CL_64 OR "$ENV{MSYSTEM}" MATCHES "64" OR CMAKE_C_COMPILER MATCHES "64") SET(CMAKE_LIBRARY_ARCHITECTURE "x64" CACHE STRING "Architecture of target system (for 64bit)") else() SET(CMAKE_LIBRARY_ARCHITECTURE "x86" CACHE STRING "Architecture of target system (for 32bit)") endif() # installing to default application-location creates an error (a privileges and/or path syntax problem) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) SET(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/Install" CACHE PATH "Cmake install path" FORCE) endif() # might work with "SHARED" as well. set(PA_LIBRARY_TYPE "STATIC") set(PORTAUDIO_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/external_libraries/portaudio_sc_org/include" CACHE PATH "Portaudio include directory" FORCE) add_subdirectory("${CMAKE_SOURCE_DIR}/external_libraries/portaudio_sc_org") endif(WIN32) ############################################# # Compiler flags etc if (${CMAKE_COMPILER_IS_GNUCXX}) exec_program(${CMAKE_CXX_COMPILER} ARGS -dumpversion OUTPUT_VARIABLE _gcc_version) add_definitions("-fschedule-insns2" "-fomit-frame-pointer") add_definitions("-Wreturn-type") if(${_gcc_version} VERSION_LESS 4.8) message(FATAL_ERROR "SuperCollider requires at least gcc-4.8 when compiled with gcc.") endif() add_definitions("-ffast-math -fsigned-zeros -fno-associative-math") if(APPLE) exec_program(${CMAKE_CXX_COMPILER} ARGS --version OUTPUT_VARIABLE _gcc_version_info) if ("${_gcc_version_info}" MATCHES "Apple") add_definitions("-fpascal-strings") endif() add_definitions("-D_REENTRANT") elseif(NOT (WIN32 AND NOT CYGWIN)) add_definitions("-pthread") endif() elseif(${CMAKE_CXX_COMPILER} MATCHES icpc) set(CMAKE_COMPILER_IS_INTEL 1) add_definitions(-Wno-unknown-pragmas) add_definitions(-simd) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") set(CMAKE_COMPILER_IS_CLANG 1) endif() if(APPLE) if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/Install" CACHE STRING "Cmake install path") endif() elseif(UNIX) add_definitions(-DSC_DATA_DIR="${CMAKE_INSTALL_PREFIX}/share/SuperCollider") endif() if(WIN32) add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX -D_WIN32_WINNT=0x0600) #avoid unnecesary autolink add_definitions(-DBOOST_DATE_TIME_NO_LIB -DBOOST_ALL_NO_LIB) endif() add_definitions(-DBOOST_CHRONO_HEADER_ONLY -DBOOST_NO_AUTO_PTR) ############################################# # Detect CCache find_program(CCacheExectuable ccache) if( CCacheExectuable ) # only used with >=cmake-3.4 set( CMAKE_C_COMPILER_LAUNCHER "${CCacheExectuable}" ) set( CMAKE_CXX_COMPILER_LAUNCHER "${CCacheExectuable}" ) endif() ############################################# # Options option(NOVA_SIMD "Build with nova-simd support." ON) option(FINAL_BUILD "Build as single source file." OFF) option(FFT_GREEN "Use internal 'Green' FFT lib rather than FFTW. (Not recommended.)" OFF) if(NOT ${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm") option(SSE "Compile with support for SSE instructions." ON) option(SSE2 "Compile with support for SSE2 instructions." ON) else() # ARM platforms do not have SSE set(SSE OFF) set(SSE2 OFF) endif() set(AUDIOAPI "default" CACHE STRING "Audio API to use (one of {default,coreaudio,jack,portaudio})") if (AUDIOAPI STREQUAL jack) # here we check for JACK metadata API include(CheckIncludeFiles) CHECK_INCLUDE_FILES("jack/metadata.h" JACK_USE_METADATA_API) if(${JACK_USE_METADATA_API}) message(STATUS "using JACK metadata API") include_directories(${CMAKE_SOURCE_DIR}/external_libraries/jackey) endif() endif() option(LIBSCSYNTH "Compile libscsynth as shared library" OFF) option(INSTALL_HELP "Install help docs and examples along with the software" ON) option(SC_DOC_RENDER "Pre-render SCDoc documentation. (For putting online, etc)" OFF) option(SC_QT "Build SuperCollider with Qt GUI features" ON) option(SC_IDE "Build Qt IDE." ON) if (SC_QT) message( STATUS "Compiling with Qt GUI" ) else() if (SC_IDE) message( STATUS "Not compiling SC IDE, because it requires Qt but SC_QT is False" ) set(SC_IDE False) endif() endif (SC_QT) option(ENABLE_TESTSUITE "Compile testsuite." ON) if(CMAKE_SYSTEM_NAME MATCHES "Linux" AND NOT CMAKE_VERSION VERSION_LESS SUPERNOVA_CMAKE_MINVERSION) option(SUPERNOVA "Build with supernova as optional audio synthesis server" ON) else() option(SUPERNOVA "Build with supernova as optional audio synthesis server" OFF) endif() option(SN_MEMORY_DEBUGGING "Build supernova for memory debugging (disable memory pools).") option(SC_MEMORY_DEBUGGING "Build sclang&scsynth for memory debugging (disable memory pools).") option(GC_SANITYCHECK "Enable sanity checks in the sclang garbage collector.") option(NO_LIBSNDFILE "Disable soundfile functionality. (Not recommended.)" OFF) if(WIN32) option(NO_AVAHI "Disable Avahi support. (Not recommended.)" ON) else(WIN32) option(NO_AVAHI "Disable Avahi support. (Not recommended.)" OFF) endif(WIN32) option(NO_GPL3 "Disable GPL3 code, for pure-GPL2 situations. (Not recommended.)" OFF) option(SCLANG_SERVER "Build with internal server." ON) option(SC_WII "Build sclang with WII support (broken on osx after 10.7)" OFF) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) option(NATIVE "Optimize binary for this architecture (binaries may not run on other machines).") endif() if(CMAKE_COMPILER_IS_GNUCXX) option(LTO "Use GCC's link time optimizer' (experimental).") endif() option(SC_SYMLINK_CLASSLIB "Place a symlink of SCCLassLibrary instead of copying" OFF) option(SYSTEM_BOOST "Use boost libraries from system" OFF) option(SYSTEM_YAMLCPP "Use yaml-cpp library from system" OFF) option(FORTIFY "Define -D_FORTIFY_SOURCE=2 to check for programming errors" OFF) ############################################# # some default libraries if (NOT WIN32) find_package(Pthreads) if (NOT PTHREADS_FOUND) message(SEND_ERROR "cannot find libpthreads") endif() include_directories(${PTHREADS_INCLUDE_DIR}) endif() if(SYSTEM_BOOST) set(Boost_USE_MULTITHREADED ON) find_package( Boost 1.50.0 COMPONENTS thread system filesystem program_options regex test_exec_monitor ) endif() if (Boost_FOUND) link_directories(${Boost_LIBRARY_DIRS}) else() message(STATUS "building boost libraries manually") endif() if(SYSTEM_YAMLCPP) find_package(YamlCpp) else() set(YAMLCPP_FOUND OFF) endif() ############################################# # some preprocessor flags if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG) if (SSE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse") set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -msse") if(NOT APPLE AND NOT CMAKE_COMPILER_IS_CLANG) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse") endif() endif() if (SSE2) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2") endif() if (NATIVE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native") endif() if( CMAKE_VERSION VERSION_LESS 3.1 ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -std=c++11") if(CMAKE_COMPILER_IS_CLANG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -stdlib=libc++") endif() else() set( CMAKE_CXX_STANDARD 11 ) if(CMAKE_COMPILER_IS_CLANG) # workaround set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -stdlib=libc++") endif() endif() if(FORTIFY) add_definitions( -D_FORTIFY_SOURCE=2 ) endif() add_definitions(-fvisibility=hidden) endif() if (CMAKE_COMPILER_IS_INTEL AND NOT WIN32) if (SSE) add_definitions(-mia32) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") # disable warnings add_definitions(-diag-disable 170) # pointer points outside of underlying object ... used heavily in sclang add_definitions(-diag-disable 279) # controlling expression is constant endif() if(MSVC) foreach(flag CMAKE_C_FLAGS CMAKE_CXX_FLAGS) set(${flag} "${${flag}} /wd4018") # signed/unsigned mismatch set(${flag} "${${flag}} /wd4102") # unreferenced label set(${flag} "${${flag}} /wd4267") # conversion from 'size_t' to 'int', possible loss of data set(${flag} "${${flag}} /wd4244") # conversion from '__int64' to 'int', possible loss of data set(${flag} "${${flag}} /wd4305") # '=' : truncation from 'double' to 'float' set(${flag} "${${flag}} /wd4309") # '=' : truncation of constant value set(${flag} "${${flag}} /wd4800") # forcing value to bool 'true' or 'false' (performance warning) set(${flag} "${${flag}} /wd4996") # The POSIX name for this item is deprecated. endforeach() add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) endif(MSVC) if (SC_MEMORY_DEBUGGING) add_definitions(-DDISABLE_MEMORY_POOLS) add_definitions(-DENABLE_MEMORY_CHECKS) endif() if(MINGW) # no-strict-aliasing was introduced because of problems with MinGW/GCC 4.9.2 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mstackrealign -fno-strict-aliasing") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mstackrealign -fno-strict-aliasing") endif() # support for building on Raspberry Pi 1/2/3 and BBB if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") foreach(flag CMAKE_C_FLAGS CMAKE_CXX_FLAGS) set(${flag} "${${flag}} -mfloat-abi=hard") set(${flag} "${${flag}} -mfpu=neon") endforeach() elseif(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR STREQUAL "armv6l") foreach(flag CMAKE_C_FLAGS CMAKE_CXX_FLAGS) set(${flag} "${${flag}} -march=armv6") set(${flag} "${${flag}} -mtune=arm1176jzf-s") set(${flag} "${${flag}} -mfloat-abi=hard") set(${flag} "${${flag}} -mfpu=vfp") endforeach() endif() if (NO_GPL3) add_definitions(-DNO_GPL3) endif() ############################################# # subdirectories add_subdirectory(external_libraries) if(NOT YAMLCPP_FOUND) set(YAMLCPP_LIBRARY yaml) set(YAMLCPP_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/external_libraries/yaml-cpp-0.3.0/include) endif() configure_file(common/SC_Version.hpp.in common/SC_Version.hpp) include_directories(${CMAKE_CURRENT_BINARY_DIR}/common) file(GLOB_RECURSE ClassLibrary SCClassLibrary/*sc) file(GLOB_RECURSE HelpSource HelpSource/*) file(GLOB_RECURSE Sounds sounds/*) file(GLOB_RECURSE Examples examples/*) if(APPLE) include(cmake_modules/MacAppFolder.cmake) set(ide_name ${scappbundlename}) else() set(ide_name scide) endif() add_subdirectory(server) add_subdirectory(lang) add_subdirectory(platform) add_subdirectory(editors) if(UNIX AND NOT APPLE) install(DIRECTORY include/common include/plugin_interface include/server include/lang DESTINATION ${CMAKE_INSTALL_PREFIX}/include/SuperCollider FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" ) install(FILES SCVersion.txt DESTINATION ${CMAKE_INSTALL_PREFIX}/include/SuperCollider ) endif() if (WIN32) set(auxresourcesdir "${SC_WIN_BUNDLE_NAME}" CACHE STRING "Resources directory") elseif(APPLE) set(auxresourcesdir ${scappbundlename} CACHE STRING "Resources directory") else() set(auxresourcesdir "share/SuperCollider" CACHE STRING "Resources directory") endif() set(SCCLASSLIB_EXCLUDE_REGEX "IGNOREME") if(NOT SC_QT) set(SCCLASSLIB_EXCLUDE_REGEX "${SCCLASSLIB_EXCLUDE_REGEX}|QtCollider") endif() if(WIN32) set(SCCLASSLIB_EXCLUDE_REGEX "${SCCLASSLIB_EXCLUDE_REGEX}") endif() if(APPLE) if(SC_SYMLINK_CLASSLIB) #if there are folders inside SCCLassLibrary abort cmake. file(GLOB classlibraryfolders "${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/SCClassLibrary/[^.]*") foreach(onedirectory ${classlibraryfolders}) message( "${onedirectory}" ) if(NOT IS_SYMLINK "${onedirectory}") message(FATAL_ERROR "Symlinking will fail ! SCClassLibrary folder already exists and has directories inside, please delete it first." ) endif() endforeach(onedirectory) message(STATUS "Will create symlink of SCClassLibrary to ${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/SCClassLibrary" ) if(NOT EXISTS "{CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/SCClassLibrary") install( CODE "EXECUTE_PROCESS(COMMAND mkdir ${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/SCClassLibrary)" ) endif() #symlink the folders inside SCCLassLibrary. Check if QtCollider folder should be symlinked or not. file(GLOB classlibraryfolders RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary" "SCClassLibrary/[^.]*") foreach(onedirectory ${classlibraryfolders}) if(NOT "${onedirectory}" MATCHES "${SCCLASSLIB_EXCLUDE_REGEX}") install( CODE "EXECUTE_PROCESS(COMMAND ln -shF ${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/${onedirectory} ${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/SCClassLibrary/${onedirectory} )" ) endif() endforeach(onedirectory) endif() else() install(DIRECTORY SCClassLibrary DESTINATION ${auxresourcesdir} REGEX ${SCCLASSLIB_EXCLUDE_REGEX} EXCLUDE PATTERN "*~" EXCLUDE PATTERN "*#" EXCLUDE ) endif() if(NOT APPLE) install(DIRECTORY sounds DESTINATION ${auxresourcesdir}) install(DIRECTORY examples DESTINATION ${auxresourcesdir}) elseif(APPLE) install(DIRECTORY examples DESTINATION ${auxresourcesdir}) endif() if (WIN32) set( AdditionalInstallFiles README.md README_WINDOWS.md CHANGELOG.md COPYING AUTHORS ) elseif(APPLE) set( AdditionalInstallFiles README.md README_OS_X.md CHANGELOG.md COPYING AUTHORS ) else() set( AdditionalInstallFiles README.md README_LINUX.md CHANGELOG.md COPYING AUTHORS ) endif() install(FILES ${AdditionalInstallFiles} DESTINATION ${auxresourcesdir}) if(INSTALL_HELP) if(SC_SYMLINK_CLASSLIB AND APPLE) message(STATUS "Will create symlink of HelpSource to ${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/HelpSource") if(EXISTS "${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/HelpSource") message(FATAL_ERROR "Symlinking will fail ! HelpSource folder already exists, please delete it first." ) endif() install( CODE "EXECUTE_PROCESS(COMMAND ln -shF ${CMAKE_CURRENT_SOURCE_DIR}/HelpSource ${CMAKE_INSTALL_PREFIX}/${auxresourcesdir}/HelpSource )" ) elseif(NOT APPLE) install(DIRECTORY HelpSource DESTINATION ${auxresourcesdir} REGEX ${SCCLASSLIB_EXCLUDE_REGEX} EXCLUDE PATTERN "*~" EXCLUDE PATTERN "*#" EXCLUDE ) endif() endif() ############################################# # # build scdoc help files # list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/Common") list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/Platform") list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/SCDoc") list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/DefaultLibrary") list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/JITLib") list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/SCClassLibrary/backwards_compatibility") # this folder has an extension to Platform that disables the loadStartupFiles method list(APPEND BUILD_CLASSLIBRARIES "${CMAKE_CURRENT_SOURCE_DIR}/platform/disable_startup_files") foreach(arg ${BUILD_CLASSLIBRARIES}) set(BUILD_CLASSLIBRARYPATH "${BUILD_CLASSLIBRARYPATH}+${arg}\n") endforeach() configure_file(build_sclang.cfg.in ${CMAKE_CURRENT_BINARY_DIR}/build_sclang.cfg) if(SC_DOC_RENDER) file(GLOB_RECURSE SCDocSources RELATIVE HelpSource .*[^~]) file(GLOB_RECURSE SCDocClasses RELATIVE SCClassLibrary/SCDoc *.sc) add_custom_target(doc ALL COMMAND $/sclang${CMAKE_EXECUTABLE_SUFFIX} -l ${CMAKE_CURRENT_BINARY_DIR}/build_sclang.cfg platform/renderAllHelp.scd ${CMAKE_CURRENT_SOURCE_DIR}/HelpSource ${CMAKE_CURRENT_BINARY_DIR}/RenderedHelp WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS sclang ${SCDocSources} ${SCDocClasses}) endif() set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "RenderedHelp") ############################################# # # testsuite # if(ENABLE_TESTSUITE) add_subdirectory(testsuite) endif() ############################################# # CPack support set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) if(APPLE) set(CPACK_GENERATOR "DragNDrop") set(CPACK_DMG_FORMAT "UDBZ") set(CPACK_DMG_VOLUME_NAME "${scappbundlename}") set(CPACK_SYSTEM_NAME "OSX") # set(CPACK_PACKAGE_FILE_NAME "${scappbundlename}-${PROJECT_VERSION}") set(CPACK_DMG_DS_STORE "${CMAKE_SOURCE_DIR}/package/ds_store") set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/package/background.png") set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/icons/SCcube.icns") endif() if(NOT WIN32) # We define a custom 'package' target in platform/windows/CMakeLists.txt include(CPack) endif() ############################################# # hide advanced variables mark_as_advanced(AVAHI_LIBRARIES AVAHI_INCLUDE_DIRS AVAHI_INCLUDE_DIR AVAHI_LIBRARY-COMMON AVAHI_LIBRARY-CLIENT) mark_as_advanced(DL) mark_as_advanced(EMACS_EXECUTABLE) mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_LIBRARY_DIR) mark_as_advanced(JACK JACK_INCLUDE_DIR JACK_LIBRARY) mark_as_advanced(MATH_LIBRARY) mark_as_advanced(QT_QMAKE_EXECUTABLE) mark_as_advanced(SNDFILE SNDFILE_LIBRARY_DIR) SuperCollider-Source/common/000755 000765 000024 00000000000 13007315613 017144 5ustar00crucialstaff000000 000000 SuperCollider-Source/COPYING000644 000765 000024 00000104513 12321461510 016707 0ustar00crucialstaff000000 000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . SuperCollider-Source/editors/000755 000765 000024 00000000000 13007315613 017325 5ustar00crucialstaff000000 000000 SuperCollider-Source/examples/000755 000765 000024 00000000000 13007315613 017472 5ustar00crucialstaff000000 000000 SuperCollider-Source/external_libraries/000755 000765 000024 00000000000 13007315613 021532 5ustar00crucialstaff000000 000000 SuperCollider-Source/HelpSource/000755 000765 000024 00000000000 13007315613 017725 5ustar00crucialstaff000000 000000 SuperCollider-Source/icons/000755 000765 000024 00000000000 13007315613 016767 5ustar00crucialstaff000000 000000 SuperCollider-Source/include/000755 000765 000024 00000000000 13007315613 017277 5ustar00crucialstaff000000 000000 SuperCollider-Source/INSTALL000644 000765 000024 00000000246 12321461510 016703 0ustar00crucialstaff000000 000000 See the platform specific build and install instructions in: README_IPHONE.md README_JAILBROKEN_IPHONE.md README_LINUX.md README_OS_X.md README_WINDOWS.md README.md SuperCollider-Source/lang/000755 000765 000024 00000000000 13007315613 016575 5ustar00crucialstaff000000 000000 SuperCollider-Source/package/000755 000765 000024 00000000000 13007315613 017247 5ustar00crucialstaff000000 000000 SuperCollider-Source/platform/000755 000765 000024 00000000000 13007315613 017500 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/000755 000765 000024 00000000000 13007315613 017716 5ustar00crucialstaff000000 000000 SuperCollider-Source/README.md000644 000765 000024 00000010063 12766171707 017152 0ustar00crucialstaff000000 000000 [![Build Status](https://travis-ci.org/supercollider/supercollider.svg?branch=master)](https://travis-ci.org/supercollider/supercollider) Welcome to SuperCollider! ========================= **SuperCollider** is an environment and programming language for real time audio synthesis and algorithmic composition. It provides an interpreted object-oriented language which functions as a network client to a state of the art, realtime sound synthesis server. SuperCollider was written by James McCartney (http://audiosynth.com) over a period of many years. It is now an open source GPL'd project maintained and developed by James and various others. It is used by musicians, scientists, and artists working with sound. http://supercollider.github.io/ This README is a first help for anyone new to SuperCollider. There are many good resources available for learning SuperCollider, with up to date links from the site listed above, including links to forums and mailing lists. Usage ----- SuperCollider consists of three separate components: 1. scsynth or supernova - audio engine (the "server") 2. sclang - programming language runtime interpreter including Qt graphical user interfaces 3. IDE (integrated development environment) - an editor for writing code and running supercollider To begin using SuperCollider, you usually start up the IDE: - on Mac OS this is `SuperCollider.app` - on Linux and Windows, this is the `scide` executable You can get further help by using the IDE's integrated help system which can be invoked via the "Help" menu or using the key combination `Ctrl+D` (on Linux, Windows) or `Cmd+D` (on Mac OS). In the Help menu, you will also find an action that will take you directly to the help page on using the IDE. When starting the SuperCollider IDE, the audio server is not started automatically. You can start it using the "Language > Boot Server" menu action, or using the key combination `Ctrl+B` (on Linux, Windows) or `Cmd+B` (on Mac OS). This is just to remind you in case you're impatient and can't understand why you're not immediately getting sound. We suggest you to proceed by reading the tutorials available in the help system. Please note that some help pages are not up-to-date with the latest development of SuperCollider, especially when mentioning the code editing environment. Regarding this, it is best to refer to the help page specifically about the new SuperCollider IDE. Also, please explore the IDE menus, which will let you discover a lot of functionality of the coding environment. To get further information on SuperCollider usage or development, you should subscribe to the mailing lists: http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx We hope you enjoy SuperCollider; please get involved in the active community! Reporting bugs -------------- Please report bugs to the github issue tracker or discuss on the sc-users mailing list. https://github.com/supercollider/supercollider/issues Building the Source Code ------------------------ Platform specific build and install instructions can be found in the following files: - [README_OS_X.md](README_OS_X.md) - [README_LINUX.md](README_LINUX.md) - [README_WINDOWS.md](README_WINDOWS.md) - [README_IPHONE.md](README_IPHONE.md) - [README_JAILBROKEN_IPHONE.md](README_JAILBROKEN_IPHONE.md) License ------- SuperCollider is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See [COPYING](COPYING) for the license text. - SuperCollider 3.1 was released on October 31, 2007 - SuperCollider 3.2 was released on February 19, 2008 - SuperCollider 3.3 was released on April 30, 2009 - SuperCollider 3.4 was released on July 15, 2010 - SuperCollider 3.5 was released on March 16, 2012 - SuperCollider 3.6 was released on November 28, 2012 - SuperCollider 3.7 was released on March 13, 2016 Outro ----- Thanks to James McCartney, for making this great piece of audio software publicly and freely available! SuperCollider-Source/README_LINUX.md000644 000765 000024 00000021562 12766171707 020137 0ustar00crucialstaff000000 000000 Supercollider 3 for linux ========================= Intro ----- SuperCollider is a synthesis engine (scsynth or supernova) and programming language (sclang), originally Mac-based but now very widely used and actively developed on Linux. Stefan Kersten first ported the code to Linux in 2003. Build requirements ------------------ (most of these will be available in your linux distribution as packages ) * gcc >= 4.8 http://www.gnu.org/software/gcc * jack and libjack * http://jackit.sourceforge.net * jack audio connection kit * libsndfile >= 1.0 * http://www.mega-nerd.com/libsndfile * _the_ soundfile i/o library * cmake >= 2.8.11 * http://www.cmake.org * cross-platform build system * cmake >= 3.1 is required for supernova (an alternate server with parallel processing capabilities). supernova is built by default if cmake is new enough. * fftw >= 3.0 * http://www.fftw.org * fast FFT transform library (for frequency-domain analysis, phase-vocoder effects) * libxt * http://www.X.org * X toolkit intrinsics Build requirements (optional features) -------------------------------------- (most of these will be available in your linux distribution as packages) * Qt >= 5.3 (+ qtwebkit) * http://qt-project.org * cross-platform graphical user interface library, for Qt IDE and sclang's Qt GUI kit * Qt >= 5.0 should work, but build-test is done against 5.3 * As of this writing, there are known issues with building on Qt >= 5.6. * alsa * http://www.alsa-project.org * advanced linux sound architecture drivers and library, for sclang's MIDI interface * libudev * http://www.freedesktop.org/software/systemd/man/libudev.html * interaction with the device manager of linux (used for HID support) * libreadline >= 5 * http://savannah.gnu.org/projects/readline * provides convenient CLI interface for sclang * libavahi-client * http://www.avahi.org * a more powerful zeroconf service discovery implementation * libcwiid * http://abstrakraft.org/cwiid * library for wiimote support * linux kernel >= 2.6 * http://www.kernel.org * for sclang's linux input device (LID) interface * for `scel`: the **emacs** interface see [editors/scel/README.md](editors/scel/README.md) * for `sced`: the **gedit** interface see [editors/sced/README.md](editors/sced/README.md) * for `scvim`: the **vim** interface see [editors/scvim/README.md](editors/scvim/README.md) Build requirements (debian users) --------------------------------- On debian (unstable) you can install the following packages and be set for building supercollider: - build-essential - libjack-dev or libjack-jackd2-dev - libsndfile1-dev - libasound2-dev - libavahi-client-dev - libicu-dev - libreadline6-dev - libfftw3-dev - libxt-dev - libudev-dev - libcwiid-dev (for wiimote support) - pkg-config - git (used by the Quarks package management system) - cmake (on some platforms, cmake >= 2.9 may require manual build) - qt5-default qt5-qmake qttools5-dev qttools5-dev-tools qtdeclarative5-dev libqt5webkit5-dev qtpositioning5-dev libqt5sensors5-dev libqt5opengl5-dev More details for building on embedded linux platforms (Raspberry Pi, Beaglebone Black) can be found here: http://supercollider.github.io/development/building The recommended version of gcc is 4.8 Building -------- - to build supercollider with cmake, it is suggested to do out-of-tree builds in a specific build directory: ``` $> mkdir build $> cd build $> cmake -DCMAKE_PREFIX_PATH=/path/to/qt5 .. ``` The location of `/path/to/qt5` will depend on how you installed Qt: - If you used your Linux distribution's repositories, it will be `/usr/lib/i386-linux-gnu/` (32-bit) or `/usr/lib/x86_64-linux-gnu/` (64-bit). - If you downloaded Qt from the Qt website, the path is two directories down from the top-level unpacked Qt directory: `Qt5.x.x/5.x/gcc/` (32-bit) or `Qt5.x.x/5.x/gcc_64/` (64-bit). You can see the available build options with ```cmake -LH```. - to run the build process run: ``` $> make ``` The build process can be configured using the cmake program, cmake frontends like ccmake or cmake-gui, or by simply editing the `build/CMakeCache.txt` file. For example to enable a release build run the following in your build directory: ``` $> cmake -DCMAKE_BUILD_TYPE=Release .. ``` - to install the whole program, run: ``` $> make install ``` For the above step you will probably need super-user privileges, e.g. using "sudo". Also, please run ``` $> sudo ldconfig ``` after installing for the first time. - to uninstall: ``` $> make uninstall ``` ### Qt GUI By default the Qt GUI support will be built into sclang. If you want to build without it configure cmake like this: ``` $> cmake -DSC_QT=OFF .. ``` Note: running headless SC in a X-less environment requires jackd without D-bus support. On Raspbian Jessie this requires compiling jackd rather than using the packaged version. Also note that you will get errors on sclang startup from classes requiring Qt. A workaround and more details are described in: http://supercollider.github.io/development/building-raspberrypi ### Speeding up repeated builds If you build SuperCollider repeatedly, we recommend installing `ccache` which can speed up re-compilation. Here is how to configure cmake to use it: ``` $> cmake -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc .. ``` This assumes your ccache executables are installed into `/usr/lib/ccache` - you may need to change the path to reflect your installation. Building a Debian package ------------------------- The most up-to-date debian packaging rules are maintained by the Debian Multimedia team. Repository (with debian/ folder): http://anonscm.debian.org/gitweb/?p=pkg-multimedia/supercollider.git;a=summary Running scsynth or supernova (standalone) ---------------------------- Run `scsynth --help` or `supernova --help` to get an option summary. Don't forget to start jackd before starting the server. If you want to add directories to supercollider's search path or assign default jack ports, set up your environment as described below. You can specify the number of jack input/output channels created with the options `-i` and `-o`, respectively. the `-H` option can be used to specify a jack server to connect to and to set the jack client identifier. The format is either `:` or just `` when connecting to the default server. Running sclang -------------- Supercollider comes with its own powerful IDE. Run it with: ``` $> scide ``` Alternatively you can use sclang in combination with your preferred text editor out of emacs/vim/gedit. See the `README.md` files in `editors/*` for installation and usage. Another alternative is to simply run the `sclang` executable which will provide a readline-based interface. `sclang` executes the startup file `~/.config/SuperCollider/startup.scd` after class library initialization. This file can contain statements to set up your supercollider environment, like setting default variables. An example can be found in `linux/examples/sclang.sc`. You _have_ to have a directory `~/.local/share/SuperCollider`. This is where a synthdefs directory is automatically created. It is also the place to put Extensions to the class library, in a folder called Extensions. The runtime directory is either the current working directory or the path specified with the `-d` option. Environment ----------- The jack audio driver interface is configured based on various environment variables: * SC_JACK_DEFAULT_INPUTS comma separated list of jack ports that the server's inputs should connect to by default ``` $> export SC_JACK_DEFAULT_INPUTS="system:capture_1,system:capture_2" ``` in order to connect the first ports of one jack client, it is possible to specify only the client name ``` $> export SC_JACK_DEFAULT_INPUTS="system" ``` * SC_JACK_DEFAULT_OUTPUTS comma separated list of jack ports that the server's outputs should be connected to by default. ``` $> export SC_JACK_DEFAULT_OUTPUTS="system:playback_1,system:playback_2" ``` In order to connect the first ports of one jack client, it is possible to specify only the client name ``` $> export SC_JACK_DEFAULT_OUTPUTS="system" ``` Two additional environment variables substitute directories for the default search path for plugins and synth definitions, respectively. Directory names are separated by ':' as in the unix PATH variable: * SC_PLUGIN_PATH, SC_SYNTHDEF_PATH ``` $> export SC_SYNTHDEF_PATH="./synthdefs:/home/sk/SuperCollider/synthdefs" ``` Contributors to this document ----------------------------- - stefan kersten - andi pieper - maurizio umberto puxeddu - rohan drape - mario lang - john yates - nescivi (marije baalman) - dan stowell - tim blechmann SuperCollider-Source/SCClassLibrary/000755 000765 000024 00000000000 13007315613 020474 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCDoc/000755 000765 000024 00000000000 13007315613 016607 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCVersion.txt000644 000765 000024 00000001363 13007176255 020302 0ustar00crucialstaff000000 000000 # This file is included by CMakeLists.txt, and is the single place where SC version should be updated. # Note that you need to "make install" for this information to be copied into all places.. set(PROJECT_VERSION_MAJOR 3) set(PROJECT_VERSION_MINOR 8) set(PROJECT_VERSION_PATCH .0) if(EXISTS "${CMAKE_SOURCE_DIR}/.git") execute_process( COMMAND git rev-parse --abbrev-ref HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( COMMAND git log -1 --format=%h WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE ) else() SET(GIT_BRANCH not_a_git_checkout) SET(GIT_COMMIT_HASH na) endif() SuperCollider-Source/server/000755 000765 000024 00000000000 13007315613 017162 5ustar00crucialstaff000000 000000 SuperCollider-Source/sounds/000755 000765 000024 00000000000 13007315613 017167 5ustar00crucialstaff000000 000000 SuperCollider-Source/testsuite/000755 000765 000024 00000000000 13007315613 017705 5ustar00crucialstaff000000 000000 SuperCollider-Source/travis_test_run_proto.json000644 000765 000024 00000003464 12756531745 023254 0ustar00crucialstaff000000 000000 { "tests": [ { "test": "*", "suite": "TestPlotter" }, { "test": "*", "suite": "TestUnitTest" }, { "test": "*", "suite": "TestEnv" }, { "test": "*", "suite": "TestArray" }, { "test": "*", "suite": "TestEvent" }, { "test": "*", "suite": "TestOSCBundle" }, { "test": "*", "suite": "TestNoOps" }, { "test": "*", "suite": "TestMixedBundleTester" }, { "test": "*", "suite": "TestFloat" }, { "test": "*", "suite": "TestNetAddr" }, { "test": "*", "suite": "TestCurveWarp" }, { "test": "*", "suite": "UnitTestScript" }, { "test": "*", "suite": "TestSignal" }, { "suite": "TestUnitTest", "test": "test_toreDown", "skip": true, "skipReason": "UnitTest bug" }, { "suite": "TestUnitTest", "test": "test_setUp2", "skip": true, "skipReason": "UnitTest bug" }, { "suite": "TestUnitTest", "test": "test_bootServer", "skip": true, "skipReason": "No server support on travis" }, { "test": "test_sendBundle50", "suite": "TestNetAddr", "skipReason": "No server support on travis", "skip": true }, { "test": "test_send", "suite": "TestMixedBundleTester", "skipReason": "No server support on travis", "skip": true }, { "test": "test_findPreparationMessage", "suite": "TestMixedBundleTester", "skipReason": "No server support on travis", "skip": true }, { "test": "test_prepare", "suite": "TestOSCBundle", "skipReason": "No server support on travis", "skip": true } ] }SuperCollider-Source/testsuite/CMakeLists.txt000644 000765 000024 00000000117 12321461511 022441 0ustar00crucialstaff000000 000000 if (SUPERNOVA) add_subdirectory(supernova) endif() add_subdirectory(sclang) SuperCollider-Source/testsuite/sclang/000755 000765 000024 00000000000 13007315613 021154 5ustar00crucialstaff000000 000000 SuperCollider-Source/testsuite/supernova/000755 000765 000024 00000000000 13007315613 021727 5ustar00crucialstaff000000 000000 SuperCollider-Source/testsuite/supernova/audio_backend_test.cpp000644 000765 000024 00000002100 12321461511 026230 0ustar00crucialstaff000000 000000 #define BOOST_TEST_MAIN #include #include #define protected public #include "audio_backend/audio_backend.hpp" #include "audio_backend/portaudio.hpp" using namespace nova; namespace { void tick(void) {} } template void test_backend(void) { backend be; BOOST_REQUIRE(!be.audiostream_ready()); device_list devs = be.list_devices(); be.open_audio_stream(devs[0], devs[0].inchannels, devs[0], devs[0].outchannels, devs[0].defaultSampleRate); BOOST_REQUIRE(be.audiostream_ready()); BOOST_REQUIRE(!be.is_active()); be.activate(); BOOST_REQUIRE(be.is_active()); boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); xt.sec += 1; boost::thread::sleep(xt); be.deactivate(); BOOST_REQUIRE(!be.is_active()); be.close_audio_stream(); BOOST_REQUIRE(!be.audiostream_ready()); } BOOST_AUTO_TEST_CASE( dummy_test_1 ) { test_backend >(); } BOOST_AUTO_TEST_CASE( pa_test_1 ) { test_backend >(); } SuperCollider-Source/testsuite/supernova/audio_frontend_test.cpp000644 000765 000024 00000003211 12321461511 026464 0ustar00crucialstaff000000 000000 #include #include #define protected public #include "audio_backend/audio_backend.hpp" #include "audio_backend/portaudio.hpp" #include "audio_backend/audio_frontend.hpp" using namespace nova; namespace { void tick(void) {} } BOOST_AUTO_TEST_CASE( frontend_test_1 ) { audio_frontend<&tick> af; BOOST_REQUIRE(!af.audio_is_opened()); BOOST_REQUIRE(af.audio_is_ready()); BOOST_REQUIRE(af.audio_is_active()); BOOST_REQUIRE(!af.audio_is_opened()); } BOOST_AUTO_TEST_CASE( frontend_test_2 ) { audio_frontend<&tick> af; BOOST_REQUIRE(!af.audio_is_opened()); BOOST_REQUIRE(af.audio_is_ready()); BOOST_REQUIRE(af.audio_is_active()); af.open_portaudio_backend(); BOOST_REQUIRE(!af.audio_is_ready()); BOOST_REQUIRE(!af.audio_is_active()); device_list devs = af.list_devices(); af.open_audio_stream(devs[0], devs[0].inchannels, devs[0], devs[0].outchannels, devs[0].defaultSampleRate); BOOST_REQUIRE(af.audio_is_ready()); BOOST_REQUIRE(!af.audio_is_active()); af.activate_audio(); BOOST_REQUIRE(af.audio_is_ready()); BOOST_REQUIRE(af.audio_is_active()); boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); xt.sec += 1; boost::thread::sleep(xt); af.deactivate_audio(); BOOST_REQUIRE(af.audio_is_ready()); BOOST_REQUIRE(!af.audio_is_active()); af.close_audio_stream(); BOOST_REQUIRE(!af.audio_is_ready()); BOOST_REQUIRE(!af.audio_is_active()); af.close_audio_backend(); BOOST_REQUIRE(af.audio_is_ready()); BOOST_REQUIRE(af.audio_is_active()); BOOST_REQUIRE(!af.audio_is_opened()); } SuperCollider-Source/testsuite/supernova/boost_test.cpp000644 000765 000024 00000000105 12321461511 024611 0ustar00crucialstaff000000 000000 #define BOOST_TEST_MAIN #include SuperCollider-Source/testsuite/supernova/buffer_manager_test.cpp000644 000765 000024 00000000500 12321461511 026425 0ustar00crucialstaff000000 000000 #include #include #include "server/buffer_manager.cpp" using namespace nova; BOOST_AUTO_TEST_CASE( buffer_manager_test ) { buffer_manager bm(1024); bm.allocate_buffer(0, 44100, 2); bm.zero_buffer(0); bm.fill_samples(0, 0, 882000, 0.2); bm.free_buffer(0); } SuperCollider-Source/testsuite/supernova/callback_interpreter_system.cpp000644 000765 000024 00000001753 12756531745 030244 0ustar00crucialstaff000000 000000 #include #include "utilities/callback_system.hpp" #include "utilities/callback_interpreter.hpp" #include "nova-tt/thread_priority.hpp" using namespace nova; namespace { int i = 0; struct dummy { void run(void) { ++i; } }; } BOOST_AUTO_TEST_CASE( callback_system_test ) { callback_system cbs; cbs.add_callback(new dummy()); cbs.run_callbacks(); BOOST_REQUIRE_EQUAL(i, 1); } BOOST_AUTO_TEST_CASE( threaded_callback_interpreter_test ) { threaded_callback_interpreter cbi; cbi.start_thread(); for (int j = 0; j != 20; ++j) cbi.add_callback(new dummy()); cbi.join_thread(); BOOST_REQUIRE_EQUAL(i, 21); } BOOST_AUTO_TEST_CASE( callback_interpreter_threadpool_test ) { { callback_interpreter_threadpool cbi(4, true, thread_priority_interval().first); for (int j = 0; j != 20; ++j) cbi.add_callback(new dummy()); } BOOST_REQUIRE_EQUAL(i, 41); } SuperCollider-Source/testsuite/supernova/CMakeLists.txt000644 000765 000024 00000002122 12756531745 024504 0ustar00crucialstaff000000 000000 set(simple_tests buffer_manager_test.cpp callback_interpreter_system.cpp memory-pool_test.cpp server_dsp_thread_queue_test.cpp server_dsp_thread_test.cpp server_node_graph_test.cpp server_scheduler_test.cpp server_synth_factory_test.cpp server_test.cpp simple_pool_test.cpp sized_array_test.cpp sndfile_backend_test.cpp static_pool_test.cpp timetag_test.cpp ) if(!APPLE) set(simple_tests ${simple_tests} static_allocator_test.cpp tl_allocator_test.cpp ) endif() if (CMAKE_SYSTEM_NAME MATCHES "Linux") set(simple_tests ${simple_tests} perf_counter_test.cpp ) endif() add_library(boost_test STATIC boost_test.cpp) target_include_directories(boost_test PUBLIC ${CMAKE_SOURCE_DIR}/external_libraries/boost) # run simple tests foreach(test ${simple_tests}) string(REPLACE .cpp "" test_name ${test} ) add_executable(${test_name} ${test}) target_link_libraries(${test_name} libsupernova boost_test boost_thread) add_test(${test_name}_run ${EXECUTABLE_OUTPUT_PATH}/${test_name}) endforeach(test) SuperCollider-Source/testsuite/supernova/default.scsyndef000644 000765 000024 00000001144 12321461511 025110 0ustar00crucialstaff000000 000000 SCgfdefault >>EzE@E@EH?<# ?333@C=?outfreqamppangateControlControlVarSawLinen  Rand BinaryOpUGenVarSaw BinaryOpUGenRand BinaryOpUGenVarSaw  BinaryOpUGen RandRandXLine LPF  BinaryOpUGenPan2 OffsetOutSuperCollider-Source/testsuite/supernova/help-In.scsyndef000644 000765 000024 00000000142 12321461511 024755 0ustar00crucialstaff000000 000000 SCgfhelp-InoutinControlInOutSuperCollider-Source/testsuite/supernova/help_Demand.scsyndef000644 000765 000024 00000000777 12321461511 025677 0ustar00crucialstaff000000 000000 SCgf help_Demand@?@@@@BA`BBBBBBBBBBB@BBD ImpulseDseq BinaryOpUGenDseq BinaryOpUGen BinaryOpUGenDemandPoll Poll SuperCollider-Source/testsuite/supernova/help_InFeedback.scsyndef000644 000765 000024 00000000321 12321461511 026443 0ustar00crucialstaff000000 000000 SCgfhelp_InFeedbackDC>outinControl InFeedbackMulAddSinOsc BinaryOpUGenOutSuperCollider-Source/testsuite/supernova/help_LocalBuf.scsyndef000644 000765 000024 00000000723 12321461511 026165 0ustar00crucialstaff000000 000000 SCgf help_LocalBuf=@?E?=G WhiteNoise BinaryOpUGen WhiteNoise BinaryOpUGen MaxLocalBufsLocalBufFFTLocalBufFFTSinOsc PV_BrickWall IFFT SinOsc PV_BrickWall IFFT SuperCollider-Source/testsuite/supernova/help_LocalIn.scsyndef000644 000765 000024 00000000536 12321461511 026021 0ustar00crucialstaff000000 000000 SCgf help_LocalIn>=>L?L ImpulseDecay WhiteNoise BinaryOpUGenLocalInDelayN BinaryOpUGenMulAddDelayN BinaryOpUGenLocalOut OutSuperCollider-Source/testsuite/supernova/help_out.scsyndef000644 000765 000024 00000000222 12321461511 025277 0ustar00crucialstaff000000 000000 SCgfhelp_out=CoutfreqControlSinOsc BinaryOpUGenOutSuperCollider-Source/testsuite/supernova/help_out2.scsyndef000644 000765 000024 00000000354 12321461511 025367 0ustar00crucialstaff000000 000000 SCgf help_out2?=CoutfreqControl BinaryOpUGenSinOsc BinaryOpUGenSinOsc BinaryOpUGenOutSuperCollider-Source/testsuite/supernova/help_PlayBuf.scsyndef000644 000765 000024 00000000275 12321461511 026042 0ustar00crucialstaff000000 000000 SCgf help_PlayBuf@outbufnumControl BufRateScaleImpulsePlayBufOutSuperCollider-Source/testsuite/supernova/help_RecordBuf.scsyndef000644 000765 000024 00000000374 12321461511 026353 0ustar00crucialstaff000000 000000 SCgfhelp_RecordBuf CDz@DDH>?@outbufnumControlXLineFormant BinaryOpUGen RecordBuf SuperCollider-Source/testsuite/supernova/help_RecordBuf_overdub.scsyndef000644 000765 000024 00000000263 12321461511 030076 0ustar00crucialstaff000000 000000 SCgfhelp_RecordBuf_overdub?outbufnumControlPlayBufFreeSelfWhenDoneOutSuperCollider-Source/testsuite/supernova/memory-pool_test.cpp000644 000765 000024 00000001233 12321461511 025745 0ustar00crucialstaff000000 000000 #include #include #include #include "server/memory_pool.hpp" namespace nova { simple_pool rt_pool; } /* namespace nova */ using namespace nova; BOOST_AUTO_TEST_CASE( init_pool ) { rt_pool.init(1024*1024); } BOOST_AUTO_TEST_CASE( vector_test ) { rt_pool.init(1024*1024); int size = 1024; std::vector > vec; for (int i = 0; i != size; ++i) vec.push_back(-i); } BOOST_AUTO_TEST_CASE( set_test ) { int size = 1024; std::set, nova::rt_pool_allocator > vec; for (int i = 0; i != size; ++i) vec.insert(-i); } SuperCollider-Source/testsuite/supernova/perf_counter_test.cpp000644 000765 000024 00000000366 12321461511 026167 0ustar00crucialstaff000000 000000 #include #include #include "../../external_libraries/nova-simd/benchmarks/perf_counter.hpp" BOOST_AUTO_TEST_CASE( perf_count_test ) { perf_counter pc; pc.start(); pc.stop(); pc.dump(); } SuperCollider-Source/testsuite/supernova/sc_plugin_loader_test.cpp000644 000765 000024 00000006160 12321461511 027003 0ustar00crucialstaff000000 000000 #include #include #include #include "sc/sc_ugen_factory.hpp" #include "server/memory_pool.hpp" #include "server/server_args.hpp" using namespace nova; using namespace std; boost::filesystem::path base_path ("/home/tim/workspace/nova-server/debug_plugins/"); BOOST_AUTO_TEST_CASE( ugen_factory_test_1 ) { server_arguments::initialize(0, 0); rt_pool.init(1024*1024); sc_factory.initialize(); sc_factory.load_plugin(base_path / "BinaryOpUGens.so"); sc_factory.load_plugin(base_path / "ChaosUGens.so"); sc_factory.load_plugin(base_path / "DelayUGens.so"); sc_factory.load_plugin(base_path / "DemandUGens.so"); sc_factory.load_plugin(base_path / "DiskIO_UGens.so"); sc_factory.load_plugin(base_path / "DynNoiseUGens.so"); sc_factory.load_plugin(base_path / "FFT_UGens.so"); sc_factory.load_plugin(base_path / "FilterUGens.so"); sc_factory.load_plugin(base_path / "GendynUGens.so"); sc_factory.load_plugin(base_path / "GrainUGens.so"); sc_factory.load_plugin(base_path / "IOUGens.so"); sc_factory.load_plugin(base_path / "KeyboardUGens.so"); sc_factory.load_plugin(base_path / "LFUGens.so"); sc_factory.load_plugin(base_path / "ML_UGens.so"); sc_factory.load_plugin(base_path / "MouseUGens.so"); sc_factory.load_plugin(base_path / "MulAddUGens.so"); sc_factory.load_plugin(base_path / "NoiseUGens.so"); sc_factory.load_plugin(base_path / "OscUGens.so"); sc_factory.load_plugin(base_path / "PanUGens.so"); sc_factory.load_plugin(base_path / "PhysicalModelingUGens.so"); sc_factory.load_plugin(base_path / "PV_ThirdParty.so"); sc_factory.load_plugin(base_path / "ReverbUGens.so"); sc_factory.load_plugin(base_path / "TestUGens.so"); sc_factory.load_plugin(base_path / "TriggerUGens.so"); sc_factory.load_plugin(base_path / "UnaryOpUGens.so"); sc_factory.load_plugin(base_path / "UnpackFFTUGens.so"); rt_pool.init(1024*1024*16, true); } const char * test_synthdefs[] = { "default.scsyndef", "help-In.scsyndef", "help_out.scsyndef", "help_out2.scsyndef", "help_InFeedback.scsyndef", "help_LocalIn.scsyndef", "help_PlayBuf.scsyndef", "help_RecordBuf.scsyndef", "help_RecordBuf_overdub.scsyndef", "help_LocalBuf.scsyndef", "help_Demand.scsyndef", }; #if 0 /* doesn't work anymore because of increased sanity checks */ BOOST_AUTO_TEST_CASE( ugen_construct_test_1 ) { for (int i = 0; i != sizeof(test_synthdefs)/sizeof(const char*); ++i) { const char * synthdef = test_synthdefs[i]; try { std::vector defs = nova::read_synthdef_file(base_path / ".." / "testsuite" / synthdef); sc_synth_prototype_ptr prtype(new sc_synth_prototype(defs[0])); sc_synth * s = new sc_synth(1000, prtype); dsp_context context(44100, 64, 0); for (int i = 0; i != 1000; ++i) s->run(context); delete s; } catch(std::runtime_error const & e) { std::cerr << e.what() << std::endl; } } } #endif SuperCollider-Source/testsuite/supernova/sc_synth_prototype_test.cpp000644 000765 000024 00000000656 12321461511 027455 0ustar00crucialstaff000000 000000 #include #include "sc/sc_synth_prototype.hpp" #include "server/synth_factory.hpp" using namespace nova; using namespace std; BOOST_AUTO_TEST_CASE( sc_synth_factory ) { synth_factory factory; const char * home_ptr = getenv("HOME"); BOOST_REQUIRE (home_ptr != 0); path home(home_ptr); register_synthdefs(factory, sc_read_synthdefs_dir(home / "share/SuperCollider/synthdefs")); } SuperCollider-Source/testsuite/supernova/sc_synthdef_test.cpp000644 000765 000024 00000000411 12321461511 025774 0ustar00crucialstaff000000 000000 #include #include #include "sc/sc_synthdef.hpp" BOOST_AUTO_TEST_CASE( sc_synthdef_test ) { std::vector defs = nova::read_synthdef_file("testsuite/default.scsyndef"); std::cout << defs[0].dump(); } SuperCollider-Source/testsuite/supernova/server_dsp_thread_queue_test.cpp000644 000765 000024 00000007015 12321461511 030401 0ustar00crucialstaff000000 000000 #include #include "dsp_thread_queue/dsp_thread_queue.hpp" namespace { struct dummy_runnable { dummy_runnable(void): i(0) {} void operator()(unsigned int dummy) { ++i; } int i; }; dummy_runnable dummy; } typedef nova::dsp_queue_interpreter dsp_queue_interpreter; typedef nova::dsp_thread_queue_item dsp_thread_queue_item; typedef nova::dsp_thread_queue dsp_thread_queue; BOOST_AUTO_TEST_CASE( dsp_thread_queue_test_1 ) { dsp_queue_interpreter interpreter(1); bool runnable = interpreter.init_tick(); BOOST_REQUIRE(!runnable); } BOOST_AUTO_TEST_CASE( dsp_thread_queue_test_2 ) { dsp_queue_interpreter interpreter(1); bool runnable = interpreter.init_tick(); if (runnable) interpreter.tick(0); } BOOST_AUTO_TEST_CASE( dsp_thread_queue_test_3 ) { dsp_queue_interpreter interpreter(1); std::unique_ptr q (new dsp_thread_queue(1)); dsp_thread_queue_item * item = q->allocate_queue_item(dummy, dsp_thread_queue_item::successor_list(), 0); q->add_initially_runnable(item); interpreter.reset_queue(std::move(q)); bool runnable = interpreter.init_tick(); BOOST_REQUIRE(runnable); interpreter.tick(0); BOOST_REQUIRE_EQUAL(item->get_job().i, 1); } BOOST_AUTO_TEST_CASE( dsp_thread_queue_test_4 ) { dsp_queue_interpreter interpreter(1); std::unique_ptr q (new dsp_thread_queue(2)); dsp_thread_queue_item * item1 = q->allocate_queue_item(dummy, dsp_thread_queue_item::successor_list(), 1); dsp_thread_queue_item::successor_list sl(1); sl[0] = item1; dsp_thread_queue_item * item2 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item2); interpreter.reset_queue(std::move(q)); bool runnable = interpreter.init_tick(); BOOST_REQUIRE(runnable); interpreter.tick(0); BOOST_REQUIRE_EQUAL(item1->get_job().i, 1); BOOST_REQUIRE_EQUAL(item2->get_job().i, 1); } BOOST_AUTO_TEST_CASE( dsp_thread_queue_test_5 ) { dsp_queue_interpreter interpreter(1); { std::unique_ptr q (new dsp_thread_queue(2)); dsp_thread_queue_item * item1 = q->allocate_queue_item(dummy, dsp_thread_queue_item::successor_list(), 1); dsp_thread_queue_item::successor_list sl(1); sl[0] = item1; dsp_thread_queue_item * item2 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item2); interpreter.reset_queue(std::move(q)); for (int i = 0; i != 2; ++i) { bool runnable = interpreter.init_tick(); BOOST_REQUIRE(runnable); interpreter.tick(0); } BOOST_REQUIRE_EQUAL(item1->get_job().i, 2); BOOST_REQUIRE_EQUAL(item2->get_job().i, 2); } { std::unique_ptr q (new dsp_thread_queue(2)); dsp_thread_queue_item * item1 = q->allocate_queue_item(dummy, dsp_thread_queue_item::successor_list(), 1); dsp_thread_queue_item::successor_list sl(1); sl[0] = item1; dsp_thread_queue_item * item2 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item2); interpreter.reset_queue(std::move(q)); for (int i = 0; i != 2; ++i) { bool runnable = interpreter.init_tick(); BOOST_REQUIRE(runnable); interpreter.tick(0); } BOOST_REQUIRE_EQUAL(item1->get_job().i, 2); BOOST_REQUIRE_EQUAL(item2->get_job().i, 2); } } SuperCollider-Source/testsuite/supernova/server_dsp_thread_test.cpp000644 000765 000024 00000012457 12756531745 027226 0ustar00crucialstaff000000 000000 #include #include #include "dsp_thread_queue/dsp_thread.hpp" #include "server/memory_pool.hpp" namespace { volatile int gint; struct dummy_runnable { dummy_runnable(void): i(0) {} void operator()(uint dummy) { ++i; for (int j = 0; j != 1000; ++j) { int l = gint; l += 1; gint = l; } } int i; }; dummy_runnable dummy; } template void run_test_1(void) { nova::dsp_thread_pool t(1); } BOOST_AUTO_TEST_CASE( dsp_thread_test_1 ) { nova::rt_pool.init(1024*1024*128); run_test_1 >(); run_test_1 >(); } template void run_test_2(void) { nova::dsp_thread_pool t(5); t.start_threads(); t.terminate_threads(); } BOOST_AUTO_TEST_CASE( dsp_thread_test_2 ) { run_test_2 >(); run_test_2 >(); } template void run_test_3(void) { nova::dsp_thread_pool t(2); t.start_threads(); t.run(); t.terminate_threads(); } BOOST_AUTO_TEST_CASE( dsp_thread_test_3 ) { run_test_3 >(); run_test_3 >(); } template void run_test_4(void) { typedef typename nova::dsp_thread_queue_item dsp_thread_queue_item; typedef typename nova::dsp_thread_queue dsp_thread_queue; typedef typename nova::dsp_thread_pool dsp_thread_pool; typedef std::unique_ptr dsp_thread_queue_ptr; dsp_thread_pool t(1); t.start_threads(); dsp_thread_queue_ptr q (new dsp_thread_queue(2)); dsp_thread_queue_item * item1 = q->allocate_queue_item(dummy, typename dsp_thread_queue_item::successor_list(), 1); typename dsp_thread_queue_item::successor_list sl(1); sl[0] = item1; dsp_thread_queue_item * item2 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item2); t.reset_queue(std::move(q)); t.run(); t.terminate_threads(); BOOST_REQUIRE_EQUAL(item1->get_job().i, 1); BOOST_REQUIRE_EQUAL(item2->get_job().i, 1); } BOOST_AUTO_TEST_CASE( dsp_thread_test_4 ) { run_test_4 >(); run_test_4 >(); } template void run_test_5(void) { typedef nova::dsp_thread_queue_item dsp_thread_queue_item; typedef nova::dsp_thread_queue dsp_thread_queue; typedef nova::dsp_thread_pool dsp_thread_pool; typedef std::unique_ptr dsp_thread_queue_ptr; dsp_thread_pool t(2); t.start_threads(); dsp_thread_queue_ptr q (new dsp_thread_queue(5)); dsp_thread_queue_item * item1 = q->allocate_queue_item(dummy, typename dsp_thread_queue_item::successor_list(), 4); typename dsp_thread_queue_item::successor_list sl(1); sl[0] = item1; dsp_thread_queue_item * item2 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item2); dsp_thread_queue_item * item3 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item3); dsp_thread_queue_item * item4 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item4); dsp_thread_queue_item * item5 = q->allocate_queue_item(dummy, sl, 0); q->add_initially_runnable(item5); t.reset_queue(std::move(q)); t.run(); t.terminate_threads(); BOOST_REQUIRE_EQUAL(item1->get_job().i, 1); BOOST_REQUIRE_EQUAL(item2->get_job().i, 1); BOOST_REQUIRE_EQUAL(item3->get_job().i, 1); BOOST_REQUIRE_EQUAL(item4->get_job().i, 1); BOOST_REQUIRE_EQUAL(item5->get_job().i, 1); } BOOST_AUTO_TEST_CASE( dsp_thread_test_5 ) { run_test_5 >(); run_test_5 >(); } template void run_test_6(void) { typedef nova::dsp_thread_queue_item dsp_thread_queue_item; typedef nova::dsp_thread_queue dsp_thread_queue; typedef nova::dsp_thread_pool dsp_thread_pool; typedef std::unique_ptr dsp_thread_queue_ptr; dsp_thread_pool t(2); t.start_threads(); dsp_thread_queue_ptr q (new dsp_thread_queue(20)); std::vector items; for (int i = 0; i != 20; ++i) { items.push_back(q->allocate_queue_item(dummy, typename dsp_thread_queue_item::successor_list(), 0)); q->add_initially_runnable(items.back()); } t.reset_queue(std::move(q)); const int iterations = 10000; for (int i = 0; i != iterations; ++i) { for (int item = 0; item != 20; ++item) BOOST_REQUIRE_EQUAL(items[item]->get_job().i, i); t.run(); } t.terminate_threads(); for (int i = 0; i != 20; ++i) BOOST_REQUIRE_EQUAL(items[i]->get_job().i, iterations); } BOOST_AUTO_TEST_CASE( dsp_thread_test_6 ) { run_test_6 >(); run_test_6 >(); } SuperCollider-Source/testsuite/supernova/server_node_graph_test.cpp000644 000765 000024 00000024110 12756531745 027204 0ustar00crucialstaff000000 000000 #include #include "server/node_graph.hpp" #include "test_synth.hpp" using namespace nova; using namespace std; BOOST_AUTO_TEST_CASE( simple_synth_test_1 ) { rt_pool.init(1024 * 1024); node_graph n; node_position_constraint to_root = std::make_pair(n.root_group(), insert); { test_synth * s = new test_synth(1000, 0); n.add_node(s, to_root); BOOST_REQUIRE_EQUAL(n.synth_count(), 1u); BOOST_REQUIRE_EQUAL(n.find_synth(1000), s); n.remove_node(s); BOOST_REQUIRE_EQUAL(n.synth_count(), 0u); } BOOST_REQUIRE_EQUAL(n.group_count(), 1u); { test_synth * s = new test_synth(1000, 0); n.add_node(s/* , node_position_constraint() */); BOOST_REQUIRE_EQUAL(n.synth_count(), 1u); n.remove_node(s); BOOST_REQUIRE_EQUAL(n.synth_count(), 0u); } BOOST_REQUIRE_EQUAL(n.group_count(), 1u); } BOOST_AUTO_TEST_CASE( simple_synth_test_2 ) { node_graph n; group * g = new group(1); n.add_node(g); BOOST_REQUIRE_EQUAL(n.find_group(1), g); n.remove_node(g); } BOOST_AUTO_TEST_CASE( simple_synth_test_3 ) { node_graph n; group * g = new group(1); n.add_node(g); { node_position_constraint to_group = std::make_pair(g, insert); test_synth * s = new test_synth(1000, 0); n.add_node(s, to_group); n.remove_node(s); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( simple_synth_test_4 ) { node_graph n; group * g = new group(1); n.add_node(g); test_synth * s = new test_synth(1000, 0); { node_position_constraint to_group = std::make_pair(g, insert); n.add_node(s, to_group); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( simple_synth_test_5 ) { node_graph n; test_synth * s = new test_synth(1000, 0); test_synth * s2 = new test_synth(1001, 0); n.add_node(s); n.add_node(s2); n.remove_node(s); n.remove_node(s2); } BOOST_AUTO_TEST_CASE( simple_synth_test_6 ) { node_graph n; test_synth * s1 = new test_synth(1000, 0); n.add_node(s1); test_synth * s2 = new test_synth(1001, 0); { node_position_constraint to_group = std::make_pair(n.root_group(), insert); n.add_node(s2, to_group); } test_synth * s3 = new test_synth(1002, 0); { node_position_constraint position = std::make_pair(s1, after); n.add_node(s3, position); } test_synth * s4 = new test_synth(1003, 0); { node_position_constraint position = std::make_pair(s1, before); n.add_node(s4, position); } //n.dump("test.dot"); n.remove_node(s1); n.remove_node(s2); n.remove_node(s3); n.remove_node(s4); } BOOST_AUTO_TEST_CASE( free_all_test ) { node_graph n; group * g = new group(1); n.add_node(g); BOOST_REQUIRE_EQUAL(n.group_count(), 2u); node_position_constraint to_group = std::make_pair(g, insert); test_synth * s = new test_synth(1000, 0); n.add_node(s, to_group); test_synth * s2 = new test_synth(1001, 0); n.add_node(s2, to_group); group * g2 = new group(1002); n.add_node(g2, to_group); BOOST_REQUIRE_EQUAL(n.synth_count(), 2u); BOOST_REQUIRE_EQUAL(n.group_count(), 3u); BOOST_REQUIRE(n.find_node(s->id())); BOOST_REQUIRE(n.find_node(s2->id())); BOOST_REQUIRE(n.find_node(g2->id())); n.group_free_all(g); BOOST_REQUIRE(!n.find_node(s->id())); BOOST_REQUIRE(!n.find_node(s2->id())); BOOST_REQUIRE(!n.find_node(g2->id())); BOOST_REQUIRE_EQUAL(n.synth_count(), 0u); BOOST_REQUIRE_EQUAL(n.group_count(), 2u); BOOST_REQUIRE(n.find_node(g->id())); n.remove_node(g); BOOST_REQUIRE(!n.find_node(g->id())); BOOST_REQUIRE_EQUAL(n.group_count(), 1u); } BOOST_AUTO_TEST_CASE( free_deep_test ) { node_graph n; group * g = new group(1); n.add_node(g); BOOST_REQUIRE_EQUAL(n.group_count(), 2u); node_position_constraint to_group = std::make_pair(g, insert); test_synth * s = new test_synth(1000, 0); n.add_node(s, to_group); test_synth * s2 = new test_synth(1001, 0); n.add_node(s2, to_group); group * g2 = new group(1002); n.add_node(g2, to_group); BOOST_REQUIRE_EQUAL(n.synth_count(), 2u); BOOST_REQUIRE_EQUAL(n.group_count(), 3u); BOOST_REQUIRE(n.find_node(s->id())); BOOST_REQUIRE(n.find_node(s2->id())); BOOST_REQUIRE(n.find_node(g2->id())); n.group_free_deep(g); BOOST_REQUIRE(!n.find_node(s->id())); BOOST_REQUIRE(!n.find_node(s2->id())); BOOST_REQUIRE(n.find_node(g2->id())); BOOST_REQUIRE_EQUAL(n.synth_count(), 0u); BOOST_REQUIRE_EQUAL(n.group_count(), 3u); BOOST_REQUIRE(n.find_node(g2->id())); BOOST_REQUIRE(n.find_node(g->id())); n.remove_node(g); BOOST_REQUIRE(!n.find_node(g->id())); BOOST_REQUIRE(!n.find_node(g2->id())); BOOST_REQUIRE_EQUAL(n.group_count(), 1u); } BOOST_AUTO_TEST_CASE( queue_construction_test_1 ) { node_graph n; test_synth * s = new test_synth(1000, 0); test_synth * s2 = new test_synth(1001, 0); n.add_node(s); n.add_node(s2); unique_ptr q = n.generate_dsp_queue(); n.remove_node(s); n.remove_node(s2); } BOOST_AUTO_TEST_CASE( queue_construction_test_2 ) { node_graph n; group * g = new group(1); n.add_node(g); unique_ptr q = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q->total_node_count(), 0u); n.remove_node(g); } BOOST_AUTO_TEST_CASE( queue_construction_test_3 ) { node_graph n; test_synth * s = new test_synth(1000, 0); n.add_node(s); unique_ptr q1 = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q1->total_node_count(), 1u); test_synth * s2 = new test_synth(3, 0); n.add_node(s2); unique_ptr q2 = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q2->total_node_count(), 1u); n.remove_node(s); n.remove_node(s2); } BOOST_AUTO_TEST_CASE( pgroup_test_1 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); BOOST_REQUIRE_EQUAL(n.find_group(1), g); unique_ptr q = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q->total_node_count(), 0u); n.remove_node(g); } BOOST_AUTO_TEST_CASE( pgroup_test_2 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); { node_position_constraint to_group = std::make_pair(g, insert); test_synth * s = new test_synth(2, 0); n.add_node(s, to_group); n.remove_node(s); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( pgroup_test_3 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); test_synth * s = new test_synth(2, 0); { node_position_constraint to_group = std::make_pair(g, insert); n.add_node(s, to_group); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( pgroup_test_4 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); { node_position_constraint to_group = std::make_pair(g, insert); test_synth * s = new test_synth(2, 0); n.add_node(s, to_group); unique_ptr q = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q->total_node_count(), 1u); n.remove_node(s); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( pgroup_test_5 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); { node_position_constraint to_group = std::make_pair(g, insert); test_synth * s1 = new test_synth(2, 0); test_synth * s2 = new test_synth(3, 0); n.add_node(s1, to_group); n.add_node(s2, to_group); unique_ptr q = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q->total_node_count(), 2u); n.remove_node(s1); n.remove_node(s2); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( pgroup_test_6 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); { node_position_constraint to_group = std::make_pair(g, insert); test_synth * s1 = new test_synth(2, 0); test_synth * s2 = new test_synth(3, 0); test_synth * s3 = new test_synth(4, 0); n.add_node(s1, to_group); n.add_node(s2, to_group); n.add_node(s3, to_group); unique_ptr q = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q->total_node_count(), 3u); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( pgroup_test_7 ) { node_graph n; parallel_group * g = new parallel_group(1); n.add_node(g); { node_position_constraint to_group = std::make_pair(g, insert); group * g1 = new group(2); group * g2 = new group(3); group * g3 = new group(4); n.add_node(g1, to_group); n.add_node(g2, to_group); n.add_node(g3, to_group); node_position_constraint to_g1 = std::make_pair(g1, insert); node_position_constraint to_g2 = std::make_pair(g2, insert); test_synth * s1 = new test_synth(1000, 0); test_synth * s2 = new test_synth(1001, 0); n.add_node(s1, to_g1); n.add_node(s2, to_g2); unique_ptr q = n.generate_dsp_queue(); BOOST_REQUIRE_EQUAL(q->total_node_count(), 2u); } n.remove_node(g); } BOOST_AUTO_TEST_CASE( noid_test ) { rt_pool.init(1024 * 1024); node_graph n; node_position_constraint to_root = std::make_pair(n.root_group(), insert); { test_synth * s = new test_synth(1000, 0); n.add_node(s, to_root); BOOST_REQUIRE(s->id() == 1000 ); n.synth_reassign_id(1000); BOOST_REQUIRE(s->id() != 1000 ); n.remove_node(s); } { test_synth * s = new test_synth(1000, 0); n.add_node(s/* , node_position_constraint() */); BOOST_REQUIRE(s->id() == 1000 ); n.synth_reassign_id(1000); BOOST_REQUIRE(s->id() != 1000 ); n.remove_node(s); } } SuperCollider-Source/testsuite/supernova/server_sc_osc_handler_test.cpp000644 000765 000024 00000001001 12321461511 030013 0ustar00crucialstaff000000 000000 #include #include #include "../../source/server/sc_osc_handler.hpp" using namespace nova; BOOST_AUTO_TEST_CASE( sc_osc_handler_1 ) { const_cast(server_arguments::initialize(0, 0)).udp_port = 54321; sc_osc_handler handler(server_arguments::instance()); } BOOST_AUTO_TEST_CASE( sc_osc_handler_2 ) { const_cast(server_arguments::initialize(0, 0)).tcp_port = 54321; sc_osc_handler handler(server_arguments::instance()); } SuperCollider-Source/testsuite/supernova/server_scheduler_test.cpp000644 000765 000024 00000001112 12321461511 027026 0ustar00crucialstaff000000 000000 #include #include #include #include "server/server_scheduler.hpp" using namespace nova; using namespace boost; BOOST_AUTO_TEST_CASE( scheduler_test_1 ) { scheduler<> sched(1); /* sched(); */ } namespace { boost::barrier barr(2); void thread_fn(scheduler<> * sched) { for (int i = 0; i != 1000; ++i) /* (*sched)() */; barr.wait(); } } BOOST_AUTO_TEST_CASE( scheduler_test_2 ) { scheduler<> sched(1); std::thread thrd(std::bind(thread_fn, &sched)); barr.wait(); thrd.join(); } SuperCollider-Source/testsuite/supernova/server_synth_factory_test.cpp000644 000765 000024 00000001224 12321461511 027750 0ustar00crucialstaff000000 000000 #include #include "server/synth_factory.hpp" #include "test_synth.hpp" using namespace nova; using namespace std; namespace { struct test_synth_definition: public synth_definition { test_synth_definition(): synth_definition(symbol("foo")) {} abstract_synth * create_instance(int node_id) { return new test_synth(node_id, this); } }; } BOOST_AUTO_TEST_CASE( synth_factory_test_1 ) { rt_pool.init(1<<20); synth_factory sf; sf.register_definition(new test_synth_definition); unique_ptr s(sf.create_instance("foo", 1)); BOOST_REQUIRE(s.get() != 0); } SuperCollider-Source/testsuite/supernova/server_test.cpp000644 000765 000024 00000004107 12321461511 024777 0ustar00crucialstaff000000 000000 #include #include "server/server.hpp" #include "server/server_args.hpp" #include "test_synth.hpp" using namespace nova; using namespace boost; namespace { struct test_synth_definition: public synth_definition { test_synth_definition(void): synth_definition(symbol("foo")) {} abstract_synth * create_instance(int node_id) { return new test_synth(node_id, this); } }; } BOOST_AUTO_TEST_CASE( server_test_1 ) { rt_pool.init(1024 * 1024); { nova_server server(server_arguments::initialize(0, 0)); rt_pool.init(1024*1024); server.synth_factory::register_definition(new test_synth_definition()); node_position_constraint to_root = std::make_pair(server.root_group(), insert); abstract_synth * s = server.add_synth("foo", 1, to_root); server.free_node(s); } instance = 0; } BOOST_AUTO_TEST_CASE( server_test_2 ) { { nova_server server(server_arguments::initialize(0, 0)); server.synth_factory::register_definition(new test_synth_definition()); node_position_constraint to_root = std::make_pair(server.root_group(), insert); abstract_synth * s = server.add_synth("foo", 1, to_root); server.tick(); server.tick(); server.tick(); server.free_node(s); } instance = 0; } BOOST_AUTO_TEST_CASE( server_test_3 ) { { nova_server server(server_arguments::initialize(0, 0)); server.synth_factory::register_definition(new test_synth_definition()); parallel_group * g = new parallel_group(1); server.add_node(g); node_position_constraint to_group = std::make_pair(g, insert); abstract_synth * s1 = server.add_synth("foo", 2, to_group); abstract_synth * s2 = server.add_synth("foo", 3, to_group); abstract_synth * s3 = server.add_synth("foo", 4, to_group); server.tick(); server.tick(); server.tick(); server.free_node(s1); server.free_node(s2); server.free_node(s3); } instance = 0; } SuperCollider-Source/testsuite/supernova/simple_pool_test.cpp000644 000765 000024 00000001413 12756531745 026033 0ustar00crucialstaff000000 000000 #include #include #include "utilities/simple_pool.hpp" using namespace nova; using namespace std; namespace { struct foo { foo(void) {} int data[4]; }; void run_simple_test(bool locked) { simple_pool<> pool(16*1024, locked); foo* f1 = static_cast(pool.malloc(sizeof(foo))); ::new(f1) foo(); f1->~foo(); pool.free(f1); } void run_simple_test_2(bool locked) { simple_pool<> pool; pool.init(16*1024, locked); foo* f1 = static_cast(pool.malloc(sizeof(foo))); ::new(f1) foo(); f1->~foo(); pool.free(f1); } } BOOST_AUTO_TEST_CASE( simple_pool_tests ) { run_simple_test(false); run_simple_test(true); run_simple_test_2(false); run_simple_test_2(true); } SuperCollider-Source/testsuite/supernova/sized_array_test.cpp000644 000765 000024 00000006534 12321461511 026013 0ustar00crucialstaff000000 000000 #include "utilities/sized_array.hpp" #include "server/memory_pool.hpp" #include #include namespace nova { simple_pool rt_pool; } /* namespace nova */ using namespace nova; #ifdef BOOST_HAS_RVALUE_REFS using std::move; #else using boost::move; #endif BOOST_AUTO_TEST_CASE( sized_array_test_1 ) { sized_array array(5); array[0] = -1; array[1] = 3; array[4] = 44; BOOST_REQUIRE_EQUAL( array.size(), 5u ); BOOST_REQUIRE_EQUAL( array[1], 3 ); BOOST_REQUIRE_EQUAL( array[0], -1 ); BOOST_REQUIRE_EQUAL( *array.begin(), -1 ); BOOST_REQUIRE_EQUAL( array.front(), -1 ); BOOST_REQUIRE_EQUAL( array.back(), 44 ); BOOST_REQUIRE_EQUAL( *array.rbegin(), 44 ); BOOST_REQUIRE_EQUAL( *(array.rend()-1), -1 ); sized_array long_array(array); BOOST_REQUIRE_EQUAL( long_array.size(), 5u ); BOOST_REQUIRE_EQUAL( long_array[1], 3 ); BOOST_REQUIRE_EQUAL( long_array[0], -1 ); // move assignment sized_array array3(0); move(&array, &array+1, &array3); BOOST_REQUIRE_EQUAL( array3.size(), 5u ); BOOST_REQUIRE_EQUAL( array3[1], 3 ); BOOST_REQUIRE_EQUAL( array3[0], -1 ); BOOST_REQUIRE_EQUAL( array.size(), 0u ); // move assignment sized_array array4(move(array3)); BOOST_REQUIRE_EQUAL( array4.size(), 5u ); BOOST_REQUIRE_EQUAL( array4[1], 3 ); BOOST_REQUIRE_EQUAL( array4[0], -1 ); BOOST_REQUIRE_EQUAL( array3.size(), 0u ); } template void run_test_2(void) { int size = 1024; std::vector::other> vec; for (int i = 0; i != size; ++i) vec.push_back(-i); sized_array::other> array(vec); for (int i = 0; i != size; ++i) BOOST_REQUIRE_EQUAL( vec[i], array[i] ); } BOOST_AUTO_TEST_CASE( sized_array_test_2 ) { rt_pool.init(1024*1024); run_test_2, std::allocator >(); run_test_2, std::allocator >(); run_test_2, rt_pool_allocator >(); run_test_2, rt_pool_allocator >(); } BOOST_AUTO_TEST_CASE( sized_array_test_3 ) { sized_array array(5); array[0] = -1; array[1] = 3; array[4] = 44; BOOST_REQUIRE_EQUAL( array.size(), 5u ); BOOST_REQUIRE_EQUAL( array[0], -1 ); BOOST_REQUIRE_EQUAL( array[1], 3 ); BOOST_REQUIRE_EQUAL( *array.begin(), -1 ); array.resize(6, 444); BOOST_REQUIRE_EQUAL( array.size(), 6u ); BOOST_REQUIRE_EQUAL( array[0], -1 ); BOOST_REQUIRE_EQUAL( array[1], 3 ); BOOST_REQUIRE_EQUAL( array[5], 444 ); array.resize(2); BOOST_REQUIRE_EQUAL( array.size(), 2u ); BOOST_REQUIRE_EQUAL( array[0], -1 ); BOOST_REQUIRE_EQUAL( array[1], 3 ); } BOOST_AUTO_TEST_CASE( sized_array_test_4 ) { sized_array array0(int8_t(5)); sized_array array1(uint8_t(5)); sized_array array2(int16_t(5)); sized_array array3(uint16_t(5)); sized_array array4(int32_t(5)); sized_array array5(uint32_t(5)); sized_array array6(int64_t(5)); sized_array array7(uint64_t(5)); sized_array array8(size_t(5)); sized_array array9(short(5)); sized_array array10(int(5)); sized_array array11(long(5)); } SuperCollider-Source/testsuite/supernova/sndfile_backend_test.cpp000644 000765 000024 00000002003 12756531745 026600 0ustar00crucialstaff000000 000000 #include #include #include #include "audio_backend/sndfile_backend.hpp" using namespace nova; namespace { aligned_storage_ptr data(nova::calloc_aligned(64)); struct engine_functor; struct engine_functor { void init_tick(void) {} void run_tick(void); }; sndfile_backend be; void engine_functor::run_tick(void) { float * data_ptr = data.get(); be.output_mapping(&data_ptr, &data_ptr + 1); } } BOOST_AUTO_TEST_CASE( sndfile_backend_test_1 ) { BOOST_REQUIRE(!be.audio_is_opened()); BOOST_REQUIRE(!be.audio_is_active()); be.open_client("", "./output.wav", 44100, SF_FORMAT_WAV | SF_FORMAT_PCM_16, 1, 64); BOOST_REQUIRE(be.audio_is_opened()); be.activate_audio(); BOOST_REQUIRE(be.audio_is_active()); std::this_thread::sleep_for( std::chrono::seconds (1) ); be.deactivate_audio(); BOOST_REQUIRE(!be.audio_is_active()); be.close_client(); BOOST_REQUIRE(!be.audio_is_opened()); } SuperCollider-Source/testsuite/supernova/static_allocator_test.cpp000644 000765 000024 00000004003 12321461511 027013 0ustar00crucialstaff000000 000000 #include #include #include #include #include #include "utilities/static_allocator.hpp" using namespace nova; using namespace std; namespace { template void test_pool_instatiation(void) { static_allocator alloc; } struct initialized_struct { initialized_struct(int i): i(i), f(0.2) {} bool operator<(initialized_struct const & rhs) const { return i < rhs.i; } int i; double f; }; template void test_list(void) { list > vec; for (int i = 0; i != 8192; ++i) vec.push_back(T(i)); } template void test_vector(void) { vector > vec; for (int i = 0; i != 8192; ++i) vec.push_back(T(i)); } template void test_set(void) { set, static_allocator > set; for (int i = 0; i != 8192; ++i) set.insert(T(i)); } } BOOST_AUTO_TEST_CASE( static_alloc_test_1 ) { test_pool_instatiation<16, false>(); test_pool_instatiation<128, false>(); test_pool_instatiation<1024, false>(); test_pool_instatiation<4096, false>(); test_pool_instatiation<16, true>(); test_pool_instatiation<128, true>(); test_pool_instatiation<1024, true>(); test_pool_instatiation<4096, true>(); } #if 0 BOOST_AUTO_TEST_CASE( static_alloc_test_2 ) { test_list(); test_list(); test_list(); test_list(); } #endif BOOST_AUTO_TEST_CASE( static_alloc_test_3 ) { test_vector(); test_vector(); test_vector(); test_vector(); } #if 0 BOOST_AUTO_TEST_CASE( static_alloc_test_4 ) { test_set(); test_set(); test_set(); test_set(); } #endif SuperCollider-Source/testsuite/supernova/static_pool_test.cpp000644 000765 000024 00000001137 12756531745 026034 0ustar00crucialstaff000000 000000 #include #include #include "utilities/static_pool.hpp" using namespace nova; using namespace std; namespace { struct foo { foo(void) {} int data[4]; }; } BOOST_AUTO_TEST_CASE( static_pool_test ) { static_pool<16*1024> pool; foo* f1 = static_cast(pool.malloc(sizeof(foo))); ::new(f1) foo(); f1->~foo(); pool.free(f1); } BOOST_AUTO_TEST_CASE( static_pool_test_locked ) { static_pool<16*1024> pool(true); foo* f1 = static_cast(pool.malloc(sizeof(foo))); ::new(f1) foo(); f1->~foo(); pool.free(f1); } SuperCollider-Source/testsuite/supernova/test_synth.hpp000644 000765 000024 00000000777 12321461511 024654 0ustar00crucialstaff000000 000000 #include "../server/supernova/server/synth.hpp" namespace nova { class test_synth: public abstract_synth { public: test_synth(int node_id, synth_definition_ptr const & prototype): abstract_synth(node_id, prototype) {} void run(void) {} virtual float get(slot_index_t slot_id) const { return 0.f; } virtual void set(slot_index_t slot_id, sample val) {} virtual void set_control_array(slot_index_t slot_id, size_t count, sample * val) {} }; } SuperCollider-Source/testsuite/supernova/timetag_test.cpp000644 000765 000024 00000002673 12321461511 025131 0ustar00crucialstaff000000 000000 #include #include "utilities/time_tag.hpp" #include "boost/date_time/posix_time/posix_time.hpp" using namespace nova; using namespace boost; BOOST_AUTO_TEST_CASE( time_tag_test_1 ) { { time_tag tt; BOOST_REQUIRE_EQUAL(tt.get_secs(), 0u); BOOST_REQUIRE_EQUAL(tt.get_fraction(), 0u); } { time_tag tt(100, 200); BOOST_REQUIRE_EQUAL(tt.get_secs(), 100u); BOOST_REQUIRE_EQUAL(tt.get_fraction(), 200u); } { time_tag t1(0, 0); time_tag t2(0, 1); time_tag t3(0, 1); BOOST_REQUIRE(t1 < t2); BOOST_REQUIRE(t1 != t2); BOOST_REQUIRE(t2 == t3); } { time_tag t1(0, 0); time_tag t2(1, 0); time_tag t3 = t1 + t2; BOOST_REQUIRE(t2 == t3); t3 += t2; BOOST_REQUIRE(t3 == time_tag(2, 0)); } } BOOST_AUTO_TEST_CASE( time_tag_test_2 ) { using namespace boost::posix_time; time_tag first = time_tag::from_ptime(ptime(microsec_clock::universal_time())); time_tag next = time_tag::from_ptime(ptime(microsec_clock::universal_time())); BOOST_REQUIRE(first <= next); } BOOST_AUTO_TEST_CASE( time_tag_test_3 ) { using namespace boost::posix_time; time_tag now = time_tag::from_ptime(ptime(microsec_clock::universal_time())); ptime pnow = now.to_ptime(); /* std::cout << now.get_secs() << std::endl; */ /* std::cout << pnow << std::endl; */ } SuperCollider-Source/testsuite/supernova/tl_allocator_test.cpp000644 000765 000024 00000002412 12321461511 026145 0ustar00crucialstaff000000 000000 #include #include #include #include #include #include "utilities/tl_allocator.hpp" using namespace nova; using namespace std; namespace { struct initialized_struct { initialized_struct(int i): i(i), f(0.2) {} bool operator<(initialized_struct const & rhs) const { return i < rhs.i; } int i; double f; }; template void test_list(void) { list > vec; for (int i = 0; i != 8192; ++i) vec.push_back(T(i)); } template void test_vector(void) { vector > vec; for (int i = 0; i != 8192; ++i) vec.push_back(T(i)); } template void test_set(void) { set, tl_allocator > set; for (int i = 0; i != 8192; ++i) set.insert(T(i)); } } BOOST_AUTO_TEST_CASE( rt_alloc_test_1 ) { detail::tl_allocator<8 * 1024 * 1024> rt_alloc; } BOOST_AUTO_TEST_CASE( rt_alloc_test_2 ) { test_list(); test_list(); } BOOST_AUTO_TEST_CASE( rt_alloc_test_3 ) { test_vector(); test_vector(); } BOOST_AUTO_TEST_CASE( rt_alloc_test_4 ) { test_set(); test_set(); } SuperCollider-Source/testsuite/sclang/CMakeLists.txt000644 000765 000024 00000000367 12321461511 023717 0ustar00crucialstaff000000 000000 set(SCLANG ${CMAKE_CURRENT_BINARY_DIR}/../../lang/sclang${CMAKE_EXECUTABLE_SUFFIX} -l ${CMAKE_CURRENT_BINARY_DIR}/../../build_sclang.cfg) file(GLOB tests *.scd) foreach(test ${tests}) add_test(${test}_run ${SCLANG} ${test}) endforeach() SuperCollider-Source/testsuite/sclang/launch_test.py000755 000765 000024 00000004160 12524671173 024054 0ustar00crucialstaff000000 000000 #!/usr/bin/env python import fcntl import sys import os.path import subprocess import time import select # A quick-and-dirty launch test of sclang. This is temporary, but does the job for now. def non_block_read(output): fd = output.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) try: return output.readline() except: return "" def sc_output_print(output): sys.stdout.write("\t| " + output) def sc_input(proc, input): print "\t|" + ("_" * 60) print "-> " + input print "\t_" + ("_" * 60) proc.stdin.write(input + (" %s" % chr(0x1b))) timeout = 30 sclang_path = sys.argv[1] assert os.path.exists(sclang_path) env = dict(os.environ) # linux build machine is headless, so we need to use xvfb so Qt doesn't barf. if sys.platform == 'linux2': env['QT_PLATFORM_PLUGIN'] = 'offscreen' env['DISPLAY'] = ':99.0' subprocess.Popen('sh -e /etc/init.d/xvfb start', shell=True, env=env) subprocess.Popen("/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16", shell=True, env=env) proc = subprocess.Popen([sclang_path, '-i' 'python'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, env=env) launched_string = "*** Welcome to SuperCollider" start_time = time.time() output = "" while not(launched_string in output): if time.time() > (start_time + timeout): sys.exit("Timed out.") output = non_block_read(proc.stdout) error = non_block_read(proc.stderr) if error: print "ERROR:\n" + error sys.exit(error) elif output: sc_output_print(output) time.sleep(0.1) # Quit sclang sc_input(proc, "0.exit") # Watch for a clean quit output = "" start_time = time.time() while proc.poll() and time.time() < (start_time + timeout): if time.time() > (start_time + timeout): sys.exit("Timed out.") output = non_block_read(proc.stdout) error = non_block_read(proc.stderr) if error: # read the rest of the error print "ERROR:\n" + error sys.exit(error) elif output: sc_output_print(output) time.sleep(0.1) sys.exit(0)SuperCollider-Source/testsuite/sclang/sclang_crash_1.scd000644 000765 000024 00000000135 12321461511 024512 0ustar00crucialstaff000000 000000 x = { 1+1 }.def; x.instVarSize.do { |i| i.debug("index"); x.instVarAt(i).postln }; 0.exit; SuperCollider-Source/testsuite/sclang/sclang_crash_2.scd000644 000765 000024 00000000042 12321461511 024510 0ustar00crucialstaff000000 000000 { 1+1 }.def.instVarAt(1); 0.exit; SuperCollider-Source/testsuite/sclang/sclang_crash_3.scd000644 000765 000024 00000000157 12321461511 024520 0ustar00crucialstaff000000 000000 ~f = {|i| if (i == 0) { Exception("test").throw } { ~f.(i-1) }; }; try { ~f.(100000) } { }; 0.exit; SuperCollider-Source/testsuite/sclang/sclang_crash_deprecated.scd000644 000765 000024 00000000045 12321461511 026452 0ustar00crucialstaff000000 000000 b = { nil.deprecated}; b.(); 0.exit; SuperCollider-Source/sounds/a11wlk01-44_1.aiff000644 000765 000024 00000644116 12321461511 021735 0ustar00crucialstaff000000 000000 FORMH.AIFFCOMM@DSSNDH `Eha^F^ a3met/|8n5([u ^>s?]I _/ /u % D}gS/*<#KOa T -;8y cQ x % c  c C D  ) t sG#pO: Y9oB9fJj,&^>6C"iY]^K/qc//p/ OMnO80RHW=O4-/tO9nAS^IQP LpYgt c  0 T r x T !  T   y |ry.qf  D y ` T 8 c 5 1 M c C2%o@,KJ/\Zq>/b$\zffen&^ZOB 9wDgB;i;wNs{l.9zAe!CIX)}eET'A ^OrAjHSTQ z/^W #1 G/_o p0~y&F & ^xOgi]!*G/0OOnh/Hs  }~d F T w c j E D z3 % L T [ c  D XTEcAic  ) c+F, YaGqO0!80 J]K_NLz]>oDy1MXUD>X9D9HnwXn`Bc kt^7YOnnTQO//gFOl n Y/ /O"/=/1*m_2a[. .Es2tA/`k@Tn/K\| 3>I^\Mh3>[)gywgb9Dz ^8cO/^z^8#/n2O!!$1k7/Nv^0.D^t^ rrm^^  Bo c ( % s Tx$iaf<azBmwyZ  c T   %  D  D B E ckvS%[WC8cJXks p T  8 D ! 1 cc<i.[/E^]XgoDVn&@ _Hs?[QO& ^Z'5/ vS/R'6k)B/gOd$O$>gilG c c, T 9=BG,{ f T !6k;rBq2-z&tN/IHGnn nCn"F^~OO%?g</ r^ $}^W,Q37{or,b T 3 U D   ce!Xd2 5OFOE~gFgZ79|W7nE-(:nM?ao8djc)LLO/O]A@/(n3`^-RO/^|n^OOFnP^tn2&y@UFKQaNCs  D I K P D  c  c c # ( T E ( % F ^ N[5qpToW{*FYOd T'K %g\`\JOJ:C&#6/n)/WnJ<%@",A3}P) $gcw+Xg)| #vgn{weR"vX^ncn/9I)~'Z^$Lc/`ttnuxQ\<{e Rr#?p9if#[g[DS/Cs sj;\.Im ]/Ogls]%0e,XAAo^yxO%@btL A/N|ymO" cP/MWany :/MV+ )!Q'^ Jy{/%Y {>{)3!)Y{H]-  T R  % ~';/ : 8 D v c c o t c :sE5Gss,^0b osvr<&OOliIM|6 8^8FoK^./?O-nvhn./T%9J:aXJ=}UZ0 6 c B b T % c @ 8 I c p Ts"Ks  6 c - D D D } A)No!+" D 4 ks 6=$ JR/O&!5OU2^pIn2q^3YveL+iOpQ^}XZ 9rw?<ffX<>,-jY)k9+X?@ 9*I= 9]wCHG}\wjBS ? g D D  ^sMcX WOO`/s M`O p9z<Ui.m&vs,&GXEI;2i/5RAVn9ws$~.n;L3D ^iQsj`, +#^Z<{9iTXC9BVeb <| h~#L8qos!cEFO D p A&Z3W#R~$7p T(4O+RbF@n4:Q/^B (nEv0/]of-> \wO^ln!O` Sn-z :[R /0/OpR^y^3^Q/ |aCge/3i y4gUbqs   %-1 r1 _ 7 T s [ c T \ % 8Q  D "s/s 2 D }j` %  sNC^L4_+b9: zO/KFO>8Q5$sX0,) %gOS_wr9o919XX- )MA,)Abg)g{gO"9hw{2 `n,Q^V2nE 1sU^8FXj Ghn(#b=)ssM9Fs 1 c D  % [ D < ~sV+y8>WC0e/mHJo/,9C >eO ^=e)X)I/3' #Ozj 2/< 9n^G9,,)Os'G^% ;$W  c l >snN2F c  i  T  } c X <s)Kss s \ q c Y q T   mJ)Q 6Js a D Oq5B2s $  T x T 0OOk@ Yk[j_O<LAn OOn^ X>lnKAC/GU sRr^%@O5a9X'&b߬2r6QܰE#Qg:99Z8Hn"7 : T TX, % ?KO/VHbQTyK n":$P&(*8+j,",{,,v,"+*{)'p%$##$$%W%%N$#"!!e! !?!"c""!c;jX;Xe89|Bx_ؚqۑ۷ڷؐjїɊdÔƖz`ؐE؆֗ͶșKș+Bq ~mQ֯Dع 2ht?XX0p/)8"`.' mO(A/6~nOs 5* : c Frds nzI 8 + 1L S # Tf/0+ !Z"-::^KIwbv'"^+O2UD%] (ZOztV\s+/ (s c Q : TlUs o%~ T L@F_ T 0 D &c1 q_1X T :  sXy^ _ E | scbQZz c   c* o" cd?%^-o  j:K{X/O nh^9zn~/Y]%9n\Z])n>.CrOc.)@I)n-[zqQ A7mnfRn^kyv2 B?W+C =0gl$ C % s}lm  M % I. T  Y V caZ w z % Z jHd\ D  % n+ A: c uI6^dz&n 8d4,+gX#_ 1n'S+C-^3zlZ9-J:/9?b#Dn4+!/FBPTfpO\5/aIO/Qg:OhOyF8@U^[' 6]nC^@x.=(/InhfHO4Wt)P?+O77An0tbxl9?lL^g9-)n6^G?L9OtbI\^6/bMiN?J!_"/dWnJ4^]\HBnh 0H3I(/^LQV.//J"  % s w I N )s p J %  rW Q T W TniQ aV V D  c4 c d D TU4/se|aOhN~O;* 8=rl} ^ 8< 5sO/Jy> -52^$ clbuc  c , T+Xa w _J  sCRws * % w x~A/JP]n/! c  {* M c t T)(rW[ $ D K]?/n]PN2~&9E/a()Q9N$,E/1OX\D/e6-zU^[FKXX)gj4X{$pXBM:gSw=@8O[aKi%)  ^dRgzXs yScnr@kT_b11 ?A^L^"nF^O0_ R/ .y N T Q >D>OLWOOU4n).bo on0Q]^^X Z@\7* kx 3v } DJ^ `nDTor  !/Z^BIDP6O?j^ b%* c HV%   c i cjPi Rs lAg 5 D p2W^o _ c;@2xs 'e % )HJ%_d~X c< VOy;OD6$^"//#U1 ^ [5^pXMOZMz#Yn&|/nDrJO5uDV>W/.  D O s[6~ S % W] T ) L T;: < T U4C oOisNZ MP E-`kgt'O{O3a&jW7L9H{x0nqBZ)y|V:/T=t#X'GCfn;BuXwX it9| &Xb(NclDgwZn{)/A/=,EkfnO eRnkn7 _n ~U6CR ]/PsfZ^k/ OY^_0-bn'O^U|O1I {\^N'n^%  ' ch8OuTO!/"/%@,,>4/nS/3knvli6\BR7#; ^% 7 % [ TAa2 m FNM]L TO ) % Bhrs w D t 6 < ] D / sE/d TwI }s ]-^|oY/orS /fwts*;nAmD/Gnw(n^PDnj Tj^,0T4ajnH7OrnqaL>N Wg/'rs k 1sYi +' s * T #4Ojz [ /sL/? qs "sob/Wsjc nm4nkOJ)tw^ P=7&/MO*Cv}W^!^C(V_-){/O"[bR) 4nO m]T?//NY tiO292 0al) ?,( TnoH/9%] A H U D 8  T/9bsfn;{n@>^ "O!/Htp8/$"X/t r;X[n;wlFOa_.^Ui[jB D6Y/-=NnO%'Fe@/=-[uts!z *2 T i % x ?Q; $  % L n s RH D [x+ > $ Dj%0. X  %  <qn1T y\I )npzKnR9OX.s6j +/ /+~ c - ~ ns15=zm o D t-js s [sP/d2OqN=n6W ,=^~D+R/5L|3z^P"")8k9a3.*9?,/:(4ng"V/3QjxeO0_+8^[OnlrEx^%/^OR tXn[xz/omv/ }g|AKObyV2O)5 ns h ;'aPs > . sw&= T ; TUR2x -6#(0jW/r(!t`UBsn\~ ;RK 1/Bwe(3b 0&@@$Na n46`/bM f/2 /l:/#dyOBINs W$S@ c L < ( D g]b f T  T T r % |6o, c  c^C ObPgnq*%96BQF^t"3n"'_ v !?OO|| 'U^ OO+SZ s0[/ c lS(sgPx c D [f!%#sw Y D 3HI- i0 D cebBy:s) /338/l{!*"?nC]>xc 9VWc^sQKA^ni)ZX[ ^wB+m$)w9O6P,^oeW/$ k^x/IW/Wa/^ Xb/9W^?@0%n0on%`Y/nnBo2 X s T{frS Y % + cCY] ^ es]NS\Ovw N]a"d~^ ,C(8= 9IO`T^$ *Fn~ Mlpfl]^m=p^ X--v^qi Z.\V(Ol JO@ T<k kUf T g*K.%/w| T8 WrQ T l Tka c n ) j cD6^}5 T N TU3MPH*saQ;^. s/_q^PAn[^ bdnnrH,RqOVYC^r^9da6DL/hg}On^6mo#@J6O SF  cH=m 'LO{# Q cE6 UV<' c ` "i %p O c'clDOAOD~}W^TXbT9^.x^n^B^#)O~(Dr]#zQ` n/! 1pe(JKt/7bT&O @,^f\0 L9p'% .?&^Y  /"Od g?v[y'gJV`o ^4q c KI] 7/\"YJsyQuOFV:)Oq^=H]J/Dn#*g kc AL;no5Y ^O PnuGr<K^lq %pn&$^7="8OG1bfs : sm-I^  c:4/Vy/ D c7( I T ~##| /C sp TC= c J .OHj&</'KW^cx\rHn& ,%^4}^WT t6`^u'U ] nn|ts/+n!/ GG2 Oe Q c(dTUVn c q T^ @ 7s T sJ8h < 0 D l5/s !v3 /h^5AnO8nmO`Lw_BvOO)Z2)WLB6 L9t5Owz"c)MJv/^-F: *&/FIdn)[nI)xN>< N^#fO0$nen32 \n[D/?O9AnT'?>$^B%ljyUOO*n\c j]n^^[,RViH.^R"/c fv#~ 6$WhOEHn?f dyn6H/;:)>)!7CM^OO-$/= @ k1 l * T xc  D c?[rgK  4 % d -i T  T1 90: C D # iV lYus 8  cMN y@^BO0g]/'O+>nW kg/3 W5R/5OO^np% %ncR/c|gnwnIosx]OOW o sn/f:&*W{ k pzO'9m_ 6:5^0 hf& 'HJzcP/{YU JTg^yB OrEA :; [u ; , T c._ c A cd3  % Ns) D 5:. % \ )^dOd9O W C Ts ` ; c%TO/b/s O;FPnLO,lk8&^rv5/z@~1n28b9D\^(=P&j vkK/J^o^r Od sKG rO5O c ik =T n7&K/ kasGDjh/Xn/th$/e^5/6"OSD"TnXn7X{) bvWQ )YX]{r^w09n7 nsn&w=;^4H?^^%OPHZwZd/^3;H/vAe%^PC JtPJJY Nn 6Zwn.^)^lM`k G^$1E9,=O/"dy8%(^}n=O;/5HJOQPpncjT }! mnm Bn7|aT:7.O_^} c G/~Qds o z h T`% Ok) c Yw)Ons>  fO9X ^+~~/` ;n(B_/:3B[n')P~g7HaF[sX9ZF^}r]#}/c/^VcI"\ 7 mLGO~OCg:8H|O:f< ^m+ c {\ O6qdY+nt/|/ o?/#L ( T |vN D  % a ~ Pjnn ]J*}hTV'O+ ~/q\lXJO$nEPP/^+,[3^d5n'7t%z~MO%2'iaXWXj*Iwb q[$ m2;O9 d>n/O(sLW'), c _K';2  D > j % r ilgsu6Fp8x.eIT c u c % c O{Q E D j D VF % GM:}jw|GB12[k.WXl0g4sn~' B D s[ Q E? ' cgvEO;G~OM nrggwKX`XX;a]DAL^9,7 T S5y:E \n;QyX ; y^ : Fs: h T  0sO):g2j i?wj _aXwunybae)pxH/42rwz1T;'  6 | u Q T g T g c3=O-0pHO qA7 u8 " h 2Jn<)n;M99N8nBV Jn/$- | ; %  E c/s = Y  mB /^q$7w#Mb/z/h?|!n:\^j3c [ T *ZB/03OncIyO^'#A|n9>KkXfX'.U%X!YRxPe T  m c T }#%2f D f jes Tboqn\_ pN:g p)YlOHGu 7/K]% t %oAP % D 4 R T0SLnRXnO$9w.X M_$S9!]Bn` EXPg+,!gXLW])eGX|9hbO nhk{/I8/'^l/57SdO?%^8NZ&/W!teP1/61#NOPOa9D/n_/}T[^^VLs ^> I /6zOt`AYA/H]P^D/b$OnSmyON ApqQ);X*S>{g(X4;%ZQ)xmOlOZ[r/1%O+HO{A SD `{ &  T H  T 4 sy7 uW~BpTRQ/&C^_ + Od5eq ^nVt^-^Z7;mz^YD/L`^o9,1^n070Fn9^^$d|nQDO8%-OxOx^kOE/yz/>OOK/emT//>?6/=l $ >yD  %ZEQ8L aE\S~dc{ss^arsG@TpsrK3jeKah) S/:, S+/I\T//q/O?LYO/OL/VRtK^EIgTV P /hH)g  \_U$y h1/onYSqS@ `w[]s ) c c.7^S#/q OK5^3OSNKOUYVOIHLOJ@;O//On-nI_^gOR/ty/3O-Ogl`OA?EOTTPOQVWO<++O/ YR>1rIGEw?yssz=u}#bVe#sgrt /2O/Ocf[OJNTO3^ nVNVnn K?^vr[11qt7tyZaUsEE8-jJz1pwBW OM~!!^ /NPK_2[U`3 =/p " M17)@~)5$Cf: B  Bp m/cOi^T1nKt|m.**n~naZ]n^^* ^ BO:O;/ipU//@E>/!/T p!&!o |[ew Gvh-shx2C'8sP Xl  gq[*lKP.c2nj.d-YaBMg2UP /NO]nq5cuC 8 nnSFNn'^|^7nzQIgp3&Nn\O^/w J[K X04fnJ( rXr/'k0/H +w.4H'd  10$ 5lMbJJ /MOXn|6-9nI1vI0'k7j@^z^D#n]`eJ[TmF'J*))/O`8^$GX$/dcy D>nY+H T  c$On^w/%B!&T{ h5]8 ='NROIgY2_5^n@n 7/)2 %7 ^(CyV 4"W$nAO /Of^V4n6]J^iD/VaW/=b^Y}_5D,Q n.O6@A [#4!e&*_B3cA*@/^ c D S $ T s c c g h c U 1s G0ojR^~&)f?)\{1 nTn^fh< C c E ,Q"/0X^A/ $! $() /4^;"@{nDO/\q^JMnH b a,^)OjvlO*O&/ YEaWeNbs) YYyO\+3~Ht? L"/e K{lj5/2OWn8M^,/zz2;XO@da NO OOV^=ndxq9(Z))gX2gj=rNnP^Dn=2HnnTJUnnSFNn^Oq~sO%n 0nC)p&FmJta[ qu/ !z/d^^j/AIn c F a T + c sRCLs ' T  v % N0:+l % + sHGoCh9da , ?..O3~r Zu9!:)9/BBD.kAO Fdc 7ZOUh/v@w5I5yBu/Y^7\O` "nV QB *wvnR(@ :b$}+ % c ?s 7 T ` T 7 $ % hj =  % V } s %  T X* yn @E&K:51A-?)f%!v" NN`ψǩt}Z"b9Q sa8Ϋ󸢿ƻ͓mEQ[q]XTd  o D wF)!%(+,....f.--,,"++_+.+2+i+,,"+*)N'p%u#" :.Z T*KQfKĝE-)H4?n%3?ǩGհqH;>)^/zwp< R"&7)z,/3I6:{=ACEG^HIJLM%MNCMLKFIFmCi@<\8W4 /*&"6<yP' B!kO< H*Qbցк!BcЖ ӑؐ8" T=70 "'+".259,<>@BDFGIJ/JKEJJ/HGcECAL>;E7g2.%)#A %"ޤؐͭȶ0(aꡇj󐮍RGꋏ/-ۦˮuɊ g:$ m $'),".14h6v7c7 5310..-+)'p$"@ Da94 ;_NKyX' f _ yC>Nbg:c;];#\ "qٻ֯պ>{տ ִׄؐC#(9lKO{T6s   c H --Z0' $'^*A,3-,,"+e++`,",-x-;,"*G'%[" G @ |b, 5pF͠ʈǩ2HH &|N¾Džʘ #B9/ DK $5'p*-036 8S:K<=?N@AB}BBBBA?=;962//+'#} .7 ~ ʌ)4Z}[ZԡM)cգb}Vf$s?@AAA@@>=<;:8W52/+2'@#FH;  c$<֯ӪKɪșǔư ƈtș;̪<6֯cR}C pZ"[%(Y*- .0u1t11140T/@.,*(&#!;ZkT P.X XS$)S4Hy^n 9X-)X%99gKM8M Ywg9shA9J~Mn3.'xX q JyLXZ^h s $K-2ܨ>ؐO6[ԎԇԣY֯9Q!x|XSBO ZvlK "%(2*,.0246v8929:8:998W7r6I420.-8)&"Gzy< 6(ܚؠ0ʠǩ7T#&`Ѵz^ ~-Իt/7}́ЬܿXd tkk8]KKx  D D RbzT = S ck^63U-Dew|"wHX :?iC o9s } & D = @OY_cZ !1"i#$%&'p'({()Q)q)1('p&$#=! Bm&Z D/1rn$2ܙ ؐ׊ֻ#տՆrՃտ-עؐنw`Qeޯ8W ~n6yU 5NWK- "%(F*-z/2457g89:;(;u;l;:89 7531V.,")Q&g#i T! tj4\߀`v֯Y[7Tpd&3Ǟzͬ%ؐIXOUs ! RTY; !!"#t$$%&{'(*A+,. ./0j112^2222"1E01.-+)'p$!q;  ]hK ) {AIؐ- hտ/a֯*ءـfPABW}N LT )Z9R c 3 d!< 4Lr[\|;x ^5X42ۇlR̈zjpa%ħh#=ŨƚǙșɝʯKпҺ5ۙ2:X3.;O^bY D- %;O#B&*A- /135u718:8;Q<*h `VvR،)wX?f:~$ T }KZ "$&"'p(*++.0M246v79:&;(< <====<<:9y7530S-b*A&#Mg;e cT"Mڇ(аVɊkǮǩDzșnu[Qͪ<:иң 2?BT   z; $"%(6*,.0246v8 9_:e;(;<<><;:a86v31.++2($!# 4 T߈cـf'M̾vzlWɊʦu[I7$1vտ ܀#X6nDW T* "',16;??CGGJMPSsUWY5Z2Z[[ZZ.Y WTU RIO;#72.)?$_dK  #p<ʙ È&1̵Ѵ7͸ot>ɊIؐdLXJE^\=  DZ "$4%n&'(*\,".0135 6!67g7777g65420S-*'p$P!'KZ Us~ܐؒAʉșű7Mǩ7ș:)[ͣoӮՁsـۦOEA^< %| u"%/'p)+-/1374|56i7278W8t875312.,")^&P"t, /X` X6OB<& d:ʠɊ\ǩiK^ǩ(ɖz˅K4ԃـ0: ,}"&*.26`9A7CEHNJLYMMMLKJ/HFDnA>:62.2)j$Vv c|7# Г[C9>d]7>g$$G)v^.m͸d<ɯ<`Xn &:rL1s %y&y E-zZx !"L""""""";!i Qvy Da (Kވ\dؐՂzӭ;ՆekؐٽۯQN#^>)Qs  %Ky>  c"%%'p)+-d.0L1}2345616v6A54Q20.,)Q&""Ka sV6R̅zDzǩ=șBbm,EFrԠbTJs ]H\Uy ( ToeN! O>B v %a4yy)T% i 'O?@AAA@?><:8530-)%!M !X xQٗF^҉hԄտـٸ٘-ؐD֯]<ـ3\)BLN To;$ #W%'3''d%"I s3w nE'3t"%ċΧ.tv9 @;#'+2.146v776531/.+)y&# s:3y  ^])~ 98mXI5.Xw#pw=g)n J 6|#'}*-/13e4555531.+Z'p#v T&wտ~fșErM¡ßeUʧK((CـwICD/ x e#'p+2.2z58W:<>A?AOBCRCCUBAX?>"<.97g41w.N+2(0%?";dq@ C"`g6}&K Xd)pef dO I0 m!T!!!DZ Dc^ܴ ͗ɯ${/<񨬩-3^tM%֯`_ %"',"/3 58W:<>>?>=<:9"76v53Z1T.,B)Q&'"  P}9MY9g9w9 1b!&.*.2589y:8::; ;(::8;52.)%!qY" j&g:eؐӾ; 0Ήa<9i\I c%+3/37g:=w@6BDF-GG^G-FEDC5A?=;851-L(H"Bt TX0N{PE w> Fd ##'+/3689:8:k:}:x:89896<30-])&"wI NX,2ے=HտԙӶm[Pzq ӎG2Q߯T=X|w^M # Py !"m##$$'#"!9=K O +@OMMY )XBJR,Koyg/n8/tO^5^  $ N %|<f' s/O 2y#E 4?¿)SdX[&nMK҆yi/$M+<17gq;(73/+2&!y: 4lu^SMi+Qot aOg & #&)+2-(.0t12333210.+(%" (;ݢv֯CҜ Ö́zȢșȿɥz˘zؐۜy8 S jZZ;ye+ G sHV^zOkniiin^^Q$uo)P9q^ sm %O! ^ c < D8m ـKɫXós KUB7#^ G%m+20d48<>AHC.DEWEEADCBD@><:7 3/, '#> /V<5Q^0>&+):G  %ioW>  !!!! 4iu& T^lCw Bڣ, ]KʒvșǫǏǩȇ\zu2 2פqݜ68G [sZ:;'CZ z T3+W^0 ;4bR^D);[Z@4)nn'OjoeO*^^ Dd> c  N  % ~  OItt Ѣf ǩjyE \VCCVBAZ?>;9k6v3/b+u'p#iktyoI qWw a* w9HN uc !|$'*A,.0}122222"19/.+(%U!/ y7rޗـ? ~w<ϖZ Ҧտ9O'Ys w6  !^!!!!n %HG/n r  c&M!fBOq 8jJto ibnz//%OO? {; D  cvO(:m#׆ԅϲWʰǩb(_dqEczșX:Q; UK$*A/`37;(=?ABCTCCZBAz?=;(8y52/,)1%? "/' %7h^U9$cm9|t=6^3T DwK #_%'y)0*,"-Z.d/>/0F0P/.-u+{) &# 1Z) g{!xGHؐ1. Ά][ˢY˘[} տsVx]) .OF c "K"'Kda$] %  U}!j/z^ '^{^nQwL)w\u:5X?@@/ )oM^smtngB|pLKɚC+& ܶҰi۹'z{2 $+059=3@/BDEFFmEDB?=;8s528.*&"ot_ ^%L"X}VXnnmo?@#^v Rk\; #&(+,..////q.-+2(%" uOwcqYԘ0U˅zɶF5Ɋ@M̥< H֯:s X=Imu/h %-;[B ;S; Q2 z T!s>RROSe}_ 99L, ^^0n)n'7  2 E6<3 &vlsn>'XsB1Ӿ@b4Ɋ}/q:t#l*A06y;?CFI$KLuMLLJHFDBL?=>:863 /+2'm# | %n/]48K:f#r) 9-G F9Z c"%'G)X+2,-...-,+2)J&$1  *AO@خQ(Dș#&ǽԽWTþ¼ĬɊoτҨտؿ۴޺t6 ,   & T wq) s K8) %  (O*2;/+n9{56$E+nSEq..I=:s X l % ]m- fM K49=+%aտAK+ˤ˺[dγ8.ڦ#Sy. Rx; C$(,"/F2847g9J:o::897x531~/,c)Q%"a;G "-XgdXt9k)s= nsJ^>Oj1s  x ET48X807 % _wq>Ԁ*0GașŬJșɁʩ7<ЦLؐuSp/\ ,Usy\ H T!,!">""""""A!!8  K Tnf7w ;Xl_iG % "GB n u D 4t_ Ypz"=5)O90R),~'/EM c I9$8Klk;;; KZUm" ' c^3'F.^`)N9ab>Z/W,$j"]K *PCMO. tq c 2  D L J I D 0 T { c P *s]jexzhl[ssWd@ KN`lqV f/ /i =C6  J[ kn> /#O-OlypO^<4C^xy^?-6^&O_]UOOSTOE=?OfwsO }^pOrO3.=OL#^innw[Yr8nn8e(] pb?^vI)9ZXTw"pho'wDXb)hanq/?m "hpMFs ) D \ % jMNj % Q D < c srs57fNAc"_$S b/sO?n 3Gh,m1uIP;dS_nriT/(I" +ghiEC c % abl)V % q D  % /  D  cqk4w/nNlm*-m~  GI!UnQO ackDeFs  c  T l A %    % N T ws_<U4XmN&(Z /9^73^MiO^9nfcd{MKKJ*TLmMBZwdEWvdnm/@.qr7s Z T \ % $jGU. 5NK $ D o sf6/_rrnrEIC;9wl%=1:noZPn4OF/1]>;yz:"C1:j|bmM  )/v^nL]qqg:d|>x..(VIjH)q9+99/'9tp}0r'$aTB^/3H^tZ`s s F D l % o+)/ O/   D [ E T l z q T ) cM"y^i'H)ZXXP9)990)2Y`!v'-x!bwO2|:Ss % ~ D  $ % ! T m X c u { s c W U [ c i j h c X 8sdenk>b/O+ +O/i&#>~'3$YH/O'!2OgriO.O,/{m//  PT2] c p D ) %  6C7m$'m    , T sckwsK_h'vT/X:MF95?Ww0@'NwwXZ)`qF85p c c N h T  % s _ % % Y s a % % y;o   % T [ D c c;DI%w&/'O ^)Yh I-6\pf!ip irP+X/n ^k/c8B17L>9 jH@7 my %O[A*T@X/AJߡ#ޏ_22ޯc54P #gn0(i&C&/OuQ3 c E D ` % [ I=2: @>,:ZH u cgy*EX YOr^fO^/cr`/mOnK^^ ?* N[ I f)e(5wnUMH/os X H arRVs c   * % 3; . % V h j cP*}lCVngO6.F _IOtM)f63Qdnyr/ `bqn"IB c 0 2 ~R.tyloHyZ+d o % U o u c= &./2M^wvln@=s T I8eJKOVx ANBws'v9FtTO /Zmb/2b^/^9XH }NHZBE t'-w'o )aCYQYg1BВ[AST|:ѵbᄅ!s Bߋ)DUj  q &J,"27=eBGKORTVWcWTVhTRNK.G.C >:62r.)Z$;5# Q cs 0 k T z;j9n,ץ6k.% Eէ#|  [ %R 2 'Y9=Dj %xyD sIo-J 5 ;{cD /.z)Am/Uez%o^mUwW58K L?iQqIC{"&M)A+2++8)W&# Deyi !0) P02i܎QrښـCҿцΏ˓zɖzˍ2Ւ/B ]r %z)Q,].02468r:8;=)>u?AC}EHNJM'O)PQRRRQPWN KGXB=8W2,& ( cxg}0&տͻ羑^ǭʮ>6ӷ)tؐv   c rO & " * %3'y !*^ "09/BnYXm 0 f >snF2Of9JNm OXu{`jkmn D 7) % nw  c  t_:Zu7!\"#Y#I"! 1m;] dQ32&9 6ـ`5[ǥĉƁș)^Ty^B: DhZ #'p+/37g:]<>w?@ABA@r>:6v1,'"= t7&M;$@Fg2#GșeJ^*š) CH D/^+q82w>fߊ|B<3=5wL %!%Vy Tz^ y!"#$U$T#"D Ziv T232 <:O_/xl;2zwX#O$< F 4 T *.O; #&`(r)*A)) '%#< ;3 n c<`@s31Awk/ـ֖oSfW1sբ֯נ؆tqmKB[bݕ2hCfjR DE!&*/258:<<===>"><>5==<;;(:W987g531.*'~$1 m exow)xVտɍRTϲϫ}Z˧!9ɹIO= Z7W6f T6xV 2ܠAؐ.#dmt̠ɊȶfoșȻɊʞSΌ Ӑ&qM*n c\}|!E% (,"/37j;(>ADG^IKMNOPHPEONML"J/GE,B)>;8H5D20/]..-,+])Qg; h|#ݍșϹdѳQT𶽺YG%Uwșbjݿ-Tqȸʼ7[̻ع&Q, s %38K "%)W-15l89:8:@:#:!:8:#98529.}*'p$"3/fCU |{CBFMQתfϙ[ƙ#d\ T㼼dλ @Uɺ͏ 25o2DB  @ Zf'Km !!! 47 DQt*#nRO"jQXo֒A L H7gؐٲBs)^CKV TNb; $).2 59<?AD8FmHNIKLLLLLJHFDB@@><:L8754%21n/.+)o&# D2W\Q֖Y~Ӹ*Ѵ~.%\&gP/ݭ}Ǫq^?&10տٻ`+p%^ T W*6"&*a.3p8W=ADIFmGH HBHNHhHHHNGFEDB@?={<:9Z76v5,4!3W22 1/.+)*&+"(Z8_ОT<Fș93Nѵ?}xǩ[ҙ֯t9^ c Z!%)Q,0a36v9;=?ABCCCA@>=8;98W65)31/-+)Q&$%!E c/O )M^2ؐ$'ңEѼz; %zҧvwտiى!#s9/v 5b#O'{+b.255?82;(>'ACFmHuIJKJJ"HG^EpC5@=;741/,*)Q'&c$f! y7ڨ͖ǩQ 7LN/E|vfN˦hإ=<;+96v3@/{+5&!p 0|^ #ۇؐK<˥lPJt˸MѴߴ/س𴎵l<2ٹ SnnZ.s V_C" %(+`-/1357g8998W7254>210/-,"*'%9" `34KQ" B^{gߕQ͝lyǩ*†(EzdŻd1BɊ4Cտٖ(^ c`cR!&@*.37:=@CGE)FmGFFDB@S=;(8U5X22.+(%#! a, iyM T+c֯aȱ´Tjͯt}/ڤ35qmήe3^%wUϬdmz#27!TV a+$*059= @=CGbKOSVXpY=Y5XX*WWTVVTRP%MjJHNFCDCA@F><;(9X7531O.+>'p#1Y  =MBiـMMЖѲ!ܱƲ:ud&0O܋, DT : "$'p*.52D6v:>IADG'IKMOQS]TU(U;TSQOM!J/FCr?<8k41`.*'\$ `Ay ]9֯$ʻǩ TK\Gѵ,>𳺳xFY_rĞnRT #VT   !!$'+2.`1=357869G:8:;L;:8864?1/a-/+0)Q'q%r#A \y  s !Bmڲؐbuh K̪|[Y̗3<ϬqxտTU`Ms !&z*.26:=ACFHNJeLaN7OQQRRRaQPNLIFeB>:691-%(e# s3 }9!E =899U ^}Lᵸ˹@zЗֽܔ* DZu2 "$&)Q,.135;6_7O8W9;Z=4>@@@">=:8U52\.*&"" VM P Tn9/^kj+XҨ<3ƦÜ o=t,tƻtEJdt %Ndzڐ2)\) T; l# %'* , ./13578F9T:8:;t;;(:8X6314.-+2)O'($!2 % q XQֺٍЗaz[ZЏ ѝғտ׿23X s w $(C+L.0358W:=~?ACdDFG^HIJKK%JIHNFDB?<83.)$]K' M>4\'7ݚ֯i̋ș3`;k~HnF28F@H Kt{ɞKКӓ8ؐڵ-OIG  T!&*.26:6=k?AHAA?>a<;;(:::s:899"8K7g66-6!6v67b7L6v42S/[,"(%z!  D?/SL8$gYJcvQغrғ Aș+śƬ3,[·ЉOI֥ـ=rwM3ZKt T Kk!$'p)+-/1h2?2R100$//0r1:223O3456X666v5W31/-+c(%"<Y] sNO -(ބۄؐգKȘƘ`=y >„ pzԆN=B`MXl  C !&),{.1;358W:<7=[=>J>??@ABtBBcA@?>=<;(852B.)\$vmK =#G).B34czdP&}\>8Ɯ1w#ʨ_!#, YS*^ DKK#',"/36:8=H@BDFGDHHNHGMEC@=:w7g4290 .,*((&%/$J######"!FM  :Oqgws4f2ޞ{l]QM"Lr X (H| D"%'()6+2-.02468;(=e?|AIBCCCCBA@><951-/(k#~* wNV4/~"g~DB}վku ч^|A׽*q~KBݏ 2B8(2ރ;gzINnnCzC> c Z ]@ItZi/ =a(Nc#K a TIi^ 9~.ges$#g|B=݃##w q^'2 9pyO: "%1'|),".1X46v8:2;[<<<<{<;u:98W754I20/-"+2)R'%#!Y@yR S2ٸՇѯ<8Ȫƍ}o_&߼dH I`<2|Xo dLN^ "H#%'&(e*A,C.O07123<3'221s0/.,z){% - \ 1so>17CNQW#x]ޣ#p&w99j`Pw gO8#)k\^Sg_]z_|> T 5K9P;;'NY2%2 s`^:Wha8߶~B ٸؐd4ѿϠsϞփHq/WWb. P; X"%')+6,",,,,"++*D)Q(&$" ;QE c!(O)(w [֯ͣ~›d>o湓`4%Ѵj/y}Ь宮7D1֕2BrO # !j"#$%a&N'p(*o,1./1357|9W:<<<<<;69852-(#"  T}o c  6 sQBR1a;2ߋ2$jQ+ߐa?I}?R#Zp o@w y&  . w D [ D v  O{AZ* "$%&'p''V&%#!nN!E$ % P{/ )_ߐRFـCտ`ԦeӹӰӿaտ}OQsE{5Y T %cy "$<%'p)T+t-/13h456H678W89 88W7c6420.y,)Q&K"8; D} rvK)IpI֯0<̲,Ɇǩŏ?̾EB>*幓nİɊ , s $5Ke "$'.),".1t4 6v8:H<096v3/,A)Q&$#;! z7i;G@ % =EAqEGj֯$շտհ_ νͅ[]ʬ^z<ѦӨտٹۃB Ht( 3 ,% #&)Q+-R.r...S-a,"*) 'Q%#" Y@KjNtE c*5 hnAN3ـkѽ- Ѹqؕqܸjsd D ~ ;^!u$~'p*A,/j146+8@:8<=>?@A`B BC/CrCNBA?> <9741.4*>& ! S%NXz۸ؐg͍ɊUR;#o Ʀ}mG]td#õ'zͦМOտ'23*k/  DK!$H'p*-c/123?210U.-I,"+p+B+,",-t-.. .".k./000\/.,*D'p$_!nZ (YuݿQZڪـտ=wr&==,;:8W6543210U.-,f+Q*A)'%#!jK %DO X> 2۹٥֯6ԾԚPRQєY мЈИ E֯ؖڕܽ# X^/4 %v:;m w"%'c)q+2,-./01[111h0/.,=*8'%" 9TK} % : \Z9'quB:Y<ɾEU3Ѵô涪7dã1zn҃ 7PBNKmco9s JZ# &)-0/123,322y223457 8W9; ;73/-*&#! pcr/X)R$?sխt+>v g5ǩɾnԯտֻq 0X^}A %"( %I)G,/2468W9v: :[:899M88W8777g766+543210[.,*A'$!x bz\ oZj^. cH_HX g;Z*I׬Жzɭoɶz˷hτԼסڅB߶{Ph[V*QwUW-& $ c %]  !w!!!!!"I#9$&(+-/2!4?6K8W:k[?@@@A>= :8N52d.*&" DDK%IS P~տ/ȼ3̵t𳪳-oHdϽJTP^ED(̮ Tȧ{[K?ՉR~QI#)V !!(%)Q,/G135555433$222c2/11 0W/...\.<.-,+1)Q'$T!T |} xOuTg9B+տ{L( ͱ[yE^edҽ2JŦzϧҔտ KLJxXinw - , "%('p)+./1^2W22291h0Q.-J+P)&#!(;. dt^>G֪ǒBTU?muȰ/\ W\Sqܾ;c(9XqT 1#'+/37;?BDF@FFmEDCBB-B'BCDFHjJ/KMRNOPQRnRR+PNzKFB<7g1,'9!` %/d}g8޾%} ۸}//˦SVrͱgrI%+ozϙծׂ٢Q)X #2(.26:T=b?ABBA@Y>=:<;p;0;);(; ::x:8::.:F:8987|530G-)Q% N d)qְӼє)΅K^ǩžX#jоEνErǩ$δ>տEA L~" %(,!/g269V)B 1 t &b,"17;?CwFILN(OP9ONdLIVFmCAt?=<^:86v43 2!1111/.1,)'p$"K#)*ޝـ9d[ɹȭǩƩŴ&d׾}EE]YǣʂT:2 n; R%$).259,<>@BDFrHcJLLMNOoOOONMLkJYGD@<8e3.)L# 6Q kDe.<:988W76695444+321.+2&"y [BX.dؐ:˓ǩvF2)gd1E{a%۳!9tLș@G֯, DOG T 8)E"%f(/+S.3 7i;?CcFEHJ/K]LLZLK%IGWDAP=:6v2/,*A(%#!u/y $ s\6n<62ھNTԼTu&-’?ŬƄtșT Gڧ2a%x q*; x%~*R.3X7f:=@OB C`DEG^I/KLNgO\OOOOOOOO(MKI.EA=P83u.(-!k ^#[ʴ XtR^g͗Ԗȗu)婡/WƏ<gxED Opw"&+/i37;?CGKtO4RUWY[[\s\\ZXhU PKG B><9806v420.---.--E+)Q&D";% s|Cy>:= ;(8t591.*K&"A T{u<4Ђ>E#3EEƿÒ"Ƌǩm/Ɋ%$̈<տhu p"P&*.z2+58o:<=>?I??@TA BBCDEF|FmEEDMCBB0@><8o4J/+k&"0r ?2լZϕ<ʯɊ)[)m%8ϤN};ּ2^ yI c M[l;\ #'C*.1469;(=Z?B"DFHJ"KKKK8J/HpEBZ=83.0)Q%,!=1MfA K xV[2X pzE=f'[P&d_æub[Z`rؐۻDY:[ F/  "" K #&),.024&567M7L6v42V/`,"(%"AM ~ Xse On9#۲Q ;ɊȠ02ș\nKЪS?v׊ؐٚڸBޡmcXxn5s dZ"3&[*A-1M4z7g9<+=>????@@A!AB-BXB/AA@]?>>!=+;:885t2e.+)'" + c7F2օӇ Lz: ĥg&G8jA8p̣쪕<ժgk3Q %XKK! #6&*-159u=PADGJMNPPPqONLJG^Cu>:.51_-+W)Q'%#!0D.  `j)]ـՈ!z&Ŷ0)șȗOǩnjǖǮǩ`] Lץ8#h1-   &!K4 #%R'*A,/3 6v9=?BEG_IgKLWLLsKHF,C?<96:2.*&"75yfN' N s)53V@ݑMc, ɊaǠ^ǩyɫ[͂vKԑgտ<ـ6/lpg  [ %;G!'#&(+A-E.0E1B223s4W5a6v7n88l8W77x66v5531/ +'#t9 =!vD,qyؐժKȥƪrҾEλk w3'^άsNmί3%E+~9r{A y k$)Q-]036v8:=G?BEZGJ/LMO@PRPSUGVdWWCWVdU{TKRPN'JGB>%951.g+U(m%"K c/9txkـбɊk~E3ҹкTtLT Ϳ& y¿âĦȪʲK5:QMX^ J j,ZAP !"#%,&')0*Q+2+,(,F,"+*)X'p%"f t$s߾ܣـ[=2Kʘ @E|EzOvQ`wy/ n="%~'*(,"-/1?23556v67l78W8888W76s5!320@.K,")';$!6 s hl6N:Q9iOJTBqtsTkŠ&U\K>L{տ&12Oh DI#)E.j37g;K>ADFHJKKKKKJ:I5H9G^FFE]DCB^A?>=^;:885k2Z.+O'v#`<! TS5HsB ؐPӛЃ$[ʾoETܾ´ĉƅșf׭ڐBߡJ;X7l-/Okq c V]{(M R!y"#$%&2&&&&'p($()*A*++,",-}-.--,%+2*9)1'&$" U  O s1^m1wR _Q۔ـ.<ٮqa\N2(Zi9/.   %l !!"K"#%#$H$%L%%%%%%%%%%Y$$p#"!a *Dfi % +/an_[2#7j֯Dў[Azoʽf[}ΰ BӒ ֯vT>23GpB,y S %UN !"b"#9#$6$%<%%%%%%%%%%6$#"! _ gi PskHOywgF2ݰCQ.>qf9Bpߪ =O/-) K^9a3{ D {HJ'yHZ)NK2&KKv}  T  ");^3-s*-2h)]9 9v)FhNAM#In#|eGO nnbitn?FT7LizwY)u9 9w)BG<))K|8eZn lhUOE Q2 s ? c { } c : sC[KXg }/SOO/}OOzO')OsuO"O3/ FzdYT y/[OO/jO /OH^5TO|/j JWE BQC g +`EbJ@ HY ]2/G_^/OOOOOV/VS=/?s v9nNI:$1pPf# qs K s c 'srs'/ ,0 c c)!PS~S( *53 /@O OnZ^E3Nan5\^N@E^^& ^/ F?M;` Z/%/1,(/D[]/ 4^ZJnn4+nN^azO/bO .ON^nx^/ 4dlNM3y;6`+ s  < c | x c P H P c x z c J = F c c szsp3KY O}O^ =# <5I~uNnvn^^C.s^D<PsD3 [ e\c??aY^IG{` X#4Kf/   xOf^__\^pOP/pp/QOk^fst^,nj^^^nE^O1*^k/&  //~ ++&  C}G[G~C  %&$  @w` Pu OO vEk ; Ub I/C S`I Mi_ (On^^'nE7Fnns^]wZ'988CF3=.GH= YJ !e;R`b+nn+[.nUq^;'4^^^/I4B[ xtx8i:3* [ V/r^rn^ 1O@FEgT d//N`Z/gOc^hni^_Ov/JG:/+++/Bp { nO^}n0^Un=6Nnrn^O/* l//u //s M~GiMs}sdVUs 1 T  @ D < 9 ? D :  T ^sKDRMC%8,o0KkTC(Q$eL~yK k/ /FJ>/4_ dO ?O5^POOr^Q0nSl-8-Tn OlocO/^nr|}nTAEn.Oh 9_$ Sg  //&b;r<!/*>YKc, 4LK y;/W 40& /iO/bX7/cu*n`A 6F? w/`O_^p|^)nI=Knn6fz>:V,v>ET cn7[ ?p9n@^qys^9n ztatx n9^gGn6?&LM~hek^O!/r EX<p76l\FV81/6> m~\ spss\ksa4d Rqf OI3^@O9OP/+On\Y^n^O/ 6g[x\]- /kO / [x }/n]bn^//*O^LcO'',2m+&907=Ss8H@ft1?+s ,  T n v o T  *sYG<`)GZ%I<Ot^aO` Lui'OX!(`\D]3%x )^u\nn;*n?w^+RxmJ00~}wxV^njK c7d1srssOCRsssL/g^^+-9 ^}^=+WXyXZfR/h  cKlmVyR c s@=$OOU2%x c \s&n99s`Xw3߉2\q28\g-5go$)6 =qHCK _C<4} mO9n !q( W9.8Sw$xfiv(Qn|xa/i>i- D $3 ]f"v4W TO0;OS& oVQ׬Ԇ{ؐ@LO> T W  e TWv" i D+I`;!#%&&&}%$%"Z J L*&Lg;TK OmbدտӇӠo(ؐي[qqYـ،8՜(ЙF<͈>t<Ϝщ֯پ o$&Vu c  H AF}k;I!%)Q,0258:=X?ACOCCBA@R>=U;q9%6v30-+2(&|$(!sKq* D.H]n?[BܹB݊Q#d ;8-4#/+'H#h % Q D Xs)DXcǩiKΠϾЏ AD. ЬeлW3Qߚgat^*   %  " U % 1 ,en2 W/A*9D,#]ߩ#0GuU_ߖ2ܶ6ؐב֊֯m'2N u, LbKI;!#&a) +.0<2A456788W8C76530-*A&#` q 7ZZ PZ  A!M^ Z@ǺnðÉĪŦƲǩsdɊv#ȋǩƂ$àct󸵷已;ErKvU^1I D 0UD;!_%)-159[=-@DGJLMNsN=MjLJ iZo T/pfB_qډ۷QܓSۓq׳I-VSKz!sɊg8 wsC5 T(TsZ*Vz`!Z #%V'o)Q*,7-:../$//0//7.,,)&# ?Z?0pV3a1W J NLKZS0ǩr2zʝșLBd= tL@|݇7J0{ c CnZ}#'p+3.26v:==AjDG:IbKLLLmKJ/HElBS>;L73/,)(%" ]@DKHKm_ % mQA6: XɊdzr$Ư9ǩ[ɊryyK2<^ζM0i|؎2)l{ ph c wELd)[]4ZK6";Pry= 80!a9<`{Qx֒ӻ Ζ]`șŲĤÁkÕO?\hǩǚ5ƍĤČŀɊ˹xտ+w !#%'()Q)H('&%Q$\##$$& 'p(*,D./1357.89:8::;;(;:98W6$3E/,"(Y$!sNZpz 6 cH^n3.4mșǎ2QǩCmșZz]Ɋq9Do@ șˍқ֯wD@O zs @5d }#,&)Q,0}4^8WtzXWF١Q@fws ^|T c _y!#K$%'p)*,y./]01235 6B7g8g949:8:{:::8987>531E.,")6&"_N sw mq>ؐeԒQ[տ_־֯D՟m p[ܩBsV<7="&*,.0111170o/..z.4....M./1f3M5d7g9 :r;e<<=<====bK\f&AT̾¯hǩɔɊčLc!^8óǩḰWտڐߔw(OYr c (T"&)Q,0$48W:8672=.+2(]%#! K) 2 2h#.<DžċT򼥼qdνT_I7TwU&"vjz\ؐvhg w ve\Z!#%.&o'p(P).*"+2,N-\.C./l//////e..T-,x+2)'%#!NZ .kO w)2׾X ˢșLjtǩ?WKؐ ݆ka>O8/Yn ").4+8<">@BrCPCCXBAV?>P<;;(:;;t<<=>?@B%CXDEFGHNHHH+G^F.DB?<84 .)$)K9* ~ A @ c6,0hD]JrKHXɰͯ> C^s1lHhdFؾ*E%ƽ-dݼd^ș̺AـX ;/s u~ !&L+/49Y=AE_HKxMP QRSSvRPMJFB>;B741.+(%":;H ( )$-֯Ѳj+Cșгe]#O "$&')*#+2,p-/135738W999:8::;!;(::%87g5s3/0.+=(k%"& n cvl7^R$!nmؐ5Ю<ɭǢ¥S&@Ti&ÏʼnǩlMQݱc2ݹNBݽމߠXP a ?%)Q,/1346 67g77@654f3V2t11<00R///E/...!-E,"*)(z'p&\%#: | d_q#$ݢnBڊؐ+[ȟT̶m6/hħ ܪx>F{tǗ3z`̍Kff 2J]" , +$!(#%')+2,-./124W6v8;=u?BoESHLORUgWTXY0Y`Y5XWUSPrLHD@<951.l*'p$F!|V' cnm)Ӌ54w3!1/.+)i&#&o}y sVOw/D2׵` ʢǣI d 4G%BF%4duþŚǏɊp.λcҭտׯm#XFnG <E"J$'p*%,/t135=6o7g8H9-:";(<7=>>+>?i??k>>%=4<0;(:87j53*0a-V*A'_$" 3Z % OO!w ؐ^XҒ ϻΊk[`ʌɊ]XlɊɭzw[̗̑{[Z̜:<ϕ1ֶصBw5v Z!$#&)X,".14/6v8m:;A<<<<<;^:Z97g53g10.,*(&$\"Yf> i Lj4Y M*ѳڲ&> 1}Ъ\,-X}oɯҷTƅzӀ Q?XA3^M;i m  N#'*A-'/135i7!8:8;T<<:<;;G::8988#7g66I55547310H.-h,"*)(5&$"9q=i c*mn&X!`"#CܲQ !Qܑ B݁f# a h0X7(" DE/)nX R T V N 9MmV@<&z4pC U %  2 %  cAgG ^nwg b|XoY%&w9w9v?t^&d1s  '@u&ty#Z+K`;q fxQ X%PK0"</H D H5s#ng7#9)NpzgH7R33-)6gD<8) At O v_4\as , T c f e d c b a a c h k j c ] [ _ c [ 5s`FhI"y0/X-:U5q5T-q%E(Yup ~bhB^j/it=Ss A ^ c a a d c V 1sO0 ;|Q|94W^/gnTF]C&O*.TEHN Fk/ y^YC/Ot^F0/^{R/&,&f s/bOKn#?;DaLf>z-Evvg\X{f .kXs`^mzi ? H/{actEsC3GR] O>hazd9 //  /O^rn)^tpb^rO2/*|EeHstT/{kO/5iFC5OcR^kkb^hz^Os]N2nO~~On93 1?nnE TOTn n BnUO []sNn|js[GNsscs : 0 T _ x D  %  1 T ,s?Jbwy x T N e D  c<@DcEEK}}KDBs-o]TNUd/0O/nn[Cw4w^O,/^ zV /7? /"OUc/6gHiRs 1%3k&lQ  `NEY|0j;o\%wHG15 ! \O^J`O >/=^ln3O^} OiD^^nnCwrRIeCg##.XUXvpo/,[ !VhnC0&h[tF gY0cro,me,q))1B!+Wz#{u`. %AK.{Ngi&v C` "n/ (/OCQZO/OR .<c,u9lgG;{p$T"m4@PLtWP  ^O[W+5/ n&^PPF hx`2 $%  /^^/h/ /R^N/5 fAY=m/#^ `G/]^7]On/cxj/@^ nBi s/d#yv#s * c  D %  D s Ou s  : c c 1sNDSss  BLf N +]8 ~//Z rOnsq_8^}^=nh]Xou@X=VSoLL^ n||Q1^ /*6>n =6@>nYJ*&@w7ITv!sXU j(=y L!a6^~nh~^8>E bzu^D9Q*'dzOOe.r\8p!@zwni],,]gn&cJg*x9BXgT,i57&8q7AqHhQLU/pXO1&Ben/ =l+k aB; $s c c?d'ykx>X=v $^^%" N;qSOCR4FksT%} @O@0?. Kjbv6ufLVn5&? 5\Qn\Ow=3/z7IhVs 3 X c e g j c I s/%s o D   % 2 Q T WiL3^vy c P d T 4  cQwB>S^j" Q&/kcM<W4qz k;s+$"O4n,[^I<E$rn\Oa/n bG4|7= (mM}@/lznszWGJOA XaH \?rTZH:>08S V/0^ pjVOs1)vLfB~ W1/T*WBU(b8Monmwc9 5EOCP/zOK4 :hH ]_\Znr^`Gp5Yzw[gENEN)w8%H/p>I%Us C D f % + : D (*~eVH} ^'O4.(mM<z8!|F c " T  D J ! T Ss 4 *6 c c %* 5^|:9<\&z|[^?Z;#BۮnـJqS:$X" s Fv>!#@#$##"s!  "%'p), .!/1412(10/-,"* (%#!V)nKSyt< s; gQfqiؐfZ҆ Ϸ ҦԳـi-w}Z9*:w^ c;t`+ !"#y$$%&')*A+5+,,"+++*A('$!9 c84Aynj4ߵ2o4Qܭ*ݲ2ޟ#ހ2ݫtBB2UXVNOv{Vk ( T > Q3~3= D % \se"( BO@[qOw$Qpw4֨Q5L)l= c X! F bX_\  2"%R'[()Q)F(('p&&~&%$$#Z""["("!!` !Mg;Rf qt9DuBگةտԒrJ ϦɊƛ5qthwĬmCȭׯfѶӷ: dJVǩE=өؐ_)(t\ Z "$b%'p) +-b/2q468W9@99<8W642/,)&# MK 93~ wnp9W+)X@-g3Z^wfDg c  4. O Y  coe~yf/?Ons*`h?֯ TBX/ )aGi:O# "Z T # ^!! %$F'p)+-].0e1~210/U-,"+ **+2,-@./1P2425678'8W87A530- (#D %n@v9BR;)w&>M̩G^ֳᵘѵѶ[itgňɊҽ.2 'Q_ * ^ !$(m,"/37[;(?C1GEKNQ7S5TUrf@(62X}ggMw3ڭMp!ǩpǩ/AЍ+ڜqxMgu)o#tmb b  T zsI "'*R,.1(36:8=j?AuA@?P=<;r;= >@BCDDDkDSDEEFpFmE|Ck@;<7K2,'p"X O/J+`>X+ z<'<ǫк𮏪< Rov7H\\T ܥ˨Jbm[3x>^ G :o!=#&`)Q,n/258:j=;9+6v30-i*A'!$"!b{MZvv8 DBH/wq،;Uտqw֯qMل9֯)TNd\$տ OOT u- c  d iph T|3dOw@emKrX ڬGЙͪBɊșxzx!տkZqO$?^EV ? %)Q*h)O&# /U ^Z}K$*/4 68:8;=@$BDEEDBB?=;(:::=:<=@>+>>>>>>?1?r?r>=;K73.(# 7` .Zo!BۉٙeѬ8 7^ޥHCJ\ t} ap/аѸMjA`ϔLB0W vu!a#y%v'p)j+W-..0247g:@ ADTGKMOhO'MAJ/FCL@>>===>F>>>>>)=A<:98.6v40{+%H c(46-[ـKшΩ<Ɋ cظO#._dŘHD㩜jAᷪyO&ŌzMZـ 8J!&+058W:;V?AOBCDEgFQGPHNII\HG^DAW=8W3O.'(#a ku ]]nsRiJ2ُKpZ,< ֍غq۰܃Bkݗ2ާ9Xbw8^]i L"Z~Z.`y0 7CG.݊Q ٭<֯`Kɡxd峩ϬmZɤꤻ,/ݬTHK~[_'ׇؐ؅ֺտՃ֯zݯ\ :oA Q!#&)S+-y.-,+,"-05Q:8>CFHNJ KMPSWMZ$\\\ZvXEUSQON L0J?HNFDCBA@?Z=<;098W6p30l,"'(!-  ct_rМͼ[Ɋ:71_4ᢄgКښu@y)PM/ɷ0TeX[3ӯـ* x `Z$#)*.269<=+=.,޽ڃ;(e17tl;t&8ƝN DIMQ2SU\WTY\`?cf9ghh;g>edcba`_^][=Y5VTgQNLI-FcC@=:J6v2*-h(>" TPېտR?}ʳ𱈯r}DĤ)S#ԔԏQLEQGŚ|LڷtzOA?2D D^E%*/d37g:>@BCD CBA`@>==@<;;(:M9x88W8#877g6g42/,)k%! "},/qevWt`H߇$q:՛[KzU̗2R׈qvJc %35=Z#<&),/914-6q8~:8;}<8BMDF#G^HJMORRT%TTRPMKHFGD^BA?%<:873q/,"(&]$Z"!:v/K% Dn}7^>ș¿[WqB^&#צ˥nˢ8C?64) ǩҔغ# Hy/!&+20f5m:=A2CEG^HIJLJ/IEGEFB@=;:8875531/-,"*)'g%#m :;p @2Y>ܮqاZrտ )WKiWЩzNQ{vg8O+ TGWeK!I$m'p*c-J0257C9B;(=>@hABCCBA@?=;966"2/+Q'#>T 2xn8)UN;24'KUŸ诲ڝg|bקA6 O&² șΤտXh cs !%(,"/25{7g89t:(;(C@CDExFFG^HHHHNFDBo?=f; 86v30+'p"qUn sn/Axr@XD2ڷP Jɑǩ%īŠșzmX2՗~ـۣQ/ D ;D#%&*A-u0k3579`:<=$=>>>>J=Z<:97a53^0-*A&";G % h v2r[Ǩ1">l)h!Y) jmص=/dVZ‹oĂdƸș C؝pS6/ n %0\#.&),".1d48W4٤_$!8R`ew@.:+8HZ꧐- Duș5#On Y84#'),.113D56v7f78+8W89 9:8::::89r8i75311.e+2'#;$ cb^X/S]ؐԿМxș*2T57bѴOMTŪș˼#֯ڮޱ c  K"&*A-14H7g:d=,?AChDEFmFG'GFmENCAz><952/},<(%"y DXۙ֯%x翅a𰢭訬O۰L𷄺ҽ&Änā%Ƅșеz0 h %.`#*&),".g03 58:=-?BEHLOQT&VdXZ\^`D``_^[YHVdSOdK$FmAi?AB4CCCCCCCDEFmFFEtCA >+:7g3/+'p"C{ ?!X|nـFӊ~.bx[/Bz4־ف@#N|9*N^s J] #'k+".1469 ;(=J?vACEWFGHNHHHG^F%D]A>;P7O3.*'X#  T;gdI#tɯ}ǡğHHHmJZѶƷSܸ{ME1(ɊnQ\n 7"#&),/258;`=@oBEG^IKNCPSkV>Y)\^`bccc ±cS6~ Դ>+Ss  "'+.26L9<=>?3>>Q=<<;8:&87g543v22C2 1111$0/.-,<*A'$!'/ T{Tـ K8<ʟɊȵ)ǩljrrǩ6.ʓ[uӔ֯9)_6:9 K%!$'N)|+2,-./11222`10/.-,+2)?&$ RpD Hed 5g"B/OzO︢nkũТ)!Og%ͰѷK%sm2+TlĊǩ@TؐYVgG^% $(,W/3Q69<>@?AlBCE3FHNJKMOQSUWTXY}YY5WUS?OKFA<6=0e*%  >O]@|F$}@iоEekg%m˫ms@AAAo@W>=I;97g5%20.-a,*)Q'&)$t"! Mg; \3lEL տ ?pθ<n"3@'jBտkaصqܔmK CL"&*.147s9<>?@AB@BfB5AA@S?>>A=<;(9Z741.+(%!Q 4 Q jaj+, ܽTIƲİ/&1Ƃmɲz˂BEPHNKMYOCPQRSTUgVWWMXEYDZW[\^`abc(cb=`^[XkTPJE3>811=*Q# qO:O)aȑĬֵf9˥oo mBQ}"ȵѹO9pV֯z n 8\ $).38<?BEFGmG^FlDB>;s741/E-+')Q'&$#""f! Z0O mR/}XW~Qq ˗zɡzQGD<+ *a֯ٙKBߘfw&^ D_ "'+{/498P;>A$BCDE:EFFFmF8EEDDDD1DCBh@W=:8630.*'"f+ e c!A/4)QdhvșͿ Xѱ,w ʭ^q+tǬȐɊʷ/ҖnثQW91&Oxm c ';#s'*A-?02579:;(:988W8N89;(,>?@AGAA@><840,"'G" n TcߦݿqؑDpkȏĽb-𰩭k`7b 6ڭv~ƻT^B֯3wd+nO {K%B).148;(>@dBBB=@><9h64B1/.,j){&#!W r KsL uc7`Aـծ82:ـڹ 2f)n7/ y 5#['p+/37g:=@ABCDEDDDxD!CBBA?>F21 chVـKbT=======<;(840n+2%|{@ #ڡ[4<ʨĿ+ŨD >&>ùt;᳌z{t޽nȟ̫ Ւ~k3J' TQZ ;#(%'v)*|,".(03p6v9.,g)&# yu L duBTz6t&fdjdĺW߳౮>ҧ*`ɣIꧣd!Ѽoݶ %WmK !"C"k"#%(-16P:*=>@2ATBDFHJLLLLtLKJIHNEB>:850,'p# yGw %  D ? % D QYߵـӌ[tغѻVdczkɻɊɈɟɨɊI ɊʢVΈ ӼրYQtw~O!g D EqEeF;x!#%&&'p'('&$c!wKE % G Rfc^m6nW_QٶnՂ`ς:7(30-+*A)('@&%$#"!R;v YrV09BD ӸӮ:Բ:տ1փ֮֯ֈ3զӝ6<\ɊN<Мrֽqog 4/ 6ccqzZU T I1 |b\M$ b % : D ? ^ % % D OZl^n|\V&nYAM;nB45/u.2Cs - c ( T r D ym|U s % " T Y F c c : * < c r s1GVO ZOyn,OAcGinnw3?*8OL k1:,-;0Y+mM6 wObD^*OYTOOK/^JGi8n;Y^kOOR^-OM;3O/ 7dwK"  0j8L7m3m r =|9o< m8]+)/4^&G1NZ^9@W]9gXgRBCg^69KQ9-v4+aOa; ;9+  6dxha!@$WUe/ "Oy^-nq^^#n jfn/ //kO / hi,q5tJPKs  T o R cK-vg?ZM/.nMF f,i' B&OnR`n/ ]"&YY <=3SHs:;uD+lxRP iOn"bm9Luu} c e x T sYsp,>wAQYMawvYP*vT 0-/^dOs}OP4/r$/FnO~sO/"/OpuO O`/^/;PnKO u` n/`OOU/} =E8 6@7  */qO/ 7etL {(H> XF0#{dc!o%v5V9ZOOO_^jYnln> ^snD_N[\n.W^In2jOqoY h"%<a`7dD2QGW2WGN%,^,n~/^#//Ojw/fI/B1s7+Xxz!4H6za 24F~y='w>6 .U2 //s/$O^|nn4_Nn4Y^QBC^#ON^ ^w/O`{S& 2GE J/F GJ5 %Rw4v +r4/);6riyu F7Ps;!,j$k[xc% rFMRSc{8f, UT }/TOh^fqp^9n +#(Cn= 0EL*? n ^*O[XPOVabO"^9/>^O4/ F}LeOe, @8@/E$.D<J)@gKQQJi:#TPq9TKO TO+Odf[OKPVO0^nRGOn%^^(nJ@OnnK9Ennghl|I5H'%*66EH< 1xUT Ew.mw|^p;D5LKndMKnB^XD?^4O@!Od LPuA_ J ?'b'A~CTgb 8OwnnPEabGRynnA.>n/^O:/ &$! #&&  M39) a3/Q l c7/  170  CvztXDHU"/6*d6 !' ~//n/O2:MO.^97J^[1nk7^W R3X53ts4 LRN*,5%hnn[SYn^^ A! nn)+}^G/UJ1/cm&ylVX#c 8&u'3MyM|shSv67 fO^E;E^{^8"/^^6L^Oc #UT$fc5|B U$#  $2-U  06/  IX-`TJVJ M)( c K e T 3  + T T HsXe{s3"3E3q{Z0JPFBH liG&a#6#g-i)/8OOa/QM;/4BH/sOf^V3nKt}j( +lV-8,^^7/A^uzp^OIN^zOL/{ fD^o "BL5~6II6Q?X$ _O4OSE:O//.O^6nvOC^Pe)n~3pu>_rsJ^1 &tBI}WhU8qaAI (nX> E ^:OX][O2^nkpqnq^/ \w c3C9~< 5u53450rkmpklss:s9l~B}P HSO]BR)='d,bq> /O04EOH83O/  /0OOV Z8r2!e)'`'=)Y!o/4r PV< FJJB OR1S, ss~ c c 9 , @ c v Ys;[ 2C4@jjtCS  181  Q03"CZdqi / O?MZO* Oy/3D^kcnWX,M*)Q!^^nWU`nurkn ^^n!".7n^/ 36X0<0hhczl!,"7/. d;/398/$"/>E@//FRI/ /^{p/?O nVnn]eun5-5nn]fwn%>.X[Z^9I)0,s_W/sd dJfP(nvgn&^vp`^OLKnunnm^%PO1O}O ]:v KSss /09z77z;6ei/.-06&y.c./v{/ /==4/At jm b0/Ook/1O',DO8^',^!OjpeO8-5OnyO ^W^e^K:<^-OM90O%/u~\/? E&. VO UHHCIuO'? 9u^|1U9lssgPW ?O[{T(b "? ^>` 6 w; XO X-3&):5V/&^8.nQc<^v?n$1nn?C^w :iOnDn]O{/OgO^nYnn9^, izo 3<-s z A D D w QQJ{/?/w^nw2rT@?nshcnnL7An8^wOr _ /tDJ|w~Q* ,Mn>NA&i/9 Z!*!! zb;  ]m'@߂ݮ2l*IeG5Y 6g|K|#hs2߸ =cLhNg [ tY DI/(  r { !p"Z""! TV O sr c RX| # cLNKtnտSќВo?֧ؐVBZ)Qۼ BـDqZ< . F`v J c!"#%%&&&' 'p(()+2,.L0X25979;(< M#UFؐىڻQNh~ pXggz %y #&(*f+,",1+*)Q'%$L"!^ 9d!"$&v()Q**e*')Q'%" D~w:v-"q.l6șŜ>s&=PE% "ÙZšưɊeͬz2^ mf#'+.135Z6&6v6x6K5543210//Z...-8,"*)j'&$" V3 DgW^W*w6<ݤqדuʛɊd ǩ3ƭ.ņ[+Lͺ‘<)8^T} c : k % & C T ) ^ T "'p,17<@CFOG^G'ECH?;6x0*A#Z %O߾ Q܄ݐn90-[ t`x\T/  c ahj  R&f2֦"]У &͑zeɊ2ʮzc/ɊʅZԸYq,9LV l!KuK}  "%#%'p)*b+\,",-. .- *'U"! `=n=$ݒֿ%ΕOz3ȁVș2"[ͣ 7Է֯!)A' V$7)Q.?27A;(>AHCMDEDDoCBA^?=;852/,*'p$!;5 % ~/XEmQͦˊșoiǩȷ|zmρ 2=!w`n  %yP9Kp M4K/$: $Qy! ! y  <'ݟBߍ\\ G /yE3<#Q;m!$'p)+l,./50y1222'/,"'!0/ ߜ?׭҃аF<̶͆[9kɊȱǞǩ?o-Kς}EzտK{(#T)W#T "(-4158v:<=E>D?%?@J@e@5?????>>=<;(9847$6v6 5431.*&! \mnr- ـ>ȠN</qݻH>\ T ZQZE $K'p*}-036j8:R;(;7:9E7g41-)Q$b C EvXGQBKL7 ʲǪP,T]TdxνTKQi&&d%%#!;3. }@/=s cM N D =1:S[O&Y )Nvh2ٔ0҈xεK5hz`ʛA[Ϲ,Qނ:X8wcn T MJ!$)&](g*A+-b./01210/f-m+2(&$"  Z /e_+K9BOM9")v)RQO  T xo#mtI?3.H G TE8SoguR߸ySQuڸـج؂ؐBq'2ߢB.X~(nCH c  T  ; D % D pzB?4 % [ T r c g T 0 X - _i T s/~d!`s" rss a . D y f  T `9Kin4 %7X i`}99-7EuXRRDw"J;OeBys = D 5M/h.TQ m % C p T  > "$G$mntXQKgugtXXgT1w ^||iKLg.]DLxC|S"VGnn^^$,^^ni^/ ;ob.h+]\ Zyy^ c ` sIDYs}su c 0 G _A*1nyH$w < } D JsYuCG vntk2V)!FW+XDZV2G@)ggXO%)>E+3n% Cs i %x/`o96UA  T Ps}C";" c [ w T s9}E+rN07#;9C^E}JB_R /MOenVmvOh).GXw9Ez` nQ`  OOD^^Y^ +SK QK.k D t_*)(l5ja6 zs e / u  D /u0e XLBX2ޅ/  $] |g*w2doGdgBont )bs ~ T pZ  GVJYJ;<NhytRq % z _^& -ZUr6{n@O /Jb^_r|!~O9NT6 4@ @i@>=J;H86v30-)Q%\!PJZs Dr7{nR}w 4*IYB Zf"&)+-.///z..7-S,O+2*('&%{$#"! m 6E DEJBvQסΐz.;-B ɊL)ךڃݣ4DMLOSD  );UiX7>+ D,Ry] o/."HsRY A @%+20z5,8;(;;&926v3[0",)Q%X l }9!)m$1dPO)K^k: 8n!X>)wN$s#eh`E5/͞[WʠOz/<"ӲQgs2H^T9 g" R y#'p+/448W;>@AB4BGBAA?>R<9b6U3 /,)t&'"@ % Q%S)#ܫ؅с|ːșŕ©EfK٦#Rn \;Z;0 ;7Z*yZyy  &3<DĻtHJmHl>"CtCșDҊտ4 e;y!$B&())1))Q(j&$!fM <\Z9rF`a2A*X7.qpYXgny DPB!(/6X<@CDDC @=;(8V5e2.) #(h :HoX:)n 9^P7Q, I)e`  D3 % fMaAR|BN_YB6Sݨ2߷eXT 6 d'd ^ s b; i%+17=;?cACCD)Q-2&6i:8=c?ABCVCCCCB@d=:7)3.*&"  78EFݳٗխ΋ZmpiE6tԼྥ Rʾ<'#&> TtZ/ !"."""""P!! >5 vZ1 9 tb KĀYdf/]tm:}*Tp<:D5wCa Zra. "m#$%%%?$;" K} % 7p,|)a6w<# B# ~ +$A(,d.0c000.-G+R)&#`E 0 #^0@Q/{O D  s(Lh5cJ_SsD^ &^݉ڌ@֯ոԈ_ҙӱ֯_=r#W9cj  %{Z #'n+/3695:<=">'?"?@?Q=;(841[.*&"<u S E2}/̀cE!Tƿ‚.1ș`lњT\?e D}=!&+/37':j=\?ABC BA?=;(840,"'c"Vy c9iqaҼp[]mÞfFtCZtǩ{ϑؐm9 lZ!%)Q,/L1W23|3333921h/-+)/&# ;R^vr:  l<c|K6wR *bhn ;"*0058:;`;(:987g53V0',"'_" [ QK0C$*Ok c |I7F  G/ O! ^ 99x 2>n[9ƌ-!Tw²ČɊՂqߊ)| = c  3 #O.!#g&$)Q,0I36v8;=>@AB#A@g>?;|8W41d-)Q$.$ [agN?ـ KȦơ^Uǩɣ˱|Bـۤ$-J< oYXZK#',"0I47n:8? ?@D@T?>=(:7c3/+i'#"(Q= O0tl9g"x^h^+GEjɠ<+Sݚ#Pq DNZ !"! ~Kg :e(79OtO,^")T"տ :w2{uso  0; `.~gy9 c ~"#* {  c]i^6lOO)%<ݟR]L@˴zrȒǩC[ؐ6.O DIbd c"#%i'7)!+2-v/258]:=6>@@ANAB:BCVCC^Bg@=:62.)[$KU?g֯ҵ ˯șm&pg‰/ǩxk͜#Qnww) y $)Q-g1$4z7g9<3>*?A3BBIA@T>;7g33.)W#A c}MտʸUԷ_𰥭KvЩ¬;/l_tœɊBm_4 a} #&,(F)+2+,'++2*4)'&%4#"k 7KV2 4 s. 9npWs BKk!$&'m''8&%$#Q!{y/ Du*1O#  y` $'p)t*+,",g,f,+2)(%#!e6+;SW/  G3O9 9-,=ߦQ`$[`Z„EL8E2ǩʶIawJ2s VT -!"#$& 'p) + -_/2T4`56v66(5555554;1.|*A% ~ [w־ xEF/4m(7,׹=T 6kn~ DNne#&*m.159=AEGJ/LMbNYNNNMLIG:C?;K6C0+2%F qQ8-Rؿ軝==?ACE=FGHNHHQGFmDBi?<83.)Q# eQ7̳į>N9 fZ8'˩2ήLȮ8цտw   j %3H {#L%'p)*,Q./1>234~5156v7777g6u42A.*&* ;`  )H6[$ 7t L TLW4^yzoBw$X^^ C"'p+036v89:q:89p8K6532F0L.+p(%"VA eD/)7Yu2c־͐rǩhµ&!T˦<ӊֱq)K> !#%'}(*A+f,e-?../013 4P5}6v7-777g654a20.- +2)K'2$![u> WCxܔֺ ˣƝE᳏ȴ24T6Uؐ͘d$| vK !`$w'p*U-/135B68W: ;=?ACE4FmG6G{G6FmE9CA?=t:72-'!; ^_̪ȿk/GΥ 韀Hk.Z˩vt𸓽ș(9BZH   "u$ %&(1)H*A+,,-.//0123333p21/-*&"&?* O 9{5g)g:L& :8tXq0~hYsMs [yc?"%'l(?(('p&p%q$#" };M T9)n߾qթәvHϫͧ[*5mșpÎͻtMd^} E2·řșˉY_:# q(" %"%'9)G+2,.>/9/0h012345y5431/-+)'p%&"  siޟڞ֯iEɊ0.v.&@ƫJ<Ѣx٭2]oTs U ;$+(R,"/258W;=@HBDFHJ/KLMMMMPLbKIGEcB?;73.)$@ S> )tߧ؁^z .۳Kܦ ͜wǝ8;Hm0^X~ЙտbX % 9yc. "$&()*,"-/+024@5V554313.,g)&S"P i "s<Q; &Gsf-^^ )|.ec޸2ݭ!ܡQWݿ#n % " %)7,".02/34667g7J65W31/;,)Q%! V.9L#٪ؐ׫JտCY]dѩh4 X ԉhؐ:ߔl9N^2 8"%(+d.0k246v8Z:G<2=?z@AQAABB A@?j=(:863/5+2&"?y 379->ޝqӎл<=ǩƻ8€Þ)ĩǩGy HQ X "7&*/U37g:=@GBDGHJ/K KiKgKJIHmFmC@#;7g2-O'!S_ 5npӬKk.XQJ˥#˧ǩ, ^ 8$Ɋ+צQ^)t ir^ T t-yu "$'L*A-o03D57Y8:u<=?~@ABA@?>\h2=rs Y Jo"%'p*,/25w79;(<<= ====<;(9`7W520 -)%!2 w :]Xzjf-Tຶ7"d.΀Չ.= _ o I%pK!#& (**A,Q.M0%134+45565543N1/.+,+]*A)4(&%$P#="i!!M `Z{ -U h^X#c٩9 &_ѥ|=Qտ׀ه2a>^U # %pl+ = sHJ/Kt-#f݁B(@ݗ2+ux7.gR~  D Zg.K@ i P U a !.!D!% 2)KrL >ّևm̸zȁdǩɢ7KҠՔؐە޸r8< N %<Y # $&?'p()*,"-!-..--+,,"++*P)Q(&t$" ;K" j j.w߉Q&^ ?[8zʋ Kt"ն׹Q^wx7/$sF5s p - D pT(Z O!h"9""# """"?"!!!!!!!!!!!"+"#$_%%%%H$#"! Y]g' D;@/9X`2A֯Al9jM֯&ٷiBA])Fgj >Z1H.^Ey[Y/}Lށ2b? jL<) /-s 0 % r X~l D >styws sx 8Z^T)2כa ͨZZ&ֿ&*ˍ< *q~wazd" RGH]K# / B!&!"E"##$\%%s%%Q$$7##G""! *K;= cnfvـ$VПС ҸӾ0جquޠ}gs^:V( c U D  B)rZ+ "$3%&m&&&&=&%%%$c#"" !!!!!!_ N`;Z! >L>C1qX rO͠K%̿[˥˺[͢ό230TXZ)} c 6 A3 D b:Q/8dDX/&g)!7qO c 9 > + HwU` z%#:;, AK7x- ?hޗvؐ+О<%zMșF6Sș`Kϵؐ۞ަLOx 6 69!$q&)+2-L/o135v678W88|8j8W8:77d6v5,31/-+v(%!r Q 6#Cט+ Fɦǩ09^ș aԌ֖ؐڝWg;C"JK; Ros mf' #%')Q**8))Q(''A&%$#""!!!"+"# #$R% %&''<'&%$M" N XRo#܍ڱpؐӵ=W56Ytpx D K } TK nXe # ^9f_wkY6[ T @ -y`#U(9zu c ? R zi k$ % %:#aqKvGs9>d-t]WĦƊș?Ϫ(4Aqu',SJ9E;W W $'+2.2J58W:<>y?@AAA@?y=;(8{52c.+3'" J DRnݨqxTEș48ž@ș7ɯz˜dKC?0 ~&Խؐ y2߶\ Z"0&Q*A-1356707b7g7Q7654%21//o/0134J5e6v78:<=>???><:8625,&UsXb*֯zΆǩQ&-?LdTmɊLؐܘg1O^zhs T X{eA7)wV{*/2,?Dy<G5us [ #&)I,"/14y6v7888W7642/,)O%!2 WCؐdkҡ ϹέK̎a[{̻KrvcKGjͼ<ϸмӊr׽qݏw=S  |m")J/6G83.*1% ` DpFnwJWݻqZTIu"%$l&([)+<,",,,+2* ('9%#!Fw;8 TO g2\-KsEa.#RෲPT8%ܹ:OL: "U!&*".15S8;=?A1BBCCrCCCB@I=;F8g52/,)q%!4 iXQؐ0˝ǩ,L T:"Nϰw/篡d>:]/ѸͿȥqـd"%( )v*A*++s,"-.f/136P9<?>BLE G^I:JL@MP RUwXEZ\\8[XU P|KE>{7`/(+ ^ 4bSu  <0VĪɊЛԗؐKߝpVX>yGeuO^ xm 7OhPn2 l ^{)v/6ؽ֯,P/#BBsg1+B^d> c ;$ZZJ| !"#$%&&`&8%$]"  g -<'ەـ\&҃F^5֯Jـ%ھiQݢy;jb  !I&+05{:8>C,GKKNQTWTYqZ[\[rZ;XVdSQ+MJ/E@;W5/)# t sMI)+QٚwϏ,șlN:& Ʒƴ ܲȲij~gd~ K%rEcz Z!$j&()e*p+2+++]+2+},.15o9C>Ɋ4п֯.-#}erz[ES["?^"LT_M gAoq[)Qݦrg ]oH  35Z ;"%B')+2,,<+*A(9%"$ %gwTUܳq؜L֟֯׌1|2|KkW2/}5Qܰ*ݨ2+63t5 lKm$((e,"/g2:46v7888W7y6451.+Y'#W L;9]q׉CKƦq&lBu6HÞ͟)Я>]ɸ QsK) 8S}h*# !$&)Q+.2L6v;7@NEeJ/NuRUWTXY)XhVdS)NID>92,"$s*'Zm e-DUWܯWHM)'fw9qo`dwDS:i %K a T0.>J)gC09:( _b/yEs\L4 T Hg( #&7(/)*A*>)u'%" O" s2tY# }wjN ـ؄2؎ـܩ޲=)ktw , "k#$%]%%%$i#"!! ?Ze 5 cirOH t@GQ؎L<˥uLj6)šŖǩ`P%> T F, q4K G"%e(G+q.26;a?DEHzL\ORU3W XEXXWVdSPjKFm@ 81D)Q!@18 c)~ ()7 /hof&z )DwXkC4z r 1" ` c~OX/Sdfl8 nE^V&nn.%//R!s SZ1Z( tE/ts)XxPw;gXze gf,#݋*q8u(Q$  4 X!a"-"# #"! D!=Z{PKhx&v  s2K/^wkݩW ˙Ɋo+ŠEMҼ۽Tc ș_C֍F #9<gl 9M&q0/7 T "'+'.258W:8;:97g4M0,2'p"P TY#2܄ܭB a CuYU2ܖQܽ6#3Ja9ju5s ; Ls,{g#~88&K H%/f[# T vXZS },8=;%~ TfI9 _XmU)'O. T a8 ;9 n_YF& Qcrw&Bڻx~b+&0?[˓ʔzʲ@!KαE$ڙBYE^_n {y!',"1.6:>BcDFG^G4F6DgA>#94+.'] y ?ZO9 $;n';[n :D )69BX : %{f@wS. c 6 T QCX^dOK9G  Z %:<yb-F ' cV 1^Yw2 HWDw8gW&Y6W(Fh/nwh c tQUHy.qE U D Y D ` \BV Sd p`a^D9/"ޤcQosqڻ9Q.ݠ2O,9"xb n/zg] Dy##F'p+X.135%666v54 1z.)$KJP)EegcC(Wln*4uـ ٪qnܼވM^;/zX]qgԿҏ sm׺ 2)ni^+ n#/k-jX)/Y4w/H c x R6 % Nt /Nclnq{)[XjgXJ)wgJ8oIFn# <\v[FM *;)d]}AK@= h TZ|WXt7!2m|QT|BTr)0i=|tO1))N*c V #&)Q+|-..Y...Z-+2(%_!G# s#(*wEwm |rs \ Bs:g3"lgn p M | % J 4:nCT )O0Psrm/O*hHs X^ZZKo! < cUEjt/5\3tC1nu^nacinlgdnzOf@ c [yya TmGOnRMXn ^^xKHgdg )~x}(F1gXK9z3W [y ,S"2rvXzi4A=  }!"#w#$#"!iyo^ -)X *^Yn)< N/P!F#-ss 6 3 T I 3 1 T ) D 0 T  cU ^:h) j)}X{[g XZ')ROz]E1tDATm!,,a+ywc7` FZN M/{BH|RNk%M< ##j(+oV%{;}~=mzmQd(fs? P' w^Fa/ ],UH xKi>nnO1 `Y'd Xs%XSpyvQs sJTR)= _QF s 5 c c *sUNZss" z-hf#L%`%CHV  ;F;  Mkb O nVT_nz{n]QTn%^w^JCL^oun^NHN^nvo^LCJ^uz^<'0^:O4^6/B^tzp^NGL^}OI/lx^//]xk/FOO9/ Dvh+l  n.  hm; /^n4;IKZWv.J &D #  T&"(a9J2SOu=D<x0!\L!% <{(2!?m: ?T'9#l2YH  L@R@H  #! 5ev@EJdGX$-A9}= .ec"KD?}'`'l/ <Rs; :&M>~.~l*';(H[=E3IM+/>O~^>n}/EU4Dn}n{^4OXXTOKIKOSUTOHEGOX]ZOA:>OcoiO*O5/ bs ERB YGA~*h  `! r/s,/O#"9OG^^^mnnjksk'#?- ;nH2 n6Cu#GQu(+y=/MG4p(XMPAE^^>7F^pul^RMQ^wOZ/XV?/?v ]oT qv Q/!!(/1-)/I| z 1hNLt>i '%! P#.  pVJ{4~Dd)"[L)i C*/^fnnUKTnnK5?n2Ok 0w8 2gyncC3\-J3['!'I?mY4P9 R[*$)}h+$Ys s  k x c \ T T ` c q ^ s ossmzs1(m /5=e#Aii/#2?/~OuU^z^nbfmnf]^nn5D:m\!nzi_nn~?fDP,n=Y^hOh -E /}Oz/ ;nc!oL^Gi?~Kk`_{* Cp~ {J/&(-/,('/@PP/nOi^R,n`F a$n.6zO9n#egKD_m[*4 uXsgNiPbC|t:O BnO-/' _/ +:/OO| $mW7Fi'kz"%aZ?E>- c' AU"q8N( I 8Dbl'b+>c`//EN/cOhn<nO+/ *00 s//c jU]e/|(? |4?t&9IsJ;|FH}_}GGJ}~\znw0$nb&"Sd $ hX)tLh88 ^9/10,/I QC/?59nn5-8/2/@l1vIJlyr!]Ozm+4y<q 7V| Q Uy4g^,K ~a^3nZ6iq/hs<VQMrK :7^L`P]g%^ fns-& OT n) V FI|O ^yl^O?WnS[^/Y^\k)`Ynrfg1F)M;YnCk-,o/H+qO&J VvZW *3 jAcn) k'^A.T/ fZnC+K#^6>/OGs"m j\N { c-/@n4t#l 1O'rY1Z0R_/ee/_S#&^VEc^#2P7J+/^AMz$/ z!^&[XKOz3zOxBl=/2V s " rH/##b_!'/5 iss$@ u1RZ T Tzkui D b/\SVZcj<$/}qu#&_ `$f Ksoj^m3 *3 HcO\E_L 7 Mr^W/2l|}/^i/O3T7--^VO+4MnluOz>iO_ /G,$7  Pp^gBmah Dn:+uOA^]M'nv^n5w/V^NS.64-Z^5^K)[yZ^g^9^H4n9 \C_n``eO/CQ]_VSSV_[bJ~/ oq^w 'JLOnX'p.4Og'/lO.79n2^H^*^' ^|ai.nQOy ?/93;h3nc!9gOAnWH^ dX) !Cgc?tg?}iH DO^O RXvn5}OhHZeZXT  %.\gOti"/GO/KT c ! W 7 ce:/x $;5B ' T tbQ|s  r D CL0s&QOy6q~W"/Z[/zOznC2 {wnt^ OE@u2KPO?~rx"/& j cphr wn T * J c_(;/'HsnzOs rjsV c*/B'I/snDiN/ZSS]yZnKz/,*l DOLu/yr1//{^^^=eh $ ^vO;={/G-2B =/.&/X+ ^s7r sw-OHD#8?JG^v^ Y^Hdc/W cn"h ybTX_:/D z!YO &ntzOO<'n&^zs>[OXR/bCaB/wX^p kn;^S@NO!\-n"*K\O3)J w/r)cb^cm^2)w^f|JG9m9Q^03XL)qXSz^9YNx 3O +^(M;zE^rYVT>3; "/fTt^P;}pi7ns,ndysgNT1-OU6y c  cf".// T K)/Mw/-ns)P:^L >~4 # :sn^. c s/^D)6?igew`q^Z)R($#nQ ^n16  c 'zIo/8>4 c TP<4( ta: % c\{  h ? D ==s]' D vv "BtSFA % D(e =U T K s/  &snL #0nrsiSv:.^n|sq^O9_D wnNb/t +^nk6WnhV| #""[LI1bWTsOUS-&E9.OW utMBO}^^~Mrs>Tn<1(P ^p 3%woqvOF5)g^=c/6V99%un{~dHXu\^Q^ IgCGrGwC<{91^wr9dO<H"i^rQZry}{n%`ntjk( =\ _ 2syPO  % s z c ]cs/ky T ! 2 OP H s'"u #"^zV/v^^`.U-sl l^^]1 c#^].hs K 8G=o^O/ q^(%;@ \SO7,/dr>KHP\/P^?N c pX*/O{x % N -/QWI|C c { TQ/Z- % % pj!KN1 w c^dNs #  * T?EO\s G +6s /-'nbr>j&4;/Z0t"#@nWOG <f n:~Cnv[_ n hqaz M~nOp\ sR_Q(n>+52I{O]^sU*n%\O60K UM4Q/d9fN)J/?U~9og+ O 0?/7`9W W OMzX gE^ 5$Xm^ J>[F|D|1tlc;CF/^jn( !u>_Ot/QIHx_nD +s > e D `/ZFB c sY &8^;?d.s !om/O~ sPbOOCJa/{N@/(q'm{$K^{sA+ e< nVXaH"Dqsi_GO B& c & ' 6 D q^ m`2 % + c$G ]v @ 5 T "O`Go\ c W Tp  :8q ( }) T\pb v % s CDS 8# T n D e%0T? c 6 nW^a( ZV` na: >Q_^!-t" R Ih5!O|h7 & @I` /hq cWjm^h|b=l Ou/:ma q cl nF +U? C _s "_n0z&$(]OynnHzB c /OEq Dvn T 6B(9^SZ #1I?@O o3}x  [w[%\)YRn| zJ O Z};%s^z*u^AJd ck'%O`JiR c q Tj['/   c 6hp^L~/)Fu w D 6> 0= D T f ^WmwbR Y h D s C & % = ?/A.^7ddMn6^u' B<+)U9<)T9f\\vJ/pcl-iO8/nI`KnSN/<#H Y+%L#Hn _81/2=nfSss <n3KNLT^9BAdV&5O /K/CuE^L/9'`Xrd^-n#f{9x9^'O&9tfs/nA79OPL \gAB)nPb^wL)8( j5Zx {XhO c :?^Hb^) G+^;_XW n *E9rIx^ 4hg<XdOd9^W^) tu+) 892Sa 2m{9{tn+(aH)S%<})X0Wn#8w^\.x1_OZlU] T5_nep/cW l . }/p^J@ F D  96 0s C ? C Tp/dAU T 12/(^@&'#vnOR>:sYO|  xO!_zWBf/3 ]^G :\Z)SV?^^q9.s^V )~| (_ ?K)1\^Eg4l`)< nOnK M0)^STN %n!( :0j:-2<?/ ^"bz/b\n y |nu?#[tsL ^k/ & cFh,/w1I| T   QT tBg  ckt*OTcI+@  "E=9pd)0>S/Q-yX|=yBgCg1w,n}?Bgr3{)0 T^CYNXJlA/_/gVc kO#4R{>5}P6^6@/KPO^gOIE)}}5^:M^LW ] T ] yHK 'C D ip hf  D c.!s Y o + TaY . S dx{  %  clu > ; D 0 l^z fe^d=5;H tQO/k")|| 0OVj9xsYZ/ [ZNtk LB^<{E^XuYJx?{^y#_uT_x_^^ { c0'Ou6 T C d c2/~O T aA^T/vNs:. nKKnR_,4|)gn1sd0ng $=Punn 'y;h2DZwsTIO#AUs<HCs6O@KU!FOn.Y| T bOn -r2:& $PhI^ % }(P^ ^As){^d1Zz}@e|8:cOt S/99 0)/1++)7@/t^ZbO)H3ot h?C?n{_ iEWt:n,OF=  T`O]s) T s ) p T TV_O*R^(n,^'7X xc-( n _u?g9)LhF9n9d1wVC^C 9NR9~"/}O:g}a^//5g9A,uo qOB*^R/@@*>h@sKmwu^Aq/,3Yd #wkc 24/o[ c BOl T *GOr^:@0Ss*01^uN+??jGkz^)#< 0 T ] #O4 T /nOpmj]k/~.OOYJ URT rF0C ^w'kn!nh g'axLr^Q[YT T X 7 D -Q !. !? bPoe c v/r ` cSeuA % U afd< $i E 4 9 + * )sy|o| EV  cwn J42+[9Oi8yOxWMWA.LIPng4;n~4{OZbbLn*s?(BS/B =J,=^BIwH:^}sT*^ (  W c[2O.Ddswbb^i^P|(=./Z {t 9 b;BO9\'w9h7VOUKu92{.^@XV^%R)!C)lqO(X9`^-v). /U^ q/^EOOusJOsOXI|Li7] NZ#nx  x7{t ](RQ4C $bu VSvnA p/8 ,{? ! (K0\G6u<u$<+H&']?/F/ )nRE _NX$^O"/ */- t{hM$]))"m' s  B c s s k c c j n c @ sE:OssYNZss[Q[ssUENs * c  T ~ { T +  # T " D O K F D G J I D @ @ E D 2  T w c U 2s]GhN8G\$9=!/ (/OwZ^jkc^qOO^Bnq7m.t'oC ^)a_z} c~?n:Y^eO^/z ;?0 #Mk/(1^x)" y?_RS!#  ,+T  ,0, /5O n(QEh^> -!ks?zOs^))pp)L9Ep)t: :41Q4m{?n?^^_~O{/D<./L kAyH  AEU#a @n&K!*~ebZZ'a CSH _/ /Y i|fyKA  c  * T  D ;  T  c "s  c c D > N c e ?seD}>5vp ^6]2>*SM /&O&(?O? ^n!s}T}8/;rN]K7k^z;|s  I c q u p c S G J c  T q s e T M Q Y T 6 c 1 # 9 c c -s n%e F>&iq \2@6]/O69EOPLJOZedO#^#n#3x |'+7FyK(FnnRm^/FWFEG`YShDP T/;.4I>C   -62  Mng Oy_^W1n`F [3"p%eS.)4=:))LbY)J9X)FC1)>wSdLD]CvG))SHWD DtgOKX2%i9%n.%ORGCOcrlO' O4/;0m[C"N.PQ(M.Z\Sj%FM/,& r =}#*zL HKEN:0IwP L oOOO^^Oc`UOS]`O#^;5E^rvl^^~O| )ZX"| .Cs - c cEKzg}?{2vn0{;U5I ss9jC}+ss!!l/Y$eV y #Ono|~nTCKnnhiou;Wbl+fGi u,k. nnYU`ntqjn^^2 2^^^/ "  /XF%s)845- WAvNGOP/ O*&8OV9^C]N?>nrd\n#^OM/`aH/4c .`HgN4fz4? $n/-i"7%SP(;&_%PF}8j0<G=|)f  ]j&=2F*G _2/Idc/?O2OYPCO//^in O/;0&/S aT Y" MJG c } c p T } T 2 ) 8 T l t i T A ; C T c h a T I G L T W T O T o D D y T 4  cyssG&t+.~Dkoh:W 4l+#[PaU( Y-/Omh/BO^8&3^^:z.3up.@ cSm_~^)=O/ (   // d :{%-4s,(8 W7y E1H.\'el9 !% /^kRn)^OkR^(_Db1+kN$M )/{)O69=:39Y)U^I) )43*)@wXoWH))@n kYbZBt]J ^AOOMMOQQPOPTVO6^zn^O//~Os/WT2fEu#[9%hV+p/nVk<)< V_.:/T"]3n$kKy)6-k+dXnx%2 Oqd V!/v X/1JT/FO!(EO+^(/)&Nr./Z,ELXAP)sslws2$.=u(Fs C d c V L Q c | c (sen{sADNjo39 u3{oO*+sW]n&n/7TSYnn)l>v(W?COBH/ Ok/// /QOO^/ap_/lOwR^ O/1 y}"'Z:_oNi6"d wsBhj6 "18 >bO"!NPrU><Jx375|):#9e)Jd3=1DF{;p))P[J) )V{ux]s(D`w8^Ox/yO*=/ ;P@lF!d 9vHMZ\a/Rk' ^Wja}0%2rTT+ Fn?  S,.  p k/eOO}  %"ku>S3_*S' ^Oxnq^OO gkG @ D$.)` ]BxMx @(ss THdDP odM- c 8 cimu+wKB >4 UHS RrnGet@ /^uXn'^OO"wI|*?Dmn+6~5 z^C/rn/QOOP/| GZN L/\n" << "\n" << "
\n" << "
\n" << "
SuperCollider " << folder.asString.toUpper; if(doc.isExtension) { stream << " (extension)"; }; stream << "
\n"; doc.categories !? { stream << "
" << (doc.categories.collect {|r| ""++r++"" }.join(", ")) << "
\n"; }; stream << "

"; if((doc.title=="Help") and: {((thisProcess.platform.name===\windows) and: (folder=="Help")) or: {folder==""}}) { stream << "SuperCollider " << Main.version; stream << ""; } { stream << doc.title; }; stream << "

\n" << "
" << this.escapeSpecialChars(doc.summary) << "
\n" << "
\n" << "
\n"; if(doc.isClassDoc) { if(currentClass.notNil) { m = currentClass.filenameSymbol.asString; stream << ""; if(currentClass != Object) { stream << "
" << "Inherits from: " << (currentClass.superclasses.collect {|c| ""++c.name++"" }.join(" : ")) << "
\n"; }; if(currentClass.subclasses.notNil) { z = false; stream << "
" << "Subclasses: " << (currentClass.subclasses.collect(_.name).sort.collect {|c,i| if(i==12,{z=true;"… see all"; }; stream << "
\n"; }; if(currentImplClass.notNil) { stream << "
Implementing class: " << "" << currentImplClass.name << "
\n"; }; } { stream << "
Location: NOT INSTALLED!
\n"; }; }; doc.related !? { stream << "\n"; }; // FIXME: Remove this when conversion to new help system is done! if(doc.isUndocumentedClass and: {Help.respondsTo('findHelpFile')}) { x = Help.findHelpFile(name); x !? { stream << ("[ old help ]") }; }; stream << "
\n"; } *renderChildren {|stream, node| node.children.do {|child| this.renderSubTree(stream, child) }; } *renderMethod {|stream, node, cls, icls, css, pfx| var args = node.text ?? ""; // only outside class/instance methods var names = node.children[0].children.collect(_.text); var mstat, sym, m, m2, mname2; var lastargs, args2; var x, maxargs = -1; var methArgsMismatch = false; minArgs = inf; currentMethod = nil; names.do {|mname| mname2 = this.escapeSpecialChars(mname); if(cls.notNil) { mstat = 0; sym = mname.asSymbol; //check for normal method or getter m = icls !? {icls.findRespondingMethodFor(sym.asGetter)}; m = m ?? {cls.findRespondingMethodFor(sym.asGetter)}; m !? { mstat = mstat | 1; args = this.makeArgString(m); args2 = m.argNames !? {m.argNames[1..]}; }; //check for setter m2 = icls !? {icls.findRespondingMethodFor(sym.asSetter)}; m2 = m2 ?? {cls.findRespondingMethodFor(sym.asSetter)}; m2 !? { mstat = mstat | 2; args = m2.argNames !? {this.makeArgString(m2,false)} ?? {"value"}; args2 = m2.argNames !? {m2.argNames[1..]}; }; maxargs.do {|i| var a = args2[i]; var b = lastargs[i]; if(a!=b and: {a!=nil} and: {b!=nil}) { methArgsMismatch = true; } }; lastargs = args2; case {args2.size>maxargs} { maxargs = args2.size; currentMethod = m2 ?? m; } {args2.size" << "" << (pfx??" ") << "" << "" << mname2 << "" }; switch (mstat, // getter only 1, { x.value; stream << " " << args << "\n"; }, // getter and setter 3, { x.value; stream << "\n"; }, // method not found 0, { "SCDoc: In %\n" " Method %% not found.".format(currDoc.fullPath,pfx,mname2).warn; x.value; stream << ": METHOD NOT FOUND!\n"; } ); // has setter if(mstat & 2 > 0) { x.value; if(args2.size<2) { stream << " = " << args << "\n"; } { stream << "_ (" << args << ")\n"; } }; m = m ?? m2; m !? { if(m.isExtensionOf(cls) and: {icls.isNil or: {m.isExtensionOf(icls)}}) { stream << "
From extension in " << m.filenameSymbol << "
\n"; } { if(m.ownerClass == icls) { stream << "
From implementing class
\n"; } { if(m.ownerClass != cls) { m = m.ownerClass.name; m = if(m.isMetaClassName) {m.asString.drop(5)} {m}; stream << "
From superclass: " << m << "
\n"; } } }; }; }; if(methArgsMismatch) { "SCDoc: In %\n" " Grouped methods % does not have the same argument signature." .format(currDoc.fullPath, names).warn; }; // ignore trailing mul add arguments if(currentMethod.notNil) { currentNArgs = currentMethod.argNames.size; if(currentNArgs > 2 and: {currentMethod.argNames[currentNArgs-1] == \add} and: {currentMethod.argNames[currentNArgs-2] == \mul}) { currentNArgs = currentNArgs - 2; } } { currentNArgs = 0; }; if(node.children.size > 1) { stream << "
"; this.renderChildren(stream, node.children[1]); stream << "
"; }; currentMethod = nil; } *renderSubTree {|stream, node| var f, z, img; switch(node.id, \PROSE, { if(noParBreak) { noParBreak = false; } { stream << "\n

"; }; this.renderChildren(stream, node); }, \NL, { }, // these shouldn't be here.. // Plain text and modal tags \TEXT, { stream << this.escapeSpecialChars(node.text); }, \LINK, { stream << this.htmlForLink(node.text); }, \CODEBLOCK, { stream << "

"
				<< this.escapeSpecialChars(node.text)
				<< "
\n"; }, \CODE, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \EMPHASIS, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \TELETYPEBLOCK, { stream << "
" << this.escapeSpecialChars(node.text) << "
"; }, \TELETYPE, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \STRONG, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \SOFT, { stream << "" << this.escapeSpecialChars(node.text) << ""; }, \ANCHOR, { stream << " "; }, \KEYWORD, { node.children.do {|child| stream << " "; } }, \IMAGE, { f = node.text.split($#); stream << "
"; img = ""; if(f[2].isNil) { stream << img; } { stream << this.htmlForLink(f[2]++"#"++(f[3]?"")++"#"++img,false); }; f[1] !? { stream << "
" << f[1] << "" }; // ugly.. stream << "
\n"; }, // Other stuff \NOTE, { stream << "
NOTE: "; noParBreak = true; this.renderChildren(stream, node); stream << "
"; }, \WARNING, { stream << "
WARNING: "; noParBreak = true; this.renderChildren(stream, node); stream << "
"; }, \FOOTNOTE, { footNotes = footNotes.add(node); stream << "" << footNotes.size << " "; }, \CLASSTREE, { stream << "
    "; this.renderClassTree(stream, node.text.asSymbol.asClass); stream << "
"; }, // Lists and tree \LIST, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
\n"; }, \TREE, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
\n"; }, \NUMBEREDLIST, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
\n"; }, \ITEM, { // for LIST, TREE and NUMBEREDLIST stream << "
  • "; noParBreak = true; this.renderChildren(stream, node); }, // Definitionlist \DEFINITIONLIST, { stream << "
    \n"; this.renderChildren(stream, node); stream << "
    \n"; }, \DEFLISTITEM, { this.renderChildren(stream, node); }, \TERM, { stream << "
    "; noParBreak = true; this.renderChildren(stream, node); }, \DEFINITION, { stream << "
    "; noParBreak = true; this.renderChildren(stream, node); }, // Tables \TABLE, { stream << "\n"; this.renderChildren(stream, node); stream << "
    \n"; }, \TABROW, { stream << ""; this.renderChildren(stream, node); }, \TABCOL, { stream << ""; noParBreak = true; this.renderChildren(stream, node); }, // Methods \CMETHOD, { this.renderMethod ( stream, node, currentClass !? {currentClass.class}, currentImplClass !? {currentImplClass.class}, "cmethodname", "*" ); }, \IMETHOD, { this.renderMethod ( stream, node, currentClass, currentImplClass, "imethodname", "-" ); }, \METHOD, { this.renderMethod ( stream, node, nil, nil, "imethodname", nil ); }, \CPRIVATE, {}, \IPRIVATE, {}, \COPYMETHOD, {}, \CCOPYMETHOD, {}, \ICOPYMETHOD, {}, \ARGUMENTS, { stream << "

    Arguments:

    \n\n"; currArg = 0; if(currentMethod.notNil and: {node.children.size < (currentNArgs-1)}) { "SCDoc: In %\n" " Method %% has % args, but doc has % argument:: tags.".format( currDoc.fullPath, if(currentMethod.ownerClass.isMetaClass) {"*"} {"-"}, currentMethod.name, currentNArgs-1, node.children.size, ).warn; }; this.renderChildren(stream, node); stream << "
    "; }, \ARGUMENT, { currArg = currArg + 1; stream << ""; if(node.text.isNil) { currentMethod !? { if(currentMethod.varArgs and: {currArg==(currentMethod.argNames.size-1)}) { stream << "... "; }; stream << if(currArg < currentMethod.argNames.size) { if(currArg > minArgs) { "("++currentMethod.argNames[currArg]++")"; } { currentMethod.argNames[currArg]; } } { "(arg"++currArg++")" // excessive arg }; }; } { stream << if(currentMethod.isNil or: {currArg < currentMethod.argNames.size}) { currentMethod !? { f = currentMethod.argNames[currArg].asString; if( (z = if(currentMethod.varArgs and: {currArg==(currentMethod.argNames.size-1)}) {"... "++f} {f} ) != node.text; ) { "SCDoc: In %\n" " Method %% has arg named '%', but doc has 'argument:: %'.".format( currDoc.fullPath, if(currentMethod.ownerClass.isMetaClass) {"*"} {"-"}, currentMethod.name, z, node.text, ).warn; }; }; if(currArg > minArgs) { "("++node.text++")"; } { node.text; }; } { "("++node.text++")" // excessive arg }; }; stream << ""; this.renderChildren(stream, node); }, \RETURNS, { stream << "

    Returns:

    \n
    "; this.renderChildren(stream, node); stream << "
    "; }, \DISCUSSION, { stream << "

    Discussion:

    \n"; this.renderChildren(stream, node); }, // Sections \CLASSMETHODS, { if(node.notPrivOnly) { stream << "

    Class Methods

    \n"; }; this.renderChildren(stream, node); }, \INSTANCEMETHODS, { if(node.notPrivOnly) { stream << "

    Instance Methods

    \n"; }; this.renderChildren(stream, node); }, \DESCRIPTION, { stream << "

    Description

    \n"; this.renderChildren(stream, node); }, \EXAMPLES, { stream << "

    Examples

    \n"; this.renderChildren(stream, node); }, \SECTION, { stream << "

    " << this.escapeSpecialChars(node.text) << "

    \n"; if(node.makeDiv.isNil) { this.renderChildren(stream, node); } { stream << "
    "; this.renderChildren(stream, node); stream << "
    "; }; }, \SUBSECTION, { stream << "

    " << this.escapeSpecialChars(node.text) << "

    \n"; if(node.makeDiv.isNil) { this.renderChildren(stream, node); } { stream << "
    "; this.renderChildren(stream, node); stream << "
    "; }; }, { "SCDoc: In %\n" " Unknown SCDocNode id: %".format(currDoc.fullPath, node.id).warn; this.renderChildren(stream, node); } ); } *renderTOC {|stream, node| node.children !? { stream << ""; }; } *addUndocumentedMethods {|list, body, id2, id, title| var l; if(list.size>0) { l = list.collectAs(_.asString,Array).sort.collect {|name| SCDocNode() .id_(id2) .children_([ SCDocNode() .id_(\METHODNAMES) .children_([ SCDocNode() .id_(\STRING) .text_(name.asString) ]) ]); }; body.addDivAfter(id, nil, title, l); } } *renderClassTree {|stream, cls| var name, doc, desc = ""; name = cls.name.asString; doc = SCDoc.documents["Classes/"++name]; doc !? { desc = " - "++doc.summary }; if(cls.name.isMetaClassName, {^this}); stream << "
  • " << name << "" << desc << "\n"; cls.subclasses !? { stream << "
      \n"; cls.subclasses.copy.sort {|a,b| a.name < b.name}.do {|x| this.renderClassTree(stream, x); }; stream << "
    \n"; }; } *renderFootNotes {|stream| if(footNotes.notNil) { stream << "
    \n"; footNotes.do {|n,i| stream << "
    " << "[" << (i+1) << "] - "; noParBreak = true; this.renderChildren(stream, n); stream << "
    "; }; stream << "
    "; }; } *renderFooter {|stream, doc| stream << "" << "
  • "; } *renderOnStream {|stream, doc, root| var body = root.children[1]; var redirect; currDoc = doc; footNotes = nil; noParBreak = false; if(doc.isClassDoc) { currentClass = doc.klass; currentImplClass = doc.implKlass; if(currentClass != Object) { body.addDivAfter(\CLASSMETHODS,"inheritedclassmets","Inherited class methods"); body.addDivAfter(\INSTANCEMETHODS,"inheritedinstmets","Inherited instance methods"); }; this.addUndocumentedMethods(doc.undoccmethods, body, \CMETHOD, \CLASSMETHODS, "Undocumented class methods"); this.addUndocumentedMethods(doc.undocimethods, body, \IMETHOD, \INSTANCEMETHODS, "Undocumented instance methods"); body.sortClassDoc; } { currentClass = nil; currentImplClass = nil; }; this.renderHeader(stream, doc); stream << "
    \n"; this.renderTOC(stream, body); stream << "
    "; this.renderChildren(stream, body); this.renderFootNotes(stream); this.renderFooter(stream, doc); currDoc = nil; } *renderToFile {|filename, doc, root| var stream; File.mkdir(filename.dirname); stream = File(filename, "w"); if(stream.isOpen) { this.renderOnStream(stream, doc, root); stream.close; } { warn("SCDoc: Could not open file % for writing".format(filename)); } } } SuperCollider-Source/SCClassLibrary/SCDoc/TODO000644 000765 000024 00000015061 12321461510 022116 0ustar00crucialstaff000000 000000 TODO ---- - should we allow *.ext.schelp to add to related:: and categories:: ? - clean up old-help compatibility, do we really need it in both HelpBrowser-goTo and SCDoc.findHelpFile? - HelpBrowser: clean up openNewWindows setting. only have a single class variable? - how to merge methods docs for overwritten methods? replace the whole method doc, or add to it? - copymethod:: should we warn if the method signature is not the same as the target method, if any? what to do with method argstring when copying from non-class/instance to class/instance and vice versa? should we cache last used parse tree in the common case of copying many methods from the same source? - Additional triggers for dest-doc should update: - implementing class changed if(doc.redirect.notNil and: {doc.implKlass != doc.klass.tryPerform(doc.redirect.asSymbol)}) but this only works if doc.implKlass was the *old* implementing class.. so in this case we actually need to store stuff on disk. - another docs metadata changed (for link:: titles) not sure what to do about that.. actually it must be solved by a dependency system. docs that links to other docs has those as dependencies. - class hier changed (for classtree:: tag) this means we need to know if a doc uses classtree::, could be marked in the SCDocMapEntry. also we need to store last class hier on disk, or just always re-render docs that use classtree:: (once per session) - SCDoc.cpp: replace node->children with a linked list (node->next and node->tail) instead of realloc'ing? same for text strings instead of using strmerge? or realloc in blocks? - also write the arg string and the first line of each method description to a methods.js, to show in Search. - private:: now counts as a subsection (like method:: and copymethod::) this means it is a section that can't have any text in it, meaning it needs to come after any section text. an alternative would be to use the syntax: class/instancemethods optprivate subsections but that would mean it *must* come right after the class/instancemethods section header. This would be a lot better actually, since we can then collect all private methodnames easier instead of having to scan the whole section! - deprecate keyword:: and introduce a keywords:: in header only? one could then optionally use anchor::kw_word:: to set kw locations in the doc. the idea is that it would speed up metadata parsing, but I'm not sure it would. - error lines are not always correct, probably because many tags eat trailing newlines. but if we eat newlines before a tag, it will break EOL termination detection.. - move inherit-mets from JS to renderer. get rid of docmap.js loading in docs. Export those lists locally for each class doc instead. OTOH, that means that we write the whole Object method list into *each* class doc! Not so nice.. so keep it like this for the moment! (then, do we really need the subclasses/superclasses in docmap.js? yes, maybe for method search results ("class A inherited by B, etc..") but then, at least only write it to docmap.js, no need to store it in SCDocMapEntry.) * Adjust or deprecate all old classes and methods related to help: Classes: AutoClassHelper HelpSearchResult UGenHelper AutoClassHelperTest TopicHelper Help ClassHelper Helper Methods todo: *Platform, Platform : helpDir - deprecate in favor of SCDoc.helpTargetDir ? PathName : helpFilesDo Help, *Help : findHelpFile - Used by SCDoc to get old help, fix this when all old help is converted Help : findHelpFileOrElse Class, Method : hasHelpFile - in SCDoc all classes has a helpfile - even if it's an autogenerated stub Methods to deprecate? AutoClassHelper, ClassHelper, *Help, TopicHelper, UGenHelper : makeHelp Helper : initHelper TopicHelper : initTopicHelper UGenHelper : initUGenHelper *Quarks, Quarks : help *Help : makeAutoHelp Integer : isHelp AutoClassHelper, ClassHelper : initClassHelper Methods done but could be improved: // Class : helpFileForMethod - FIXME: should jump to method anchor // Method : help - FIXME: should jump to method anchor Also deprecate class.categories since this is now in the helpfiles instead? (categories can still be reached run-time from SCDoc.documents[path]) IDEAS AND IMPROVEMENTS ---------------------- * description for categories? HelpSource/category_descriptions, example: Server>Abstractions: Client-side classes representing server-side stuff show in header and category browser/overview.. extensions should be able to add such descriptions too, but not overwrite existing descriptions? * comments (* like this? *) * shortcuts for links to method in class? mlink::Node-set:: -> link::Classes/Node#-set:: or clink::Node#-set:: -> link::Classes/Node#-set:: ? * render binary op methods differently? like ArrayedCollections ++ we don't want it to display as "++ (aCollection)" do we? rather "++ aCollection" or "this ++ that" or something.. binary ops only uses chars from this list: !@%&*-+=|<>?/ Crazy ideas: - make a new renderer also in C?? integrated with sclang that can access the introspection data (classtree and methods). it could use the docnode tree directly from the parser instead of going through sclang objects - or, let both parser and renderer be standalone. * introspection data could be provided by a machine-readable file written by sclang - class tree, their methods, the filenameSymbol for each class and method. C classname F filenameSymbol CM methodname F filenameSymbol A name defaultvalue A etc... XM IM methodname etc... XM C subclassname etc... XC XC but then we need also an output mode that generates sclang code for docmap construction. - even make the whole scdoc thing in C? * find all helpsource files and render if newer than html target * copy any other files as is * write docmap.json and/or docmap.scd for sclang interface, needed by find-help-for-string, etc. * docmap is also needed internally by scdoc renderer: - document title for links - class summary for classtree:: We could have a mode to only parse the header, and run this first to create the initial docmap. then when we parse all docs fully, the other metadata would be filled in (documented methods, keywords, etc) * it should be fast enough to render all updated files at startup * the process can run in background with .unixCmd, with an action to set helpAvailable=true ... SuperCollider-Source/SCClassLibrary/Platform/linux/000755 000765 000024 00000000000 13007315613 023417 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Platform/Platform.sc000644 000765 000024 00000011556 12756534417 024422 0ustar00crucialstaff000000 000000 Platform { classvar defaultStartupFile; // IDE actions classvar <>makeServerWindowAction, <>makeSynthDescWindowAction, <>openHelpFileAction, <>openHTMLFileAction; var recordingsDir, features; var <>devpath; *initClass { defaultStartupFile = this.userConfigDir +/+ "startup.scd" } initPlatform { classLibraryDir = thisMethod.filenameSymbol.asString.dirname.dirname; helpDir = thisMethod.filenameSymbol.asString.dirname.dirname.dirname ++ "/Help"; features = IdentityDictionary.new; recordingsDir = this.userAppSupportDir +/+ "Recordings"; } name { ^this.subclassResponsibility } recompile { _Recompile } *case { | ... cases | ^thisProcess.platform.name.switch(*cases) } // directories *classLibraryDir { ^thisProcess.platform.classLibraryDir } *helpDir { ^thisProcess.platform.helpDir } userHomeDir { _Platform_userHomeDir } *userHomeDir { ^thisProcess.platform.userHomeDir } systemAppSupportDir { _Platform_systemAppSupportDir } *systemAppSupportDir { ^thisProcess.platform.systemAppSupportDir } userAppSupportDir { _Platform_userAppSupportDir } *userAppSupportDir { ^thisProcess.platform.userAppSupportDir } systemExtensionDir { _Platform_systemExtensionDir } *systemExtensionDir { ^thisProcess.platform.systemExtensionDir } userExtensionDir { _Platform_userExtensionDir } *userExtensionDir { ^thisProcess.platform.userExtensionDir } userConfigDir { _Platform_userConfigDir } *userConfigDir { ^thisProcess.platform.userConfigDir } resourceDir { _Platform_resourceDir } *resourceDir { ^thisProcess.platform.resourceDir } defaultTempDir { ^this.subclassResponsibility() } *defaultTempDir { ^thisProcess.platform.defaultTempDir } // The "ideName" is for ide-dependent compilation. // From SC.app, the value is "scapp" meaning "scide_scapp" folders will be compiled and other "scide_*" ignored. ideName { _Platform_ideName } *ideName { ^thisProcess.platform.ideName } platformDir { ^this.name.asString } *platformDir { ^thisProcess.platform.platformDir } pathSeparator { ^this.subclassResponsibility } *pathSeparator { ^thisProcess.platform.pathSeparator } isPathSeparator { |char| ^this.subclassResponsibility } *isPathSeparator { |char| ^thisProcess.platform.isPathSeparator(char) } clearMetadata { |path| ^this.subclassResponsibility } *clearMetadata { |path| ^thisProcess.platform.clearMetadata(path) } // startup/shutdown hooks startup { } shutdown { } startupFiles { ^[defaultStartupFile]; } *deprecatedStartupFiles {|paths| var postWarning = false; paths.do {|path| if (File.exists(path.standardizePath)) { warn("Deprecated startup file found: %\n".format(path)); postWarning = true; } }; if (postWarning) { postln("Please use % as startup file.\nDeprecated startup files will be ignored in future versions.\n".format(defaultStartupFile)); } } loadStartupFiles { this.startupFiles.do{|afile| afile = afile.standardizePath; if(File.exists(afile), {afile.load}) } } // features declareFeature { | aFeature | var str = aFeature.asString; if (str.first.isUpper) { Error("cannot declare class name features").throw; }; if (str.first == $_) { Error("cannot declare primitive name features").throw; }; features.put(aFeature, true); } hasFeature { | symbol | if (features.includesKey(symbol).not) { features.put( symbol, symbol.asSymbol.asClass.notNil or: { symbol.isPrimitive } ) }; ^features.at(symbol) } when { | features, ifFunction, elseFunction | ^features.asArray.inject(true, { |v,x| v and: { this.hasFeature(x) } }).if(ifFunction, elseFunction) } *when { | features, ifFunction, elseFunction | ^thisProcess.platform.when(features, ifFunction, elseFunction) } // Prefer qt but fall back to swing if qt not installed. defaultGUIScheme { if (GUI.get(\qt).notNil) {^\qt} {^\swing} } isSleeping { ^false } // unless defined otherwise // used on systems to deduce a svn directory path, if system wide location is used for installed version. (tested on Linux). devLoc{ |inpath| var outpath; if ( devpath.isNil ){ ^inpath }; outpath = inpath.copyToEnd( inpath.find( "SuperCollider") ); outpath = outpath.replace( "SuperCollider", devpath ); ^outpath; } // hook for clients to write frontend.css writeClientCSS {} killAll { |cmdLineArgs| ^this.subclassResponsibility(\killAll) } } UnixPlatform : Platform { pathSeparator { ^$/ } isPathSeparator { |char| ^(char === this.pathSeparator) } clearMetadata { |path| "rm -f %\.*meta".format(path.splitext[0].escapeChar($ )).systemCmd; } arch { var pipe, arch; pipe = Pipe("arch", "r"); arch = pipe.getLine; pipe.close; ^arch.asSymbol; } killAll { |cmdLineArgs| ("killall -9 " ++ cmdLineArgs).unixCmd; } defaultTempDir { // +/+ "" looks funny but ensures trailing slash ^["/tmp/", this.userAppSupportDir +/+ ""].detect({ |path| File.exists(path); }); } } SuperCollider-Source/SCClassLibrary/Platform/linux/extMain.sc000644 000765 000024 00000000055 12756534417 025372 0ustar00crucialstaff000000 000000 + Main { platformClass { ^LinuxPlatform } } SuperCollider-Source/SCClassLibrary/Platform/linux/extMIDIOut.sc000644 000765 000024 00000006336 12756534417 025730 0ustar00crucialstaff000000 000000 + MIDIClient { *externalSources{ ^MIDIClient.sources.select({ |src,i| // src.device != "SuperCollider" (src.uid >> 16) != this.getClientID; }) } *externalDestinations{ ^MIDIClient.destinations.select({ |src,i| // src.device != "SuperCollider" (src.uid >> 16) != this.getClientID; }) } *getClientID { _GetMIDIClientID; ^this.primitiveFailed; } } + MIDIIn{ *connectAll { |verbose=true| if(MIDIClient.initialized.not, { MIDIClient.init(verbose: verbose) }, { MIDIClient.disposeClient; MIDIClient.init(verbose: verbose); } // on Linux, supercollider creates as many MIDI ports for SC as there are devices to connect to; MIDIClient.list will find the new sources, but there will not be a matching port initialized for SC to connect it to; therefor we reinitialize the client. ); MIDIClient.externalSources.do({ |src,i| MIDIIn.connect(i,src); }); } } + MIDIOut{ // uid is not set by connect, in order to enable several connections to one output. set the uid directly, if you only want to send data to one MIDI destination. connect{ arg device = 0; MIDIOut.connect( port, device ); /* var cuid, dest; if(device.isNumber, { if(device >= 0, { if(MIDIClient.initialized.not,{ MIDIClient.init }); if ( device > MIDIClient.destinations.size, { cuid = device; },{ dest = MIDIClient.destinations.at(device); if(dest.isNil,{ "MIDIClient failed to init".warn; },{ cuid = MIDIClient.destinations.at(device).uid; }) }) },{ cuid = device; }); },{ if(device.isKindOf(MIDIEndPoint), {cuid = device.uid}); // else error }); MIDIOut.connectByUID( port,cuid );*/ } disconnect{ |cuid| var res; MIDIOut.disconnect( port, cuid ); // MIDIOut.disconnectByUID(port,cuid); // reset the uid to 0 // uid = 0; } *connect { arg outport=0, device=0; var uid,dest; if(MIDIClient.initialized.not,{ MIDIClient.init }); if(device.isNumber, { if(device >= 0, { if ( device > MIDIClient.destinations.size, { dest = MIDIClient.destinations.select{ |it| it.uid == device }.first; if(dest.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = dest.uid; }) },{ dest = MIDIClient.destinations.at(device); if(dest.isNil,{ "MIDIClient failed to init".warn; },{ uid = MIDIClient.destinations.at(device).uid; }) }) },{ uid = device; }); },{ if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); // else error }); this.connectByUID(outport,uid); } *disconnect { arg outport=0, device=0; var uid,dest; if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); if(device.isNumber, { if(device.isPositive, { if ( device > MIDIClient.destinations.size, { dest = MIDIClient.destinations.select{ |it| it.uid == device }.first; if(dest.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = dest.uid; }) },{ uid = MIDIClient.destinations.at(device).uid }); },{ uid = device; }); }); this.disconnectByUID(outport,uid); } *connectByUID {arg outport, uid; _ConnectMIDIOut ^this.primitiveFailed; } *disconnectByUID {arg outport, uid; _DisconnectMIDIOut ^this.primitiveFailed; } } SuperCollider-Source/SCClassLibrary/Platform/linux/LID.sc000644 000765 000024 00000044077 12756534417 024411 0ustar00crucialstaff000000 000000 LIDInfo { var path; printOn { | stream | super.printOn(stream); stream << $( << name << ", " << path << ", "; [ vendorID, productID, version, bustype ].collect({ | x | "0x" ++ x.asHexString(4) }).printItemsOn(stream); stream << ", " << physical << ", " << unique; stream.put($)); } postInfo { "\tName: \t%\n".postf( name ); "\tVendor and product ID: \t%, %\n".postf( vendorID, productID ); "\tPath: \t%\n".postf( path ); "\tPhysical: \t%\n".postf( physical ); "\tVersion and bustype: \t%, %\n".postf( version, bustype ); "\tUnique: \t%\n".postf( unique ); // "\tUsage name and page: \t%, \t%\n".postf( this.usageName, this.pageName ); // "\tVendor name: \t%\n".postf( vendor ); // "\tProduct name: \t%\n".postf( product ); } open{ ^LID.new( path ); } findArgs { ^[vendorID, productID, path, version, physical, unique] } } LIDAbsInfo { var action; var <>closeAction; var debugAction; classvar openDevices, eventTypes, deviceRoot = "/dev/input", action; var rawValue = 0; classvar slotTypeMap, key; *initClass { slotTypeMap = IdentityDictionary.new.addAll([ 0x0001 -> LIDKeySlot, 0x0002 -> LIDRelSlot, 0x0003 -> LIDAbsSlot, 0x0004 -> LIDMscSlot, 0x0011 -> LIDLedSlot, ]); slotTypeStrings = IdentityDictionary.new.addAll([ 0x0000 -> "Syn", 0x0001 -> "Button", 0x0002 -> "Relative", 0x0003 -> "Absolute", 0x0004 -> "Miscellaneous", 0x0011 -> "LED", 0x0012 -> "Sound", 0x0014 -> "Rep", 0x0015 -> "Force Feedback", 0x0016 -> "Power", 0x0017 -> "Force Feedback Status", 0x0FFF -> "Linear" ]); } postInfo { "\tType: \t%, %\n".postf( type, slotTypeStrings.at( type ) ); "\tCode: \t%\n".postf( code ); "\tKey: \t%\n".postf( key ); "\tSpec: \t%\n".postf( spec ); "\tValue: \t%\n".postf( this.value ); } *new { | device, evtType, evtCode | ^(slotTypeMap[evtType] ? this).newCopyArgs(device, evtType, evtCode).init.initSpec } init{ busAction = {}; debugAction = {}; action = {}; } initSpec { spec = ControlSpec(0, 1, \lin, 1, 0); } rawValue { ^rawValue } value { ^spec.unmap(rawValue) } rawValue_ { | inValue | rawValue = inValue; action.value(this); busAction.value( this ); debugAction.value( this ); } next { ^this.value } debug_{ |onoff| if ( onoff, { debugAction = { |slot| [ slot.type, slot.code, slot.value, slot.key ].postln; }; }, { debugAction = {}; }); } debug{ ^debugAction.notNil; } createBus { |server| server = server ? Server.default; if ( bus.isNil, { bus = Bus.control( server, 1 ); }, { if ( bus.index.isNil, { bus = Bus.control( server, 1 ); }); }); busAction = { |v| bus.set( v.value ); }; } freeBus { busAction = {}; bus.free; bus = nil; } // JITLib support kr { this.createBus; ^In.kr( bus ); } } LIDKeySlot : LIDSlot { initSpec { super.initSpec; rawValue = device.getKeyState(code); } } LIDRelSlot : LIDSlot { var delta = 0, <>deltaAction; initSpec { } value { ^rawValue } rawValue_ { | inDelta | delta = inDelta; rawValue = rawValue + delta; action.value(this); busAction.value( this ); debugAction.value( this ); deltaAction.value(this); } delta { ^delta } debug_{ |onoff| if ( onoff, { debugAction = { |slot| [ slot.type, slot.code, slot.value, slot.delta, slot.key ].postln; }; }, { debugAction = {}; }); } } LIDLedSlot : LIDSlot { initSpec { } value { ^rawValue } value_{ |inValue| this.rawValue_( spec.map( inValue ) ); } rawValue_ { | inValue | rawValue = inValue; device.setLEDState( code, inValue ); action.value(this); busAction.value( this ); debugAction.value( this ); } } LIDMscSlot : LIDSlot { initSpec { } value { ^rawValue } value_{ |inValue| this.rawValue_( spec.map( inValue ) ); } rawValue_ { | inValue | rawValue = inValue; device.setMSCState( code, rawValue ); action.value(this); busAction.value( this ); debugAction.value( this ); } } LIDAbsSlot : LIDSlot { var monitor, <>parentGroup; // if nil, uses default group var busArg; // cache for "/s_new" bus arg var busLoaded = false; var <>reshaping; // \elastic, \expanding classvar <>defaultNumAudio=2, <>defaultNumControl=1, <>defaultReshaping; *new { | server | ^super.newCopyArgs(server ? Server.default); } *for { | bus | bus = bus.asBus; ^this.new(bus.server).bus_(bus) } *audio { | server, numChannels | ^this.new(server).defineBus(\audio, numChannels) } *control { | server, numChannels | ^this.new(server).defineBus(\control, numChannels) } clear { this.free; this.stop; this.freeBus; monitor = nil; this.changed(\clear); } // playing and access rate { ^if(bus.isNil) { \scalar } { bus.rate } } numChannels { ^if(bus.isNil) { nil } { bus.numChannels } } index { ^if(bus.isNil) { nil } { bus.index } } fixedBus { ^reshaping.isNil } isNeutral { ^bus.isNil or: { bus.index.isNil and: { bus.numChannels.isNil } } } isMonitoring { ^monitor.isPlaying } isPlaying { ^this.index.notNil and: { server.serverRunning } } prepareOutput { } // see subclass clock { ^nil } ar { | numChannels, offset = 0, clip = \wrap | var output; if(this.isNeutral) { this.defineBus(\audio, numChannels) }; this.prepareOutput; output = InBus.ar(bus, numChannels, offset, clip); // always return an array if no channel size is specified ^if(numChannels.isNil) { output.asArray } { output } } kr { | numChannels, offset = 0, clip = \wrap | var output; if(this.isNeutral) { this.defineBus(\control, numChannels) }; this.prepareOutput; output = InBus.kr(bus, numChannels, offset, clip); // always return an array if no channel size is specified ^if(numChannels.isNil) { output.asArray } { output } } asStream { ^Routine { loop { this.asControlInput.yield } } } embedInStream { | inval | // for now, force multichannel expansion in streams early. ^this.asControlInput.embedInStream(inval); } asControlInput { if(this.isPlaying.not) { if(this.isNeutral) { this.defineBus(\control, 1) }; this.wakeUp }; ^this.busArg; } asUGenInput { ^this.value(nil) } // math support value { | something | var n; if(UGen.buildSynthDef.isNil) { ^this }; // only return when in ugen graph. something !? { n = something.numChannels }; ^if(something.respondsTo(\rate) and: { something.rate == 'audio'} or: { this.rate == \audio }) { this.ar(n) } { this.kr(n) } } composeUnaryOp { | aSelector | ^UnaryOpPlug.new(aSelector, this) } composeBinaryOp { | aSelector, something | ^BinaryOpPlug.new(aSelector, this, something) } reverseComposeBinaryOp { | aSelector, something | ^BinaryOpPlug.new(aSelector, something, this) } composeNAryOp { |aSelector, anArgList| ^thisMethod.notYetImplemented //^NAryOpPlug.new(aSelector, [this]++anArgList) // nary op ugens are not yet implemented } // bus initialization bus_ { | inBus | var bundle; if(bus != inBus) { this.setBus(inBus); if(monitor.isPlaying) { bundle = OSCBundle.new; monitor.stopToBundle(bundle); monitor.playNBusToBundle(bundle, bus: inBus); bundle.schedSend(server); } }; } // you have to stop and play explicitly setBus { | inBus | if(inBus.isNil) { Error("BusPlug:setBus: bus can't be set to nil.").throw }; if(bus != inBus) { //postf("% has new bus: % \nold bus was: %\n", this, inBus, bus); this.freeBus; bus = inBus; this.makeBusArg; busLoaded = bus.server.serverRunning; this.changed(\bus, bus); } } // returns false if failed initBus { | rate, numChannels | if(rate == \scalar) { ^true }; // no bus output if(this.isNeutral) { this.defineBus(rate, numChannels); ^true }; numChannels = numChannels ? this.numChannels; rate = rate ? this.rate; if(numChannels == bus.numChannels and: { rate == bus.rate }) { ^true // already there }; if(reshaping.isNil or: { reshaping == \static }) { ^(this.rate === rate) and: { numChannels <= bus.numChannels } }; // for now: always reshape on rate change, because rate adaption happens earlier. if(this.rate != rate) { this.defineBus(rate, numChannels); ^true }; if(reshaping == \elastic and: { numChannels != bus.numChannels }) { this.defineBus(rate, numChannels); ^true }; if(reshaping == \expanding) { if(numChannels > bus.numChannels) { this.defineBus(rate, numChannels); }; ^true }; Error("reshaping '%' not implemented".format(reshaping)).throw; } defineBus { | rate = \audio, numChannels | numChannels = numChannels ? this.numChannels; if(rate != \audio) { rate = \control }; if(numChannels.isNil) { numChannels = if(rate === \audio) { this.class.defaultNumAudio } { this.class.defaultNumControl } }; this.setBus(Bus.alloc(rate, server, numChannels)); } freeBus { var oldBus = bus; oldBus.free(true); busArg = bus = nil; busLoaded = false; } busArg { ^busArg ?? { this.makeBusArg } } makeBusArg { var index, numChannels, prefix; if(bus.isNil) { ^busArg = "" }; // still neutral prefix = if(this.rate == \audio) { "\a" } { "\c" }; index = this.index; numChannels = this.numChannels; ^busArg = if(numChannels == 1) { prefix ++ index } { { |i| prefix ++ (index + i) }.dup(numChannels) } } asMap { ^this.busArg } wakeUpToBundle {} wakeUp {} asBus { ^if(this.isNeutral) { nil } { bus } } asNodeArg { ^if(this.isNeutral) { nil } { this.busArg } } // monitoring play { | out, numChannels, group, multi=false, vol, fadeTime, addAction | var bundle = MixedBundle.new; if(this.homeServer.serverRunning.not) { ("server not running:" + this.homeServer).warn; ^this }; if(bus.rate == \control) { "Can't monitor a control rate bus.".warn; monitor.stop; ^this }; this.playToBundle(bundle, out, numChannels, group, multi, vol, fadeTime, addAction); // homeServer: multi client support: monitor only locally bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant); this.changed(\play, [out, numChannels, group, multi, vol, fadeTime, addAction]); } playN { | outs, amps, ins, vol, fadeTime, group, addAction | var bundle = MixedBundle.new; if(this.homeServer.serverRunning.not) { ("server not running:" + this.homeServer).warn; ^this }; if(bus.rate == \control) { "Can't monitor a control rate bus.".warn; monitor.stop; ^this }; this.playNToBundle(bundle, outs, amps, ins, vol, fadeTime, group, addAction); bundle.schedSend(this.homeServer, this.clock ? TempoClock.default, this.quant); this.changed(\playN, [outs, amps, ins, vol, fadeTime, group, addAction]); } fadeTime { ^0.02 } quant { ^nil } vol { ^if(monitor.isNil) { 1.0 } { monitor.vol } } vol_ { |val| this.initMonitor(val) } monitorIndex { ^if(monitor.isNil) { nil } { monitor.out } } monitorGroup { ^if(monitor.isNil) { nil } { monitor.group } } initMonitor { | vol | if(monitor.isNil) { monitor = Monitor.new }; if (vol.notNil) { monitor.vol_(vol) }; ^monitor } stop { | fadeTime, reset = false | monitor.stop(fadeTime); if(reset) { monitor = nil }; this.changed(\stop, [fadeTime, reset]); } scope { | bufsize = 4096, zoom | if(this.isNeutral.not) { ^bus.scope(bufsize, zoom) } { "Can't scope unintitialized bus".warn } } plot { | duration = 0.01, bounds, minval, maxval, separately = false | ^if(this.isNeutral.not) { this.wakeUp; bus.plot(duration, bounds, minval, maxval, separately); } { "Can't plot unintitialized bus".warn; nil } } // bundling messages playToBundle { | bundle, out, numChannels, group, multi=false, vol, fadeTime, addAction | if(bus.rate == \control) { "Can't monitor a control rate bus.".warn; monitor !? { monitor.stopToBundle(bundle) }; ^this }; this.newMonitorToBundle(bundle, numChannels); group = group ?? { if(parentGroup.isPlaying) { parentGroup } }; if(numChannels.notNil) { out = (0..numChannels-1) + (out ? 0) }; monitor.playNBusToBundle(bundle, out, nil, nil, bus, vol, fadeTime, group, addAction, multi); } playNToBundle { | bundle, outs, amps, ins, vol, fadeTime, group, addAction | if(bus.rate == \control) { "Can't monitor a control rate bus.".warn; monitor !? { monitor.stopToBundle(bundle) }; ^this }; this.newMonitorToBundle(bundle, ins !? { ins.asArray.maxItem + 1 }); group = group ?? { if(parentGroup.isPlaying) { parentGroup } }; monitor.playNBusToBundle(bundle, outs, amps, ins, bus, vol, fadeTime, group, addAction); } newMonitorToBundle { | bundle, numChannels | if(this.isNeutral) { this.initBus(\audio, numChannels) }; this.initMonitor; if(this.isPlaying.not) { this.wakeUpToBundle(bundle) }; } // making copies copy { ^this.class.new(server).copyState(this) } copyState { | proxy | var proxyBus = proxy.bus; if(this.isNeutral.not) { this.clear }; parentGroup = proxy.parentGroup; reshaping = proxy.reshaping; monitor = proxy.monitor.copy; proxyBus !? { bus = Bus.alloc(proxyBus.rate, proxyBus.server, proxyBus.numChannels); this.makeBusArg; } } // server state serverQuit { busLoaded = false; } // network node proxy support shared { ^false } homeServer { ^server } printOn { | stream | stream << this.class.name << "." << bus.rate << "(" << server << ", " << bus.numChannels <<")"; } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/extStoreOn.sc000644 000765 000024 00000022666 12766171707 026342 0ustar00crucialstaff000000 000000 + AbstractPlayControl { storeOn { | stream | source.storeOn(stream) } } + Symbol { isBasicOperator { ^#['+', '-', '*', '/', '%', '==', '!=', '<', '<=', '>', '>=', '&&', '||', '@' ].includes(this); } } + Object { // might need correction for literals. envirKey { | envir | ^(envir ? currentEnvironment).findKeyForValue(this) } envirCompileString { var key = this.envirKey; ^if(key.notNil) { "~" ++ key } { this.asCompileString }; } } + NodeProxy { key { | envir | ^super.envirKey(envir); } servStr { ^if(server != Server.default) { "(" ++ server.asCompileString ++")" } { "" } } // not ideal, but usable for now. storeOn { | stream | var key = this.key; if (currentEnvironment.includes(this)) { stream << ("~" ++ key) } { if (key.isNil) { stream << "a = NodeProxy.new" ++ this.servStr } }; } playEditString { |usePlayN, dropDefaults = false, nameStr| var editString, outs, amps; nameStr = nameStr ?? { this.asCompileString }; if (nameStr.beginsWith("a = ")) { // anon proxy nameStr = nameStr.keep(1); }; usePlayN = usePlayN ?? { if (monitor.notNil) { monitor.usedPlayN } ? false }; // if they are defaults, don't post them if (usePlayN) { editString = nameStr ++ this.playNString(dropDefaults) } { editString = nameStr ++ this.playString(dropDefaults) }; ^editString; } playString { |dropDefaults = false| var defOut = 0, defVol = 1, defNumCh = this.numChannels ? 2; var out, numCh, vol, setStr = ""; out = try { this.monitor.out } ? defOut; numCh = this.numChannels ? defNumCh; // should be able to be different, or not? vol = try { this.monitor.vol } ? defVol; if (dropDefaults.not or: { out != defOut }) { setStr = setStr ++ "\tout:" + out }; if (dropDefaults.not or: { numCh != defNumCh }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tnumChannels:" + numCh; }; if (dropDefaults.not or: { vol != defVol }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tvol:" + vol ++ "\n"; }; if (setStr.size > 0) { setStr = "(\n" ++ setStr ++ "\n)"; }; ^(".play" ++ setStr ++ ";\n"); } playNString { |dropDefaults = false| var numCh = this.numChannels ? 2; var defOuts = { |i| i } ! numCh; var defAmps = 1 ! numCh; var defIns = { |i| i + this.index } ! numCh; var defVol = 1; var defFadeTime = 0.02 ! numCh; var outs = try { this.monitor.outs } ? defOuts; var amps = try { this.monitor.amps } ? defAmps; var ins = try { this.monitor.ins } ? defIns; var vol = try { this.monitor.vol } ? defVol; var fadeTime = try { this.monitor.fadeTime } ? defFadeTime; var setStr = ""; // [\o, defOuts, outs, \a, defAmps, amps, \i, defIns, ins].postcs; if (dropDefaults.not or: { outs != defOuts }) { setStr = setStr ++ "\touts:" + outs }; if (dropDefaults.not or: { amps != defAmps }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tamps:" + amps; }; if (dropDefaults.not or: { ins != defIns }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tins:" + ins; }; if (dropDefaults.not or: { vol != defVol }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tvol:" + vol; }; if (dropDefaults.not or: { fadeTime != defFadeTime }) { if (setStr.size > 0) { setStr = setStr ++ ", \n" }; setStr = setStr ++ "\tfadeTime:" + fadeTime; }; if (setStr.size > 0) { setStr = "(\n" ++ setStr ++ "\n)"; }; ^(".playN" ++ setStr ++ ";\n"); } playNDialog { | bounds, usePlayN | var doc = this.playEditString(usePlayN).newTextWindow("edit outs:"); try { doc.bounds_(bounds) }; // swingosc safe } findInOpenDocuments { |index = 0| var src, str, startSel, doc; src = this.at(index); src ?? { "NodeProxy: no source at index %.\n".postf(index); ^this }; str = src.asCompileString; doc = Document.allDocuments.detect { |doc| startSel = doc.string.find(str); startSel.notNil; }; doc !? { doc.front.selectRange(startSel, 0); } } asCode { | includeSettings = true, includeMonitor = true, envir | var nameStr, srcStr, str, docStr, indexStr, key; var space, spaceCS; var isAnon, isSingle, isInCurrent, isOnDefault, isMultiline; envir = envir ? currentEnvironment; nameStr = envir.use { this.asCompileString }; indexStr = nameStr; isAnon = nameStr.beginsWith("a = "); isSingle = this.objects.isEmpty or: { this.objects.size == 1 and: { this.objects.indices.first == 0 } }; isInCurrent = envir.includes(this); isOnDefault = server === Server.default; // [\isAnon, isAnon, \isSingle, isSingle, \isInCurrent, isInCurrent, \isOnDefault, isOnDefault].postln; space = ProxySpace.findSpace(this); spaceCS = try { space.asCode } { inform("// ".format(this.asCompileString)); "" }; docStr = String.streamContents { |stream| if(isSingle) { str = nameStr; srcStr = if (this.source.notNil) { this.source.envirCompileString } { "" }; if ( isAnon ) { // "a = NodeProxy.new" if (isOnDefault.not) { str = str ++ "(" ++ this.server.asCompileString ++ ")" }; if (srcStr.notEmpty) { str = str ++ ".source_(" ++ srcStr ++ ")" }; } { if (isInCurrent) { // ~out if (srcStr.notEmpty) { str = str + "=" + srcStr }; } { // Ndef('a') - put sourceString before closing paren. if (srcStr.notEmpty) { str = str.copy.drop(-1) ++ ", " ++ srcStr ++ nameStr.last }; } }; } { // multiple sources if (isAnon) { str = nameStr ++ ";\n"; indexStr = "a"; }; this.objects.keysValuesDo { |index, item| srcStr = item.source.envirCompileString ? ""; isMultiline = srcStr.includes(Char.nl); if (isMultiline) { srcStr = "(" ++ srcStr ++ ")" }; srcStr = indexStr ++ "[" ++ index ++ "] = " ++ srcStr ++ ";\n"; str = str ++ srcStr; }; }; stream << str << if (str.keep(-2).includes($;)) { "\n" } { ";\n" }; // add settings to compile string if(includeSettings) { stream << this.nodeMap.asCode(indexStr, true); }; // include play settings if playing ... // hmmm - also keep them if not playing, // but inited to something non-default? if (this.rate == \audio and: includeMonitor) { if (this.monitor.notNil) { if (this.isMonitoring) { stream << this.playEditString(this.monitor.usedPlayN, true) } }; }; }; isMultiline = docStr.drop(-1).includes(Char.nl); if (isMultiline) { docStr = "(\n" ++ docStr ++ ");\n" }; ^docStr } document { | includeSettings = true, includeMonitor = true | var nameStr = this.class.asString ++"_" ++ this.key; ^this.asCode(includeSettings, includeMonitor) .newTextWindow("document-" ++ nameStr) } } + BinaryOpPlug { envirCompileString { var astr, bstr, opstr, str = ""; var basic = operator.isBasicOperator; astr = a.envirCompileString; bstr = b.envirCompileString; if(b.isKindOf(AbstractOpPlug)) { bstr = "(%)".format(bstr) }; opstr = if(basic.not) { ".%(" } { " % " }.format(operator); str = str ++ astr ++ opstr ++ bstr; if(basic.not) { str = str ++ ")" }; ^str } } + UnaryOpPlug { envirCompileString { ^(a.envirCompileString ? "") ++ " " ++ operator } } + ProxySpace { // where am I globally accessible? asCode { var key; if (this == thisProcess.interpreter.p) { ^"p" }; if (this == currentEnvironment) { ^"currentEnvironment" }; if (Ndef.all.includes(this)) { key = Ndef.all.findKeyForValue(this); ^"Ndef.all[%]".format(key.asCompileString); }; if (ProxySpace.all.includes(this)) { key = ProxySpace.all.findKeyForValue(this); ^"ProxySpace.all[%]".format(key.asCompileString); }; ^"/***( cannot locate this proxyspace )***/" } storeOn { | stream, keys, includeSettings = true, includeMonitors = true | var proxies, hasGlobalClock; hasGlobalClock = clock.isKindOf(TempoBusClock); stream << "\n(\n"; if(hasGlobalClock) { stream <<< this.asCode << ".makeTempoClock(" << clock.tempo << ");\n\n"; }; // find keys for all parents if(keys.notNil) { proxies = IdentitySet.new; keys.do { |key| var p = envir[key]; p !? { p.getFamily(proxies) } }; keys = proxies.collect { |item| item.key(envir) }; } { keys = envir.keys }; if(hasGlobalClock) { keys.remove(\tempo) }; // add all objects to compilestring keys.do { |key| var proxy = envir.at(key); stream << proxy.asCode(includeSettings, includeMonitors, this.envir) << "\n"; }; stream << ");\n"; } documentOutput { ^this.document(nil, true) } document { | keys, onlyAudibleOutput = false, includeSettings = true | var str; if(onlyAudibleOutput) { keys = this.monitors.collect { |item| item.key(envir) }; }; str = String.streamContents { |stream| stream << "// ( p = ProxySpace.new(s).push; ) \n\n"; this.storeOn(stream, keys, includeSettings); // this.do { |px| if(px.monitorGroup.isPlaying) { // stream << px.playEditString << ".play; \n" // } // }; }; // ^str.newTextWindow((name ? "proxyspace").asString) ^Document((name ? "proxyspace").asString, str); } } + ProxyNodeMap { asCode { | namestring = "", dropOut = false | ^String.streamContents({ |stream| var map; if(dropOut) { map = this.copy; map.removeAt(\out); map.removeAt(\i_out); } { map = this }; if(map.notEmpty) { stream << namestring << ".set(" <<<* map.asKeyValuePairs << ");" << Char.nl; }; if(rates.notNil) { stream << namestring << ".setRates(" <<<* rates << ");" << Char.nl; } }); } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/InBus.sc000644 000765 000024 00000020202 12756534417 025230 0ustar00crucialstaff000000 000000 InBus : UGen { *ar { | bus, numChannels, offset = 0, clip | ^this.multiNew('audio', Ref(bus), numChannels, offset, clip); } *kr { | bus, numChannels, offset = 0, clip | ^this.multiNew('control', Ref(bus), numChannels, offset, clip); } *new1 { |rate, bus, numChannels, offset, clip| var out, index, n, busRate; bus = bus.value.asBus; busRate = bus.rate; n = bus.numChannels; numChannels = numChannels ? n; if(offset.isNumber and: { offset + numChannels <= n }) { index = bus.index + offset; // then we can optimize } { offset = offset + (0 .. numChannels-1); offset = if(clip === \wrap) { offset % n } { min(offset, n - 1) }; index = (bus.index + offset).unbubble; numChannels = 1; }; out = if(index.isInteger) { if(busRate === 'audio') { InFeedback.ar(index, numChannels) } { In.kr(index, numChannels) } } { if(busRate === 'audio') { XInFeedback.ar(index, numChannels) } { XIn.kr(index, numChannels) } }; ^if(rate === busRate) { out } { // if not the same rate, convert rates if(rate === 'audio') { K2A.ar(out) } { A2K.kr(out) } }; } } XIn { *ar { | which, n | ^XFade2.ar( // use equal power crossfading for audio rate In.ar(which.round(2), n), In.ar(which.trunc(2) + 1, n), (which * 2 - 1).fold2(1) ) } *kr { | which, n | ^LinXFade2.kr( // use linear crossfading for control rate In.kr(which.round(2), n), In.kr(which.trunc(2) + 1, n), (which * 2 - 1).fold2(1) ) } } XInFeedback { *ar { | which, n | ^XFade2.ar( InFeedback.ar(which.round(2), n), InFeedback.ar(which.trunc(2) + 1, n), (which * 2 - 1).fold2(1) ); } } // listens on a number of busses and plays out to various other busses Monitor { var 1 } or: { outs.asArray.isSeries(1).not } or: { ins.asArray.isSeries(1).not } } *warnPlayN { this.deprecated(thisMethod); } *warnPlayN_ { |flag| this.deprecated(thisMethod); } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/NodeMap.sc000644 000765 000024 00000007426 12756534417 025550 0ustar00crucialstaff000000 000000 NodeMap : IdentityDictionary { var <>upToDate = false; var setArgs; clear { super.clear; upToDate = false; this.changed(\clear); } updateArgs { setArgs = this.asKeyValuePairs.asOSCArgArray; upToDate = true; } get { |key| ^this.at(key) } set { |...args| this.putPairs(args); upToDate = false; this.changed(\set, args); } unset { |... keys| keys.do { |x| this.put(x, nil) }; this.changed(\unset, keys); } unmap { |... keys| keys.do { |x| this.put(x, nil) }; this.changed(\unmap, keys); } asOSCArgArray { if(upToDate.not) { this.updateArgs }; ^setArgs } send { |server, nodeID, latency| var bundle = List.new; this.addToBundle(bundle, nodeID); server.listSendBundle(latency, bundle); } sendToNode { |node, latency| node = node.asTarget; this.send(node.server, node.nodeID, latency) } addToBundle { |bundle, target| var msg = this.setMsg(target); msg !? { bundle.add(this.setMsg(target)) } } addToEvent { |event| this.keysValuesDo { |key, val| event.put(key, val.asControlInput) } } setMsg { |target| if(this.isEmpty) { ^nil }; if(upToDate.not) { this.updateArgs }; ^["/n_set", target.asControlInput] ++ setArgs } unmapArgsToBundle { |bundle, target, keys| var args; if(this.isEmpty) { ^this }; keys = keys ?? { this.keys }; keys.do { |key| var val = this.at(key); if(val.isNumber.not and: { val.isSequenceableCollection.not }) { args = args ++ [key, -1, val.numChannels] } }; if(args.notNil) { bundle.add([48, target.asNodeID] ++ args) }; } setn { ^this.deprecated(thisMethod, this.class.findRespondingMethodFor(\set)) } mapn { ^this.deprecated(thisMethod, this.class.findRespondingMethodFor(\set)) } map { ^this.deprecated(thisMethod, this.class.findRespondingMethodFor(\set)) } } ProxyNodeMap : NodeMap { var rates, <>proxy; clear { this.keys.do { |key| this.set(key, nil) }; upToDate = false; this.changed(\clear); } put { |key, item| if(proxy.notNil) { if(this.at(key).isKindOf(NodeProxy)) { this.at(key).removeChild(proxy); }; if(item.isKindOf(NodeProxy)) { item.addChild(proxy); } }; super.put(key, item) } wakeUpParentsToBundle { | bundle, checkedAlready | this.pairsDo({ |key, item| item.wakeUpToBundle(bundle, checkedAlready) }); } // map works only for proxies so far map { |...args| this.putPairs(args); upToDate = false; this.changed(\map, args); } mapEnvir { |... keys| if(keys.isEmpty) { keys = this.keys }; this.map(currentEnvironment.getPairs(keys)); } // unoptimized parents { var res = Array.new; this.do { |item| if(item.isKindOf(NodeProxy)) { res = res.add(item) } }; ^res } controlNames { var res = Array.new; this.keysValuesDo { |key, value| var rate = if(value.rate == \audio) { \audio } { \control }; res = res.add(ControlName(key, nil, rate, value)) }; ^res } settingKeys { var res; this.keysValuesDo { |key, val| if(val.isNumber or: { val.isSequenceableCollection }) { res = res.add(key) } } ^res } mappingKeys { var res; this.keysValuesDo { |key, val| if(val.isNumber.not and: { val.isSequenceableCollection.not }) { res = res.add(key) } } ^res } changed { |...args| proxy.changed(*args) } hasRates { ^rates.notNil and: { rates.notEmpty } } setRates { |args| //this.deprecated(thisMethod); // maybe deprecate later rates = rates ?? { IdentityDictionary.new }; rates.putPairs(args); } ratesFor { arg keys; ^rates !? { rates.atAll(keys) } } // maybe not needed at all isMapped { |key| var val = this.at(key); this.deprecated(thisMethod); ^val.isNumber.not and: { val.isSequenceableCollection.not } } } + BusPlug { asOSCArgEmbeddedArray { |array| ^this.asControlInput.asOSCArgEmbeddedArray(array) } } + Object { wakeUpToBundle {} } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/NodeProxy.sc000644 000765 000024 00000065726 13007174002 026137 0ustar00crucialstaff000000 000000 NodeProxy : BusPlug { var awake=true, clock, <>quant; classvar <>buildProxyControl, <>buildProxy; *new { | server, rate, numChannels, inputs | var res = super.new(server).init; if(rate.notNil or: { numChannels.notNil }) { res.initBus(rate, numChannels) }; inputs.do { |o| res.add(o) }; ^res } init { nodeMap = ProxyNodeMap.new; objects = Order.new; loaded = false; reshaping = defaultReshaping; this.linkNodeMap; } clear { | fadeTime = 0 | this.free(fadeTime, true); // free group and objects this.removeAll; // take out all objects children = nil; // for now: also remove children this.stop(fadeTime, true); // stop any monitor monitor = nil; this.fadeTime = fadeTime; // set the fadeTime one last time for freeBus this.freeBus; // free the bus from the server allocator this.init; // reset the environment this.changed(\clear, [fadeTime]); } end { | fadeTime, reset = false | var dt = fadeTime ? this.fadeTime; fork { this.free(dt, true); (dt + (server.latency ? 0)).wait; this.stop(0, reset); }; this.changed(\end, [fadeTime, reset]); } isPlaying { ^group.isPlaying } free { | fadeTime, freeGroup = true | var bundle; var oldGroup = group; if(this.isPlaying) { bundle = MixedBundle.new; if(fadeTime.notNil) { bundle.add([15, group.nodeID, "fadeTime", fadeTime]) }; this.stopAllToBundle(bundle, fadeTime); if(freeGroup) { oldGroup = group; group = nil; bundle.sched((fadeTime ? this.fadeTime) + (server.latency ? 0), { oldGroup.free }); }; bundle.send(server); this.changed(\free, [fadeTime, freeGroup]); } } release { | fadeTime | this.free(fadeTime, false) } pause { if(this.isPlaying) { objects.do { |item| item.pause(clock, quant) } }; paused = true; this.changed(\pause); } resume { paused = false; if(this.isPlaying) { objects.do { |item| item.resume(clock, quant) } }; this.changed(\resume); } fadeTime_ { | dur | if(dur.isNil) { this.unset(\fadeTime) } { this.set(\fadeTime, dur) }; } fadeTime { ^nodeMap.at(\fadeTime) ? 0.02; } asGroup { ^group.asGroup } asTarget { ^group.asGroup } asNodeID { ^group.asNodeID } nodeID { ^group.nodeID } parentGroup_ { | node | if(node.isPlaying.not) { "node not playing and registered: % \n".postf(node); ^this }; parentGroup = node; if(group.isPlaying) { group.moveToHead(parentGroup) }; } // setting the source source_ { | obj | this.put(nil, obj, 0) } prime { | obj | this.put(nil, obj, 0, nil, false); } sources_ { | list | this[0..] = list; } source { ^objects.at(0).source } sources { ^objects.array.collect(_.source) } add { | obj, channelOffset = 0, extraArgs, now = true | this.put(objects.pos, obj, channelOffset, extraArgs, now) } at { | index | ^objects.at(index).source } put { | index, obj, channelOffset = 0, extraArgs, now = true | var container, bundle, oldBus = bus; if(obj.isNil) { this.removeAt(index); ^this }; if(index.isSequenceableCollection) { ^this.putAll(obj.asArray, index, channelOffset) }; bundle = MixedBundle.new; container = obj.makeProxyControl(channelOffset, this); container.build(this, index ? 0); // bus allocation happens here if(this.shouldAddObject(container, index)) { // server sync happens here if necessary if(server.serverRunning) { container.loadToBundle(bundle, server) } { loaded = false; }; this.prepareOtherObjects(bundle, index, oldBus.notNil and: { oldBus !== bus }); } { format("failed to add % to node proxy: %", obj, this).inform; ^this }; this.putNewObject(bundle, index, container, extraArgs, now); this.changed(\source, [obj, index, channelOffset, extraArgs, now]); } prepareOtherObjects { |bundle, index, busChanged| var tempReshaping; if(index.isNil) { this.removeAllToBundle(bundle); } { this.removeToBundle(bundle, index); }; if(busChanged) { tempReshaping = reshaping; reshaping = nil; this.rebuildDeepToBundle(bundle, true, nil, [this.fadeTime, quant, clock]); reshaping = tempReshaping; }; } putNewObject { |bundle, index, container, extraArgs, now| objects = objects.put(index ? 0, container); if(server.serverRunning) { if(awake && now) { this.prepareToBundle(nil, bundle); container.wakeUpParentsToBundle(bundle); nodeMap.wakeUpParentsToBundle(bundle); this.sendObjectToBundle(bundle, container, extraArgs, index) }; bundle.schedSend(server, clock ? TempoClock.default, quant); } } putAll { | list, index = (0), channelOffset = 0 | channelOffset = channelOffset.asArray; if(index.isSequenceableCollection) { max(list.size, index.size).do { |i| this.put(index.wrapAt(i), list.wrapAt(i), channelOffset.wrapAt(i)) } }{ list.do { |item, i| this.put(i + index, item, channelOffset.wrapAt(i)) } } } putSeries { | first, second, last, value | last = last ?? { max(1, max(objects.size, value.size)) - 1 }; this.putAll(value.asArray, (first, second..last)) } filter { | i, func | this.put(i, \filter -> func) } removeFirst { | fadeTime | this.removeAt(objects.indices.first, fadeTime) } removeLast { | fadeTime | this.removeAt(objects.indices.last, fadeTime) } removeAll { | fadeTime | this.removeAt(nil, fadeTime) } removeAt { | index, fadeTime | var bundle = MixedBundle.new; if(index.isNil) { this.removeAllToBundle(bundle, fadeTime) } { this.removeToBundle(bundle, index, fadeTime) }; this.changed(\source, [nil, index, fadeTime]); if(server.serverRunning) { bundle.schedSend(server) }; } rebuild { var bundle = MixedBundle.new; this.rebuildDeepToBundle(bundle, false, nil, [this.fadeTime, quant, clock]); bundle.schedSend(server, clock ? TempoClock.default, quant); } mold { |numChannels, rate, argReshaping, fadeTime| var bundle, oldBus = bus, tempReshaping; fadeTime = fadeTime ?? { this.fadeTime }; bundle = MixedBundle.new; tempReshaping = reshaping; if(numChannels.isNil and: { rate.isNil }) { // adjust to the source objects reshaping = argReshaping ? \expanding; this.rebuildDeepToBundle(bundle, false, nil, [fadeTime, quant, clock]) } { // adjust to given shape reshaping = argReshaping ? \elastic; this.initBus(rate, numChannels); // if necessary, rebuild without adjustment if(bus !== oldBus) { reshaping = nil; this.rebuildDeepToBundle(bundle, true, nil, [fadeTime, quant, clock]) } }; reshaping = tempReshaping; if(server.serverRunning) { bundle.schedSend(server, clock ? TempoClock.default, quant) }; } lag { | ... args | nodeMap.setRates(args); this.rebuild; } setRates { | ... args | nodeMap.setRates(args); this.rebuild; } setBus { | argBus | super.setBus(argBus); this.linkNodeMap; } server_ { | inServer | this.deprecated(thisMethod); if(this.isNeutral.not) { this.end; loaded = false; }; server = inServer; } group_ { | inGroup | var bundle; if(inGroup.server !== server) { Error("cannot move to another server").throw }; NodeWatcher.register(inGroup.isPlaying_(true)); // assume it is playing if(this.isPlaying) { bundle = MixedBundle.new; this.stopAllToBundle(bundle); group = inGroup; this.sendAllToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, 0.0); } { group = inGroup }; } read { | proxies | this.putAll(proxies) } readFromBus { | busses | var n, x; busses = busses.asCollection; n = this.numChannels; busses.do { arg item, i; x = min(item.numChannels ? n, n); this.put(i, SynthControl.new("system_link_" ++ this.rate ++ "_" ++ x), 0, ["in", item.index, "out", this.index] ) }; } // modifying context, setting controls set { | ... args | // pairs of keys or indices and value nodeMap.set(*args); if(this.isPlaying) { server.sendBundle(server.latency, [15, group.nodeID] ++ args.asOSCArgArray); } } setn { | ... args | this.set(*args) } setGroup { | args, useLatency = false | if(this.isPlaying) { server.sendBundle(if(useLatency) { server.latency }, [15, group.nodeID] ++ args.asOSCArgArray ); } } map { | ... args | // key(s), proxy, key(s), proxy ... this.set(*args) } mapn { | ... args | "NodeProxy: mapn is deprecated, please use map instead".postln; this.map(*args) } xset { | ... args | this.xFadePerform(\set, args) } xmap { | ... args | this.xFadePerform(\map, args) } xsetn { | ... args | this.xFadePerform(\set, args) } xmapn { | ... args | "NodeProxy: xmapn is decrepated, please use xmap instead".postln; this.xFadePerform(\map, args) } xunset { | ... args | this.xFadePerform(\unset, args) } xFadePerform { | selector, args | var bundle; if(this.isPlaying) { nodeMap.performList(selector, args); this.sendEach(nil, true) } { this.performList(selector, args) } } mapEnvir { | ... keys | // map to current environment nodeMap.mapEnvir(*keys); if(this.isPlaying) { nodeMap.sendToNode(group); }; } unset { | ... keys | var bundle = List.new; this.unsetToBundle(bundle, keys); if(bundle.notEmpty) { server.listSendBundle(server.latency, bundle) }; } unmap { | ... keys | var bundle; if(keys.isEmpty) { keys = nodeMap.mappingKeys; if(keys.isEmpty) { ^this } }; if(this.isPlaying) { bundle = List.new; nodeMap.unmapArgsToBundle(bundle, group.nodeID, keys); if(bundle.notEmpty) { server.listSendBundle(server.latency, bundle) }; }; nodeMap.unmap(*keys); } nodeMap_ { | map | this.setNodeMap(map, false) } setNodeMap { | map, xfade = true | var bundle; if(map.isNil) { ^this.unmap }; map.set(\fadeTime, this.fadeTime); // keep old fadeTime nodeMap.clear; nodeMap = map; this.linkNodeMap; if(this.isPlaying) { bundle = MixedBundle.new; if(xfade) { this.sendEach(nil,true) } { this.unsetToBundle(bundle); // unmap old nodeMap.addToBundle(bundle, group); // map new bundle.schedSend(server, clock ? TempoClock.default, quant); } }; } // play proxy as source of receiver <-- { | proxy | var bundle = MixedBundle.new, fadeTime = this.fadeTime; this.source = proxy; if(proxy.monitor.isPlaying) { proxy.stop(fadeTime: fadeTime); if(monitor.isPlaying.not) { this.playToBundle(bundle, fadeTime: fadeTime) } }; bundle.add(proxy.moveBeforeMsg(this)); bundle.schedSend(server); } // map receiver to proxy input // second argument is an adverb <>> { | proxy, key = \in | proxy.perform('<<>', this, key); ^proxy } // map proxy to receiver input // second argument is an adverb <<> { | proxy, key = \in | var ctl, rate, numChannels, canBeMapped; if(proxy.isNil) { ^this.unmap(key) }; ctl = this.controlNames.detect { |x| x.name == key }; rate = ctl.rate ?? { if(proxy.isNeutral) { if(this.isNeutral) { \audio } { this.rate } } { proxy.rate } }; numChannels = ctl !? { ctl.defaultValue.asArray.size }; canBeMapped = proxy.initBus(rate, numChannels); // warning: proxy should still have a fixed bus if(canBeMapped) { if(this.isNeutral) { this.defineBus(rate, numChannels) }; this.xmap(key, proxy); } { "Could not link node proxies, no matching input found.".warn }; ^proxy // returns first argument for further chaining } // starting processes spawn { | extraArgs, index = 0 | var bundle, obj, i; if(server.serverRunning.not) { "server '%' not running\n".postf(server); ^this }; obj = objects.at(index); if(obj.notNil) { i = this.index; bundle = this.getBundle; if(loaded.not) { this.loadToBundle(bundle) }; obj.spawnToBundle(bundle, { nodeMap.asOSCArgArray ++ extraArgs.value.asOSCArgArray }, this); bundle.schedSend(server); } } send { | extraArgs, index, freeLast = true | var bundle, obj, fadeTime = this.fadeTime; if(objects.isEmpty) { ^this }; if(server.serverRunning.not) { "server '%' not running\n".postf(server); ^this }; if(index.isNil) { bundle = this.getBundle; if(freeLast) { this.stopAllToBundle(bundle, fadeTime) }; if(loaded.not) { this.loadToBundle(bundle) }; this.sendAllToBundle(bundle, extraArgs); bundle.schedSend(server); } { obj = objects.at(index); if(obj.notNil) { bundle = this.getBundle; if(freeLast) { obj.stopToBundle(bundle, fadeTime) }; if(loaded.not) { this.loadToBundle(bundle) }; this.sendObjectToBundle(bundle, obj, extraArgs, index); bundle.schedSend(server); } } } sendAll { | extraArgs, freeLast = true | this.send(extraArgs, nil, freeLast); } sendEach { | extraArgs, freeLast = true | var bundle; if(server.serverRunning.not) { "server '%' not running\n".postf(server); ^this }; bundle = this.getBundle; if(freeLast, { this.stopAllToBundle(bundle) }); if(loaded.not) { this.loadToBundle(bundle) }; this.sendEachToBundle(bundle, extraArgs); bundle.schedSend(server) } quantize { | ... proxies | var quant = this.quant ? 1.0; ([this]++proxies).do { |x| x.quant = quant; x.send; } } wakeUp { // do not touch internal state if already playing if(this.isPlaying.not) { this.deepWakeUp } } deepWakeUp { var bundle = MixedBundle.new; if(server.serverRunning.not) { "server '%' not running\n".postf(server); ^this }; this.wakeUpToBundle(bundle); bundle.schedSend(server, clock ? TempoClock.default, quant) } // making copies copy { ^this.class.new(server).copyState(this) } copyState { |proxy| super.copyState(proxy); proxy.objects.keysValuesDo { |key, val| objects[key] = val.copy }; this.nodeMap = proxy.nodeMap.copy; loaded = false; awake = proxy.awake; paused = proxy.paused; clock = proxy.clock; quant = proxy.quant; } // gui support typeStr { if(this.rate === 'audio') { ^"ar" + this.numChannels }; if(this.rate === 'control') { ^"kr" + this.numChannels }; ^"ir"; } edit { | nSliders, parent, bounds | ^NdefGui(this, nSliders ? this.getKeysValues.size.max(5), parent, bounds); } trace { |index = 0| var obj = objects[index]; if(obj.nodeID.notNil) { server.sendMsg(\n_trace, obj.nodeID); } { "Cannot trace a% %".format( if(obj.class.name.asString.first.isVowel) { "n" } { "" }, obj.class.name ).warn; }; } // interproxy structure and reading other busses orderNodes { | ... proxies | var msg = this.moveBeforeMsg(*proxies); msg !? { server.sendBundle(nil, msg) } } getFamily { | set, alreadyAsked | var parents; parents = IdentitySet.new; alreadyAsked = alreadyAsked ?? { IdentitySet.new }; if(alreadyAsked.includes(this).not) { alreadyAsked.add(this); objects.do { arg obj; parents.addAll(obj.parents) }; parents.addAll(nodeMap.parents); parents.do { arg proxy; proxy.getFamily(parents, alreadyAsked) }; set.add(this); set.addAll(parents); }; ^set } getStructure { | alreadyAsked | var parents, substructure; parents = List.new; alreadyAsked = alreadyAsked ?? { IdentitySet.new }; if(alreadyAsked.includes(this).not) { alreadyAsked.add(this); objects.do { arg obj; parents.addAll(obj.parents) }; parents.addAll(nodeMap.parents); substructure = parents.collect { arg proxy; proxy.getStructure(alreadyAsked) }; ^[this, substructure.flatten(1)]; }; ^nil } moveBeforeMsg { | ... proxies | var list; ([this] ++ proxies).do { |el| if(el.isPlaying) { list = list.add(el.group); if(el.monitor.isPlaying) { list = list.add(el.monitor.group) // debatable. maybe check whether special } } }; ^list !? { Node.orderNodesMsg(list) } } // node map settings internalKeys { ^#[\out, \i_out, \gate, \fadeTime]; } // return names in the order they have in .objects controlNames { | except, addNodeMap = true | var all = Array.new; // Set doesn't work, because equality undefined for ControlName except = except ? this.internalKeys; objects.do { |el| el.controlNames.do { |item| if(except.includes(item.name).not and: { all.every { |cn| cn.name !== item.name } }) { all = all.add(item); } }; }; ^if (addNodeMap.not or: nodeMap.isNil) { all } { this.addNodeMapControlNames(all, except) }; } // if a name is set in nodemap, overwrite the values in objCtlNames; // if a key is set in the nodemap, but is not used in the objects yet, add at the end. addNodeMapControlNames { |objCtlNames, except = #[]| nodeMap.controlNames .reject { |ctlname| except.includes(ctlname.name) } .do { |mapCtl| var index = objCtlNames.detectIndex { |objCtl| objCtl.name == mapCtl.name }; if (index.notNil) { objCtlNames.put(index, mapCtl) } { objCtlNames = objCtlNames.add(mapCtl) } }; ^objCtlNames } resetNodeMap { this.nodeMap = ProxyNodeMap.new; this.linkNodeMap; } cleanNodeMap { var nodeMapSettingKeys, nodeMapMappingKeys, keysToUnset, keysToUnmap, currentKeys; if (nodeMap.isNil) { ^this }; nodeMapSettingKeys = difference(nodeMap.settingKeys ? [], this.internalKeys); nodeMapMappingKeys = difference(nodeMap.mappingKeys ? [], this.internalKeys); currentKeys = this.controlNames(addNodeMap: false).collect(_.name); keysToUnset = difference(nodeMapSettingKeys, currentKeys); keysToUnmap = difference(nodeMapMappingKeys, currentKeys); keysToUnset.do(this.unset(_)); keysToUnmap.do(this.unmap(_)); } controlKeys { | except, noInternalKeys = true | var list = Array.new; if (noInternalKeys) { except = except ++ this.internalKeys; }; this.controlNames.do { |el, i| if(except.includes(el.name).not) { list = list.add(el.name) } } ^list } getKeysValues { | keys, except, withDefaults = true, noInternalKeys = true | var pairs, result = [], myKeys, defaults; if (noInternalKeys) { except = except ++ this.internalKeys; }; pairs = this.controlKeysValues(keys, except).clump(2); #myKeys, defaults = pairs.flop; myKeys.collect { |key, i| var val, doAdd; val = nodeMap[key]; doAdd = withDefaults or: val.notNil; if (doAdd) { result = result.add([ key, (val ? defaults[i]).value ]); }; } ^result } // controlPairs, gets default values controlKeysValues { | keys, except | var list, fullList; except = except ? this.internalKeys; fullList = this.controlNames(except); if(keys.isNil or: { keys.isEmpty }) { list = Array(fullList.size * 2); fullList.do { |cn| list.add(cn.name).add(cn.defaultValue) } } { list = Array(keys.size * 2); keys.do { |key| var val = fullList.detect { |cn| cn.name == key }; val = if(val.isNil) { 0 } { val.defaultValue }; list.add(key).add(val) } } ^list; } // derive names and default args from synthDefs supplementNodeMap { | keys, replaceOldKeys=false | this.controlNames.do { |el| var key = el.name; if ( ( replaceOldKeys or: { nodeMap.at(key).isNil } ) and: { keys.isNil or: { keys.includes(key) } } ) { nodeMap.set(key, el.defaultValue) } } } // bundling messages getBundle { var bundle = MixedBundle.new; this.prepareToBundle(nil, bundle); ^bundle } // start group if necessary prepareToBundle { | argGroup, bundle, addAction = \addToTail | if(this.isPlaying.not) { group = Group.basicNew(server, this.defaultGroupID); NodeWatcher.register(group); group.isPlaying = server.serverRunning; if(argGroup.isNil and: { parentGroup.isPlaying }) { argGroup = parentGroup }; bundle.addPrepare(group.newMsg(argGroup ?? { server.asGroup }, addAction)); } } // bundle: apply the node map settings to the entire group sendAllToBundle { | bundle, extraArgs | var args = Thunk({ nodeMap.asOSCArgArray ++ extraArgs.value.asOSCArgArray }); objects.do { arg item; item.playToBundle(bundle, args, this); } } // bundle: apply the node map settings to each synth separately sendEachToBundle { | bundle, extraArgs | objects.do { arg item; this.sendObjectToBundle(bundle, item, extraArgs) } } // bundle: send single object sendObjectToBundle { | bundle, object, extraArgs, index | var target, nodes; var synthID = object.playToBundle(bundle, { nodeMap.asOSCArgArray ++ extraArgs.value.asOSCArgArray }, this); if(synthID.notNil) { if(index.notNil and: { objects.size > 1 }) { // if nil, all are sent anyway // make list of nodeIDs following the index nodes = Array(4); objects.doRange({ arg obj; var id = obj.nodeID; if(id.notNil and: { id != synthID }) { nodes = nodes ++ id ++ synthID }; }, index + 1); if(nodes.size > 0) { bundle.add(["/n_before"] ++ nodes.reverse) }; }; } } // bundle: remove single object removeToBundle { | bundle, index, fadeTime | var obj, dt, playing; playing = this.isPlaying; obj = objects.removeAt(index); if(obj.notNil) { dt = fadeTime ? this.fadeTime; if(playing) { obj.stopToBundle(bundle, dt) }; obj.freeToBundle(bundle, this); } } // bundle: remove all objects removeAllToBundle { | bundle, fadeTime | var dt, playing; dt = fadeTime ? this.fadeTime; playing = this.isPlaying; objects.do { arg obj; if(playing) { obj.stopToBundle(bundle, dt) }; obj.freeToBundle(bundle, this); }; objects.makeEmpty; } // bundle: stop single process stopAllToBundle { | bundle, fadeTime | var obj, dt; dt = fadeTime ? this.fadeTime; if(this.isPlaying) { objects.do { |obj| obj.stopToBundle(bundle, dt) } } } loadToBundle { | bundle | this.reallocBusIfNeeded; objects.do { arg item, i; item.loadToBundle(bundle, server); }; loaded = true; } unsetToBundle { | bundle, keys | var pairs = this.controlKeysValues(keys); if(this.isPlaying) { if(pairs.notEmpty) { bundle.add([15, group.nodeID] ++ pairs) } }; nodeMap.unset(*pairs[0,2..]) } wakeUpToBundle { | bundle, checkedAlready | if(checkedAlready.isNil) { checkedAlready = IdentitySet.new }; if(checkedAlready.includes(this).not) { checkedAlready.add(this); this.wakeUpParentsToBundle(bundle, checkedAlready); if(loaded.not) { this.loadToBundle(bundle) }; if(awake and: { this.isPlaying.not }) { this.prepareToBundle(nil, bundle); this.sendAllToBundle(bundle); }; }; } wakeUpParentsToBundle { | bundle, checkedAlready | nodeMap.wakeUpParentsToBundle(bundle, checkedAlready); objects.do { arg item; item.wakeUpParentsToBundle(bundle, checkedAlready) }; } rebuildDeepToBundle { |bundle, busWasChangedExternally = true, checkedAlready, timeArgs| var oldBus = bus; if(checkedAlready.isNil or: { checkedAlready.includes(this).not }) { this.rebuildToBundle(bundle, timeArgs); if(busWasChangedExternally or: { bus !== oldBus }) { //"%: rebuilding children\n".postf(this); if(checkedAlready.isNil) { checkedAlready = IdentitySet.new }; checkedAlready.add(this); children.do { |item| item.rebuildDeepToBundle(bundle, false, checkedAlready, timeArgs) }; if(monitor.isPlaying) { //postf("in % restarting monitor\n", this); monitor.playNBusToBundle(bundle, bus: bus, fadeTime: timeArgs[0]); } } } } rebuildToBundle { |bundle, timeArgs| // we need to pass and temporarily set the timing information // so that freeBus has the correct fadeTime. var prevTimeArgs = [this.fadeTime, quant, clock]; timeArgs !? { this.fadeTime = timeArgs[0]; quant = timeArgs[1]; clock = timeArgs[2] }; loaded = false; nodeMap.upToDate = false; // if mapped to itself //"rebuilding proxy: % (% channels, % rate)\n".postf(this, this.numChannels, this.rate); if(this.isPlaying) { this.stopAllToBundle(bundle); objects.do { |item| item.freeToBundle(bundle, this) }; objects.do { |item, i| item.build(this, i) }; this.loadToBundle(bundle); this.sendAllToBundle(bundle); } { objects.do { |item| item.freeToBundle(bundle, this) }; objects.do { |item, i| item.build(this, i) }; }; timeArgs !? { this.fadeTime = prevTimeArgs[0]; quant = prevTimeArgs[1]; clock = prevTimeArgs[2] }; this.changed(\rebuild); } // allocation freeBus { var oldBus = bus, c; if(oldBus.isNil) { ^this }; if(this.isPlaying) { c = (clock ? TempoClock.default); c.sched(server.latency ? 0.01 + quant.nextTimeOnGrid(c) + this.fadeTime, { oldBus.free(true); nil }); CmdPeriod.doOnce { if(oldBus.index.notNil) { oldBus.free(true) } }; } { oldBus.free(true) }; busArg = bus = nil; busLoaded = false; } reallocBusIfNeeded { // bus is reallocated only if the server was not booted on creation. if(busLoaded.not and: { bus.notNil }) { bus.realloc; this.linkNodeMap } } serverQuit { busLoaded = false; loaded = false; } // network support shouldAddObject { | obj | ^obj.readyForPlay } // shared node proxy overrides this defaultGroupID { ^server.nextNodeID } // private implementation linkNodeMap { var index = this.index; if(index.notNil) { nodeMap.set(\out, index, \i_out, index) }; nodeMap.proxy = this; } generateUniqueName { var uniqueName = this.identityHash; // if named, add the name so we see it // in synthdef names of the server's nodes. if(this.key.notNil, { uniqueName = this.key ++ uniqueName; }); ^server.clientID.asString ++ uniqueName ++ "_"; } prepareOutput { var parentPlaying; parentPlaying = this.addToChild; if(parentPlaying) { this.deepWakeUp }; } addToChild { var childProxyControl = buildProxyControl; if(childProxyControl.notNil) { childProxyControl.addParent(this); }; ^childProxyControl.isPlaying; } addChild { |proxy| children = children.add(proxy); //"%: added child: % in %\n".postf(this, proxy, children); } removeChild { |proxy| children.remove(proxy); //"%: removed child: % in %\n".postf(this, proxy, children); } // renames synthdef so one can use it in patterns nameDef { |name, index = 0| var func = objects[index].synthDef.func; name = name ?? { "New SynthDef name: ".post; (this.key ++ "_" ++ index).asSymbol.postcs; }; ^SynthDef(name, func); } } Ndef : NodeProxy { classvar <>defaultServer, <>all; var <>key; *initClass { all = () } *new { | key, object | // key may be simply a symbol, or an association of a symbol and a server name var res, server, dict; if(key.isKindOf(Association)) { server = Server.named.at(key.value); if(server.isNil) { Error("Ndef(%): no server found with this name.".format(key)).throw }; key = key.key; } { server = defaultServer ? Server.default; }; dict = this.dictFor(server); res = dict.envir.at(key); if(res.isNil) { res = super.new(server).key_(key); dict.initProxy(res); dict.envir.put(key, res) }; object !? { res.source = object }; ^res; } *ar { | key, numChannels, offset = 0 | ^this.new(key).ar(numChannels, offset) } *kr { | key, numChannels, offset = 0 | ^this.new(key).kr(numChannels, offset) } *clear { | fadeTime | all.do(_.clear(fadeTime)); all.clear; } *dictFor { | server | var dict = all.at(server.name); if(dict.isNil) { dict = ProxySpace.new(server); // use a proxyspace for ease of access. all.put(server.name, dict); dict.registerServer; }; ^dict } copy { |toKey| if(key == toKey) { Error("cannot copy to identical key").throw }; ^this.class.new(toKey).copyState(this) } proxyspace { ^this.class.dictFor(this.server) } storeOn { | stream | this.printOn(stream); } printOn { | stream | var serverString = if (server == Server.default) { "" } { " ->" + server.name.asCompileString; }; stream << this.class.name << "(" <<< this.key << serverString << ")" } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/operators.sc000644 000765 000024 00000004123 12756534417 026232 0ustar00crucialstaff000000 000000 AbstractOpPlug : AbstractFunction { composeUnaryOp { |aSelector| ^UnaryOpPlug.new(aSelector, this) } composeBinaryOp { | aSelector, something | ^BinaryOpPlug.new(aSelector, this, something) } reverseComposeBinaryOp { | aSelector, something | ^BinaryOpPlug.new(aSelector, something, this) } composeNAryOp { | aSelector, anArgList | ^{ this.value(anArgList).performList(aSelector, anArgList) } } writeInputSpec { Error("use .ar or .kr to use within a synth.").throw; } asUGenInput { ^this.value(nil) } } UnaryOpPlug : AbstractOpPlug { var >operator, >a; *new { | operator, a | ^super.newCopyArgs(operator, a) } isNeutral { ^a.isNeutral } rate { ^a.rate } numChannels { |max| var n; max = max ? 0; n = a.numChannels(max); ^n !? { max(n, max) } } value { |obj| ^a.value(obj).perform(operator) } initBus { |rate, numChannels| ^a.initBus(rate, numChannels) } wakeUp { a.wakeUp } prepareForProxySynthDef { |proxy| ^{ this.value(proxy) } } asControlInput { "UnaryOpPlug: Cannot calculate this value. Use direct mapping only.".warn; ^this } } BinaryOpPlug : AbstractOpPlug { var >operator, <>a, <>b; *new { | operator, a, b | ^super.newCopyArgs(operator, a, b) } value { |proxy| ^a.value(proxy).perform(operator, b.value(proxy)) } initBus { | rate, numChannels | ^a.initBus(rate, numChannels) and: { b.initBus(rate, numChannels) }; } isNeutral { ^a.isNeutral and: { b.isNeutral } } rate { // \audio < \control < \scalar // note that function.rate is defined as \stream var arate = \scalar, brate = \scalar; if(a.respondsTo(\rate)) { arate = a.rate }; if(b.respondsTo(\rate)) { brate = b.rate }; ^if(arate < brate) { arate } { brate } } numChannels { |max| var n1, n2, res; max = max ? 0; n1 = a.numChannels(max); if(n1.notNil) { max = n1 }; n2 = b.numChannels(max); res = if(n1.isNil) { n2 } { if(n2.isNil) { n1 } { max(n1, n2) } }; ^res !? { max(max, res) } } wakeUp { a.wakeUp; b.wakeUp; } asControlInput { "BinaryOpPlug: Cannot calculate this value. Use direct mapping only.".warn; ^this } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/ProxyInterfaces.sc000644 000765 000024 00000022477 12756534417 027355 0ustar00crucialstaff000000 000000 // lightweight objects that insulate different ways of playing/stopping. // the bundle that is passed in is a MixedBundle AbstractPlayControl { var channelOffset; var buildMethods, <>proxyControlClasses; // see wrapForNodeProxy for methods *new { | source, channelOffset = 0 | ^super.newCopyArgs(source, channelOffset); } build { ^true } pause { this.stop } resume { this.start } nodeID { ^nil } readyForPlay { ^true } distributable { ^false } // shared proxy support loadToBundle {} spawnToBundle {} // only active in synthcontrols playToBundle { | bundle, args | bundle.addOnSendMessage(this, \play); //no latency (latency is in stream already) ^nil //return a nil object instead of a synth } stopToBundle { | bundle | bundle.addOnSendMessage(this, \stop); } freeToBundle {} set {} controlNames { ^nil } play { this.subclassResponsibility(thisMethod) } stop { this.subclassResponsibility(thisMethod) } wakeUpParentsToBundle {} addParent { "wrong object in NodeProxy.buildControl".error } // for now. parents { ^nil } store {} copy { ^this.class.new.copyState(this) } copyState { |control| source = control.source; // source is not copied, assumed to be stateless channelOffset = control.channelOffset; paused = control.paused; } } // The stream is a pause stream. This is meant for running in the proxy to control inner properties so it is stopped when removed. StreamControl : AbstractPlayControl { var stream, nodeID; var all; var px } }); } } } activeProxies { ^this.arProxyNames({ |px, key| px.isPlaying }) } playingProxies { ^this.arProxyNames({ |px, key| px.monitor.isPlaying }) } existingProxies { ^this.arProxyNames } arProxyNames { |func = true| ^this.proxyNames(\audio, func) } krProxyNames { |func = true| ^this.proxyNames(\control, func) } proxyNames { |rate, func=true| var pxs; pxs = SortedList(8, { |a,b| a < b }); this.keysValuesDo({ arg key, px; if (px.rate === rate) { if (func.value(px, key), { pxs.add(key) }) } }); ^pxs; } doFunctionPerform { |selector| ^this[selector] } // making copies copy { ^super.copy.copyState(this) } copyState { |proxySpace| server = proxySpace.server; fadeTime = proxySpace.fadeTime; quant = proxySpace.quant; reshaping = proxySpace.reshaping; awake = proxySpace.awake; group = proxySpace.group; if(proxySpace.clock.isKindOf(TempoBusClock)) { this.makeTempoClock( proxySpace.clock.tempo, proxySpace.clock.beats, proxySpace.clock.seconds ) } { clock = proxySpace.clock; } } // global access add { if(name.notNil) { if(this.class.all[name].isNil) { this.class.all.put(name, this) } { "there is already an environment with this name".warn }; } { "a ProxySpace with no name cannot be added to the repository".warn } } remove { this.class.all.removeAt(name) } *clearAll { this.all.do({ arg item; item.clear }); } printOn { |stream| stream << this.class.name; if(envir.isEmpty) { stream << " ()\n"; ^this }; stream << " ( " << (name ? "") << Char.nl; this.keysValuesDo { arg key, item, i; stream << "~" << key << " - "; stream << if(item.rate === 'audio') { "ar" } { if(item.rate === 'control', { "kr" }, { "ir" }) } << "(" << item.numChannels << ") " << if(i.even) { "\t\t" } { "\n" }; }; stream << "\n)\n" } postln { Post << this } includes { |proxy| ^envir.includes(proxy) } size { ^envir.size } *findSpace { |proxy, getCode = false| var space = [ currentEnvironment, thisProcess.interpreter.p ] .detect { |cand| cand.isKindOf(this) and: { cand.includes(proxy) } }; if (space.notNil) { ^space }; space = ProxySpace.all.detect(_.includes(proxy)); if (space.notNil) { ^space }; space = Ndef.all.detect(_.includes(proxy)); if (space.notNil) { ^space }; // none found ^nil } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/ProxySynthDef.sc000644 000765 000024 00000010775 12756534417 027014 0ustar00crucialstaff000000 000000 ProxySynthDef : SynthDef { var <>rate, <>numChannels; var <>canReleaseSynth, <>canFreeSynth; classvar <>sampleAccurate=false; *new { | name, func, rates, prependArgs, makeFadeEnv = true, channelOffset = 0, chanConstraint, rateConstraint | var def, rate, numChannels, output, isScalar, envgen, canFree, hasOwnGate; var hasGateArg=false, hasOutArg=false; var outerBuildSynthDef = UGen.buildSynthDef; def = super.new(name, { var out, outCtl; // build the controls from args output = SynthDef.wrap(func, rates, prependArgs); output = output.asUGenInput; // protect from user error if(output.isKindOf(UGen) and: { output.synthDef != UGen.buildSynthDef }) { Error("Cannot share UGens between NodeProxies:" + output).throw }; // protect from accidentally wrong array shapes if(output.containsSeqColl) { "Synth output should be a flat array.\n%\nFlattened to: %\nSee NodeProxy helpfile:routing\n\n".format(output, output.flat).warn; output = output.flat; }; output = output ? 0.0; // determine rate and numChannels of ugen func numChannels = output.numChannels; rate = output.rate; isScalar = rate === 'scalar'; // check for out key. this is used by internal control. func.def.argNames.do { arg name; if(name === \out) { hasOutArg = true }; if(name === \gate) { hasGateArg = true }; }; if(isScalar.not and: hasOutArg) { "out argument is provided internally!".error; // avoid overriding generated out ^nil }; // rate is only scalar if output was nil or if it was directly produced by an out ugen // this allows us to conveniently write constant numbers to a bus from the synth // if you want the synth to write nothing, return nil from the UGen function. if(isScalar and: { output.notNil } and: { UGen.buildSynthDef.children.last.isKindOf(AbstractOut).not }) { rate = 'control'; isScalar = false; }; //detect inner gates canFree = UGen.buildSynthDef.children.canFreeSynth; hasOwnGate = UGen.buildSynthDef.hasGateControl; makeFadeEnv = if(hasOwnGate and: { canFree.not }) { "The gate control should be able to free the synth!\n%".format(func).warn; false } { makeFadeEnv and: { (isScalar || canFree).not }; }; hasOwnGate = canFree && hasOwnGate; //only counts when it can actually free synth. if(hasOwnGate.not && hasGateArg) { "supplied gate overrides inner gate.".error; ^nil }; //"gate detection:".postln; //[\makeFadeEnv, makeFadeEnv, \canFree, canFree, \hasOwnGate, hasOwnGate].debug; // constrain the output to the right number of channels if supplied // if control rate, no channel wrapping is applied // and wrap it in a fade envelope envgen = if(makeFadeEnv) { EnvGate(1, nil, nil, 2, if(rate === 'audio') { 'sin' } { 'lin' }) } { 1.0 }; if(chanConstraint.notNil and: { chanConstraint < numChannels } and: { isScalar.not }, { if(rate === 'audio') { postf("%: wrapped channels from % to % channels\n", NodeProxy.buildProxy, numChannels, chanConstraint); output = NumChannels.ar(output, chanConstraint, true); numChannels = chanConstraint; } { postf("%: kept first % channels from % channel input\n", NodeProxy.buildProxy, chanConstraint, numChannels); output = output.keep(chanConstraint); numChannels = chanConstraint; } }); output = output * envgen; //"passed in rate: % output rate: %\n".postf(rateConstraint, rate); if(isScalar, { output }, { // rate adaption. \scalar proxy means neutral if(rateConstraint.notNil and: { rateConstraint != \scalar and: { rateConstraint !== rate }}) { if(rate === 'audio') { output = A2K.kr(output); rate = 'control'; postf("%: adopted proxy input to control rate\n", NodeProxy.buildProxy); } { if(rateConstraint === 'audio') { output = K2A.ar(output); rate = 'audio'; postf("%: adopted proxy input to audio rate\n", NodeProxy.buildProxy); } } }; outCtl = Control.names(\out).ir(0) + channelOffset; (if(rate === \audio and: { sampleAccurate }) { OffsetOut } { Out }).multiNewList([rate, outCtl] ++ output) }) }); UGen.buildSynthDef = outerBuildSynthDef; // set the synthDefs instvars, so they can be used later def.rate = rate; def.numChannels = numChannels; def.canReleaseSynth = makeFadeEnv || hasOwnGate; def.canFreeSynth = def.canReleaseSynth || canFree; //[\defcanReleaseSynth, def.canReleaseSynth, \defcanFreeSynth, def.canFreeSynth].debug; ^def } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/TempoBusClock.sc000644 000765 000024 00000000655 12756534417 026734 0ustar00crucialstaff000000 000000 TempoBusClock : TempoClock { var <>control; classvar <>default; *new { | control, tempo, beats, seconds | ^super.new(tempo, beats, seconds).control_(control) } setTempoAtBeat { | newTempo, beats | control.set(\fadeTime, 0.0, \tempo, newTempo); ^super.setTempoAtBeat(newTempo, beats) } setTempoAtSec { | newTempo, secs | control.set(\fadeTime, 0.0, \tempo, newTempo) ^super.setTempoAtSec(newTempo, secs) } } SuperCollider-Source/SCClassLibrary/JITLib/ProxySpace/wrapForNodeProxy.sc000644 000765 000024 00000022670 12756534417 027513 0ustar00crucialstaff000000 000000 // these extensions provide means to wrap Objects so that they // make sense within the server bus system according to a node proxy. ////////////////////// graphs, functions, numericals and arrays ////////////////// + Object { // objects can define their own wrapper classes dependent on // how they play, stop, build, etc. see SynthDefControl for example // the original (wrapped) object can be reached by the .source message // for objects that only create ugen graphs, define prepareForProxySynthDef(proxy) proxyControlClass { ^SynthDefControl } makeProxyControl { | channelOffset = 0 | ^this.proxyControlClass.new(this, channelOffset); } // any preparations that have to be done to prepare the object // implement 'prepareForProxySynthDef' to return a ugen func // this method is called from within the Control buildForProxy { | proxy, channelOffset = 0, index | var channelConstraint, rateConstraint; var argNames = this.argNames; if(proxy.fixedBus) { channelConstraint = proxy.numChannels; rateConstraint = proxy.rate; }; ^ProxySynthDef( SystemSynthDefs.tempNamePrefix ++ proxy.generateUniqueName ++ index, this.prepareForProxySynthDef(proxy, channelOffset), proxy.nodeMap.ratesFor(argNames), nil, true, channelOffset, channelConstraint, rateConstraint ); } prepareForProxySynthDef { ^this.subclassResponsibility(thisMethod) } defaultArgs { ^nil } argNames { ^nil } // support for unop / binop proxy isNeutral { ^true } initBus { ^true } wakeUp {} } + Function { prepareForProxySynthDef { ^this } argNames { ^def.argNames } defaultArgs { ^def.prototypeFrame } } + AbstractFunction { prepareForProxySynthDef { ^{ this.value } } } + SimpleNumber { proxyControlClass { ^StreamControl } buildForProxy { | proxy, channelOffset = 0 | ^[this].buildForProxy(proxy, channelOffset) } } + Synth { // better information about common error prepareForProxySynthDef { | proxy | Error( "A synth is no valid source for a proxy.\n" "For instance, ~out = { ... }.play would cause this and should be:\n" "~out = { ... }; ~out.play; or (~out = { ... }).play;" ).throw; } } + Array { proxyControlClass { ^StreamControl } buildForProxy { | proxy, channelOffset = 0 | proxy.initBus(\control, this.size); ^( type: \fadeBus, array: this, proxy: proxy, channelOffset: channelOffset, finish: #{ var proxy = ~proxy; ~out = proxy.index + ~channelOffset; ~group = proxy.group; ~rate = proxy.rate; ~numChannels = proxy.numChannels; ~fadeTime = proxy.fadeTime; ~curve = proxy.nodeMap.at(\curve); } ) } } + SequenceableCollection { prepareForProxySynthDef { | proxy | ^{ this.collect({ |el| el.prepareForProxySynthDef(proxy).value }) } // could use SynthDef.wrap, but needs type check for function. } } + BusPlug { prepareForProxySynthDef { | proxy | proxy.initBus(this.rate, this.numChannels); ^{ this.value(proxy) } } } + AbstractOpPlug { prepareForProxySynthDef { | proxy | proxy.initBus(this.rate, this.numChannels); ^{ this.value(proxy) } } } // needs a visit: lazy init + channelOffset + Bus { prepareForProxySynthDef { | proxy | ^BusPlug.for(this).prepareForProxySynthDef(proxy); } } ///////////////////////////// SynthDefs and alike //////////////////////////////////// + SynthDef { buildForProxy {} numChannels { ^nil } // cannot know this rate { ^nil } } + Symbol { buildForProxy {} proxyControlClass { ^SynthControl } } ///////////////////////////// Pattern - Streams /////////////////////////////////// + Stream { proxyControlClass { ^StreamControl } buildForProxy { ^PauseStream.new(this) } } + PauseStream { buildForProxy { ^this } proxyControlClass { ^StreamControl } } + PatternProxy { buildForProxy { "a numerical pattern does not make sense here.".error; ^nil } } + TaskProxy { proxyControlClass { ^StreamControl } buildForProxy { | proxy, channelOffset = 0 | ^PauseStream(this.endless.asStream <> ( nodeProxy: proxy, channelOffset: channelOffset, server: { proxy.server }, out: { proxy.index }, group: { proxy.group } ) ) } } + EventPatternProxy { proxyControlClass { ^PatternControl } buildForProxy { | proxy, channelOffset = 0 | proxy.initBus(\audio); ^this.endless.buildForProxy(proxy, channelOffset) } } + Pattern { proxyControlClass { ^PatternControl } buildForProxy { | proxy, channelOffset = 0 | var player = this.asEventStreamPlayer; var event = player.event.buildForProxy(proxy, channelOffset); proxy.initBus(\audio); ^event !? { player }; } } + Event { proxyControlClass { ^StreamControl } buildForProxy { | proxy, channelOffset = 0 | var ok, index, server, numChannels, rate, finish, out, group; ok = if(proxy.isNeutral) { rate = this.at(\rate) ? 'audio'; numChannels = this.at(\numChannels); numChannels !? { numChannels = numChannels + channelOffset }; proxy.initBus(rate, numChannels); } { rate = proxy.rate; // if proxy is initialized, it is user's responsibility numChannels = proxy.numChannels; true }; ^if(ok) { index = proxy.index; server = proxy.server; out = { var n = proxy.numChannels; if(n.isNil) { -1 } { (~channelOffset ? channelOffset) % n + index } }; group = { proxy.group.asNodeID }; this.use({ ~proxy = proxy; ~server = server; ~group = group; ~out = out.value; finish = ~finish; ~finish = { finish.value; proxy.nodeMap.addToEvent(currentEnvironment); ~out = out.value; } }); this } { nil } } } /////////// pluggable associations ////////////// + Association { buildForProxy { | proxy, channelOffset = 0, index | ^AbstractPlayControl.buildMethods[key].value(value, proxy, channelOffset, index) } proxyControlClass { ^AbstractPlayControl.proxyControlClasses[key] ? SynthDefControl } } + AbstractPlayControl { makeProxyControl { ^this.deepCopy } //already wrapped, but needs to be copied /* these adverbial extendible interfaces are for supporting different role schemes. it is called by Association, so ~out = \filter -> ... will call this. The first arg passed is the value of the association */ *initClass { proxyControlClasses = ( filter: SynthDefControl, xset: StreamControl, pset: StreamControl, set: StreamControl, stream: PatternControl, setbus: StreamControl, setsrc: StreamControl ); buildMethods = ( filter: #{ | func, proxy, channelOffset = 0, index | var ok, ugen; if(proxy.isNeutral) { ugen = func.value(Silent.ar); ok = proxy.initBus(ugen.rate, ugen.numChannels + channelOffset); if(ok.not) { Error("NodeProxy input: wrong rate/numChannels").throw } }; { | out | var e = EnvGate.new * Control.names(["wet"++(index ? 0)]).kr(1.0); if(proxy.rate === 'audio') { XOut.ar(out, e, SynthDef.wrap(func, nil, [In.ar(out, proxy.numChannels)])) } { XOut.kr(out, e, SynthDef.wrap(func, nil, [In.kr(out, proxy.numChannels)])) }; }.buildForProxy( proxy, channelOffset, index ) }, set: #{ | pattern, proxy, channelOffset = 0, index | var args = proxy.controlNames.collect(_.name); Pchain( (type: \set, \id: { proxy.group.nodeID }), pattern, (args: args) ).buildForProxy( proxy, channelOffset, index ) }, pset: #{ | pattern, proxy, channelOffset = 0, index | Pbindf( pattern, \play, { proxy.set(*proxy.controlNames.collect(_.name).envirPairs.asOSCArgArray) } ).buildForProxy( proxy, channelOffset, index ) }, xset: #{ | pattern, proxy, channelOffset = 0, index | Pbindf( pattern, \play, { proxy.xset(*proxy.controlNames.collect(_.name).envirPairs.asOSCArgArray) } ).buildForProxy( proxy, channelOffset, index ) }, setbus: #{ | pattern, proxy, channelOffset = 0, index | var ok = proxy.initBus(\control); if(ok.not) { Error("NodeProxy input: wrong rate").throw }; Pbindf( pattern, \type, \bus, \id, Pfunc { proxy.group.nodeID }, \array, Pkey(\value).collect { |x| x.asArray.keep(proxy.numChannels) }, \out, Pfunc { proxy.index } ).buildForProxy( proxy, channelOffset, index ) }, setsrc: #{ | pattern, proxy, channelOffset = 0, index = 0 | pattern.collect { |event| event[\type] = \rest; proxy.put(index + 1, event[\source]); event }.buildForProxy( proxy, channelOffset, index ); }, control: #{ | values, proxy, channelOffset = 0, index | { Control.kr(values) }.buildForProxy( proxy, channelOffset, index ); }, filterIn: #{ | func, proxy, channelOffset = 0, index | var ok, ugen; if(proxy.isNeutral) { ugen = func.value(Silent.ar); ok = proxy.initBus(ugen.rate, ugen.numChannels + channelOffset); if(ok.not) { Error("NodeProxy input: wrong rate/numChannels").throw } }; { | out | var in; var egate = EnvGate.new; var wetamp = Control.names(["wet"++(index ? 0)]).kr(1.0); var dryamp = 1 - wetamp; if(proxy.rate === 'audio') { in = In.ar(out, proxy.numChannels); XOut.ar(out, egate, SynthDef.wrap(func, nil, [in * wetamp]) + (dryamp * in)) } { in = In.kr(out, proxy.numChannels); XOut.kr(out, egate, SynthDef.wrap(func, nil, [in * wetamp]) + (dryamp * in)) }; }.buildForProxy( proxy, channelOffset, index ) }, mix: #{ | func, proxy, channelOffset = 0, index | { var e = EnvGate.new * Control.names(["mix"++(index ? 0)]).kr(1.0); e * SynthDef.wrap(func); }.buildForProxy( proxy, channelOffset, index ) }; ) } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/extFunction.sc000644 000765 000024 00000000702 12756534417 026224 0ustar00crucialstaff000000 000000 + Object { valueFuncProxy { ^this } reduceFuncProxy { ^this } postString { ^this.asString } } + AbstractFunction { reduceFuncProxy { arg args; ^this.valueArray(args).valueFuncProxy(args) } } + Function { postString { ^this.asCompileString } } + UnaryOpFunctionProxy { postString { ^a.postString ++ "." ++ selector } } + BinaryOpFunctionProxy { postString { ^a.postString + selector.asBinOpString + b.postString } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/extPostAsCode.sc000644 000765 000024 00000001320 12766171707 026440 0ustar00crucialstaff000000 000000 + PatternProxy { // like asCompileString, but with full source etc. asCode { var mykey = this.key.asCompileString; var str; str = "" ++ this.class.name ++ "("; if(source.isNil or: { source == this.class.default }) { str = str ++ mykey; } { str = str ++ this.repositoryArgs.asCompileString.drop(1).drop(-1); }; str = str ++ ")"; if(this.envir.notNil and: { this.envir.notEmpty }) { str = str ++ ".set(" ++ this.envir.asKeyValuePairs.asCompileString.drop(1).drop(-1) ++ ")" }; str = str ++ ";" ^str } } + Tdef { printOn { |stream| ^this.storeOn(stream); } } + Pdef { printOn { |stream| ^this.storeOn(stream); } } + Pdefn { printOn { |stream| ^this.storeOn(stream); } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/extRoutine.sc000644 000765 000024 00000002127 12756534417 026067 0ustar00crucialstaff000000 000000 + Pattern { lock { arg n=1; ^Pfin(n.asStream, this.asStream) } } + Stream { fastForward { arg by, tolerance=0, inevent; var t = 0, delta = 0, event; if(by <= 0) { ^0.0 }; inevent = inevent ?? { Event.default }; while { t.roundUp(tolerance) < by } { event = this.next(inevent.copy); if(event.isNil) { ("end of stream. Time left:" + (by - t)).inform; ^t - by }; event = event.copy.put(\freq, \rest); event.play; delta = event.delta; if(delta.isNil) { ("end of stream. Time left:" + (by - t)).inform; ^t - by }; t = t + delta; }; ^t - by // time left to next event } } + EventStreamPlayer { xplay { arg fadeTime, argClock, doReset = false, quant=1.0; if (doReset, { this.reset }); clock = argClock ? clock ? TempoClock.default; stream = PfadeIn(originalStream, fadeTime).asStream; clock.play(this, quant); } xstop { arg fadeTime; stream = PfadeOut(stream, fadeTime).asStream; } } + PauseStream { xplay { arg fadeTime, argClock, doReset = false, quant=1.0; this.play(argClock, doReset, quant); } xstop { // stop after fade? this.stop; } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/Fdef.sc000644 000765 000024 00000010431 12756534417 024562 0ustar00crucialstaff000000 000000 // maybe we want to call "value" "reduce" and only use one class. Maybe : Ref { classvar callFunc; classvar <>defaultValue; classvar <>protected = false, <>verbose = false; source { ^value } source_ { arg obj; this.value = obj; this.changed(\source, obj) } clear { value = nil } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } valueEnvir { arg ... args; ^this.notYetImplemented(thisMethod) //^value.valueEnvir(*args) ? defaultValue } valueArrayEnvir { arg ... args; ^this.notYetImplemented(thisMethod) //^value.valueArrayEnvir(args) ? defaultValue } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } // this allows recursion apply { arg ... args; ^this.reduceFuncProxy(args, false) } // function composition o { arg ... args; ^NAryValueProxy(this, args) } <> { arg that; ^o (this, that) } // use in list comprehension all { ^this.source.all } do { arg function; this.source.do(function) // problem: on the fly change is not picked up in this case. } doesNotUnderstand { arg selector ... args; ^this.composeNAryOp(selector, args) } // streams and patterns embedInStream { arg inval; ^Prout { arg inval; var curVal, str; var outval; while { if(curVal !== value) { str = value.asStream; curVal = value }; outval = str.next(inval); outval.notNil } { inval = outval.yield; } }.embedInStream(inval) } // math composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // used by AbstractFunction:reduceFuncProxy // to prevent reduction of enclosed functions valueFuncProxy { arg args; if(verbose and: { value.isNil }) { ("Maybe: incomplete definition: %\n").postf(this.infoString(args)) }; ^this.catchRecursion { (value ? defaultValue).valueFuncProxy(args) } } reduceFuncProxy { arg args, protect=true; if(verbose and: { value.isNil }) { ("Maybe: incomplete definition: %\n").postf(this.infoString(args)) }; ^if(protect.not) { (value ? defaultValue).reduceFuncProxy(args) } { this.catchRecursion { (value ? defaultValue).reduceFuncProxy(args) } } } catchRecursion { arg func; var val, previous; try { protect { previous = current; current = this; if(this.includedInCallers) { if(verbose) { ("* ! Couldn't solve a recursive definition in %\n") .postf(this.infoString) }; callFunc.value(this, callers, \recursion); this.throw; }; // add this to the list of current callers callers = callers.add(this); // evaluate function val = func.value; callFunc.value(this, callers, val); } { |exception| if(verbose and: { exception.isKindOf(Exception)} ) { ("Error or incomplete specification" + exception.errorString).postln; }; /* if(exception.isKindOf(this.class).not) { Exception.throw; }*/ // remove again callers.pop; current = previous; }; } ^val } includedInCallers { ^callers.notNil and: { callers.includes(this) } } postString { var res = this.findKey; ^if(res.notNil) { "~" ++ res } { this.asString } } infoString { arg args; var who, str="", src; who = this.findKey; if(who.isNil) { ^this.asString }; who = "~" ++ who; src = this.source.postString; if(args.notNil and: {args.notEmpty}) { args = args.collect(_.postString); str = "\nArguments passed: %".format(args) }; ^"% <- %".format(who, src.asString) ++ str } findKey { ^currentEnvironment.findKeyForValue(this) } storeOn { arg stream; // maybe should try to catch a recursion here: stream << this.class.name << "(" <<< value << ")" } } Fdef : Maybe { classvar <>all; *initClass { all = IdentityDictionary.new } *new { arg key, val; var res; res = all[key]; if(res.isNil) { res = super.new.source_(val); all[key] = res } { if(val.notNil) { res.source = val }; } ^res } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/OpFunctionProxy.sc000644 000765 000024 00000005527 12756534417 027056 0ustar00crucialstaff000000 000000 UnaryOpFunctionProxy : UnaryOpFunction { valueFuncProxy { arg args; ^this.reduceFuncProxy(args) } reduceFuncProxy { arg args; ^a.reduceFuncProxy(args).perform(selector) } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // behave like a pattern embedInStream { arg inval; ^this.value.embedInStream(inval) } } BinaryOpFunctionProxy : BinaryOpFunction { valueFuncProxy { arg args; ^this.reduceFuncProxy(args) } reduceFuncProxy { arg args; ^a.reduceFuncProxy(args) .perform(selector, b.reduceFuncProxy(args), adverb) } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // behave like a pattern embedInStream { arg inval; ^this.value.embedInStream(inval) } } NAryOpFunctionProxy : NAryOpFunction { reduceFuncProxy { arg args; ^a.reduceFuncProxy(args).performList(selector, arglist.collect(_.reduceFuncProxy(args))) } valueFuncProxy { arg args; ^this.reduceFuncProxy(args) } value { arg ... args; ^this.reduceFuncProxy(args) } valueArray { arg args; ^this.reduceFuncProxy(args) } composeUnaryOp { arg aSelector; ^UnaryOpFunctionProxy.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunctionProxy.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunctionProxy.new(aSelector, this, anArgList) } // behave like a pattern embedInStream { arg inval; ^this.value.embedInStream(inval) } } // maybe make it an abstract function object. NAryValueProxy : NAryOpFunctionProxy { *new { arg receiver, args; ^super.new(nil, receiver, args ? []) } reduceFuncProxy { arg args; ^a.reduceFuncProxy(arglist.collect(_.reduceFuncProxy(args))) } storeOn { arg stream; stream << "o(" <<< a << "," <<<* arglist << ")" // is it always so? } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/Pdef.sc000644 000765 000024 00000043403 12756534417 024601 0ustar00crucialstaff000000 000000 // contains numerical / value patterns PatternProxy : Pattern { var envir; var >clock, quant, <>condition=true, reset; // quant value for new pattern insertio can be an array, like [quant, phase, timingOffset] // in EventPatternProxy it can be [quant, phase, timingOffset, onset] classvar <>defaultQuant, defaultEnvir; *new { arg source; ^super.new.source_(source) } *default { ^1 } // safe for duration patterns *defaultValue { ^1 } clock { ^clock ? TempoClock.default } quant { ^quant ?? { this.class.defaultQuant } } quant_ { arg val; quant = val } source_ { arg obj; var pat = if(obj.isKindOf(Function)) { this.convertFunction(obj) }{ obj }; if (obj.isNil) { pat = this.class.default }; pattern = pat; source = obj; // keep original here. this.changed(\source, obj); } setSource { arg obj; pattern = obj; source = obj; // keep original here. this.changed(\source, obj); } count { arg n=1; condition = { |val,i| i % n == 0 } } reset { reset = reset ? 0 + 1 } sched { arg func; if(quant.isNil) { func.value } { this.clock.schedAbs(quant.nextTimeOnGrid(this.clock), { func.value; nil }) } } convertFunction { arg func; ^Prout { var inval = func.def.prototypeFrame !? { inval = this.defaultEvent }; func.value( inval ).embedInStream(inval) } } *parallelise { arg list; ^Ptuple(list) } pattern_ { arg pat; this.source_(pat) } timingOffset_ { arg val; quant = quant.instill(2, val) } timingOffset { arg val; ^quant.obtain(2) } phase_ { arg val; quant = quant.instill(1, val) } phase { arg val; ^quant.obtain(1) } quantBeat_ { arg val; quant = quant.instill(0, val) } quantBeat { arg val; ^quant.obtain(0) } set { arg ... args; if(envir.isNil) { this.envir = this.class.event }; args.pairsDo { arg key, val; envir.put(key, val) }; this.changed(\set, args); } unset { arg ... args; if(envir.notNil) { args.do { arg key; envir.removeAt(key) }; this.changed(\unset, args); } } get { arg key; ^if(envir.notNil) { envir[key] } { nil }; } place { arg ... args; if(envir.isNil) { this.envir = this.class.event }; args.pairsDo { arg key, val; envir.place(key, val) }; // place is defined in the event. } isEventPattern { ^false } receiveEvent { ^nil } embed { |val| ^if(val.notNil) { Pchain(this, val) } { this }.embedInStream } embedInStream { arg inval, embed = true, default; var outval, count = 0; var pat = pattern; var test = condition; var resetTest = reset; var stream = pattern.streamArg(embed); while { this.receiveEvent(inval); // used in subclass if( (reset !== resetTest) or: { pat !== pattern and: { test.value(outval, count) } } ) { pat = pattern; test = condition; resetTest = reset; count = 0; stream = this.constrainStream(stream, pattern.streamArg(embed)); }; outval = stream.next(inval) ? default; count = count + 1; outval.notNil }{ inval = outval.yield; }; ^inval } asStream { ^Routine { arg inval; this.embedInStream(inval, false) } } endless { arg default; ^Prout { arg inval; this.embedInStream(inval, true, default ? this.class.defaultValue) } } constrainStream { arg stream, newStream; ^if(this.quant.isNil) { newStream } { Pseq([PfinQuant(EmbedOnce(stream), this.quant, clock), newStream]).asStream } } defaultEvent { if(envir.isNil) { envir = this.class.event }; ^if(envir[\independent] === true) { (parent:envir) } { envir } } storeArgs { ^[pattern] } copy { ^super.copy.copyState(this) } copyState { |proxy| envir = proxy.envir.copy; this.source = proxy.source; } // these following methods are factored out for the benefit of subclasses // they only work for Pdef/Tdef/Pdefn. *removeAll { this.clear; this.all.makeEmpty; } *clear { this.all.do { arg pat; pat.clear } } clear { this.stop; this.source = nil; ^nil } remove { if(this.class.hasGlobalDictionary) { this.class.all.removeAt(this.key) }; this.clear; } // backward compatibility *basicNew { arg source; ^super.new.init(source) } // global storage *at { arg key; ^if(this.hasGlobalDictionary) { this.all.at(key) } { nil } } repositoryArgs { ^[this.key, this.source] } *postRepository { arg keys, stream; if(this.hasGlobalDictionary.not) { Error("This class has no global repository.").throw }; keys = keys ?? { this.all.keys }; stream = stream ? Post; keys.do { arg key; var item; item = this.all[key]; if(item.notNil and: { item.source !== this.default }) { stream << item.class.name << "(" <<<* item.repositoryArgs << ")"; if(item.envir.notNil and: { item.envir.notEmpty }) { stream << ".set(" <<<* item.envir.asKeyValuePairs << ")" }; stream << ";\n" }; }; } *event { arg proxyClass = PatternProxy; var event, res; if(defaultEnvir.isNil) { defaultEnvir = Event.default; defaultEnvir.parent = defaultEnvir.parent.copy.putAll( ( forward: #{ 1 }, proxyClass: proxyClass, get: {|e, key| var x = e.at(key); if(x.isKindOf(e.proxyClass).not) { x = e.proxyClass.new; e.put(key, x); }; x }, place: { |e, key, val| var x = e.at(key); if(x.isKindOf(e.proxyClass).not) { x = e.proxyClass.new; e.put(key, x) }; x.source_(val) } ) ); }; event = defaultEnvir.copy; // event[\self] = event; // this risks a crash on storeOn. ^event } *hasGlobalDictionary { ^false } } Pdefn : PatternProxy { var all; *initClass { all = IdentityDictionary.new; } *new { arg key, item; var res = this.at(key); if(res.isNil) { res = super.new(item).prAdd(key); } { if(item.notNil) { res.source = item } } ^res } map { arg ... args; if(envir.isNil) { this.envir = () }; args.pairsDo { |key, name| envir.put(key, Pdefn(name)) }; this.changed(\map, args); } storeArgs { ^[key] } // assume it was created globally copy { |toKey| if(key == toKey) { Error("cannot copy to identical key").throw }; ^this.class.new(toKey).copyState(this) } prAdd { arg argKey; key = argKey; all.put(argKey, this); } *hasGlobalDictionary { ^true } } // contains time patterns (tasks) TaskProxy : PatternProxy { var playQuant; classvar <>defaultQuant=1.0; storeArgs { ^[source] } source_ { arg obj; pattern = if(obj.isKindOf(Function)) { this.convertFunction(obj) }{ obj }; if (obj.isNil) { pattern = this.class.default; source = obj; }; this.wakeUp; source = obj; this.changed(\source, obj); } convertFunction { arg func; ^Prout { |inevent| var inval = func.def.prototypeFrame !? { this.defaultEvent }; if(inevent.isNumber or: {inevent.isNil} or: { inval.isNil }) { inevent = inval } { inevent.copy.parent_(inval); }; func.value(inevent) } } isEventPattern { ^true } *default { ^Pn(this.defaultValue, 1) } // here, the streams return values which are used as durations // for scheduling the stream itself constrainStream { arg stream, newStream; ^if(this.quant.isNil) { newStream } { Pseq([ EmbedOnce(Pconst(thisThread.clock.timeToNextBeat(this.quant), stream, 0.001)), newStream ]).asStream } } align { arg argQuant; quant = argQuant; this.source = this.source.copy; } ////////// playing interface ////////// playOnce { arg argClock, doReset = (false), quant; var clock = argClock ? this.clock; ^PauseStream.new(this.asProtected.asStream).play(clock, doReset, quant ? this.quant) } play { arg argClock, doReset=false, quant; playQuant = quant ? this.quant; if(player.isNil) { player = this.playOnce(argClock, doReset, playQuant); } { // resets when stream has ended or after pause/cmd-period: if (player.streamHasEnded or: { player.wasStopped }) { doReset = true }; if(player.isPlaying.not) { player.play(argClock, doReset, playQuant); } { if (doReset) { player.reset }; } } } wakeUp { if(this.isPlaying) { this.play(quant:playQuant) } } asProtected { ^Pprotect(this, { if(this.player.notNil) { this.player.streamError } }) } // check playing states: isPlaying { ^player.notNil and: { player.wasStopped.not } } isActive { ^this.isPlaying and: { player.streamHasEnded.not } } hasSource { ^source.notNil } hasEnvir { ^envir.notNil } hasPlayer { ^player.notNil } hasEnded { ^player.isNil or: { player.streamHasEnded } } isPaused { ^player.isNil or: { player.wasStopped } } canPause { ^player.notNil and: { player.canPause } } fork { arg clock, quant, event; if (event.notNil and: { envir.notNil }) { event.parent_(envir) }; ^Routine { this.embedInStream(event) }.play(clock ? thisThread.clock, quant) } stop { player.stop; player = nil; } pause { if(player.notNil) { this.sched { player.pause } } } resume { arg clock, quant; player !? { player.resume(clock ? this.clock, quant ? this.quant) } } } Tdef : TaskProxy { var all; *initClass { all = IdentityDictionary.new; } *new { arg key, item; var res = this.at(key); if(res.isNil) { res = super.new(item).prAdd(key); } { if(item.notNil) { res.source = item } } ^res } storeArgs { ^[key] } copy { |toKey| if(key == toKey) { Error("cannot copy to identical key").throw }; ^this.class.new(toKey).copyState(this) } prAdd { arg argKey; key = argKey; all.put(argKey, this); } *hasGlobalDictionary { ^true } } // contains event patterns EventPatternProxy : TaskProxy { var <>fadeTime; classvar <>defaultQuant=1.0; storeArgs { ^[source] } source_ { arg obj; if(obj.isKindOf(Function)) // allow functions to be passed in { pattern = PlazyEnvirN(obj) } { if (obj.isNil) { pattern = this.class.default } { pattern = obj } }; envir !? { pattern = pattern <> envir }; this.wakeUp; source = obj; this.changed(\source, obj); } envir_ { arg dict; envir = dict; this.source = source; } *defaultValue { ^Event.silent } embedInStream { arg inval, embed = true, default; var outval, count=0; var pat = pattern; var test = condition; var resetTest = reset; var stream = pattern.streamArg(embed); var cleanup = EventStreamCleanup.new; while { this.receiveEvent(inval); if( (reset !== resetTest) or: { pat !== pattern and: { test.value(outval, count) } } ) { pat = pattern; test = condition; resetTest = reset; count = 0; // inval is the next event that will be yielded // constrainStream may add some values to it so *it must be yielded* stream = this.constrainStream(stream, pattern.streamArg(embed), inval, cleanup); }; outval = stream.next(inval) ? default; count = count + 1; outval.notNil }{ outval = cleanup.update(outval); inval = outval.yield; if(inval.isNil) { ^nil.alwaysYield } }; ^inval } constrainStream { arg stream, newStream, inval, cleanup; var delta, tolerance; var quantBeat, catchUp, deltaTillCatchUp, forwardTime, quant = this.quant; ^if(this.quant.isNil) { cleanup !? { cleanup.exit(inval) }; newStream } { quantBeat = this.quantBeat ? 0; catchUp = this.outset; delta = thisThread.clock.timeToNextBeat(quant); tolerance = quantBeat % delta % 0.125; if(catchUp.notNil) { deltaTillCatchUp = thisThread.clock.timeToNextBeat(catchUp); forwardTime = quantBeat - delta + deltaTillCatchUp; delta = newStream.fastForward(forwardTime, tolerance) + deltaTillCatchUp; }; if(fadeTime.isNil) { if(delta == 0) { cleanup !? { cleanup.exit(inval) }; newStream } { Pseq([ EmbedOnce( Pfindur(delta, stream, tolerance).asStream, cleanup ), newStream ]).asStream } }{ Ppar([ EmbedOnce( PfadeOut(stream, fadeTime, delta, tolerance), cleanup ), PfadeIn(newStream, fadeTime, delta, tolerance) ]).asStream } } } *parallelise { arg list; ^Ppar(list) } outset_ { arg val; quant = quant.instill(3, val) } outset { arg val; ^this.quant.obtain(3) } // branching from another thread fork { arg argClock, quant, protoEvent; // usual fork arg order: clock, quant, ... argClock = argClock ? thisThread.clock; ^EventStreamPlayer(this.asStream, protoEvent).play(argClock, true, quant) } // playing one instance // playOnce { arg argClock, protoEvent, quant; ^this.fork(argClock ? this.clock, quant ? this.quant, protoEvent) } ////////// playing interface ////////// play { arg argClock, protoEvent, quant, doReset=false; playQuant = quant ? this.quant; if(player.isNil) { player = EventStreamPlayer(this.asProtected.asStream, protoEvent); player.play(argClock, doReset, playQuant); } { // resets when stream has ended or after pause/cmd-period: if(player.streamHasEnded or: { player.wasStopped }) { doReset = true }; protoEvent !? { player.event = protoEvent }; if(player.isPlaying.not) { player.play(argClock, doReset, playQuant); } { if(doReset) { player.reset }; } } } } Pdef : EventPatternProxy { var all; storeArgs { ^[key] } *new { arg key, item; var res = this.at(key); if(res.isNil) { res = super.new(item).prAdd(key); } { if(item.notNil) { res.source = item } } ^res } map { arg ... args; if(envir.isNil) { this.envir = () }; args.pairsDo { |key, name| envir.put(key, Pdefn(name)) } } prAdd { arg argKey; key = argKey; all.put(argKey, this); } copy { |toKey| if(key == toKey) { Error("cannot copy to identical key").throw }; ^this.class.new(toKey).copyState(this) } *hasGlobalDictionary { ^true } *initClass { var phraseEventFunc; all = IdentityDictionary.new; Class.initClassTree(Event); phraseEventFunc = { var pat, event, outerEvent, recursionLevel, instrument, embeddingLevel, freq, rest; embeddingLevel = ~embeddingLevel ? 0; // infinite recursion catch freq = ~freq.value; rest = freq.isKindOf(Symbol); // check for outer rests if(rest) { ~freq = freq }; pat = (~repository ? all).at(~instrument); if(pat.notNil and: { embeddingLevel < 8 }) { pat = pat.pattern; // optimization. outer pattern takes care for replacement // preserve information from outer pattern, but not delta. recursionLevel = ~recursionLevel; if(~transparency.isNil or: { ~transparency > (recursionLevel ? 0) } ) { outerEvent = currentEnvironment.copy } { outerEvent = Event.default; outerEvent.use { ~type = \phrase; ~recursionLevel = recursionLevel; } }; if(recursionLevel.notNil) { if(recursionLevel > 0) { // in recursion, some inner values have to be overridden instrument = ~instrument; pat = pat.collect { |inval| inval.use { ~instrument = instrument; ~parent = outerEvent; ~recursionLevel = recursionLevel - 1; }; inval }; } { // play pattern in the ordinary way ~type = \note; }; } { // avoid recursion, if instrument not set. outerEvent.put(\embeddingLevel, embeddingLevel + 1); outerEvent.parent_(Event.parentEvents.default); }; // maybe add a Pprotect here. // pat.asProtected pat = Pfindur(~sustain.value, pat); outerEvent.put(\delta, nil); // block delta modification by Ppar outerEvent.put(\instrument, ~synthDef ? \default); pat.play(thisThread.clock, outerEvent, 0.0); } { ~type = \note; ~play.value; } }; Event.addEventType(\phrase, phraseEventFunc); } } PbindProxy : Pattern { var <>pairs, dict, <>which, <>repeats, <>default; *new { arg dict, which, repeats=inf, default; ^super.newCopyArgs(dict, which, repeats, default); } storeArgs { ^[dict,which,repeats,default ] } embedInStream { arg inval; var keyStream, key; keyStream = which.asStream; repeats.value(inval).do({ key = keyStream.next(inval); if(key.isNil) { ^inval }; inval = (dict.at(key) ? default).embedInStream(inval); }); ^inval } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/Psym.sc000644 000765 000024 00000004706 12756534417 024656 0ustar00crucialstaff000000 000000 Psym : FilterPattern { var <>dict; *new { arg pattern, dict; ^super.new(pattern).dict_(dict) } storeArgs { ^[pattern,dict] } lookupClass { ^Pdef } lookUp { arg key; ^(dict ?? { this.lookupClass.all }).at(key.asSymbol) ?? { this.lookupClass.default } } embedInStream { arg inval; var str, outval, pat; str = pattern.asStream; while { outval = str.next(inval); outval.notNil } { pat = this.getPattern(outval); inval = pat.embedInStream(inval); }; ^inval } getPattern { arg key; ^if(key.isSequenceableCollection) { this.lookupClass.parallelise( key.collect {|each| this.lookUp(each) } ); } { this.lookUp(key) } } } Pnsym : Psym { lookupClass { ^Pdefn } } Ptsym : Psym { var <>quant, <>dur, <>tolerance; *new { arg pattern, dict, quant, dur, tolerance = 0.001; ^super.newCopyArgs(pattern, dict, quant, dur, tolerance) } storeArgs { ^[ pattern, dict, quant, dur, tolerance ] } embedInStream { arg inval; var outval, pat, quantVal, durVal; var str = pattern.asStream; var quantStr = quant.asStream; var durStr = dur.asStream; while { outval = str.next(inval); quantVal = quantStr.next(inval) ? quantVal; durVal = durStr.next(inval) ? durVal; outval.notNil } { pat = Psync(this.getPattern(outval), quantVal, durVal, tolerance); inval = pat.embedInStream(inval); }; ^inval } } Pnsym1 : Pnsym { embedInStream { arg inval; var which, outval, pat, currentStream; var str = pattern.asStream; var streams = IdentityDictionary.new; while { which = str.next(inval); which.notNil } { pat = this.getPattern(which); currentStream = streams.at(pat); if(currentStream.isNil) { currentStream = pat.asStream; streams.put(pat, currentStream); }; outval = currentStream.next(inval); outval ?? { ^inval }; inval = outval.yield }; ^inval } } Psym1 : Psym { embedInStream { arg inval; var which, outval, pat, currentStream; var str = pattern.asStream; var streams = IdentityDictionary.new; var cleanup = EventStreamCleanup.new; while { which = str.next(inval); which.notNil } { pat = this.getPattern(which); currentStream = streams.at(pat); if(currentStream.isNil) { currentStream = pat.asStream; streams.put(pat, currentStream); }; outval = currentStream.next(inval); if(outval.isNil) { ^cleanup.exit(inval) }; cleanup.update(outval); inval = outval.yield }; ^cleanup.exit(inval); } } SuperCollider-Source/SCClassLibrary/JITLib/Patterns/Pxfade.sc000644 000765 000024 00000003506 12756534417 025132 0ustar00crucialstaff000000 000000 PfadeIn : FilterPattern { var <>fadeTime, <>holdTime=0, <>tolerance; *new { arg pattern, fadeTime=1.0, holdTime=0.0, tolerance=0.0001; ^super.new(pattern).fadeTime_(fadeTime).holdTime_(holdTime).tolerance_(tolerance) } embedInStream { arg inval; var outval, elapsed=0, stream, c; stream = pattern.asStream; if(holdTime > 0.0) { Event.silent(holdTime, inval).yield }; loop { outval = stream.next(inval); if(outval.isNil) { ^nil.yield }; elapsed = elapsed + outval.delta; c = elapsed / fadeTime; if(c >= 1.0) { inval = outval.yield; ^stream.embedInStream(inval); } { outval = outval.copy; outval[\amp] = c.max(0) * outval[\amp]; // outval[\amp] = (c.max(0) * pi * 0.25).sin * outval[\amp]; inval = outval.yield; } } } storeArgs { ^[ pattern, fadeTime, holdTime, tolerance ] } } PfadeOut : PfadeIn { embedInStream { arg inval; var outval, elapsed=0, cleanup, stream, c; stream = pattern.asStream; cleanup = EventStreamCleanup.new; loop { inval = stream.next(inval) ?? { ^cleanup.exit(inval) }; cleanup.update(inval); elapsed = elapsed + inval.delta; if(elapsed.round(tolerance) <= holdTime) { inval = inval.yield; } { c = elapsed - holdTime / fadeTime; if(c >= 1.0) { ^cleanup.exit(inval); } { inval[\amp] = (1.0 - c.max(0)) * inval[\amp]; inval = inval.yield; } } } } } PfinQuant : FilterPattern { var <>quant, <>clock; *new { arg pattern, quant, clock; ^super.new(pattern).quant_(quant).clock_(clock) } embedInStream { arg inval; var value, stream = pattern.asStream; var referenceClock = clock ? thisThread.clock; var endAt = quant.nextTimeOnGrid(referenceClock); while { value = stream.next(inval); value.notNil and: { referenceClock.beats < endAt } } { inval = value.yield; }; ^inval } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/EnvirGui.sc000644 000765 000024 00000017151 12756534417 024300 0ustar00crucialstaff000000 000000 EnvirGui : JITGui { var useRanger = true; editKeys { ^prevState[\editKeys] } addReplaceKey { |replaced, replacer, spec| var pv = this.viewForParam(replaced); replaceKeys.put(replaced, replacer); if (pv.notNil) { pv.label_(replacer) }; } removeReplaceKey { |replacer| var pv = this.viewForParam(replacer); var replaced = replaceKeys.removeAt(replaced); if (pv.notNil) { pv.label_(replacer) }; } *new { |object, numItems = 8, parent, bounds, makeSkip = true, options = #[]| ^super.new(object, numItems, parent, bounds, makeSkip = true, options); } setDefaults { if (parent.notNil) { skin = skin.copy.put(\margin, 0@0) }; defPos = 530@660; minSize = 250 @ (numItems * skin.buttonHeight + (skin.margin.y * 2)); } makeViews { |options| var height = skin.buttonHeight; specs = ().parent_(Spec.specs); replaceKeys = (); prevState = ( overflow: 0, keysRotation: 0, editKeys: []); labelWidth = zone.bounds.width * 0.17; this.makeOptionalViews(options); paramViews = { ParamView(zone, Rect(0, 0, bounds.width - 20, height)) .background_(skin.background); }.dup(numItems); paramViews.do { |pv| pv.zone.visible_(false); }; zone.decorator.reset.shift(zone.bounds.width - 16, 0); scroller = EZScroller(zone, Rect(0, 0, 12, numItems * height), numItems, numItems, { |sc| keysRotation = sc.value.asInteger.max(0); } ).visible_(false); scroller.slider.resize_(3); } name_ { |name| if (hasWindow) { parent.name_(this.winName(name)) }; if (nameView.notNil) { nameView.string_(name) }; } makeOptionalViews { |options, height = 20| var extraFuncs = ( name: { this.makeNameView(70, height) }, CLR: { this.makeClrBut(30, height) }, doc: { this.makeDocBut(30, height) }, proto: { this.makeProtoBut(40, height) }, parent: { this.makeParentBut(40, height) }, know: { this.makeKnowBut(70, height) } ); options.do { |key| extraFuncs[key].value; }; } makeNameView { |nameWid, height| nameView = StaticText(zone, Rect(0,0, nameWid, height)) .font_(font).align_(0); } makeClrBut { |width, height| Button(zone, width@height).font_(font) .states_([[\CLR, skin.fontColor, skin.background]]) .action_({ arg btn, mod; if (mod.isAlt) { object.clear } { "Safety - use alt-click to clear object.".postln; } }) } makeProtoBut { |width, height| protoBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["proto", skin.fontColor, skin.offColor] ]) .enabled_(false) .action_({ EnvirGui(object.proto) }); } makeParentBut { |width, height| parentBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["parent", skin.fontColor, skin.offColor] ]) .enabled_(false) .action_({ EnvirGui(object.parent) }); } makeKnowBut { |width, height| knowBut = Button(zone, Rect(0,0, width, height)) .font_(font).resize_(3) .states_([ ["know: false", skin.fontColor, skin.offColor], ["know: true", skin.fontColor, skin.onColor] ]) .enabled_(false) .action_({ |but| object.know = (but.value > 0) }); } makeDocBut { |width, height| docBut = Button(zone, width@height).font_(font) .states_([[\doc, skin.fontColor, skin.background]]) .enabled_(false) .action_({ |but, mod| if (object.notNil) { object.asCompileString.newTextWindow }; }) } accepts { |obj| ^(obj.isNil or: { obj.isKindOf(Dictionary) }) } // backwards compatibility envir_ { |envir| this.object_(envir) } envir { ^object } highlight { |index, prefix, color| var parView = paramViews[index]; var parName = this.editKeys[index]; parView.background_(color ? skin.onColor2); if (prefix.notNil and: parName.notNil) { parName = prefix ++ parName; }; parView.label_(parName); } unhighlight { |index| var parView = paramViews[index]; var parName = this.editKeys[index] ? ""; parView.background_(skin.offColor); parView.label_(parName); } // also get specs as state that may have changed getState { var newKeys, overflow, currSpecs; if (object.isNil) { ^(editKeys: [], overflow: 0, keysRotation: 0) }; newKeys = object.keys.asArray.sort; overflow = (newKeys.size - numItems).max(0); keysRotation = keysRotation.clip(0, overflow); newKeys = newKeys.drop(keysRotation).keep(numItems); currSpecs = newKeys.collect{ |key| [key, this.getSpec(key, object[key])] }; ^( object: object, editKeys: newKeys, overflow: overflow, keysRotation: keysRotation, specs: currSpecs ) } checkUpdate { var newState = this.getState; var newKeys = newState[\editKeys]; var newSpecs = newState[\specs]; this.updateButtons; if (object.isNil) { prevState = newState; ^this.showFields(0); }; if (newState[\overflow] > 0) { scroller.visible_(true); scroller.numItems_(object.size); scroller.value_(newState[\keysRotation]); } { scroller.visible_(false); }; if (newKeys == prevState[\editKeys]) { this.setByKeys(newKeys); } { this.setByKeys(newKeys); this.showFields(newKeys.size); }; if (newSpecs != prevState[\specs]) { this.updateViewSpecs(newSpecs); }; prevState = newState.put(\object, object.copy); } updateButtons { var flag = object.notNil; if (protoBut.notNil) { protoBut.enabled_(flag and: { object.proto.notNil }) }; if (parentBut.notNil) { parentBut.enabled_(flag and: { object.parent.notNil }) }; if (knowBut.notNil) { knowBut.enabled_(flag).value_((flag and: { object.know }).binaryValue) }; if (docBut.notNil) { docBut.enabled_(flag) }; } // backwards compat clearFields { |num| ^this.showFields(num) } showFields { |num = 0| paramViews.do { |pv, i| var isInUse = i < num; pv.visible_(isInUse); } } setByKeys { |newKeys| var prevEnvir = prevState[\object] ?? {()}; var newVal, oldVal, oldKey; newKeys.do { |newKey, i| var isSameKey; var paramView = paramViews[i]; oldKey = prevState[\editKeys][i]; isSameKey = oldKey == newKey; newVal = object[newKey]; oldVal = prevEnvir[newKey]; if (isSameKey.not) { paramView.label_(replaceKeys[newKey] ? newKey); paramView.spec_(this.getSpec(newKey, newVal)); paramView.value_(newVal); paramView.action = this.setFunc(newKey); } { if (oldVal != newVal) { paramView.value_(newVal) }; }; }; } setFunc { |key| ^{ |elem| object.put(key, elem.value) } } showKeyFor { |key| ^(replaceKeys[key] ? key) } colorizeArea { |area, hilite = true| if (hilite) { area.background_(skin.hiliteColor); } { area.background_(skin.background); }; } updateViewSpecs { |newSpecs| newSpecs.do { |pair| var name, spec, pv; #name, spec = pair; if (spec.notNil) { pv = this.viewForParam(name); if (pv.notNil) { pv.spec_(spec) }; }; }; } viewForParam { |name| name = replaceKeys[name] ? name; ^paramViews.detect { |pv| pv.label == name }; } putSpec { |key, obj| var pview, spec, value; // clear local spec only if (obj.isNil) { specs.put(key, nil); ^this }; spec = obj.asSpec; specs.put(key, spec); pview = this.viewForParam(key); if (pview.notNil) { value = pview.value; pview.spec_(spec); pview.value_(value) } } // this finds global specs and local specs in the gui only // - use JITLibExtensions for specs attached to the JITGui objects. // precedence: global specs first, then cached local, // else guess an initial spec and remember it. getSpec { |key, value| var spec = specs[key]; if (spec.isNil) { spec = Spec.guess(key, value); specs.put(key, spec); }; ^spec } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/extJITgui.sc000644 000765 000024 00000003775 12756534417 024433 0ustar00crucialstaff000000 000000 + NodeProxy { gui { | numItems, bounds, preset| // which options to support? numItems = numItems ?? { max(8, this.controlKeys.size) }; ^NdefGui(this, numItems, nil, bounds, options: preset); } } + ProxySpace { gui { | numItems, bounds, preset| numItems = numItems ?? { max(12, this.envir.size) }; ^ProxyMixer(this, numItems, nil, bounds, options: preset); } } + Ndef { *gui { |server, numItems, bounds, preset| var space; server = server ? Server.default; space = all[server.name]; numItems = numItems ?? { max(12, try { space.envir.size } ? 0) }; ^NdefMixer(space, numItems, nil, bounds, options: preset); } } + Tdef { *gui { | numItems, bounds, preset| numItems = numItems ?? { max(12, all.size) }; ^TdefAllGui(numItems, nil, bounds, options: preset); } gui { | numItems, bounds, preset| numItems = numItems ?? { max(8, this.envir.size) }; ^TdefGui(this, numItems, nil, bounds, options: preset); } } + Pdef { *gui { | numItems, bounds, preset| numItems = numItems ?? { max(12, all.size) }; ^PdefAllGui(numItems, nil, bounds, options: preset); } gui { | numItems, bounds, preset| numItems = numItems ?? { max(8, this.envir.size) }; ^PdefGui(this, numItems, nil, bounds, options: preset); } } + Dictionary { /* This method was introducing a conflict with the use of .gui(view,bounds) which is what the Object.gui system expects everything to be able to respond to. For the 3.5 release we decided (felix, julian, adc) to detect what args are passed in and just switch between systems. a Number indiciates jitlib usage: how many items to show in an editor. Nil would result in the super implementation which is a simple string representation of the key values list. A cleaner solution will be decided upon later. */ gui { |...args| var numItems, bounds, preset; if(args[0].isNumber,{ # numItems, bounds, preset = args; numItems = numItems ?? { max(12, this.size) }; ^EnvirGui(this, numItems, nil, bounds, options: preset); },{ ^super.gui(*args) }) } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/extPxMixWindow.sc000644 000765 000024 00000003047 12766171707 025525 0ustar00crucialstaff000000 000000 /* ** lock proxymixer to fixed size. ** can move border between nameview and slider to show long proxy names s.boot; n = NdefMixer(s); "bcdefghijk".do { |k| Ndef(k.asSymbol).ar }; "qwrtyu".do { |k| Ndef(k.asSymbol).kr }; n.enableNameResize; n.getNameLeftBorder; n.setNameLeftBorder(200); n.shiftNameLeftBorder(10); n.shiftNameLeftBorder(-10); n.shiftArBorder(10); n.shiftArBorder(-10); */ + ProxyMixer { enableNameResize { |flag = true| var canDrag = false; if (flag) { arZone.mouseDownAction = { |arZone, x, y| // if between slider and nameView, startDrag var nameLeft = this.getNameLeftBorder; canDrag = x.absdif(nameLeft) < 15; }; arZone.mouseMoveAction = { |arZone, x, y| if (canDrag) { this.setNameLeftBorder(x.postln) }; }; arZone.mouseUpAction = { canDrag = false }; } { arZone.mouseDownAction = nil; arZone.mouseMoveAction = nil; arZone.mouseUpAction = nil; } } makeWindow { parent = Window(this.winName, bounds.copy.resizeBy(10, 10), resizable: false ).front; parent.addFlowLayout; hasWindow = true; } getNameLeftBorder { ^arGuis[0].nameView.bounds.left; } setNameLeftBorder { |xpos = 250| arGuis.do { |ag| var moniZone = ag.monitorGui.zone; var nvbnds = ag.nameView.bounds; var nvbndsRight = nvbnds.right; moniZone.bounds_(moniZone.bounds.width_(xpos)); nvbnds = nvbnds.left_(xpos); nvbnds = nvbnds.width_(nvbndsRight - xpos); ag.nameView.bounds_(nvbnds); } } shiftNameLeftBorder { |x = 0| this.setNameLeftBorder(this.getNameLeftBorder + x); } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/extSoftSet.sc000755 000765 000024 00000007567 12756534417 024675 0ustar00crucialstaff000000 000000 + Spec { *guess { |key, value| if (value.isKindOf(SimpleNumber).not) { ^nil }; ^if (value.abs > 0) { [value/20, value*20, \exp].asSpec } { [-2, 2, \lin].asSpec }; } *suggestString { |key, value| ^"Spec.add(" + this.guess(key, value).storeArgs + ");" } } + Dictionary { softPut { |param, val, within = 0.025, mapped = true, lastVal, spec| var curVal, curValNorm, newValNorm, lastValNorm, maxDiff; curVal = this.at(param); spec = (spec ? param).asSpec; if (curVal.isNil or: spec.isNil) { this.put(param, val); ^true }; curValNorm = spec.unmap( curVal ); maxDiff = max(within, spec.step); if (mapped) { newValNorm = spec.unmap(val); if (lastVal.notNil) { lastValNorm = spec.unmap(lastVal) }; } { newValNorm = val; lastValNorm = lastVal; val = spec.map(val); }; if ( (newValNorm.absdif(curValNorm) <= maxDiff) // new val is close enough // or controller remembers last value it sent. or: { lastValNorm.notNil and: { curValNorm.absdif(lastValNorm) <= maxDiff } }) { this.put(param, val); ^true } { ^false } } softSet { |param, val, within = 0.025, mapped = true, lastVal, spec| this.softPut(param, val, within, mapped, lastVal, spec); } } + PatternProxy { softSet { |param, val, within = 0.025, mapped = true, lastVal, spec| if(envir.isNil) { if (mapped.not) { spec = (spec ? param).asSpec; val = spec.map(val); ^this.set(param, val) } } { ^this.envir.softPut(param, val, within, lastVal, mapped, spec) } } } + NodeProxy { get { |param| ^this.nodeMap.at(param).value ?? { this.getDefaultVal(param) }; } getDefaultVal { |key| this.objects.do { |obj| obj.controlNames.do { |ctlname| if (ctlname.name == key) { ^ctlname.defaultValue } } }; ^nil } // must have a spec nudgeSet { |param, incr = 0.02, spec| var curValNorm, newValNorm; spec = (spec ? param).asSpec; curValNorm = spec.unmap( this.get(param) ); newValNorm = (curValNorm + incr).clip(0, 1); this.set(param, spec.map(newValNorm)); } nudgeVol { |incr = 0.02, spec| var curVolNorm, newVolNorm; spec = (spec ? \amp).asSpec; curVolNorm = spec.unmap(this.vol); newVolNorm = (curVolNorm + incr).clip(0, 1); this.vol_(spec.map(newVolNorm)) } softSet { |param, val, within = 0.025, mapped = true, lastVal, spec| var curVal, curValNorm, newValNorm, maxDiff, hasLast, lastValNorm; spec = (spec ? param).asSpec; curVal = this.get(param); if (curVal.isNil or: spec.isNil) { this.set(param, val); ^true }; curValNorm = spec.unmap( curVal ); maxDiff = max(within, spec.step); hasLast = lastVal.notNil; if (mapped) { newValNorm = spec.unmap(val); if (hasLast) { lastValNorm = spec.unmap(lastVal) }; } { newValNorm = val; val = spec.map(val); lastValNorm = lastVal; if (hasLast) { lastVal = spec.map(lastValNorm) }; }; // [\hasLast, hasLast, \curVal, curVal, \val, val].postln; if ( (newValNorm.absdif(curValNorm) <= maxDiff) // is Close Enough // or was the last value controller remembers. or: { hasLast and: { curValNorm.absdif(lastValNorm) <= maxDiff } }) { this.set(param, val); ^true } { ^false } } // val and lastVal are assumed to be mapped. // allows pausing when vol is 0. softVol_ { |val, within=0.025, pause=true, lastVal, spec| var curVolNorm, newVolNorm, hasLast, lastVolNorm; spec = (spec ? \amp).asSpec; hasLast = lastVal.notNil; curVolNorm = spec.unmap(this.vol); newVolNorm = spec.unmap(val); lastVolNorm = if (hasLast) { spec.unmap(lastVal) }; if ( (curVolNorm.absdif(newVolNorm) <= within) or: { hasLast and: { curVolNorm.absdif(lastVolNorm) <= within } } ) { this.vol_(val); if (pause) { if (val == 0) { // wait for vol to go down before pausing fork { 0.05.wait; this.pause } } { this.resume } }; ^true } { ^false } } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/JITGui.sc000644 000765 000024 00000011207 12756534417 023637 0ustar00crucialstaff000000 000000 /*** Abstract superclass for TdefGui,PdefGui, TdefAllGui, PdefAllGui EnvirGui, MonitorGui, NPGui, NdefGui, ProxyMixer (ProxySpaceGui), ParamGui, and possibly others to follow. common traits: an observed object (a proxy, monitor, space, envir, ...) a skipjack for watching it; a getState method for getting all the observed state a prevState instvar for keeping the old state around; a checkUpdate method for comparing old and new state, and updating the gui elements that have changed; parent, minimum bounds for its numItems, actual bounds; if the object has settings, make an EnvirGui or ParamGui ParamGui can do sliders or knobs ... Simpler ones: EnvirGui, TaskProxyGui; ***/ JITGui { var lastOutBus; *initClass { Class.initClassTree(Spec); Class.initClassTree(Server); Spec.add(\ampx4, [0, 4, \amp]); Spec.add(\fadePx, [0, 100, \amp, 0, 0.02]); lastOutBus = Server.default.options.numAudioBusChannels; } // options can be: \level, \name, \fade *new { |object, parent, bounds, makeSkip=true, options = #[]| ^super.newCopyArgs(object, 0, parent, bounds).init(makeSkip, options) } setDefaults { |options| var minWidth = 0; config = ( level: options.includes(\level), name: options.includes(\name), fade: options.includes(\fade) ); if (parent.notNil) { skin = skin.copy.put(\margin, 0@0) }; // a lot more negotiations, based on which options should be there defPos = 10@260; minWidth = 200; if (config.level) { minWidth = minWidth + 60 }; if (config.name) { minWidth = minWidth + 60 }; if (config.fade) { minWidth = minWidth + 60 }; minSize = minWidth @ (skin.buttonHeight + (skin.margin.y * 2)); /// "MonitorGui-minSize: %\n".postf(minSize); } makeViews { |options| var fullWid = zone.bounds.width; var height = zone.bounds.height - (skin.margin.y * 2); var levelWid = if (config.level, 60, 0); var nameWid = if (config.name, 60, 0); var fadeWid = if (config.fade, 60, 0); var playWid = 40, outWid = 30; var sliderWidth = fullWid - (levelWid + playWid + outWid + nameWid + fadeWid) - 4; zone.decorator.margin_(0@0); zone.visible_(false); this.makeVol(sliderWidth + levelWid, height); this.makePlayOut(playWid, outWid, height); if (config.name) { this.makeNameView(nameWid, height) }; if (config.fade) { this.makeFade(fadeWid, height) }; } accepts { |obj| ^(obj.isNil or: { obj.isKindOf(NodeProxy) }) } makeNameView { |width, height| nameView = DragSource(zone, Rect(0,0, width, height)) .font_(font).align_(0).resize_(3) } makeFade { |width = 60, height = 18| fadeBox = EZNumber(zone, width@height, \fade, \fadePx, { |num| try { object.fadeTime_(num.value) } }, try { object.fadeTime } ? 0.02, labelWidth: 28, numberWidth: width - 28 ); fadeBox.labelView.font_(font).background_(skin.foreground); fadeBox.numberView.font_(font).background_(skin.foreground); fadeBox.view.resize_(3); } makeVol { |width, height| var showLev = config.level.binaryValue; ampSl = EZSlider(zone, (width @ height), "", \amp, // for now, leave "vol" out { arg sl; if(object.notNil) { object.vol_(sl.value) } }, 0, false, labelWidth: 0, //labelWidth: showLev * 20, // for now, leave "vol" out numberWidth: showLev * 40, gap: 1@1 ); ampSl.labelView.font_(font).align_(0); ampSl.view.resize_(2); } makePlayOut { |playWid, outWid, height| playBut = Button(zone, Rect(0,0, playWid, height)) .font_(font).resize_(3) .states_([ [ \play, skin.fontColor, skin.offColor], [ \stop, skin.fontColor, skin.onColor ] ]) .action_({ arg btn, modif; var func; var alt = modif.notNil and: { modif.isAlt }; var shift = modif.notNil and: { modif.isShift }; if(object.notNil) { [ { if(shift) { object.playNDialog(usePlayN:true) } { if (alt) { object.end } { object.stop } }; }, { if(shift) { object.playNDialog(usePlayN:true) } { if (alt) { object.vol_(0) } }; // play silently object.play; } ].at(btn.value).value; btn.value_((try { object.monitor.isPlaying } ? false).binaryValue); } { "MonitorGui - no proxy to play!".warn; btn.value_(0); } }); setOutBox = EZNumber(zone, outWid@height, "", [0, lastOutBus, \lin, 1], { |box, mod| if (object.notNil) { if (object.monitor.isNil) { "MonitorGui - monitor is nil, cannot set outs yet.".postln; box.numberView.string = "-" } { object.monitor.out_(box.value.asInteger); }; }; }, 0, labelWidth: 1, unitWidth: 1); // 1 is workaround for EZNumber resize bug setOutBox.view.resize_(3); setOutBox.numberView .background_(skin.background) .stringColor_(skin.fontColor) .font_(font).align_(\center); } getState { var isAudio, newState; var monitor, outs, amps, newHasSeriesOut; var plays = 0, playsSpread = false; newState = ( object: nil, name: \_none_, isAudio: false, monPlaying: 0, vol: 1, playsSpread: false, out: 0, monFade: 0.02 ); if (object.isNil) { ^newState }; newState.putPairs([ \object, object, \name, object.key, \isAudio, object.rate == \audio ]); monitor = object.monitor; if (monitor.isNil) { ^newState }; newState.putPairs([ \monPlaying, monitor.isPlaying.binaryValue, \vol, monitor.vol, \out, monitor.out ? 0, \playsSpread, monitor.hasSeriesOuts.not, \monFade, monitor.fadeTime ]); ^newState; } checkUpdate { var newState = this.getState; // // don't know why early exit suppresses changes in play state. fix later... // if (newState == prevState) { ^this }; if (newState[\object] != prevState[\object]) { zone.visible_(newState[\object].notNil); }; if (newState[\isAudio] != prevState[\isAudio]) { zone.enabled_(newState[\isAudio]); }; if (nameView.notNil) { if (newState[\name] != prevState[\name]) { nameView.object_(newState[\object]) .string_(newState[\name].asString); }; }; if (newState[\vol] != prevState[\vol]) { ampSl.value_(newState[\vol]); }; if (newState[\monPlaying] != prevState[\monPlaying]) { playBut.value_(newState[\monPlaying]); }; if (newState[\out] != prevState[\out]) { setOutBox.value_(newState[\out]); }; if (fadeBox.notNil) { if (newState[\monFade] != prevState[\monFade]) { fadeBox.value_(newState[\monFade] ? 0.02); } }; prevState = newState; } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/NdefGui.sc000644 000765 000024 00000027210 12756534417 024066 0ustar00crucialstaff000000 000000 // basic gui for a nodeproxy, with monitor or not. NdefGui : JITGui { classvar 500) { // two lines, break them up near the middle numLines = 2; xpositions = options.collect( NdefGui.buttonSizes[_] ).integrate; width = width * 0.5 + (xpositions.absdif(width * 0.5).minItem); }; if (numItems > 0) { width = width.max(320) }; // min width of NdefParamGui defPos = 300@20; minSize = width @ (numItems * skin.buttonHeight + (skin.buttonHeight * numLines)); // "NdefGui - width: % minSize: %\n".postf(width, minSize); if (parent.notNil) { skin = skin.copy.margin = 0@0; }; } *makeButFuncs { buttonFuncs = ( name: { |ng, height| ng.makeNameView(buttonSizes[\name], height) }, type: { |ng, height| ng.makeTypeView(buttonSizes[\type], height) }, CLR: { |ng, height| ng.makeClrBut(buttonSizes[\CLR], height) }, reset: { |ng, height| ng.makeResetBut(buttonSizes[\reset], height) }, scope: { |ng, height| ng.makeScopeBut(buttonSizes[\scope], height) }, doc: { |ng, height| ng.makeDocBut(buttonSizes[\doc], height) }, end: { |ng, height| ng.makeEndBut(buttonSizes[\end], height) }, fade: { |ng, height| ng.makeFadeBox(buttonSizes[\fade], height) }, monitor:{ |ng, height, options| ng.makeMonitor(buttonSizes[\monitor], height, npOptions: options) }, monitorM:{|ng, height, options| ng.makeMonitor(buttonSizes[\monitorM], height, npOptions: options) }, monitorL:{|ng, height, options| ng.makeMonitor(buttonSizes[\monitorL], height, npOptions: options) }, pausR: { |ng, height| ng.makePauseBut(buttonSizes[\pausR], height) }, sendR: { |ng, height| ng.makeSendBut(buttonSizes[\sendR], height) }, rip: { |ng, height| ng.makeRipBut(buttonSizes[\rip], height) }, ed: { |ng, height| ng.makeEdBut(buttonSizes[\ed], height) }, poll: { |ng, height| ng.makePollBut(buttonSizes[\poll], height) }, wake: { |ng, height| ng.makeWakeBut(buttonSizes[\wake], height) } ) } accepts { |obj| ^(obj.isNil or: { obj.isKindOf(NodeProxy) }) } makeViews { |options| var lineBreakIndex, hasName, hasMonitor, resizer, butLines; // "NdefGui - zone.bounds: % zone.decorator.margin: %\n".postf(zone.bounds, zone.decorator.margin); options.do { |option| buttonFuncs[option].value(this, skin.buttonHeight, options); }; // a clumsy way to figure out how to set resizes for all children. lineBreakIndex = zone.children.detectIndex { |a, i| var b = zone.children[i + 1]; b.notNil and: { b.bounds.left < a.bounds.left } }; butLines = if (lineBreakIndex.isNil) { [zone.children] } { [zone.children.keep(lineBreakIndex + 1), zone.children.drop(lineBreakIndex + 1)] }; butLines.do { |butLine| var resizer = 1; var resizeIndex; var monIndex = if (monitorGui.notNil) { butLine.detectIndex(_ == monitorGui.zone) }; var nameIndex = if (nameView.notNil) { butLine.detectIndex(_ == nameView) }; if (monIndex.notNil) { resizeIndex = monIndex; } { if (nameIndex.notNil) { resizeIndex = nameIndex; } }; // [\monIndex, monIndex, \nameIndex, nameIndex, \resizeIndex, resizeIndex].postcs; if (resizeIndex.notNil) { butLine.do { |element, i| if (i == resizeIndex) { resizer = 2 }; if (i > resizeIndex) { resizer = 3 }; // [i, element, resizer].postln; element.resize_(resizer); }; }; }; if (numItems > 0) { zone.decorator.nextLine.shift(0, 2); zone.bounds; paramGui = NdefParamGui(object, numItems, zone, Rect(0,0, zone.bounds.width - (skin.margin.x * 2), 0)); } } makeNameView { |nameWid, height| nameView = DragBoth(zone, Rect(0,0, nameWid, height)) .font_(font).align_(\center) .background_(skin.background) .stringColor_(skin.fontColor); nameView.receiveDragHandler_({ var drag = View.currentDrag; if (drag.isKindOf(String)) { drag = drag.interpret }; this.object_(drag); }); } makeTypeView { |width, height| typeView = StaticText(zone, width@height).string_("-").align_(0) .background_(skin.background) .stringColor_(skin.fontColor) .font_(font).align_(\center); } makeClrBut { |width, height| Button(zone, width@height).font_(font) .states_([[\CLR, skin.fontColor, skin.offColor]]) .action_({ arg btn, mod; if (mod.isAlt) { object.clear } { "Safety - use alt-click to clear object.".postln; } }) } makeWakeBut { |width, height| wakeBut = Button(zone, width@height).font_(font) .states_([[\WAKE, skin.fontColor, skin.offColor], [\WAKE, skin.fontColor, skin.onColor]]) .action_({ object.resume.wakeUp; wakeBut.value_(1); }) } makeResetBut { |width, height| Button(zone, width@height).font_(font) .states_([[\reset, skin.fontColor, skin.offColor]]) .action_({ |view, mod| object !? { if (mod.notNil and: { mod.isAlt }) { this.object.resetNodeMap; } { this.object.cleanNodeMap; }; this.checkUpdate; } }) } makeScopeBut { |width, height| Button(zone, width@height).font_(font) .states_([[\scope, skin.fontColor, skin.offColor]]) .action_({ object !? { object.scope } }) } makeDocBut { |width, height| Button(zone, width@height).font_(font) .states_([[\doc, skin.fontColor, skin.offColor]]) .action_({ |but, mod| var alt = mod.notNil and: { mod.isAlt }; if (object.notNil) { if (alt) { try { ProxySpace.findSpace(object).document(object.key) }; } { object.document; } } }) } makeEndBut { |width, height| Button(zone, width@height).font_(font) .states_([[\end, skin.fontColor, skin.offColor]]) .action_({ object !? { object.end } }) } makeFadeBox { |width = 60, height = 18| fadeBox = EZNumber(zone, width@height, \fade, \fadePx, { |num| try { object.fadeTime_(num.value) } }, try { object.fadeTime } ? 0.02, labelWidth: 28, numberWidth: width - 28 ); fadeBox.labelView.font_(font) .background_(skin.background) .stringColor_(skin.fontColor); fadeBox.numberView.font_(font) .background_(skin.background) .stringColor_(skin.fontColor) .refresh; } makeMonitor { |width, height, npOptions| var monOptions = npOptions.sect([\level, \play]); monitorGui = MonitorGui(object, zone, width@height, false, monOptions); } makePauseBut { |width, height| pauseBut = Button(zone, width@height).font_(font) .states_([ ["paus", skin.fontColor, skin.onColor], ["rsum", skin.fontColor, skin.offColor] ]) .action_({ arg btn; object !? { [ { object.resume; }, { object.pause; } ].at(btn.value).value; } }); } makeSendBut { |width, height| sendBut = Button(zone, width@height).font_(font) .states_([ ["send", skin.fontColor, skin.offColor], ["send", skin.fontColor, skin.onColor] ]) .action_({ arg btn, mod; var alt = mod.notNil and: { mod.isAlt }; if(object.notNil and: (btn.value == 0)) { if (alt) { object.rebuild } { object.send } }; btn.value_(1 - btn.value) }) } makeEdBut { |width, height| edBut = Button(zone, width@height).font_(font) .states_([['ed', skin.fontColor, skin.offColor], ['ed', skin.fontColor, skin.onColor]]) } makeRipBut { |width, height| Button(zone, width@height).font_(font) .states_([['^', skin.fontColor, skin.offColor]]) .action_({ this.class.new(object, numItems) }) } makePollBut { |width, height| Button(zone, width@height).font_(font) .states_([[\poll, skin.fontColor, skin.offColor]]) .action_({ object !? { object.bus.getn(action: { |arr| (object.asCompileString + "poll:" + arr).postln }) } }) } getState { var newState = ( object: object, name: \_none_, type: "-", isPlaying: object.isPlaying, isPaused: false, canSend: false, fadeTime: 0.02 ); if (object.isNil) { ^newState }; newState.putPairs([ \name, object.key, \type, object.typeStr, \isPaused, object.paused, \canSend, object.sources.size > 0, \fadeTime, object.fadeTime, \isPlaying, object.isPlaying ]); ^newState } checkUpdate { var newState = this.getState; if (monitorGui.notNil) { monitorGui.checkUpdate }; if (paramGui.notNil) { paramGui.checkUpdate }; // update common stuff first if (newState[\object] != prevState[\object]) { if (monitorGui.notNil) { monitorGui.object_(object) }; if (paramGui.notNil) { paramGui.object_(object) }; }; if (newState[\name] != prevState[\name]) { this.name_(newState[\name]) }; if (typeView.notNil) { if (newState[\type] != prevState[\type]) { // typeView.string_(newState[\type].asString) } }; if (fadeBox.notNil) { if (newState[\fadeTime] != prevState[\fadeTime]) { fadeBox.value_(newState[\fadeTime]) } }; if (pauseBut.notNil) { if (newState[\isPaused] != prevState[\isPaused]) { pauseBut.value_(newState[\isPaused].binaryValue) } }; if (sendBut.notNil) { if (newState[\canSend] != prevState[\canSend]) { sendBut.value_(newState[\canSend].binaryValue); } }; if (wakeBut.notNil) { if (newState[\isPlaying] != prevState[\isPlaying]) { wakeBut.value_(newState[\isPlaying].binaryValue) } }; prevState = newState; } // support overwriting the param names shown, e.g. for ProxyChain addReplaceKey { |replaced, replacer, spec| if (paramGui.notNil) { paramGui.addReplaceKey(replaced, replacer, spec) } } removeReplaceKey { |replaced| if (paramGui.notNil) { paramGui.removeReplaceKey(replaced) } } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/NdefParamGui.sc000644 000765 000024 00000007710 12756534417 025052 0ustar00crucialstaff000000 000000 NdefParamGui : EnvirGui { var 0) { scroller.visible_(true); scroller.numItems_(newState[\settings].size); scroller.value_(newState[\keysRotation]); } { scroller.visible_(false); }; if (newKeys == prevState[\editKeys]) { this.setByKeys(newKeys, newState[\settings]); } { this.setByKeys(newKeys, newState[\settings]); this.showFields(newKeys.size); }; if (newSpecs != prevState[\specs]) { this.updateViewSpecs(newSpecs); }; prevState = newState; } setByKeys { |newKeys, newSettings| var prevSettings = prevState[\settings] ? []; var newVal, oldVal, oldKey; newKeys.do { |newKey, i| var paramView = paramViews[i]; newVal = newSettings.detect { |pair| pair[0] == newKey }; if (newVal.notNil) { newVal = newVal[1] }; oldKey = prevState[\editKeys][i]; if (oldKey.notNil) { oldVal = prevSettings.detect { |pair| pair[0] == oldKey }; if (oldVal.notNil) { oldVal = oldVal[1] }; }; if (oldKey != newKey) { paramView.label_(replaceKeys[newKey] ? newKey); paramView.spec_(this.getSpec(newKey, newVal)); paramView.value_(newVal); paramView.action = this.setFunc(newKey); } { if (oldVal != newVal) { paramView.value_(newVal) }; }; }; } setFunc { |key| ^{ |sl| // this special key (#) allows to set the source from a slider if(key == '#') { object.source = sl.value } { object.set(key, sl.value) } } } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/ParamView.sc000644 000765 000024 00000004322 12766171707 024437 0ustar00crucialstaff000000 000000 ParamView { var action, 0) { arNames = arNames.drop(arKeysRotation).keep(numItems); newState[\arNames] = arNames; } { arKeysRotation = 0; }; arKeysRotation = min(arKeysRotation, newState[\arOverflow]); arScroller.numItems_(fullSize).value_(arKeysRotation).visible_(newState[\arOverflow] > 0); if (arNames != prevArNames) { arGuis.do { |argui, i| var newName = arNames[i]; var newPx = object.envir[newName]; argui.object_(newPx); argui.zone.visible_(newPx.notNil); }; }; arGuis.do { |gui| var pxIsEdited = gui.object.notNil and: { gui.object == editGui.object }; gui.checkUpdate; if(gui.hasName.not) { gui.name = this.proxyspace.findKeyForValue(gui.object) }; gui.edBut.value_(pxIsEdited.binaryValue); }; krNames = newState[\krNames]; prevKrNames = prevState[\krNames]; fullSize = krNames.size; if (newState[\krOverflow] > 0) { krNames = krNames.drop(krKeysRotation).keep(numItems); newState[\krNames] = krNames; } { krKeysRotation = 0; }; krKeysRotation = min(krKeysRotation, newState[\krOverflow]); krScroller.numItems_(fullSize) .value_(krKeysRotation).visible_(newState[\krOverflow] > 0); if (krNames != prevKrNames) { krGuis.do { |krgui, i| var newName = krNames[i]; var newPx = object.envir[newName]; krgui.object_(newPx); krgui.zone.visible_(newPx.notNil); }; }; krGuis.do { |gui| var pxIsEdited = gui.object.notNil and: { gui.object == editGui.object }; gui.checkUpdate; if(gui.hasName.not) { gui.name = this.proxyspace.findKeyForValue(gui.object) }; gui.edBut.value_(pxIsEdited.binaryValue); }; editGui.checkUpdate; prevState = newState; } } NdefMixer : ProxyMixer { object_ { |obj| obj = Server.named.at(obj) ? obj; if (obj.isKindOf(Server)) { super.object_(Ndef.dictFor(obj)); } } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/ProxyMonitorGui.sc000644 000765 000024 00000014342 12756534417 025705 0ustar00crucialstaff000000 000000 ProxyMonitorGui { var lastOutBus; *new { |proxy, w, bounds, showLevel=false, showPlayN=true, showName=true, showPauseSend = true, makeWatcher=true, skin| ^super.new.init(w, bounds, showLevel, showPlayN, showName, showPauseSend, makeWatcher, skin) .proxy_(proxy); } *initClass { Class.initClassTree(Server); lastOutBus = Server.default.options.numAudioBusChannels; } proxy_ { |inproxy| if (proxy.isNil or: proxy.isKindOf(NodeProxy)) { proxy = inproxy; this.updateAll; } { warn("ProxyMonitorGui: % is not a nodeproxy.".format(inproxy)) }; } init { |w, bounds, showLevel, showPlayN, showName, showPauseSend, makeWatcher, skin| var font; var nameWid = 60; var playWid = 34; var outWid = 20; var playNWid = 20; var pausSendWid = playWid * 2; var defaultBounds = 400@20; var height; var widthSum, sliderWidth, winBounds, viewBounds; skin = skin ? GUI.skins[\jitSmall]; font = GUI.font.new(*skin.fontSpecs); usesPlayN = showPlayN; usesName = showName; usesPausSend = showPauseSend; bounds = bounds ? defaultBounds; if (w.notNil) { win = w; viewBounds = bounds ? defaultBounds; } { viewBounds = bounds; if (bounds.isKindOf(Point)) { winBounds = Rect(80,400,0,0).setExtent(bounds.x, bounds.y); } { winBounds = bounds; }; // [\winBounds, winBounds, \viewBounds, viewBounds].postln; win = Window(this.class.name.asString, winBounds, false).front; }; zone = GUI.compositeView.new(win, viewBounds); zone.background_(skin.foreground); flow = FlowLayout(zone.bounds, 0@0, 0@0); zone.decorator = flow; zone.resize_(2); if (viewBounds.isKindOf(Rect)) { viewBounds = viewBounds.extent }; // [\bounds, bounds, \winBounds, winBounds, \viewBounds, viewBounds].postln; widthSum = (showName.binaryValue * nameWid) + playWid + outWid + (showPlayN.binaryValue * playNWid) + (showPauseSend.binaryValue * pausSendWid); sliderWidth = viewBounds.x - widthSum; height = viewBounds.y; ampSl = EZSlider(zone, (sliderWidth @ height), \vol, \db, { arg slid; if(proxy.notNil) { proxy.vol_(slid.value.dbamp); } }, 0, false, labelWidth: showLevel.binaryValue * 20, numberWidth: showLevel.binaryValue * 40); ampSl.labelView.font_(font).align_(0); ampSl.view.resize_(2); // should have four states: ... playBut = Button(zone, Rect(0,0,playWid, height)) .font_(font).resize_(3) .states_([ [ if (usesPlayN, \playN, \play), skin.fontColor, skin.offColor], [ \stop, skin.fontColor, skin.onColor ] ]); playBut.action_({ arg btn, modif; if(proxy.notNil) { [ { if (modif.isAlt) { proxy.end } { proxy.stop }; }, { if (modif.isAlt) { proxy.vol_(0) }; if (usesPlayN) { proxy.playN } { proxy.play } } ].at(btn.value).value } }); setOutBox = EZNumber(zone, outWid@height, nil, [0, lastOutBus, \lin, 1], { |box, mod| if (proxy.notNil) { if (proxy.monitor.isNil) { "ProxyMonitorGui - cant set outs yet.".postln } { proxy.monitor.out_(box.value.asInteger); }; }; }, 0); setOutBox.view.resize_(3); setOutBox.numberView.font_(font).align_(0); if (usesPlayN) { playNDialogBut = GUI.button.new(zone, Rect(0,0, playNWid, height)) .font_(font).resize_(3) .states_([ ["-=", skin.fontColor, skin.offColor], ["-<", skin.fontColor, skin.onColor] ]) .action_({ |box, mod| if (proxy.notNil) { proxy.playNDialog }; box.value_(1 - box.value); }); }; if (usesName) { nameView = DragBoth(zone, Rect(0,0, nameWid, height)); nameView.font_(font).align_(0).resize_(3) .setBoth_(false) .receiveDragHandler = { this.proxy_(View.currentDrag) }; }; if (usesPausSend) { pauseBut = GUI.button.new(zone, Rect(0,0,34,height)) .font_(font).resize_(3) .states_([ ["paus", skin.fontColor, skin.onColor], ["rsum", skin.fontColor, skin.offColor] ]) .action_({ arg btn; if(proxy.notNil, { [ { proxy.resume; }, { proxy.pause; } ].at(btn.value).value; }) }); sendBut = Button(zone, Rect(0,0,34,height)) .font_(font).resize_(3) .states_([ ["send", skin.fontColor, skin.offColor], ["send", skin.fontColor, skin.onColor] ]) .action_({ arg btn, mod; if(proxy.notNil and: (btn.value == 0)) { if (mod.isAlt) { proxy.rebuild } { proxy.send } }; btn.value_(1 - btn.value) }) }; if (makeWatcher) { this.makeWatcher }; } makeWatcher { skipjack.stop; skipjack = SkipJack({ this.updateAll }, 0.5, { win.isClosed }, ("ProxyMon" + try { proxy.key }).asSymbol ); skipjack.start; } updateAll { var monitor, outs, amps, newHasSeriesOut; var currState; var currVol=0, pxname='', isAudio=false, plays=0, playsSpread=false, pauses=0, canSend=0; var type = "-"; if (win.isClosed) {skipjack.stop; ^this }; if (proxy.notNil) { pxname = proxy.key ? 'anon'; type = proxy.typeStr; canSend = proxy.objects.notEmpty.binaryValue; pauses = proxy.paused.binaryValue; isAudio = proxy.rate == \audio; monitor = proxy.monitor; plays = monitor.isPlaying.binaryValue; if (monitor.notNil, { currVol = proxy.monitor.vol; playsSpread = proxy.monitor.hasSeriesOuts.not; outs = monitor.outs; }); }; currState = [currVol, pxname, isAudio, plays, outs, playsSpread, pauses, canSend]; if (currState != oldState) { // "ProxyMonitorGui - updating.".postln; if (currVol.notNil) { ampSl.value_(currVol.ampdb) }; if (usesName) { nameView.object_(proxy).string_(pxname) }; playBut.value_(plays); if (usesPausSend) { pauseBut.value_(pauses); sendBut.value_(canSend); }; if (isAudio != oldState[2]) { [ampSl, playBut, setOutBox, playNDialogBut].reject(_.isNil).do(_.enabled_(isAudio)); }; // dont update if typing into numberbox - should be tested with SwingOSC! if (setOutBox.numberView.hasFocus.not) { setOutBox.value_(try { outs[0] } ? 0); if (usesPlayN) { playNDialogBut.value_(playsSpread.binaryValue) }; } }; oldState = currState; } clear { proxy = nil } } SuperCollider-Source/SCClassLibrary/JITLib/GUI/TaskProxyGui.sc000644 000765 000024 00000024346 12756534417 025165 0ustar00crucialstaff000000 000000 TaskProxyGui : JITGui { var 0) or: { parent.isKindOf(Window) }) { skin.margin } { 0@0 }; zone.decorator = FlowLayout(zone.bounds, zoneMargin, skin.gap); nameBut = Button(zone, Rect(0,0, nameWidth, height)) .font_(font) .resize_(2) .states_([ [" ", skin.fontColor, skin.onColor] ]) .keyDownAction_({ |btn, char| char.postcs; if (char.ascii == 127) { object.clear; object.class.all.removeAt(btn.states.first.first.asSymbol); object = nil; }; }); playBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ [" >", skin.fontColor, skin.offColor], [" _", skin.fontColor, skin.onColor ], [" |", skin.fontColor, skin.offColor ] ]) .action_({ |but| var string; if (object.notNil) { if (History.started) { // historical action, sets cmdLine and gets recorded. string = object.asCompileString ++ [".play;", ".play;", ".stop;" ][but.value]; thisProcess.interpreter.cmdLine_(string) .interpretPrintCmdLine; } { // a-historical, but faster [ { object.play }, { object.play }, { object.stop } ][but.value].value }; this.checkUpdate; }; }); pauseBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["paus", skin.fontColor, skin.onColor], ["rsum", skin.fontColor, skin.offColor] ]) .action_({ |but| var string; if (object.notNil) { if (History.started) { // "// historical".postln; string = object.asCompileString ++ [".resume;", ".pause;" ][but.value]; thisProcess.interpreter.cmdLine_(string) .interpretPrintCmdLine; } { // "// faster".postln; [ { object.resume },{ object.pause } ][but.value].value }; this.checkUpdate; }; }); srcBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["src", skin.fontColor, skin.offColor], ["src", skin.fontColor, skin.onColor] ]) .action_({ |but| this.openDoc(this.srcString); but.value_(object.hasSource.binaryValue) }); envBut = Button(zone, Rect(0,0, width, height)) .font_(font) .resize_(3) .states_([ ["env", skin.fontColor, skin.offColor], ["env", skin.fontColor, skin.onColor] ]) .action_({ |but, mod| if (mod.isAlt) { this.class.new(object, max(object.envir.size, 8), nil, 400@20); } { if (object.envir.isNil) { this.openDoc(this.editString) } { this.openDoc(this.editStrings) } }; but.value_(object.hasEnvir.binaryValue) }); if (numItems > 0) { this.makeEnvirGui(lineWidth, height) }; this.checkUpdate; } makeEnvirGui { |lineWidth, height| zone.decorator.nextLine.shift(0, 2); envirGui = EnvirGui( try { this.object.envir }, numItems, zone, Rect(0, 20, lineWidth, numItems * height), false ); } accepts { |obj| ^obj.isNil or: { obj.isKindOf(PatternProxy) } } name_ { |name| super.name_(name); nameBut.states_(nameBut.states.collect(_.put(0, name.asString))).refresh; } getState { if (object.isNil) { ^(playState: 0, hasSource: 0, hasEnvir: 0, canPause: 0, isPaused: 0) }; ^( isPlaying: object.isPlaying, // == proxy is playing now or will play isActive: object.isActive, // == really does something right now hasSource: object.source.notNil, // has a source hasEnvir: object.envir.notNil, // has an envir canPause: object.canPause, isPaused: object.isPaused ).collect(_.binaryValue) .put(\name, this.getObjectKey) .put(\object, object); } checkUpdate { var newState = this.getState; var playState; // compare newState and prevState, update gui items as needed if (newState == prevState) { ^this }; if (newState[\object].isNil) { prevState = newState; zone.visible_(false); ^this; }; zone.visible_(true); if (newState[\name] != prevState[\name]) { // name this.name_(newState[\name]); }; playState = newState[\isPlaying] * 2 - newState[\isActive]; newState.put(\playState, playState); if (playState != prevState[\playState]) { // stopped/playing/ended // 0 is stopped, 1 is active, 2 is playing but waiting: playBut.value_(playState).refresh; }; if (newState[\hasSource] != prevState[\hasSource]) { srcBut.value_(newState[\hasSource]).refresh; }; if (newState[\hasEnvir] != prevState[\hasEnvir]) { // has envir envBut.value_(newState[\hasEnvir]).refresh; }; if (newState[\canPause] != prevState[\canPause]) { pauseBut.visible_(newState[\canPause] > 0).refresh; }; if (newState[\isPaused] != prevState[\isPaused]) { pauseBut.value_(newState[\isPaused]).refresh; }; if (envirGui.notNil) { if (envirGui.object != object.envir) { envirGui.object_(object.envir); }; envirGui.checkUpdate; }; prevState = newState } clear { object = nil; this.checkUpdate } srcString { ^this.class.observedClass.asString ++ "(" + this.getObjectKey.asCompileString + "," + object.source.asCompileString + ");\n" } editString { |edKey| var keyText = if (edKey.isNil) { "\\anyKey, nil" } { edKey.asCompileString + "," + object.envir[edKey].asCompileString }; ^(this.class.observedClass.asString ++ "(" + this.getObjectKey.asCompileString + ").set(" + keyText + ");\n" ) } editStrings { |edKeys| edKeys = edKeys ? this.getUsedKeys; ^edKeys.collect (this.editString(_)) } getUsedKeys { if (object.envir.isNil) { ^[] }; ^usedKeys = object.envir.keys.rejectAs(_ == \self, Array).sort; } openDoc { |strings, bounds| var doc = strings.join.newTextWindow("edit me"); try { doc.bounds_(bounds ? Rect(0, 400, 400, 200)) }; } } TdefGui : TaskProxyGui { *observedClass { ^Tdef } } PdefGui : TaskProxyGui { *observedClass { ^Pdef } } TaskProxyAllGui :JITGui { var prefix = "", <>filtering = false; var 0); }); filTextV = TextView(zone, Rect(60,0, 80, skin.headHeight)) .string_("") .enterInterpretsSelection_(false) .resize_(2) .keyDownAction_({ |txvw, char, mod, uni, keycode| var str = txvw.string; if (str == "") { str = nil }; this.prefix_(txvw.string); }); filTextV .background_(skin.background) .stringColor_(skin.fontColor); edits = Array.fill(numItems, { this.class.tpGuiClass.new( numItems: 0, parent: zone, bounds: Rect(0,0, zone.bounds.width - 16, skin.buttonHeight), makeSkip: false ) }); parent.view.decorator.left_(zone.bounds.right - 12) .top_(zone.bounds.top + skin.headHeight); scroller = EZScroller(parent, Rect(0, 0, 12, numItems * skin.buttonHeight), numItems, numItems, { |sc| keysRotation = sc.value.asInteger.max(0) } ).visible_(false); scroller.slider.resize_(3); // if (options.includes(\edit)) { // editZone = CompositeView.new(parent,) // zone.resize_(1); // }; } getState { ^(object: object); } checkUpdate { var newState = this.getState; var overflow, tooMany; if (newState[\object] != prevState[\object]) { zone.visible_(newState[\object].notNil); }; if (newState[\object].isNil) { prevState = newState; ^this }; if (object.notNil) { names = object.keys.as(Array); try { names.sort }; if (filtering) { if (prefix == "") { names = names.reject { |name| name.asString.includes($_) }; } { names = names.select { |name| name.asString.contains(prefix) }; }; }; overflow = (names.size - numItems).max(0); if (overflow > 0) { scroller.visible_(true); scroller.numItems_(names.size); scroller.value_(keysRotation ? overflow); names = names.drop(keysRotation).keep(numItems); } { scroller.visible_(false); }; edits.do { |edit, i| edit.object_(object[names[i]]) }; if (tpGui.notNil) { tpGui.checkUpdate }; }; prevState = newState; } } PdefnGui : JITGui { *observedClass { ^Pdefn } accepts { |obj| ^obj.isNil or: { obj.isKindOf(this.class.observedClass) } } getState { // get all the state I need to know of the object I am watching var state = (object: object); object !? { state.put(\source, object.source) }; ^state } checkUpdate { var newState = this.getState; var show = newState[\object].notNil; zone.visible_(show); if (show.not) { prevState = newState; ^this }; if (newState[\object] != prevState[\object]) { this.name_(this.getName); }; // works with a little delay, but works if (newState[\source] != prevState[\source]) { defer { csView.textField.string_(object.asCode); }; }; prevState = newState; } } TdefAllGui : TaskProxyAllGui { *observedClass { ^Tdef } *tpGuiClass { ^TdefGui } setDefaults { defPos = 10@660; minSize = 260 @ (numItems + 1 * 20); } } PdefAllGui : TaskProxyAllGui { *observedClass { ^Pdef } *tpGuiClass { ^PdefGui } setDefaults { defPos = 270@660; minSize = 260 @ (numItems + 1 * 20); } } PdefnAllGui : TaskProxyAllGui { *observedClass { ^Pdefn } *tpGuiClass { ^PdefnGui } setDefaults { defPos = 540@660; minSize = 260 @ (numItems + 1 * 20); } } SuperCollider-Source/SCClassLibrary/deprecated/3.8/000755 000765 000024 00000000000 13007315613 023104 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/deprecated/3.8/deprecated-3.8.sc000644 000765 000024 00000001243 12774256331 026054 0ustar00crucialstaff000000 000000 + Object { openHelpFile { this.deprecated(thisMethod); this.help } } + String { openHelpFile { this.deprecated(thisMethod); this.help } } + Method { openHelpFile { this.deprecated(thisMethod); this.help } } + Quark { openHelpFile { this.deprecated(thisMethod); this.help } } // openTextFile is actually the same as openDocument + String { openTextFile { arg selectionStart=0, selectionLength=0; this.deprecated(thisMethod); this.openDocument(selectionStart, selectionLength) } } + Symbol { openTextFile { arg selectionStart=0, selectionLength=0; this.deprecated(thisMethod); ^this.openDocument(selectionStart, selectionLength) } } SuperCollider-Source/SCClassLibrary/DefaultLibrary/dumpFullInterface.sc000644 000765 000024 00000007650 12756534417 027374 0ustar00crucialstaff000000 000000 + Class { dumpFullInterface { ("\nFull Interface for " ++ this.name).postln; // post the superclasses ("\nSuperclasses: " ++ this.superclasses).postln; // Instance methods this.dumpAllMethods; // Class methods this.class.dumpAllMethods; } dumpAllMethods { var methodlist, superclasses, prependString, superPrependString, name; methodlist = IdentitySet[]; if(this.isMetaClass, { prependString = "\nClass Methods for "; superPrependString = "\nClass Methods inherited from "; name = this.asString.copyToEnd(5); superclasses = name.asSymbol.asClass.superclasses; }, { prependString = "\nInstance Methods for "; superPrependString = "\nInstance Methods inherited from "; name = this.name; superclasses = this.superclasses; } ); (prependString ++ name ++ "\n").postln; this.methods.do({ arg meth; var numargs, methname; methname = meth.name; methodlist.add(methname); numargs = meth.argNames.size - 1; " ".post; methname.post; " ( ".post; meth.argNames.do({ arg name, i; if (i > 0, { // skip 'this' name.post; if (i < numargs, { ", ".post; }); }); }); " )\n".post; }); // Methods for superclasses superclasses.do({ arg superclass, superobject, supername; if(this.isMetaClass, { superobject = superclass.class; }, { superobject = superclass; } ); supername = superobject.asString; if(supername.containsStringAt(0, "Meta_"), { supername = supername.copyToEnd(5) }); (superPrependString ++ supername ++ "\n").postln; superobject.methods.do({ arg meth; var numargs, methname; methname = meth.name; if(methodlist.includes(methname).not, { methodlist.add(methname); numargs = meth.argNames.size - 1; " ".post; methname.post; " ( ".post; meth.argNames.do({ arg name, i; if (i > 0, { // skip 'this' name.post; if (i < numargs, { ", ".post; }); }); }); " )\n".post; }); }); }); // include methods for Class if(this.isMetaClass, {"\nMethods inherited from Class\n".postln; Class.dumpInterface; }); } dumpMethodList { var mList, sc; mList = IdentityDictionary.new; // repository for methods this.collectMethods(mList); // get them sc = this; // to print superclass chain { sc != Object }.while({ (sc.name ++ " : ").post; sc = sc.superclass; }); "Object".postln; mList.asSortedArray.do({ |pair| (pair[0] ++ " <" ++ pair[1].ownerClass.name ++ "-" ++ pair[0] ++ ">").post; (pair[1].argNames.size > 1).if({ " (".post; pair[1].argNames.do({ |argname, i| (i > 1).if({ ", ".post }); (i > 0).if({ argname.post; }); }); ")".post; }); "".postln; }); } collectMethods { arg list; // only collect if not Object or Class ((this.name != \Object) && (this.name != \Class)).if({ this.methods.do({ |meth| // if keys already includes methodname, // then a subclass has overridden this superclass method, so don't add list.keys.includes(meth.name).not.if({ list.put((meth.name.asString).asSymbol, meth); }); }); superclass.asClass.collectMethods(list); // go up a level }); } helpFileForMethod { arg methodSymbol; this.findRespondingMethodFor(methodSymbol).ownerClass.help; } // show all subclasses of this class sorted in alpha order (not tree order) dumpSubclassList { var list, listCollector; // recursive function to collect class objects listCollector = { arg node, l; l.add(node); node.subclasses.do({ arg n; listCollector.value(n, l) }); }; list = List.new; listCollector.value(this, list); // do the recursion list.sort({ arg a, b; a.name < b.name }) // sort it .do({ arg n; // and iterate to post the class names (w/ supers) n.name.post; n.superclasses.do({ arg s; (" : " ++ s.name).post; }); "\n".post; }); ("\n" ++ list.size.asString ++ " classes listed.").postln; } } SuperCollider-Source/SCClassLibrary/DefaultLibrary/extNumber.sc000644 000765 000024 00000000752 12756534417 025730 0ustar00crucialstaff000000 000000 // method extensions // add or replace methods // This allows you to add or redefine methods without changing the original file. // A file may contain either class definitions, or method extensions, but never both. // Do not name an extension file with the same name as a class definition file. + Number { half { ^this * 0.5 } twice { ^this * 2 } } + Point { *big { arg x, y; ^this.new(2*x, 10*y) } swap { ^this.class.new(y, x) } conjugate { ^this.class.new(x, y.neg) } } SuperCollider-Source/SCClassLibrary/DefaultLibrary/Main.sc000644 000765 000024 00000013574 12766171707 024651 0ustar00crucialstaff000000 000000 Main : Process { var = min }{ this.scVersionMajor >= maj }; } *versionAtMost { |maj, min| ^if((maj==this.scVersionMajor) and:{min.notNil}){ this.scVersionMinor <= min }{ this.scVersionMajor <= maj }; } pid { _GetPid ^this.primitiveFailed } // PRIVATE prArgv { _Argv ^[] } recompile { platform.recompile } escapeWindow { platform.escapeWindow } exitFullScreen { platform.exitFullScreen } *overwriteMsg { _MainOverwriteMsg ^this.primitiveFailed } } MethodOverride { var operator, >a; *new { arg operator, a; ^super.newCopyArgs(operator, a) } next { arg inval; var vala; vala = a.next(inval); if (vala.isNil, { ^nil },{ ^vala.perform(operator); }); } reset { a.reset } storeOn { arg stream; stream <<< a << "." << operator } } BinaryOpStream : Stream { var >operator, >a, >b; *new { arg operator, a, b; ^super.newCopyArgs(operator, a, b) } next { arg inval; var vala, valb; vala = a.next(inval); if (vala.isNil, { ^nil }); valb = b.next(inval); if (valb.isNil, { ^nil }); ^vala.perform(operator, valb); } reset { a.reset; b.reset } storeOn { arg stream; stream << "(" <<< a << " " << operator.asBinOpString << " " <<< b << ")" } } BinaryOpXStream : Stream { var operator, a, b, vala; *new { arg operator, a, b; ^super.newCopyArgs(operator, a, b) } next { arg inval; var valb; if (vala.isNil) { vala = a.next(inval); if (vala.isNil) { ^nil }; valb = b.next(inval); if (valb.isNil, { ^nil }); }{ valb = b.next(inval); if (valb.isNil) { vala = a.next(inval); if (vala.isNil) { ^nil }; b.reset; valb = b.next(inval); if (valb.isNil) { ^nil }; }; }; ^vala.perform(operator, valb); } reset { vala = nil; a.reset; b.reset } storeOn { arg stream; stream << "(" <<< a << " " << operator.asBinOpString; stream << ".x"; stream << " " <<< b << ")" } } NAryOpStream : Stream { var >operator, >a, arglist; var isNumeric; *new { arg operator, a, arglist; ^super.newCopyArgs(operator, a).arglist_(arglist) } arglist_ { arg list; // optimization isNumeric = list.every({ arg item; item.isNumber or: {item.class === Symbol} }); arglist = list; } next { arg inval; var vala, values; vala = a.next(inval); if (vala.isNil, { ^nil }); values = if (isNumeric) { arglist } { arglist.collect({ arg item; var res; res = item.next(inval); if(res.isNil) { ^nil }; res }) }; ^vala.performList(operator, values); } reset { a.reset; arglist.do({ arg item; item.reset }) } storeOn { arg stream; stream <<< a << "." << operator << "(" <<<* arglist << ")" } } SuperCollider-Source/SCClassLibrary/Common/Streams/EventStreamCleanup.sc000644 000765 000024 00000002406 12756534417 027457 0ustar00crucialstaff000000 000000 // Cleanup functions are passed a flag. // The flag is set false if nodes have already been freed by CmdPeriod // This caused a minor change to TempoClock:clear and TempoClock:cmdPeriod EventStreamCleanup { var <>functions; // cleanup functions from child streams and parent stream *new { ^super.new.clear } clear { functions = IdentitySet.new; } addFunction { |event, function | if(event.isKindOf(Dictionary)) { functions.add(function); event[\addToCleanup] = event[\addToCleanup].add(function); }; } addNodeCleanup { |event, function | if(event.isKindOf(Dictionary)) { functions.add(function); event[\addToNodeCleanup] = event[\addToNodeCleanup].add(function); }; } update { | event | if(event.isKindOf(Dictionary)) { functions.addAll(event[\addToNodeCleanup]); functions.addAll(event[\addToCleanup]); functions.removeAll(event[\removeFromCleanup]); }; ^event } exit { | event, freeNodes = true | if(event.isKindOf(Dictionary)) { this.update(event); if(functions.notEmpty) { functions.do(_.value(freeNodes) ); event[\removeFromCleanup] = event[\removeFromCleanup].addAll(functions); }; this.clear; }; ^event } terminate { | freeNodes = true | functions.do(_.value(freeNodes)); this.clear } } SuperCollider-Source/SCClassLibrary/Common/Streams/FilterPatterns.sc000644 000765 000024 00000043706 12756534417 026670 0ustar00crucialstaff000000 000000 FilterPattern : Pattern { var <>pattern; *new { arg pattern; ^super.new.pattern_(pattern) } } Pn : FilterPattern { var <>repeats, <>key; *new { arg pattern, repeats=inf, key; ^super.newCopyArgs(pattern, repeats, key ) } storeArgs { ^[pattern,repeats, key] } embedInStream { | event | if(key.isNil) { repeats.value(event).do { event = pattern.embedInStream(event) }; } { repeats.value(event).do { event = pattern.embedInStream(event); event[key] = true; }; event[key] = false; }; ^event; } } Pgate : Pn { *new { arg pattern, repeats=inf, key ; ^super.new(pattern).repeats_(repeats).key_(key) } storeArgs { ^[pattern,repeats, key] } embedInStream { | event | var stream, output; repeats.do { stream = pattern.asStream; output = stream.next(event); while { if (event[key] == true) { output = stream.next(event) }; output.notNil; } { event = output.copy.embedInStream(event) } }; ^event; } } FuncFilterPattern : FilterPattern { var <>func; *new { arg func, pattern; ^super.new(pattern).func_(func) } storeArgs { ^[func,pattern] } } Pcollect : FuncFilterPattern { embedInStream { arg inval; var stream, outval; stream = pattern.asStream; loop { outval = stream.next(inval); if (outval.isNil) { ^inval }; // NOTE: Normally we would expect 'stream' to do processRest. // But the 'collect' func is not under control of the stream, // so that's not a safe assumption here. The func may return // a rest, so we have to 'processRest' the collect value. inval = yield(func.value(outval, inval).processRest(inval)); } } asStream { ^pattern.streamArg.collect(func); } } Pselect : FuncFilterPattern { embedInStream { arg inval; var stream, outval; stream = pattern.asStream; loop { while ({ outval = stream.next(inval); if (outval.isNil) { ^inval }; func.value(outval, inval).not }); inval = yield(outval); } } asStream { ^pattern.streamArg.select(func); } } Preject : FuncFilterPattern { embedInStream { arg inval; var stream, outval; stream = pattern.asStream; loop { while ({ outval = stream.next(inval); if (outval.isNil) { ^inval }; func.value(outval, inval); }); inval = yield(outval); } } asStream { ^pattern.streamArg.reject(func); } } Pfset : FuncFilterPattern { var <>cleanupFunc; *new { |func, pattern, cleanupFunc| ^super.new(func, pattern).cleanupFunc_(cleanupFunc) } embedInStream { arg inevent; var event, cleanup = EventStreamCleanup.new; // cleanup should actually not be passed in // but retaining (temporarily) for backward compatibility var envir = Event.make({ func.value(cleanup) }); var stream = pattern.asStream; var once = true; loop { inevent.putAll(envir); event = stream.next(inevent); if(once) { cleanup.addFunction(event, { |flag| envir.use({ cleanupFunc.value(flag) }); }); once = false; }; if (event.isNil) { ^cleanup.exit(inevent) } { cleanup.update(event); }; inevent = yield(event); if(inevent.isNil) { ^cleanup.exit(event) } }; } } Psetpre : FilterPattern { var <>name, <>value; *new { arg name, value, pattern; ^super.new(pattern).name_(name).value_(value) } storeArgs { ^[name,value,pattern] } filterEvent { arg event, val; ^event[name] = val; } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var val, inevent, filteredEvent; var valStream = value.asStream; var evtStream = pattern.asStream; loop { val = valStream.next(event); if (val.isNil or: event.isNil) { ^cleanup.exit(event) }{ event = event.copy; filteredEvent = this.filterEvent(event, val); }; inevent = evtStream.next(filteredEvent); if (inevent.isNil) { ^cleanup.exit(event) }; cleanup.update(inevent); event = yield(inevent); // if(event.isNil) { nil.yield; ^inevent } } } } Paddpre : Psetpre { filterEvent { arg event, val; ^event[name] = event[name] + val; } } Pmulpre : Psetpre { filterEvent { arg event, val; ^event[name] = event[name] * val; } } Pset : FilterPattern { var <>name, <>value; *new { arg name, value, pattern; ^super.new(pattern).name_(name).value_(value) } storeArgs { ^[name,value,pattern] } filterEvent { arg event, val; ^event[name] = val; } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var val, inEvent; var valStream = value.asStream; var evtStream = pattern.asStream; loop { inEvent = evtStream.next(event); // if (event.isNil) { ^nil.yield }; if (inEvent.isNil) { ^cleanup.exit(event) }; val = valStream.next(inEvent); if (val.isNil) { ^cleanup.exit(event) }; this.filterEvent(inEvent, val); cleanup.update(inEvent); event = inEvent.yield; } } } Padd : Pset { filterEvent { arg event, val; ^event[name] = event[name] + val; } } Pmul : Pset { filterEvent { arg event, val; ^event[name] = event[name] * val; } } Psetp : Pset { embedInStream { arg event; var evtStream, val, inevent; var valStream = value.iter; while { val = valStream.next(event); val.notNil }{ evtStream = pattern.asStream; while { inevent = evtStream.next(event); if(event.isNil) { ^nil.yield }; inevent.notNil; } { this.filterEvent(inevent, val); event = inevent.yield; }; }; ^event; } } Paddp : Psetp { filterEvent { arg event, val; ^event[name] = event[name] + val; } } Pmulp : Psetp { filterEvent { arg event, val; ^event[name] = event[name] * val; } } Pstretch : FilterPattern { var <>value; *new { arg value, pattern; ^super.new(pattern).value_(value) } storeArgs { ^[value,pattern] } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var inevent; var val, delta; var valStream = value.asStream; var evtStream = pattern.asStream; loop { inevent = evtStream.next(event).asEvent; if (inevent.isNil) { ^cleanup.exit(event) }; val = valStream.next(inevent); if (val.isNil) { ^cleanup.exit(event) }; delta = event[\delta]; if (delta.notNil) { inevent[\delta] = delta * val; }; inevent[\dur] = inevent[\dur] * val; cleanup.update(inevent); event = yield(inevent); } } } Pstretchp : Pstretch { embedInStream { arg event; var evtStream, val, inevent, delta; var valStream = value.asStream; while { val = valStream.next(event); val.notNil } { evtStream = pattern.asStream; while { inevent = evtStream.next(event); inevent.notNil } { delta = inevent[\delta]; if (delta.notNil) { inevent[\delta] = delta * val; }; inevent[\dur] = inevent[\dur] * val; event = inevent.yield; }; }; ^event; } } // needs testing - hjh Pplayer : FilterPattern { var <>subPattern; *new { arg playerPattern, subPattern; ^super.newCopyArgs(playerPattern, subPattern) } storeArgs { ^[ pattern, subPattern ] } embedInStream { arg event; var player, inevent; var playerStream = pattern.asStream; var stream = subPattern.asStream; loop{ inevent = stream.next(event); if (inevent.isNil) { ^event }; player = playerStream.next(event); if (player.isNil) { ^event }; inevent.parent = player.event; event = yield(inevent); } } // backward compatibility: unnecessary var playerPattern was removed playerPattern { ^pattern } playerPattern_ { |playerPattern| pattern = playerPattern } } Pdrop : FilterPattern { var <>count; *new { arg count, pattern; ^super.new(pattern).count_(count) } storeArgs { ^[count,pattern] } embedInStream { arg event; var inevent; var stream = pattern.asStream; count.value(event).do { inevent = stream.next(event); if (inevent.isNil, { ^event }); }; loop { inevent = stream.next(event); if (inevent.isNil, { ^event }); event = inevent.yield; }; } } Pfin : FilterPattern { var <>count; *new { arg count, pattern; ^super.new(pattern).count_(count) } storeArgs { ^[count,pattern] } embedInStream { arg event; var inevent; var stream = pattern.asStream; var cleanup = EventStreamCleanup.new; count.value(event).do({ inevent = stream.next(event) ?? { ^event }; cleanup.update(inevent); event = inevent.yield; }); ^cleanup.exit(event) } } // it is not correct to call stream.next(nil) on a value stream // but there is no good way to distinguish in Pfin so we need a subclass // might be ok to deprecate this now Pfinval : Pfin { embedInStream { arg event; var inevent; var stream = pattern.asStream; count.value(event).do({ inevent = stream.next(event); if (inevent.isNil, { ^event }); event = inevent.yield; }); ^event } } Pfindur : FilterPattern { var <>dur, <>tolerance; *new { arg dur, pattern, tolerance = 0.001; ^super.new(pattern).dur_(dur).tolerance_(tolerance) } storeArgs { ^[dur,pattern,tolerance] } embedInStream { arg event; var item, delta, elapsed = 0.0, nextElapsed, inevent; var localdur = dur.value(event); var stream = pattern.asStream; var cleanup = EventStreamCleanup.new; loop { inevent = stream.next(event).asEvent ?? { ^event }; cleanup.update(inevent); delta = inevent.delta; nextElapsed = elapsed + delta; if (nextElapsed.roundUp(tolerance) >= localdur) { // must always copy an event before altering it. // fix delta time and yield to play the event. inevent = inevent.copy.put(\delta, localdur - elapsed).yield; ^cleanup.exit(inevent); }; elapsed = nextElapsed; event = inevent.yield; } } } Psync : FilterPattern { var <>quant, <>maxdur, <>tolerance; *new { arg pattern, quant, maxdur, tolerance = 0.001; ^super.new(pattern).quant_(quant).maxdur_(maxdur).tolerance_(tolerance) } storeArgs { ^[pattern,quant,maxdur,tolerance] } embedInStream { arg event; var item, stream, delta, elapsed = 0.0, nextElapsed, clock, inevent; var localquant = quant.value(event), localmaxdur = maxdur.value(event); var cleanup = EventStreamCleanup.new; stream = pattern.asStream; loop { inevent = stream.next(event).asEvent; if(inevent.isNil) { if(localquant.notNil) { delta = elapsed.roundUp(localquant) - elapsed; if(delta > 0) { Event.silent(delta, event).yield }; ^cleanup.exit(event); }; }; cleanup.update(inevent); delta = inevent.delta; nextElapsed = elapsed + delta; if (localmaxdur.notNil and: { nextElapsed.round(tolerance) >= localmaxdur }) { inevent = inevent.copy; inevent.put(\delta, localmaxdur - elapsed); event = inevent.yield; ^cleanup.exit(event); } { elapsed = nextElapsed; event = inevent.yield; }; }; } } Pconst : FilterPattern { var <>sum, <>tolerance; *new { arg sum, pattern, tolerance=0.001; ^super.new(pattern).sum_(sum).tolerance_(tolerance) } storeArgs { ^[sum,pattern,tolerance] } embedInStream { arg inval; var delta, elapsed = 0.0, nextElapsed, str=pattern.asStream, localSum = sum.value(inval); loop ({ delta = str.next(inval); if(delta.isNil) { inval = (localSum - elapsed).yield; ^inval }; nextElapsed = elapsed + delta; if (nextElapsed.round(tolerance) >= localSum) { inval = (localSum - elapsed).yield; ^inval }{ elapsed = nextElapsed; inval = delta.yield; }; }); } } Plag : FilterPattern { var <>lag; *new { arg lag, pattern; ^super.new(pattern).lag_(lag) } storeArgs { ^[lag,pattern] } embedInStream { arg event; var item; var stream = pattern.asStream; var inevent = event.copy; event = Event.silent(lag.value(event), event).yield; loop { inevent = stream.next(event); if (inevent.isNil) { ^event}; event = inevent.yield; }; } } Pbindf : FilterPattern { var <>patternpairs; *new { arg pattern ... pairs; if (pairs.size.odd, { Error("Pbindf should have odd number of args.\n").throw }); ^super.new(pattern ? Event.default).patternpairs_(pairs) } storeArgs { ^[pattern] ++ patternpairs } embedInStream { arg event; var cleanup = EventStreamCleanup.new; var eventStream; var outevent; var streampairs = patternpairs.copy; var endval = streampairs.size - 1; forBy (1, endval, 2) { arg i; streampairs.put(i, streampairs[i].asStream); }; eventStream = pattern.asStream; loop{ outevent = eventStream.next(event); if (outevent.isNil) { ^cleanup.exit(event) }; forBy (0, endval, 2) { arg i; var name = streampairs[i]; var stream = streampairs[i+1]; var streamout = stream.next(outevent); if (streamout.isNil) { ^cleanup.exit(event) }; if (name.isSequenceableCollection) { if (name.size > streamout.size) { ("the pattern is not providing enough values to assign to the key set:" + name).warn; ^outevent }; name.do { arg key, i; outevent.put(key, streamout[i].processRest(outevent)); }; }{ outevent.put(name, streamout); }; }; cleanup.update(outevent); event = yield(outevent); }; } } Pstutter : FilterPattern { var <>n; *new { arg n, pattern; ^super.new(pattern).n_(n) } storeArgs { ^[n,pattern] } embedInStream { arg event; var inevent, nn; var stream = pattern.asStream; var nstream = n.asStream; while { (inevent = stream.next(event)).notNil } { if((nn = nstream.next(event)).notNil) { nn.abs.do { event = inevent.copy.yield; }; } { ^event }; }; ^event; } } PdurStutter : Pstutter { // float streams embedInStream { arg event; var dur, stut; var durs = pattern.asStream; var stutts = n.asStream; while({ (dur = durs.next(event)).notNil and: {(stut = stutts.next(event)).notNil} },{ if(stut > 0,{ // 0 skips it if(stut > 1,{ dur = dur / stut; stut.do({ event = dur.yield; }) },{ event = dur.yield }) }) }) ^event; } } Pclutch : FilterPattern { var <>connected; *new { arg pattern, connected = true; ^super.new(pattern).connected_(connected) } storeArgs { ^[ pattern, connected ] } embedInStream { arg inval; var clutchStream = connected.asStream; var stream = pattern.asStream; var outval, clutch; while { clutch = clutchStream.next(inval); clutch.notNil } { if(clutch === true or: { clutch == 1 }) { outval = stream.next(inval); if(outval.isNil) { ^inval }; inval = outval.yield; } { outval ?? { outval = stream.next(inval) }; inval = outval.copy.yield; }; } } } Pwhile : FuncFilterPattern { embedInStream {arg event; while({ func.value(event) },{ event = pattern.embedInStream(event); }); ^event; } } Pwrap : FilterPattern { var <>lo, <>hi; *new { arg pattern,lo,hi; ^super.new(pattern).lo_(lo).hi_(hi) } storeArgs { ^[pattern,lo,hi] } embedInStream { arg event; var next; var stream = pattern.asStream; var loStr = lo.asStream; var hiStr = hi.asStream; var loVal, hiVal; while({ loVal = loStr.next(event); hiVal = hiStr.next(event); next = stream.next(event); next.notNil and: { loVal.notNil } and: { hiVal.notNil } },{ event = next.wrap(loVal, hiVal).yield }); ^event; } } Ptrace : FilterPattern { var <>key, printStream, prefix; *new { arg pattern, key, printStream, prefix = ""; ^super.newCopyArgs(pattern, key, printStream, prefix) } storeArgs { ^[ pattern, key, printStream, prefix ] } embedInStream { arg inval; var func, collected; printStream = printStream ? Post; if(key.isNil) { collected = pattern.collect {|item| printStream << prefix << item << Char.nl; item } } { func = { |val, item, prefix| if(val.isKindOf(Function) and: { item.isKindOf(Environment) }) { val = item.use { val.value }; printStream << prefix << val << "\t(printed function value)\n"; } { printStream << prefix << val << Char.nl; }; }.flop; collected = pattern.collect {|item| var val = item.atAll(key.asArray).unbubble; func.value(val, item, prefix); item } }; ^collected.embedInStream(inval) } } Pclump : FilterPattern { var <>n; *new { arg n, pattern; ^super.new(pattern).n_(n) } embedInStream { arg event; var next, list, nval; var stream = pattern.asStream; var nstream = n.asStream; loop { list = []; nval = nstream.next(event); if (nval.isNil) { ^event }; nval.do { next = stream.next(event); if (next.isNil) { if (list.size > 0) { event = list.yield }; ^event }; list = list.add(next); }; event = list.yield; } } storeArgs { ^[ n, pattern ] } } Pflatten : Pclump { embedInStream { arg event; var next, nval; var stream = pattern.asStream; var nstream = n.asStream; while { next = stream.next(event); nval = nstream.next(event); next.notNil and: { nval.notNil }; }{ if (next.isKindOf(SequenceableCollection)) { next = next.flatten(nval); next.do {|item| event = item.yield }; }{ event = next.yield; } } ^event } } Pdiff : FilterPattern { embedInStream { arg event; var stream = pattern.asStream; var next, prev = stream.next(event); while { next = stream.next(event); next.notNil; }{ event = (next - prev).yield; prev = next; } ^event } } Prorate : FilterPattern { var <>proportion; *new { arg proportion, pattern=1; ^super.new(pattern).proportion_(proportion) } embedInStream { arg inval; var val, c; var str = pattern.asStream; var prop = proportion.asStream; loop { val = str.next(inval); c = prop.next(inval); if(val.isNil or: { c.isNil }) { ^inval }; if(c.isSequenceableCollection) { c.do { |el| inval = yield(el * val) } } { inval = yield(c * val); inval = yield(1 - c * val); } } } storeArgs { ^[proportion,pattern] } } Pavaroh : FilterPattern { var <>aroh, <>avaroh, <>stepsPerOctave; *new { arg pattern, aroh, avaroh, stepsPerOctave=12; ^super.newCopyArgs(pattern, aroh, avaroh, stepsPerOctave) } storeArgs { ^[pattern, aroh, avaroh, stepsPerOctave ] } embedInStream { arg inval; var me, melast = 0, scale; var mestream = pattern.asStream; var stepsStr = stepsPerOctave.asStream, stepVal; while { stepVal = stepsStr.next(inval); me = mestream.next(inval); me.notNil and: { stepVal.notNil } } { scale = if(me >= melast) { aroh } { avaroh }; melast = me; inval = me.degreeToKey(scale, stepVal).yield }; ^inval } } SuperCollider-Source/SCClassLibrary/Common/Streams/FuncStreamAsRoutine.sc000644 000765 000024 00000000426 12756534417 027613 0ustar00crucialstaff000000 000000 FuncStreamAsRoutine : Routine { var <>nextFunc; var <>resetFunc; *new { arg nextFunc, resetFunc; ^super.new({ arg inval; loop { inval = yield(thisThread.nextFunc.value(inval)) } }) .nextFunc_(nextFunc).resetFunc_(resetFunc) } reset { ^resetFunc.value } } SuperCollider-Source/SCClassLibrary/Common/Streams/History.sc000644 000765 000024 00000034373 12756534417 025363 0ustar00crucialstaff000000 000000 History { // adc 2006, Birmingham; rewrite 2007. classvar <>forwardFunc, verbose = false, <>recordLocally = true, saveFolder = "~/Desktop/", keepsLog = true; classvar <>current, <>maxShortLength=65; var 0) { // reverse indexing lineIndices = (e.endLine.min(linesSize) .. e.startLine.min(linesSize)); lineIndices.do { |index| var time, id, code, waittime; #time, id, code = lines[index]; waittime = time - (lastTimePlayed ? time); lastTimePlayed = time; waittime.wait; if (e.verbose) { code.postln }; code.compile.value; // so it does not change cmdLine. }; }; 0.5.wait; "history is over.".postln; }).set(\startLine, 0, \endLine, 0); } makeCurrent { History.current = this; hasMovedOn = true } isCurrent { ^this === History.current } play { |start=0, end, verbose=true| // line numbers; // starting from past 0 may not work. start = start.clip(0, lines.lastIndex); end = (end ? lines.lastIndex).clip(0, lines.lastIndex); player.set(\startLine, start, \endLine, end, \verbose, verbose); player.play; } stop { player.stop; } addLine { |now, authID, lineStr| var line = [ now, authID, lineStr ]; if (lines.isEmpty) { lines.add(line); lineShorts.add(this.class.shorten(line)); } { lines.addFirst(line); lineShorts.addFirst(this.class.shorten(line)); }; keys.add(authID); } // simple editing removeAt { |index| if (index.isKindOf(Collection)) { index.sort.reverseDo (this.removeAt(_)); ^this }; if (index < lines.size) { // ignore out of range indices, keep lists synced. [lines, lineShorts].do(_.removeAt(index)); }; hasMovedOn = true; } removeLast { this.removeAt(lines.size - 1) } keep { |num| lines = lines.keep(num); lineShorts = lineShorts.keep(num); hasMovedOn = true; } drop { |num| lines = lines.drop(num); lineShorts = lineShorts.drop(num); hasMovedOn = true; } // loading from and saving to files *saveCS { |path, forward=false| current.saveCS(path, forward) } saveCS { |path, forward=false| var file, lines2write; lines2write = if (forward) { lines.reverse } { lines }; path = path ?? { saveFolder ++ "history_" ++ this.class.timeStamp ++ ".scd" }; file = File(path.standardizePath, "w"); file.write(lines2write.asCompileString); inform("History written to:" + path); file.close; } *loadCS { |path, forward=false| current.loadCS(path, forward) } loadCS { |path, forward=false| var file, ll; protect { file = File(path.standardizePath, "r"); ll = file.readAllString; } { file.close; }; ll !? { ll = ll.compile.value; if (forward) { ll = ll.reverse }; this.lines_(ll) }; } // network setups support *network { } *localOn { recordLocally = true } *localOff { recordLocally = false } // string formatting utils storyString { var alone = lines.collectAs({ |line| line[1] }, IdentitySet).size == 1; var str; str = "///////////////////////////////////////////////////\n"; str = str ++ format("// History, as it was on %.\n", this.class.dateString); str = str ++ "///////////////////////////////////////////////////\n\n"; lines.reverseDo { |x| var now, id, cmdLine; #now, id, cmdLine = x; str = str ++ format("// - % - % \n", this.class.formatTime(now), if(alone) { "" } { "(" ++ id ++ ")" } ); if(cmdLine.find("\n").notNil and: { cmdLine[0] != $( }) { cmdLine = format("(\n%\n);", cmdLine) }; str = str ++ cmdLine ++ "\n\n"; }; ^str; } *saveStory { |path| current.saveStory(path) } saveStory { |path| var file; path = path ?? { saveFolder ++ "History_" ++ this.class.timeStamp ++ ".scd" }; file = File(path.standardizePath, "w"); file.write(this.storyString); file.close; } *formatTime { arg val; var h, m, s; h = val div: (60 * 60); val = val - (h * 60 * 60); m = val div: 60; val = val - (m * 60); s = val; ^"%:%:%".format(h, m, s.round(0.01)) } *unformatTime { arg str; var h, m, s; #h, m, s = str.split($:).collect(_.interpret); ^h * 60 + m * 60 + s } *prettyString { |str| // remove returns at beginning or end of the string var startIndex = str.detectIndex({ |ch| ch != $\n }); var endChar = str.last; var lastCharIndex = str.lastIndex; while { endChar == $\n } { lastCharIndex = lastCharIndex - 1; endChar = str[lastCharIndex]; }; // [startIndex, lastCharIndex].postln; ^str.copyRange(startIndex, lastCharIndex); } // convert to shortline for gui *shorten { |line, maxLength| var time, id, lineStr, head, length; #time, id, lineStr = line; head = (this.formatTime(time) + "-" + id + "- "); maxLength = maxLength ? maxShortLength; ^head ++ lineStr.keep(maxLength - head.size); } // not used yet *getTimeFromString { arg str; var ts, i; if(str.beginsWith("// - ").not) { ^nil }; i = str.find(" - ", offset: 4); if(i.isNil) { i = 10 }; // assume it's ok. ts = str[5..i+2].postln.split($:).collect(_.asFloat); ^ts[0] * (60 * 60) + (ts[1] * 60) + ts[2] } // not used yet *asLines { arg str; var indices; indices = str.findAll("// -"); ^str.clumps(indices.differentiate) } /* // problem: interpreter cancels backslashes etc. *stream { arg str, func; var lastTime=0, time; func = func ?? { {|str| var dt = ~prev / str.size; fork { 0.2.wait; // wait until result from last evaluation is printed str.do {|char| char.post; dt.wait; }; str.compile.value; }; } }; ^Routine { this.asLines(str).do { |line| time = this.getTimeFromString(line) ? lastTime; (prev:lastTime, delta: time - lastTime, play: { func.(line); }).yield; lastTime = time; } } } *play { arg str, clock; str = str ? Document.current.string; ^this.stream(str).asEventStreamPlayer.play(clock); } *playDocument { } */ *cmdPeriod { this.enter("// thisProcess.cmdPeriod"); } // log file support - global only *makeLogFolder { var supportDir = thisProcess.platform.userAppSupportDir; var specialFolder = supportDir ++ "/HistoryLogs"; if (pathMatch(supportDir).isEmpty) { logFolder = ""; ^this }; if (pathMatch(specialFolder).isEmpty) { specialFolder.mkdir; if (pathMatch(specialFolder).isEmpty) { logFolder = supportDir; // if not there, put it in flat } } { logFolder = specialFolder; }; // ("// History.logFolder:" + logFolder).postln; } *showLogFolder { openOS(logFolder) } *checkLogStarted { var isOpen; if (logFile.isNil) { this.startLog }; isOpen = logFile.isOpen; ^if (isOpen.not) { this.startLog; ^logFile.isOpen } { true }; } *startLog { var timeStamp = this.timeStamp; var timeString = this.dateString; // open file with current date logPath = logFolder ++ "/log_History_" ++ timeStamp ++ ".scd"; logFile = File(logPath, "w"); if (logFile.isOpen) { logFile.write(format("// History, as it was on %.\n\n", timeString) ++ "[\n" /*]*/ ); "// History.logFile opened.".inform; } { "// History: could not open logFile!".warn; }; } *addToLog { |line| // add a single line if (this.checkLogStarted) { try { logFile.write(line.asCompileString ++ ",\n") } { "// History: could not write to logFile!".warn; } } { warn("// History: logFile is not open!"); }; } *endLog { // close file try { logFile.write( /*[*/ "];") }; try { logFile.close; "// History.logFile closed.".inform; }; } *showLogFile { Document.open(this.logPath) } matchKeys { |key| var indices = []; if (key == \all) { ^(0..lines.size - 1) }; if (key.isNil) { ^nil }; // list of keys: if (key.isArray) { lines.do { |line, i| if (key.includes(line[1])) { indices = indices.add(i) } } } { lines.do { |line, i| if (line[1] == key) { indices = indices.add(i) } } }; ^indices } matchString { |str, ignoreCase=true| var indices = []; if (str.notNil and: (str != "")) { lines.do { |line, i| if (line[2].find(str, ignoreCase).notNil) { indices = indices.add(i) } }; ^indices } { ^nil } } indicesFor { |keys, string=""| var indicesK, indicesS, indicesFound; indicesK = this.matchKeys(keys); indicesS = this.matchString(string); // [\indicesK, indicesK, \indicesS, indicesS].postln; indicesFound = if (indicesK.notNil) { if (indicesS.notNil) { indicesK.sect(indicesS) } { indicesK } } { if (indicesS.notNil) { indicesS } { (0.. lines.size - 1) } }; ^indicesFound } *makeWin { |where, numItems=8| ^current.makeWin(where, numItems) } makeWin { |where, numItems=8| var gui = HistoryGui(this, numItems); if (where.notNil) { gui.moveTo(where.x, where.y); }; ^gui } *document { current.document } document { arg title=""; // platform dependent ... var docTitle; Platform.case( \windows, { // not sure this works in 3.7.0? this.storyString.newTextWindow("History_documented"); }, { // docTitle = title ++ Date.getDate.format("%Y-%m-%e-%Hh%M-History"); Document.new(docTitle, this.storyString) // path not working yet // .path_(docTitle); // don't lose title. } ) } *readFromDoc { |path| var file, line, count = 0, lineStrings = [], comLineIndices = [], splitPoints; file = File(path.standardizePath, "r"); if (file.isOpen.not) { ("History: file" + path + "not found!").warn; ^false }; // read all lines, keep indices of commentlines while { line = file.getLine; line.notNil } { lineStrings = lineStrings.add(line); if (line.beginsWith("// - ")) { splitPoints = line.findAll(" - "); comLineIndices = comLineIndices.add([count] ++ splitPoints); }; count = count + 1; }; ^comLineIndices.collect { |list, i| var lineIndex, sep1, sep2, nextComIndex; var comLine, timeStr, time, key, codeStr; #lineIndex, sep1, sep2 = list; comLine = lineStrings[lineIndex]; timeStr = comLine.copyRange(sep1 + 3, sep2 - 1); time = History.unformatTime(timeStr); key = comLine.copyToEnd(sep2 + 3).select(_.isAlphaNum).asSymbol; nextComIndex = (comLineIndices[i + 1] ? [lineStrings.size]).first; codeStr = lineStrings.copyRange(lineIndex + 1, nextComIndex - 2).join; [time, key, codeStr]; }; } *checkPath { |path| var ext = path.splitext[1]; if ([\sc, \scd, \txt, \nil, \rtf].includes(ext.asSymbol)) { ^true } { warn("History: file format" + ext + "for story files likely not supported! Please use .txt, .scd, or other text format."); ^false }; } // load file saved with saveStory *loadStory { |path| current.loadStory(path) } loadStory { |path| var lines; if (this.class.checkPath(path)) { lines = this.class.readFromDoc(path); if (lines == false) { warn("History: no lines, so could not be loaded.") } { this.lines_(lines.reverse) } }; } *rewrite { |path, open = true| var lines, time, repath, file2; lines = path.load; if (lines.isNil) { "no history, no future.".warn; ^this }; time = path.basename.splitext.first.keep(-13).split($_).collect { |str, i| str.clump(2).join("-:"[i]); }.join($ ); repath = path.splitext.collect { |str, i| str ++ ["_rewritten.", ""][i] }.join; file2 = File.open(repath, "w"); file2.write("// History rewritten from" + time); lines.do { |line| var time, tag, code; #time, tag, code = line; file2.write("\n\n\n// when: % - who: % \n\n(\n%\n)\n".format(time, tag, code)); }; file2.close; if (open) { repath.openTextFile }; } } SuperCollider-Source/SCClassLibrary/Common/Streams/IOStream.sc000644 000765 000024 00000015305 12756534417 025377 0ustar00crucialstaff000000 000000 IOStream : Stream { reset { this.pos = 0; } skip { arg n; this.pos = this.pos + n; } comma { this.put(Char.comma);} space { this.put(Char.space); } nl { this.put(Char.nl); } ff { this.put(Char.ff); } tab { this.put(Char.tab); } << { arg item; item.printOn(this); } <<< { arg item; item.storeOn(this); } <<* { arg collection; collection.printItemsOn(this); } <<<* { arg collection; collection.storeItemsOn(this); } readUpTo { arg delimiter = $\f; var string, char; string = String.new; char = this.next; if(char.isNil) { ^nil }; while ({ char.notNil and: { char != delimiter } },{ string = string.add(char); char = this.next; }); ^string } flush {} pos_ { ^this.subclassResponsibility(thisMethod) } } CollStream : IOStream { var <>collection, = collection.size, { ^nil },{ pos = pos + 1; ^collection.at(pos - 1); }) } nextN { arg n; ^collection.species.fill(n, { this.next; }); } contents { ^collection.copyRange(0, collection.size-1); } put { arg item; //_RWStream_Put if (pos >= collection.size, { pos = collection.size + 1; collection = collection.add(item); },{ collection.put(pos, item); pos = pos + 1; }) } putAll { arg aCollection; collection = collection.overWrite(aCollection, pos); pos = pos + aCollection.size; } // write { arg item; // /* writes any of the following items as binary: // a double float, // a long, // an rgb color, // a char, // the name of a Symbol as chars, // the indexable part of any non-Slot format object, // (i.e. Strings, Int8Arrays, Int16Arrays, // Signals, etc.) // */ // _CollStream_Write // ^this.primitiveFailed; // } getChar { ^this.next; } getInt8 { ^this.next.bitAnd(255); } getInt16 { ^this.getInt8.leftShift(8).bitOr(this.getInt8); } getInt32 { ^this.getInt16.leftShift(16).bitOr(this.getInt16); } getFloat { ^Float.from32Bits(this.getInt32); } getDouble { ^Float.from64Bits(this.getInt32, this.getInt32); } getPascalString { var size = this.getInt8; ^String.fill(size, { this.getChar.asAscii }) } // array should be some subclass of RawArray read { |array| array.readFromStream(this); } // // collection should be an Int8Array putChar { arg aChar; this.put(aChar.ascii); } putInt8 { arg anInteger; this.put(anInteger.bitAnd(255)); } putInt16 { arg anInteger; this.putInt8(anInteger.rightShift(8)); this.putInt8(anInteger); } putInt16LE { arg anInteger; this.putInt8(anInteger); this.putInt8(anInteger.rightShift(8)); } putInt32 { arg anInteger; this.putInt8(anInteger.rightShift(24)); this.putInt8(anInteger.rightShift(16)); this.putInt8(anInteger.rightShift(8)); this.putInt8(anInteger); } putInt32LE { arg anInteger; this.putInt8(anInteger); this.putInt8(anInteger.rightShift(8)); this.putInt8(anInteger.rightShift(16)); this.putInt8(anInteger.rightShift(24)); } putFloat { arg aFloat; aFloat = aFloat.asFloat; this.putInt32(aFloat.as32Bits); } putDouble { arg aFloat; aFloat = aFloat.asFloat; this.putInt32(aFloat.high32Bits); this.putInt32(aFloat.low32Bits); } putFloatLE { arg aFloat; aFloat = aFloat.asFloat; this.putInt32LE(aFloat.as32Bits); } putDoubleLE { arg aFloat; aFloat = aFloat.asFloat; this.putInt32LE(aFloat.low32Bits); this.putInt32LE(aFloat.high32Bits); } putString { arg aString; aString.do({ arg char; this.putChar(char); }); } putPascalString { arg aString; this.putInt8(aString.size); this.putString(aString); } } LimitedWriteStream : CollStream { var <>limit, <>limitFunc; atLimit { ^pos >= limit } put { arg item; var newpos; newpos = pos + 1; if (newpos > limit, { limitFunc.value; limitFunc = nil; },{ super.put(item); }); } putAll { arg aCollection; var newpos; newpos = pos + aCollection.size; if (newpos > limit, { aCollection = aCollection.copyFromStart(limit - pos - 1); collection = collection.overWrite(aCollection, pos); pos = limit; limitFunc.value; limitFunc = nil; },{ collection = collection.overWrite(aCollection, pos); pos = newpos; }); } } Post { classvar <>formats; *initClass { formats = IdentityDictionary[ $c -> { |x| x.asCompileString }, ]; } //*flush { this.flushPostBuf } * << { arg item; item.printOn(this); } * <<< { arg item; item.storeOn(this); } * <<* { arg collection; collection.printItemsOn(this); } * <<<* { arg collection; collection.storeItemsOn(this); } * put { arg item; item.post; } * putAll { arg aCollection; aCollection.post; } * comma { this.put(Char.comma);} * space { this.put(Char.space); } * nl { this.put(Char.nl); } * ff { this.put(Char.ff); } * tab { this.put(Char.tab); } * close { this.flush; } } Pretty : IOStream { var <>out, <>level = 0, <>state; *new { arg out; var stream; stream = super.new.out_(out); stream.state_(PrettyEcho(stream)); ^stream } put { arg char; state.put(char); } close { out.close; } } PrettyState { var <>pretty; *new { arg pretty; ^super.new.pretty_(pretty); } } PrettyEcho : PrettyState { put { arg char; // echo chars until new line if ((char == $\n) || (char == $\r), { pretty.out.put($\n); pretty.state_(PrettyEat(pretty)); },{ if (char == ${ , /* } */ { pretty.out.put($\n); pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); pretty.level = pretty.level + 1; pretty.state_(PrettyEat(pretty)); },{ if ( /*{*/ char == $}, { pretty.level = pretty.level - 1; pretty.out.put($\n); pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); pretty.state_(PrettyEat(pretty)); },{ pretty.out.put(char); }) }) }); } } PrettyEat : PrettyState { put { arg char; if (char == ${, /*}*/ { pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); pretty.level = pretty.level + 1; },{ if (((char == $\n) || (char == $\r)) && (pretty.level == 0), { pretty.out.put($\n); },{ if (char.isSpace.not, { if ( /*{*/ char == $}, { pretty.level = pretty.level - 1; pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.out.put($\n); },{ pretty.level.do({ pretty.out.put($\t) }); pretty.out.put(char); pretty.state_(PrettyEcho(pretty)); }); }); }); }); } } SuperCollider-Source/SCClassLibrary/Common/Streams/ListPatterns.sc000644 000765 000024 00000023140 12756534417 026344 0ustar00crucialstaff000000 000000 Pindex : Pattern { var listPat, indexPat, repeats; *new { arg listPat, indexPat, repeats=1; ^super.newCopyArgs(listPat, indexPat, repeats) } storeArgs { ^[listPat,indexPat,repeats] } embedInStream { arg inval; var indexStream, index, item, itemCount; var listStream = listPat.asStream; repeats.value(inval).do { var list = listStream.next(inval); if (list.isNil) { ^inval }; indexStream = indexPat.asStream; itemCount = 0; while { index = indexStream.next(inval); index.notNil }{ itemCount = itemCount + 1; item = list.wrapAt(index); inval = item.embedInStream(inval); }; if(itemCount == 0) { ^inval } }; ^inval; } } ListPattern : Pattern { var <>list, <>repeats=1; *new { arg list, repeats=1; if (list.size > 0) { ^super.new.list_(list).repeats_(repeats) }{ Error("ListPattern (" ++ this.name ++ ") requires a non-empty collection; received " ++ list ++ ".").throw; } } copy { ^super.copy.list_(list.copy) } storeArgs { ^[ list, repeats ] } } Pseq : ListPattern { var <>offset; *new { arg list, repeats=1, offset=0; ^super.new(list, repeats).offset_(offset) } embedInStream { arg inval; var item, offsetValue; offsetValue = offset.value(inval); if (inval.eventAt('reverse') == true, { repeats.value(inval).do({ arg j; list.size.reverseDo({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); }); },{ repeats.value(inval).do({ arg j; list.size.do({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); }); }); ^inval; } storeArgs { ^[ list, repeats, offset ] } } Pser : Pseq { embedInStream { arg inval; var item; var offsetValue = offset.value(inval); if (inval.eventAt('reverse') == true, { repeats.value(inval).reverseDo({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); },{ repeats.value(inval).do({ arg i; item = list.wrapAt(i + offsetValue); inval = item.embedInStream(inval); }); }); ^inval; } } Pshuf : ListPattern { embedInStream { arg inval; var item, stream; var localList = list.copy.scramble; repeats.value(inval).do({ arg j; localList.size.do({ arg i; item = localList.wrapAt(i); inval = item.embedInStream(inval); }); }); ^inval; } } Prand : ListPattern { embedInStream { arg inval; var item; repeats.value(inval).do({ arg i; item = list.at(list.size.rand); inval = item.embedInStream(inval); }); ^inval; } } Pxrand : ListPattern { embedInStream { arg inval; var item, size; var index = list.size.rand; repeats.value(inval).do({ arg i; size = list.size; index = (index + (size - 1).rand + 1) % size; item = list.at(index); inval = item.embedInStream(inval); }); ^inval; } } Pwrand : ListPattern { var <>weights; *new { arg list, weights, repeats=1; ^super.new(list, repeats).weights_(weights) } embedInStream { arg inval; var item, wVal; var wStr = weights.asStream; repeats.value(inval).do({ arg i; wVal = wStr.next(inval); if(wVal.isNil) { ^inval }; item = list.at(wVal.windex); inval = item.embedInStream(inval); }); ^inval } storeArgs { ^[ list, weights, repeats ] } } Pfsm : ListPattern { embedInStream { arg inval; var item, index=0; var maxState = ((list.size - 1) div: 2) - 1; repeats.value(inval).do({ index = 0; while({ index = list.at(index).choose.clip(0, maxState) * 2 + 2; item = list.at(index - 1); item.notNil },{ inval = item.embedInStream(inval); }); }); ^inval; } } Pdfsm : ListPattern { var <>startState; *new { arg list, startState=0, repeats=1; ^super.new( list, repeats ).startState_(startState) } embedInStream { arg inval; var currState, sigStream; var sig, state, stream; var numStates = list.size - 1; repeats.value(inval).do({ currState = startState; sigStream = list[0].asStream; while({ sig = sigStream.next(inval); state = list[currState + 1]; if( sig.isNil, { false }, { if( state.includesKey(sig), { #currState, stream = state[sig]; }, { #currState, stream = state[\default]; }); currState.notNil and: {currState < numStates}; }) }, { inval = stream.embedInStream(inval); }) }); ^inval; } } Pswitch : Pattern { var <>list, <>which=0; *new { arg list, which=0; ^super.new.list_(list).which_(which) } embedInStream { arg inval; var item, index; var indexStream = which.asStream; while ({ (index = indexStream.next(inval)).notNil; },{ inval = list.wrapAt(index.asInteger).embedInStream(inval); }); ^inval; } storeArgs { ^[ list, which ] } } Pswitch1 : Pswitch { embedInStream { arg inval; var cleanup = EventStreamCleanup.new; var index, outval; var streamList = list.collect({ arg pattern; pattern.asStream; }); var indexStream = which.asStream; loop { if ((index = indexStream.next(inval)).isNil) { ^cleanup.exit(inval) }; outval = streamList.wrapAt(index.asInteger).next(inval); if (outval.isNil) { ^cleanup.exit(inval) }; cleanup.update(outval); inval = outval.yield; }; } } Ptuple : ListPattern { embedInStream { arg inval; var item, streams, tuple, outval; repeats.value(inval).do({ arg j; var sawNil = false; streams = list.collect({ arg item; item.asStream }); while ({ tuple = Array.new(streams.size); streams.do({ arg stream; outval = stream.next(inval); if (outval.isNil, { sawNil = true; }); tuple.add(outval); }); sawNil.not },{ inval = yield(tuple); }); }); ^inval; } } Place : Pseq { embedInStream { arg inval; var item; var offsetValue = offset.value(inval); if (inval.eventAt('reverse') == true, { repeats.value(inval).do({ arg j; list.size.reverseDo({ arg i; item = list.wrapAt(i + offsetValue); if (item.isSequenceableCollection, { item = item.wrapAt(j); }); inval = item.embedInStream(inval); }); }); },{ repeats.value(inval).do({ arg j; list.size.do({ arg i; item = list.wrapAt(i + offsetValue); if (item.isSequenceableCollection, { item = item.wrapAt(j); }); inval = item.embedInStream(inval); }); }); }); ^inval; } } // similar to Place, but the list is an array of Patterns or Streams Ppatlace : Pseq { embedInStream { |inval| var consecutiveNils = 0, index, repeat, item; var streamList = list.collect({ |item| item.asStream }); var offsetValue = offset.value(inval); var localRepeats = repeats.value(inval); index = repeat = 0; while { (repeat < localRepeats) and: { consecutiveNils < list.size } } { if(inval.eventAt(\reverse) == true) { item = streamList.wrapAt(offsetValue - index - 1); } { item = streamList.wrapAt(offsetValue + index); }; if((item = item.next(inval)).notNil) { consecutiveNils = 0; inval = item.embedInStream(inval); } { consecutiveNils = consecutiveNils + 1; }; if((index = index + 1) == list.size) { index = 0; repeat = repeat + 1; }; }; ^inval; } } Pslide : ListPattern { // 'repeats' is the number of segments. // 'len' is the length of each segment. // 'step' is how far to step the start of each segment from previous. // 'start' is what index to start at. // indexing wraps around if goes past beginning or end. // step can be negative. var <>len, <>step, <>start, <>wrapAtEnd; *new { arg list, repeats = 1, len = 3, step = 1, start = 0, wrapAtEnd = true; ^super.new(list, repeats).len_(len).step_(step).start_(start) .wrapAtEnd_(wrapAtEnd); } embedInStream { arg inval; var item; var pos = start; var stepStr = step.asStream, stepVal; var lengthStr = len.asStream, lengthVal; repeats.value(inval).do { lengthVal = lengthStr.next(inval); if(lengthVal.isNil) { ^inval }; if(wrapAtEnd) { lengthVal.do { |j| item = list.wrapAt(pos + j); inval = item.embedInStream(inval); } } { lengthVal.do { |j| item = list.at(pos + j); if(item.notNil) { inval = item.embedInStream(inval); } { ^inval }; } }; stepVal = stepStr.next(inval); if(stepVal.isNil) { ^inval }; pos = pos + stepVal; }; ^inval; } } Pwalk : ListPattern { // random walk pattern - hjh - jamshark70@gmail.com var <>startPos, // starting index <>stepPattern, // pattern for steps <>directionPattern; // pattern should return a stream of: // 1 to move in direction of stepPattern // -1 to reverse the direction of stepPattern // a new direction will be chosen when the walker // reaches a boundary *new { arg list, stepPattern, directionPattern = 1, startPos = 0; ^super.new(list).startPos_(startPos) .stepPattern_(stepPattern ?? { Prand([-1, 1], inf) }) .directionPattern_(directionPattern ? 1); } storeArgs { ^[list, stepPattern, directionPattern, startPos] } embedInStream { arg inval; var step; var index = startPos.value(inval); var stepStream = stepPattern.asStream; var directionStream = directionPattern.asStream; // 1 = use steps as is; -1 = reverse direction var direction = directionStream.next(inval) ? 1; // start with first value while({ // get step, stop when nil (step = stepStream.next(inval)).notNil },{ inval = list[index].embedInStream(inval); // get value/stream out step = step * direction; // apply direction // if next thing will be out of bounds if(((index + step) < 0) or: { (index + step) >= list.size }, { direction = directionStream.next(inval) ? 1; // next direction, or 1 step = step.abs * direction.sign; // apply to this step }); index = (index + step) % list.size; }); ^inval; } } SuperCollider-Source/SCClassLibrary/Common/Streams/NodeEvents.sc000644 000765 000024 00000006316 12756534417 025770 0ustar00crucialstaff000000 000000 /* This file defines Group and Synth event types similar to the Group and Synth classes. They follow the conventions of patterns, using integers (0,1,2,3) for addActions and integer nodeID's as targets. For example, g = (type: \Group, id: 2); g.play; a = (type: \Synth, group: 2) a.play; Would start a group with nodeID = 2 and play a synth within that group. If the event id is left unspecified, it is automatically allocated when the event is played. Caution, Event-play returns a time value, so an expression of the form a = (type: \Group, id: 1).play will assign the default duration of 1 to the variable a, not the group event! The interface to these events is a hybrid of the Pattern and Node control interfaces consisting of play, stop, pause, resume release, set, map, before, after, headOf, tailOf event[\id] can be an array. In this case, a set of nodes corresponding to each element of the array will be created and the order of the id's will be the order of the nodes running on the server. (In other word, the nodes are created in reverse order when event[\addAction] is 0 or 2. With the exception of ~server, ~latency, and ~instrument any key in the event can have an array as a value and the standard rules of multi-channel expansion will be followed. These event types can be used in patterns, but are probably more useful for more static use in system configuration or to control individual synths. Here is a simple example of its use: ( g = (type: \Group, id: [2,3,4,5,6], group: 0, addAction: 1); // define a multiple Group event g.play; // play it h = g.split; // split it into individual groups b = (type:\Synth, freq: [500,510], group: [2,3]); // make a Synth event b.play; c = b.split; b.set(\freq,[1000,1200]) c[0].set(\freq,700); c[1].set(\freq,400); h[0].release; h[1].release; g.stop; ) */ +Event { *checkIDs { | id, server | if (id.isNil) {^nil}; if (id.asArray.first < (if(server.notNil) { server.options.initialNodeID } { 1000 })) { ^id}; ^nil } asEventStreamPlayer {} sendOSC { | msg | if (this[\isPlaying]) { this[\server].sendBundle(this[\latency], *(msg.flop) ) } } set { | ... args | // this.sendOSC([15, this[\id]] ++ (args.asOSCArgArray)); args = ([15, this[\id]] ++ args).flop.asOSCArgBundle; if (this[\isPlaying]) { this[\server].sendBundle( this[\latency], *args ) } } stop { this.use { ~stopServerNode.value } } pause { this.use { ~pauseServerNode.value } } resume { this.use { ~resumeServerNode.value } } release { |releaseTime| this.use { ~releaseServerNode.value(releaseTime) } } free { this.use { ~freeServerNode.value } } synth { this.parent = Event.parentEvents[\synthEvent]; } group { this.parent = Event.parentEvents[\groupEvent]; } split { | key = \id | var event; if (this[\isPlaying] == true) { ^this[key].asArray.collect { |keyVal| event = this.copy.put(key, keyVal); NodeWatcher.register(event); event; } } { ^this[key].asArray.collect { |keyVal| this.copy.put(key, keyVal) } } } nodeID { ^(this[\id].asArray[0]) } asGroup { var type = this[\type]; if(type == \Group) { ^this }; ^this[\group].asGroup } } SuperCollider-Source/SCClassLibrary/Common/Streams/PatternConductor.sc000644 000765 000024 00000002505 12756534417 027210 0ustar00crucialstaff000000 000000 /* PatternConductor provides interactive control of patterns. When a Conductor is stopped it flushes its queue, immediately ending any notes left hanging by the pattern. */ PatternConductor { var <>patterns, <>event, <>quant, <>eventStreamPlayers; var <>clock, defaultPauseTempo, <>defaultStopTempo; *new { |patterns, event, quant| ^super.new .patterns_(patterns.asArray) .event_(event ? Event.default) .quant_(quant ? 0).tempo_(1).defaultPauseTempo_(1e-8).defaultStopTempo_(1e+8); } play { Routine.run({ this.prPlay }, 64, TempoClock.default, quant) } prPlay { if (clock.notNil) { this.stop }; CmdPeriod.add(this); clock = TempoClock(tempo); eventStreamPlayers = patterns.collect { | p | p.asEventStreamPlayer(event) }; eventStreamPlayers.do { | p | p.play(clock, false, 0) }; } pause { | pauseTempo| clock.tempo = pauseTempo ? defaultPauseTempo } resume { clock.tempo = tempo } stop { |stopTempo| var oldClock; oldClock = clock; eventStreamPlayers.do { | p | p.stop }; clock.tempo = stopTempo ? defaultStopTempo; Task({ while {oldClock.queue.size >= 2 } { yield(1) }; oldClock.stop }).play(clock); clock = nil; eventStreamPlayers = nil; CmdPeriod.remove(this); } tempo_ { | temp | tempo = temp; if (clock.notNil) { clock.tempo_(tempo) }; } cmdPeriod { clock = nil } } SuperCollider-Source/SCClassLibrary/Common/Streams/Patterns.sc000644 000765 000024 00000042047 12766171707 025517 0ustar00crucialstaff000000 000000 Pattern : AbstractFunction { // concatenate Patterns ++ { arg aPattern; ^Pseq.new([this, aPattern]) } // compose Patterns <> { arg aPattern; ^Pchain(this, aPattern) } play { arg clock, protoEvent, quant; ^this.asEventStreamPlayer(protoEvent).play(clock, false, quant) } // phase causes pattern to start somewhere in the current measure rather than on a downbeat // offset allows pattern to compute ahead a bit to allow negative lags for strummed chords // and to ensure one pattern computes ahead of another asStream { ^Routine({ arg inval; this.embedInStream(inval) }) } iter { ^this.asStream } streamArg { ^this.asStream } asEventStreamPlayer { arg protoEvent; ^EventStreamPlayer(this.asStream, protoEvent); } embedInStream { arg inval; ^this.asStream.embedInStream(inval); } do { arg function; this.asStream.do(function) } // filtering operations collect { arg function; ^Pcollect.new(function, this) } select { arg function; ^Pselect.new(function, this) } reject { arg function; ^Preject.new(function, this) } // function composition composeUnaryOp { arg operator; ^Punop.new(operator, this) } composeBinaryOp { arg operator, pattern, adverb; ^Pbinop.new(operator, this, pattern, adverb) } reverseComposeBinaryOp { arg operator, pattern, adverb; ^Pbinop.new(operator, pattern, this, adverb) } composeNAryOp { arg selector, argList; ^Pnaryop.new(selector, this, argList); } ////////////////////// mtranspose { arg n; ^Paddp(\mtranspose, n, this) } ctranspose { arg n; ^Paddp(\ctranspose, n, this) } gtranspose { arg n; ^Paddp(\gtranspose, n, this) } detune { arg n; ^Paddp(\detune, n, this) } scaleDur { arg x; ^Pmulp(\dur, x, this) } addDur { arg x; ^Paddp(\dur, x, this) } stretch { arg x; ^Pmulp(\stretch, x, this) } lag { arg t; ^Plag(t, this) } legato { arg x; ^Pmulp(\legato, x, this) } db { arg db; ^Paddp(\db, db, this) } clump { arg n; ^Pclump(n, this) } flatten { arg n = 1; ^Pflatten(n, this) } repeat { arg n=inf; ^Pn(this, n) } keep { arg n; ^Pfin(n, this) } drop { arg n; ^Pdrop(n, this) } stutter { arg n; ^Pstutter(n, this) } finDur { arg dur, tolerance = 0.001; ^Pfindur(dur, this, tolerance) } fin { arg n; ^Pfin(n, this) } trace { arg key, printStream, prefix=""; ^Ptrace(this, key, printStream, prefix) } differentiate { ^Pdiff(this) } integrate { ^Plazy { var sum = 0; this.collect { |x| sum = sum + x } } } ////////////////////// // realtime recording // for NRT see Pattern:asScore // path: if nil, auto-generate path // dur: if nil, record until pattern stops (infinite pattern = problem) // fadeTime: allow extra time after last Event for nodes to become silent record { |path, headerFormat = "AIFF", sampleFormat = "float", numChannels = 2, dur = nil, fadeTime = 0.2, clock(TempoClock.default), protoEvent(Event.default), server(Server.default), out = 0| var buf, bus, recsynth, pattern, defname, cond, startTime; if(dur.notNil) { pattern = Pfindur(dur, this) } { pattern = this }; path ?? { if(thisProcess.platform.name == \windows) { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Main.elapsedTime.round(0.01) ++ "." ++ headerFormat; } { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Date.localtime.stamp ++ "." ++ headerFormat; }; }; fork { cond = Condition.new; buf = Buffer.alloc(server, 65536, numChannels); SynthDef(defname = ("patrec"++numChannels).asSymbol, { |bufnum, bus, out| var sig = In.ar(bus, numChannels); DiskOut.ar(bufnum, sig); Out.ar(out, sig); }).add; bus = Bus.audio(server, numChannels); server.sync(cond); buf.write(path, headerFormat, sampleFormat, numFrames: 0, startFrame: 0, leaveOpen: true); server.sync(cond); "Recording pattern into % at %\n".postf(path, thisThread.beats); recsynth = server.nextNodeID; Pprotect( // Pfset has a cleanupFunc, which executes even if pattern is stopped by cmd-. Pfset(nil, Pseq([ Pfuncn { startTime = thisThread.beats; (type: \rest, delta: 0) }, (type: \on, instrument: defname, bufnum: buf, bus: bus, out: out, id: recsynth, delta: 0), pattern <> (out: bus), Plazy { Pn((type: \rest, delta: (fadeTime ? 0) .roundUp(buf.numFrames / server.sampleRate)), 1) } ], 1), { (type: \kill, id: recsynth).play } ), // on error, killing the recsynth triggers rest of cleanup below { (type: \kill, id: recsynth).play } ).play(clock, protoEvent, quant: 0); // clean up after recording synth stops OSCpathResponder(server.addr, ['/n_end', recsynth], { |time, resp, msg| resp.remove; cond.unhang; }).add; cond.hang; buf.close.free; bus.free; server.sendMsg(\d_free, defname); "Finished recording % at %\n".postf(path, thisThread.beats); } } } Pfunc : Pattern { var <>nextFunc; // Func is evaluated for each next state var <>resetFunc; // Func is evaluated for each next state *new { arg nextFunc, resetFunc; ^super.newCopyArgs(nextFunc, resetFunc) } storeArgs { ^[nextFunc] ++ resetFunc } asStream { ^FuncStream.new(nextFunc, resetFunc) } } Prout : Pattern { var <>routineFunc; *new { arg routineFunc; ^super.newCopyArgs(routineFunc) } storeArgs { ^[routineFunc] } asStream { ^Routine.new(routineFunc) } embedInStream { arg inval; ^routineFunc.value(inval) } } Pfuncn : Pattern { var <>func, <>repeats; *new { arg func, repeats = 1; ^super.newCopyArgs(func, repeats) } storeArgs { ^[func,repeats] } embedInStream { arg inval; repeats.value(inval).do({ inval = func.value(inval).processRest(inval).yield; }); ^inval } } // Punop and Pbinop are used to create patterns in response to math operations Punop : Pattern { var <>operator, <>a; *new { arg operator, a; ^super.newCopyArgs(operator, a) } storeOn { arg stream; stream <<< a << "." << operator } embedInStream { arg inval; var stream, outval; stream = a.asStream; loop { outval = stream.next(inval); if (outval.isNil) { ^inval }; inval = yield(outval.perform(operator)); } } asStream { ^UnaryOpStream.new(operator, a.asStream); } } Pbinop : Pattern { var <>operator, <>a, <>b, <>adverb; *new { arg operator, a, b, adverb; ^super.newCopyArgs(operator, a, b, adverb) } storeOn { arg stream; stream << "(" <<< a << " " << operator.asBinOpString; if(adverb.notNil) { stream << "." << adverb }; stream << " " <<< b << ")" } asStream { if (adverb.isNil) { ^BinaryOpStream.new(operator, a.asStream, b.asStream); }; if (adverb == 'x') { ^BinaryOpXStream.new(operator, a.asStream, b.asStream); }; ^nil } } Pnaryop : Pattern { var <>operator, <>a, <>arglist; *new { arg operator, a, arglist; ^super.newCopyArgs(operator, a, arglist) } storeOn { arg stream; stream <<< a << "." << operator << "(" <<<* arglist << ")" } embedInStream { arg inval; var streamA, streamlist, vala, values, isNumeric; streamA = a.asStream; // optimization isNumeric = arglist.every { arg item; item.isNumber or: {item.class === Symbol} }; if (isNumeric) { loop { vala = streamA.next(inval); if (vala.isNil) { ^inval }; inval = yield(vala.performList(operator, arglist)); } }{ streamlist = arglist.collect({ arg item; item.asStream }); loop { vala = streamA.next(inval); if (vala.isNil) { ^inval }; values = streamlist.collect({ arg item; var result = item.next(inval); if (result.isNil) { ^inval }; result }); inval = yield(vala.performList(operator, values)); } }; } asStream { ^NAryOpStream.new(operator, a.asStream, arglist.collect({ arg item; item.asStream })); } } PdegreeToKey : Pnaryop { *new { arg pattern, scale, stepsPerOctave=12; ^super.new('degreeToKey', pattern, [scale, stepsPerOctave]) } // this is not reversible // but it would save as something that played the same //storeArgs { ^[ pattern, scale, stepsPerOctave ] } } Pchain : Pattern { var <>patterns; *new { arg ... patterns; ^super.newCopyArgs(patterns); } <> { arg aPattern; var list; list = patterns.copy.add(aPattern); ^this.class.new(*list) } embedInStream { arg inval; var streams, inevent, cleanup = EventStreamCleanup.new; streams = patterns.collect(_.asStream); loop { inevent = inval.copy; streams.reverseDo { |str| inevent = str.next(inevent); if(inevent.isNil) { ^cleanup.exit(inval) }; }; cleanup.update(inevent); inval = yield(inevent); }; } storeOn { arg stream; stream << "("; patterns.do { |item,i| if(i != 0) { stream << " <> " }; stream <<< item; }; stream << ")" } } Pevent : Pattern { var <>pattern, <>event; *new { arg pattern, event; ^super.newCopyArgs(pattern, event ?? { Event.default }); } storeArgs { ^[pattern, event] } embedInStream { arg inval; var outval; var stream = pattern.asStream; loop { outval = stream.next(event); if (outval.isNil) { ^inval }; inval = outval.yield } } } Pbind : Pattern { var <>patternpairs; *new { arg ... pairs; if (pairs.size.odd, { Error("Pbind should have even number of args.\n").throw; }); ^super.newCopyArgs(pairs) } storeArgs { ^patternpairs } embedInStream { arg inevent; var event; var sawNil = false; var streampairs = patternpairs.copy; var endval = streampairs.size - 1; forBy (1, endval, 2) { arg i; streampairs.put(i, streampairs[i].asStream); }; loop { if (inevent.isNil) { ^nil.yield }; event = inevent.copy; forBy (0, endval, 2) { arg i; var name = streampairs[i]; var stream = streampairs[i+1]; var streamout = stream.next(event); if (streamout.isNil) { ^inevent }; if (name.isSequenceableCollection) { if (name.size > streamout.size) { ("the pattern is not providing enough values to assign to the key set:" + name).warn; ^inevent }; name.do { arg key, i; event.put(key, streamout[i].processRest(event)); }; }{ event.put(name, streamout); }; }; inevent = event.yield; } } } Pmono : Pattern { var <>synthName, <>patternpairs; *new { arg name ... pairs; if (pairs.size.odd, { Error("Pmono should have odd number of args.\n").throw; }); ^super.newCopyArgs(name.asSymbol, pairs) } embedInStream { | inevent | ^PmonoStream(this).embedInStream(inevent) } } PmonoArtic : Pmono { embedInStream { |inevent| ^PmonoArticStream(this).embedInStream(inevent) } } Pseries : Pattern { // arithmetic series var <>start=0, <>step=1, <>length=inf; *new { arg start = 0, step = 1, length=inf; ^super.newCopyArgs(start, step, length) } storeArgs { ^[start,step,length] } embedInStream { arg inval; var outval, counter = 0; var cur = start.value(inval); var len = length.value(inval); var stepStr = step.asStream, stepVal; while { counter < len } { stepVal = stepStr.next(inval); if(stepVal.isNil) { ^inval }; outval = cur; cur = cur + stepVal; counter = counter + 1; inval = outval.yield; }; ^inval; } } Pgeom : Pattern { // geometric series var <>start=1.0, <>grow=1.0, <>length=inf; *new { arg start = 0, grow = 1, length=inf; ^super.newCopyArgs(start, grow, length) } storeArgs { ^[start,grow,length] } embedInStream { arg inval; var outval, counter = 0; var cur = start.value(inval); var len = length.value(inval); var growStr = grow.asStream, growVal; while { counter < len } { growVal = growStr.next(inval); if(growVal.isNil) { ^inval }; outval = cur; cur = cur * growVal; counter = counter + 1; inval = outval.yield; }; ^inval; } } Pbrown : Pattern { var <>lo, <>hi, <>step, <>length; *new { arg lo=0.0, hi=1.0, step=0.125, length=inf; ^super.newCopyArgs(lo, hi, step, length) } storeArgs { ^[lo,hi,step,length] } embedInStream { arg inval; var cur; var loStr = lo.asStream, loVal; var hiStr = hi.asStream, hiVal; var stepStr = step.asStream, stepVal; loVal = loStr.next(inval); hiVal = hiStr.next(inval); stepVal = stepStr.next(inval); cur = rrand(loVal, hiVal); if(loVal.isNil or: { hiVal.isNil } or: { stepVal.isNil }) { ^inval }; length.value(inval).do { loVal = loStr.next(inval); hiVal = hiStr.next(inval); stepVal = stepStr.next(inval); if(loVal.isNil or: { hiVal.isNil } or: { stepVal.isNil }) { ^inval }; cur = this.calcNext(cur, stepVal).fold(loVal, hiVal); inval = cur.yield; }; ^inval; } calcNext { arg cur, step; ^cur + step.xrand2 } } Pgbrown : Pbrown { calcNext { arg cur, step; ^cur * (1 + step.xrand2) } } Pwhite : Pattern { var <>lo, <>hi, <>length; *new { arg lo=0.0, hi=1.0, length=inf; ^super.newCopyArgs(lo, hi, length) } storeArgs { ^[lo,hi,length] } embedInStream { arg inval; var loStr = lo.asStream; var hiStr = hi.asStream; var hiVal, loVal; length.value(inval).do({ hiVal = hiStr.next(inval); loVal = loStr.next(inval); if(hiVal.isNil or: { loVal.isNil }) { ^inval }; inval = rrand(loVal, hiVal).yield; }); ^inval; } } Pprob : Pattern { var <>hi, <>lo, <>length, pattern1, <>pattern2; *new { arg pattern1, pattern2; ^super.newCopyArgs(pattern1, pattern2) } storeArgs { ^[pattern1,pattern2] } embedInStream { arg inval; var stream1, stream2, val1, val2; stream1 = pattern1.asStream; while { (val1 = stream1.next(inval)).notNil; }{ stream2 = pattern2.asStream; while { (val2 = stream2.next(inval)).notNil; }{ inval = yield( val1 + val2 ); }; }; ^inval } } Pstep3add : Pattern { var <>pattern1, <>pattern2, <>pattern3; *new { arg pattern1, pattern2, pattern3; ^super.newCopyArgs(pattern1, pattern2, pattern3) } storeArgs { ^[pattern1,pattern2,pattern3] } embedInStream { arg inval; var stream1, stream2, stream3, val1, val2, val3; stream1 = pattern1.asStream; while { (val1 = stream1.next(inval)).notNil; }{ stream2 = pattern2.asStream; while { (val2 = stream2.next(inval)).notNil; }{ stream3 = pattern3.asStream; while { (val3 = stream3.next(inval)).notNil; }{ inval = yield( val1 + val2 + val3 ); }; }; }; ^inval; } } PstepNfunc : Pattern { var patterns; *new { arg function, patterns; ^super.newCopyArgs(function ? { |x| x }, patterns) } storeArgs { ^[function,patterns] } embedInStream { arg inval; var val; var size = patterns.size; var max = size - 1; var streams = Array.newClear(size); var vals = Array.newClear(size); // this variable is needed because of recursion var f = { arg inval, level=0; var val; streams[level] = patterns[level].asStream; while{ vals[level] = val = streams[level].next(inval); val.notNil; }{ if(level < max) { inval = f.value(inval, level + 1) }{ inval = yield(function.value(vals)); } }; inval; }; ^f.value(inval); } } PstepNadd : PstepNfunc { *new { arg ... patterns; ^super.new({ arg vals; vals.sum }, patterns) } storeArgs { ^patterns } } // returns relative time (in beats) from moment of embedding Ptime : Pattern { var <>repeats; *new { arg repeats=inf; ^super.newCopyArgs(repeats) } storeArgs { ^[repeats] } embedInStream { arg inval; var start = thisThread.beats; repeats.value(inval).do { inval = (thisThread.beats - start).yield }; ^inval } } // if an error is thrown in the stream, func is evaluated Pprotect : FilterPattern { var <>func; *new { arg pattern, func; ^super.new(pattern).func_(func) } storeArgs { ^[ pattern, func ] } asStream { var rout = Routine(pattern.embedInStream(_)); rout.exceptionHandler = { |error| func.value(error, rout); nil.handleError(error) }; ^rout } } // access a key from the input event Pkey : Pattern { var <>key, <>repeats; *new { |key| ^super.newCopyArgs(key) } storeArgs { ^[key] } // avoid creating a routine asStream { var keystream = key.asStream; ^FuncStream({ |inevent| inevent !? { inevent[keystream.next(inevent)] } }); } } Pif : Pattern { var <>condition, <>iftrue, <>iffalse, <>default; *new { |condition, iftrue, iffalse, default| ^super.newCopyArgs(condition, iftrue, iffalse, default) } storeArgs { ^[condition, iftrue, iffalse,default] } asStream { var condStream = condition.asStream, trueStream = iftrue.asStream, falseStream = iffalse.asStream; ^FuncStream({ |inval| var test; if((test = condStream.next(inval)).isNil) { nil } { if(test) { trueStream.next(inval) ? default } { falseStream.next(inval) ? default }; }; }, { // reset func condStream.reset; trueStream.reset; falseStream.reset; }) } } SuperCollider-Source/SCClassLibrary/Common/Streams/Penv.sc000644 000765 000024 00000000441 12756534417 024617 0ustar00crucialstaff000000 000000 Penv : Env { embedInStream { arg inval; var startTime; startTime = thisThread.endBeat ? thisThread.beats; thisThread.endBeat = this.times.sum + startTime; while { thisThread.beats < thisThread.endBeat } { inval = yield(this.at(thisThread.beats - startTime))}; ^inval } } SuperCollider-Source/SCClassLibrary/Common/Streams/Pfx.sc000644 000765 000024 00000013672 12766171707 024456 0ustar00crucialstaff000000 000000 Pfx : FilterPattern { var <>fxname, <>pairs; *new { arg pattern, fxname ... pairs; if (pairs.size.odd, { Error("Pfx should have even number of args.\n").throw }); ^super.new(pattern).fxname_(fxname).pairs_(pairs) } storeArgs { ^[pattern, fxname] ++ pairs } embedInStream { arg inevent; var stream, cleanup = EventStreamCleanup.new; var server = inevent[\server] ?? { Server.default }; var id = server.nextNodeID; var event = inevent.copy; var cleanupEvent; pairs.pairsDo {|name, value| event[name] = value; }; event[\addAction] = 0; // \addToHead event[\instrument] = fxname; event[\type] = \on; event[\id] = id; event[\delta] = 0; cleanupEvent = (type: \off, parent: event); cleanup.addFunction(event, { |flag| if (flag) { cleanupEvent.play } }); inevent = event.yield; stream = pattern.asStream; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; inevent = event.yield; }; } isolate { ^Prout { arg inevent; var outputData, synthDesc; synthDesc = (inevent[\synthLib] ?? { SynthDescLib.global }).at(fxname); if(synthDesc.isNil) { Error("Pfx: SynthDesc not found: %".format(fxname)).throw }; outputData = synthDesc.outputData; if(outputData.size > 1) { Error("Pfx does not support more than one output UGen.").throw }; if(outputData.isEmpty) { this.embedInStream(inevent) } { outputData = outputData.unbubble; if(outputData[\numChannels] > SystemSynthDefs.numChannels) { Error("Pfx: SynthDef % has too many channels." "Set SystemSynthDefs.numChannels >= %" .format(fxname, outputData[\numChannels])).throw }; Pbus(this, inevent[\endTime] ? 2.0, inevent[\fadeTime] ? 0.02, outputData[\numChannels], outputData[\rate] ).embedInStream(inevent) } } } } Pfxb : Pfx { *new { arg pattern, fxname ... pairs; if (pairs.size.odd, { Error("Pfx should have even number of args.\n").throw }); ^super.new(pattern, fxname, *pairs).isolate } } PAbstractGroup : FilterPattern { embedInStream { arg inevent; var server, groupID, event, cleanup; var stream, lag = 0, clock = thisThread.clock, groupReleaseTime = inevent[\groupReleaseTime] ? 0.1, cleanupEvent; var eventType = this.class.eventType; cleanup = EventStreamCleanup.new; server = inevent[\server] ?? { Server.default }; groupID = server.nextNodeID; event = inevent.copy; event[\addAction] = 0; // \addToHead event[\type] = eventType; event[\delta] = 0; event[\id] = groupID; cleanupEvent = (type: \kill, parent: event); cleanup.addFunction(event, { | flag | if (flag) { cleanupEvent.lag_(lag - clock.beats + groupReleaseTime).play } }); inevent = event.yield; inevent !? { inevent = inevent.copy; inevent[\group] = groupID; }; stream = pattern.asStream; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; lag = max(lag, clock.beats + event.use { ~sustain.value }); inevent = event.yield; inevent.put(\group, groupID); } } *embedLoop { arg inevent, stream, groupID, ingroup, cleanup; var event, lag; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; lag = event[\dur]; inevent = event.yield; inevent.put(\group, groupID); } } } Pgroup : PAbstractGroup { *eventType { ^\group } } PparGroup : PAbstractGroup { *eventType { ^\parGroup } } Pbus : FilterPattern { var <>numChannels, <>rate, <>dur, <>fadeTime; *new { arg pattern, dur=2.0, fadeTime=0.02, numChannels=2, rate=\audio; ^super.new(pattern).dur_(dur).numChannels_(numChannels).rate_(rate).fadeTime_(fadeTime) } storeArgs { ^[ pattern, dur, fadeTime, numChannels, rate ] } embedInStream { arg inevent; var server, groupID, linkID, bus, ingroup, cleanup; var patterns, event, freeBus, stream, cleanupEvent; cleanup = EventStreamCleanup.new; server = inevent[\server] ?? { Server.default }; groupID = server.nextNodeID; linkID = server.nextNodeID; ingroup = inevent[\group]; dur = dur ?? { server.latency }; // allocate a new bus number and make a type group event // could use a special event type for this: if(rate == \audio) { bus = server.audioBusAllocator.alloc(numChannels); freeBus = { server.audioBusAllocator.free(bus) }; } { bus = server.controlBusAllocator.alloc(numChannels); freeBus = { server.controlBusAllocator.free(bus) }; }; CmdPeriod.doOnce(freeBus); // also free the bus when cmd-period is run event = inevent.copy; event[\addAction] = 0; // \addToHead event[\type] = \group; event[\delta] = 0; event[\id] = groupID; event[\group] = ingroup; // when stream ends, the bus number has to be released // so add a function to the cleanup that does this after the link synth has faded out cleanup.addFunction(event, { defer(freeBus, fadeTime.abs + dur) }); // return the group event event.yield; // allocate a synth that links from the inner bus to the outer bus inevent = event = inevent.copy; event[\type] = \on; event[\group] = groupID; event[\addAction] = 3; // \addBefore event[\delta] = 0; event[\id] = linkID; event[\fadeTime] = fadeTime; event[\instrument] = format("system_link_%_%", rate, numChannels); event[\in] = bus; // doneAction = 3; remove and deallocate both this synth and the preceeding node // (which is the group). event[\msgFunc] = #{ |out, in, fadeTime, gate=1| [\out, out, \in, in, \fadeTime, fadeTime, \gate, gate, \doneAction, 3] }; // when stream ends, the synth has to fade out. // so add a type-off event to the cleanup cleanupEvent = (type: \off, parent: event, fadeTime: fadeTime.abs, hasGate: true, gate: 0); cleanup.addFunction(event, { | flag | if(flag) { defer({ cleanupEvent.play }, dur) } }); // return the link synth event inevent = event.yield; // now embed the event stream stream = Pchain(pattern, (group: groupID, out: bus)).asStream; loop { // if stream ends, run cleanup event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; inevent = event.yield; } } } SuperCollider-Source/SCClassLibrary/Common/Streams/Plambda.sc000644 000765 000024 00000003635 12756534417 025257 0ustar00crucialstaff000000 000000 Plambda : FilterPattern { var <>scope; *new { arg pattern, scope; ^super.new(pattern).scope_(scope) } embedInStream { arg inval; var embedScope, stream, outval, parentScope; stream = pattern.asStream; inval !? { parentScope = inval[\eventScope] }; embedScope = (scope.copy ? ()).parent_(parentScope); while { inval = inval.copy ? (); inval[\eventScope] = embedScope; outval = stream.next(inval); outval.notNil } { // return outer scope outval = outval.copy; outval[\eventScope] = outval[\eventScope].eventAt(\parent); inval = outval.yield }; ^inval } storeArgs { ^if(scope.notNil) { [pattern, scope] } { [pattern] } } } Plet : Pattern { var <>pattern, <>key, <>return; *new { arg key, pattern, return; ^super.newCopyArgs(pattern, key, return) } embedInStream { arg inval; var str = pattern.asStream, val, sval, outval, scope; var returnStr = return.asStream, returnVal; while { outval = str.next(inval); returnVal = returnStr.next(inval); outval.notNil } { scope = inval[\eventScope]; if(scope.isNil) { Error("no scope defined in event").throw }; // don't transmit scope val = outval.copy; if(val.eventAt(\eventScope).notNil) { val[\eventScope] = nil }; scope[key] = val; inval = (returnVal ? outval).yield; } } silent { return = Event.silent } storeArgs { ^[key, pattern] ++ return } } Pget : Pattern { var <>key, <>default, <>repeats; *new { arg key, default, repeats = 1; ^super.newCopyArgs(key, default, repeats) } embedInStream { arg inval; var scope = inval[\eventScope], outval; if(scope.isNil) { Error("no scope defined in event").throw }; repeats.value(inval).do { outval = scope[key] ? default; if(outval.isNil) { ^inval }; outval.yield }; ^inval } storeArgs { var list = [key]; if(repeats != 1) { ^[key, default, repeats] }; if(default.notNil) { ^[key, default] } ^[key] } } SuperCollider-Source/SCClassLibrary/Common/Streams/PmonoStreams.sc000644 000765 000024 00000007004 12756534417 026340 0ustar00crucialstaff000000 000000 // these are internal classes, used by Pmono and PmonoArtic // they're not likely to work well if you try to use them outside that context PmonoStream : Stream { var pattern, id, server, cleanup, currentCleanupFunc, event, streamout, name, streampairs, endval, msgFunc, hasGate, synthLib, desc, schedBundleArray, schedBundle; *new { |pattern| ^super.newCopyArgs(pattern) } embedInStream { |inevent| inevent ?? { ^nil.yield }; this.prInit(inevent); loop { if(this.prDoStreams) { // always on the first iteration; should not happen thereafter if(id.isNil) { this.prInitNode }; cleanup.update(event); inevent = event.yield; this.prSetNextEvent(inevent); } { ^cleanup.exit(inevent) } } } // private methods abstracted out for the benefit of subclasses // you should not use these directly prInit { |inevent| cleanup = EventStreamCleanup.new; streampairs = pattern.patternpairs.copy; endval = pattern.patternpairs.size - 1; forBy (1, endval, 2) { | i | streampairs[i] = streampairs[i].asStream }; event = inevent.copy; event.use { synthLib = ~synthLib ?? { SynthDescLib.global }; ~synthDesc = desc = synthLib.match(pattern.synthName); if (desc.notNil) { ~hasGate = hasGate = desc.hasGate; ~msgFunc = desc.msgFunc; }{ ~msgFunc = ~defaultMsgFunc; ~hasGate = hasGate = false; }; msgFunc = ~msgFunc; } } prInitNode { event.use { if (~id.notNil) { ~type = \monoSet; id = ~id; } { // If the event is a rest, no node would be created // so there is no need to add a cleanup function // (for a node that will never exist). If a later // event is not a rest, ~id will be nil and the // cleanup will be set at that time. if(event.isRest.not) { ~type = \monoNote; ~instrument = pattern.synthName; cleanup.addFunction(event, currentCleanupFunc = { | flag | if (flag) { (id: id, server: server, type: \off, hasGate: hasGate, schedBundleArray: schedBundleArray, schedBundle: schedBundle).play }; currentCleanupFunc = nil; }); }; }; // this should happen whether or not ~id is nil ~updatePmono = { | argID, argServer | id = argID; server = argServer; schedBundleArray = ~schedBundleArray; schedBundle = ~schedBundle; }; }; } prDoStreams { forBy (0, endval, 2) { | i | name = streampairs[i]; streamout = streampairs[i+1].next(event); streamout ?? { ^false }; if (name.isSequenceableCollection) { name.do { | n, i | event[n] = streamout[i].processRest(event) }; }{ event[name] = streamout; }; }; ^true } prSetNextEvent { |inevent| event = inevent.copy; event.use{ ~server = server; ~id = id; ~type = \monoSet; ~msgFunc= msgFunc; }; } } PmonoArticStream : PmonoStream { embedInStream { |inevent| var sustain, rearticulating = true; inevent ?? { ^nil.yield }; this.prInit(inevent); loop { if(this.prDoStreams) { if(rearticulating and: { event.isRest.not }) { event[\id] = nil; this.prInitNode; rearticulating = false; }; sustain = event.use { ~sustain.value }; if(sustain.notNil and: { sustain < event.delta }) { event[\removeFromCleanup] = event[\removeFromCleanup].add(currentCleanupFunc); thisThread.clock.sched(sustain, { currentCleanupFunc.value(true); rearticulating = true; }); }; cleanup.update(event); inevent = event.yield; this.prSetNextEvent(inevent); } { ^cleanup.exit(inevent) } } } } SuperCollider-Source/SCClassLibrary/Common/Streams/Ppar.sc000644 000765 000024 00000005451 12756534417 024617 0ustar00crucialstaff000000 000000 Ppar : ListPattern { initStreams { arg priorityQ; list.do({ arg pattern, i; priorityQ.put(0.0, pattern.asStream); }); } embedInStream { arg inval; var assn; var priorityQ = PriorityQueue.new; repeats.value(inval).do({ arg j; var outval, stream, nexttime, now = 0.0; this.initStreams(priorityQ); // if first event not at time zero if (priorityQ.notEmpty and: { (nexttime = priorityQ.topPriority) > 0.0 }) { outval = Event.silent(nexttime, inval); inval = outval.yield; now = nexttime; }; while { priorityQ.notEmpty } { stream = priorityQ.pop; outval = stream.next(inval).asEvent; if (outval.isNil) { nexttime = priorityQ.topPriority; if (nexttime.notNil, { // that child stream ended, so rest until next one outval = Event.silent(nexttime - now, inval); inval = outval.yield; now = nexttime; },{ priorityQ.clear; }); } { // requeue stream priorityQ.put(now + outval.delta, stream); nexttime = priorityQ.topPriority; outval.put(\delta, nexttime - now); inval = outval.yield; // inval ?? { this.purgeQueue(priorityQ); ^nil.yield }; now = nexttime; }; }; }); ^inval; } } Ptpar : Ppar { initStreams { arg priorityQ; forBy(0, list.size-1, 2, { arg i; priorityQ.put(list.at(i).value, list.at(i+1).asStream); }); } } Pgpar : Ppar { embedInStream { arg inevent; var server, ids, patterns, event, ingroup, cleanup, stream; var lag = 0, clock = thisThread.clock, groupReleaseTime = inevent[\groupReleaseTime] ? 0.1; server = inevent[\server] ?? { Server.default }; ingroup = inevent[\group]; ids = { server.nextNodeID } ! this.numberOfGroups; event = inevent.copy; event[\addAction] = 1; event[\type] = \group; event[\delta] = 0; event[\id] = ids; event[\group] = ingroup; inevent = event.yield.copy; cleanup = EventStreamCleanup.new; cleanup.addFunction(inevent, { | flag | if (flag) { ( lag: lag - clock.beats + groupReleaseTime, type: \kill, id: ids, server: server ).play }; }); patterns = this.wrapPatterns(ids); stream = this.class.implClass.new(patterns, repeats).asStream; inevent !? { inevent = inevent.copy; inevent[\group] = ingroup }; loop { event = stream.next(inevent) ?? { ^cleanup.exit(inevent) }; cleanup.update(event); lag = max(lag, clock.beats + event.use { ~sustain.value }); inevent = event.yield; } } numberOfGroups { ^list.size } wrapPatterns { arg ids; ^ids.collect { |id, i| Psetpre(\group, id, list[i]) }; } *implClass { ^Ppar } } Pgtpar : Pgpar { numberOfGroups { ^list.size div: 2 } wrapPatterns { arg ids; var patterns = list.copy; ids.do { |id, i| patterns[((i << 1) + 1)] = Psetpre(\group, id, patterns[(i << 1) + 1]) }; ^patterns } *implClass { ^Ptpar } } SuperCollider-Source/SCClassLibrary/Common/Streams/Ppatmod.sc000644 000765 000024 00000004233 12756534417 025316 0ustar00crucialstaff000000 000000 Plazy : Pattern { var <>func; *new { arg func; ^super.new.func_(func) } //asStream { arg ... args; // ^func.valueArray(args).asStream // } embedInStream { arg inval; ^func.value(inval).embedInStream(inval) } storeArgs { ^[func] } } PlazyEnvir : Plazy { var <>passEvent=false; embedInStream { arg inval; ^if(inval.isNil) { func.value.embedInStream(inval) } { inval.use { if(passEvent) { func.valueEnvir(inval) } { func.valueEnvir }.embedInStream(inval) } } } } PlazyEnvirN : PlazyEnvir { var genFunc; *new { arg func; ^super.new(func).makeGenFunc } embedInStream { arg inval; var patterns; ^if(inval.isNil) { func.value.embedInStream(inval) } { inval.use { patterns = if(passEvent) { genFunc.valueEnvir(inval) } { genFunc.valueEnvir }; }; if(patterns.size > 1) { Ppar(patterns).embedInStream(inval) } { patterns.unbubble.embedInStream(inval) } } } // expand arguments makeGenFunc { genFunc = if(func.def.argNames.notNil) { func.envirFlop } { func } } } Penvir : Pattern { var <>envir, <>pattern, <>independent; *new { arg envir, pattern, independent=true; ^super.newCopyArgs(envir, pattern, independent) } storeArgs { ^[envir,pattern,independent] } embedInStream { arg inval; if(independent) { Event.new(8, nil, envir) } { envir } .use { pattern.embedInStream(inval) }; ^inval } } Ppatmod : Pattern { var <>pattern, <>func, <>repeats=1; *new { arg pattern, func, repeats; ^super.newCopyArgs(pattern, func, repeats) } embedInStream { arg inval; var localPat; localPat = pattern.value(inval).copy; repeats.do({ arg i; inval = localPat.embedInStream(inval); localPat = func.value(localPat, i); }); ^inval; } storeArgs { ^[pattern, func, repeats] } } Peventmod : Pattern { var <>func, <>event, <>repeats; *new { arg func, event, repeats=inf; ^super.newCopyArgs(func, event, repeats) } embedInStream { arg inval; var localEvent = event.copy ?? { Event.default }; repeats.value(inval).do { arg i; if(inval.isNil) { ^nil.yield }; localEvent.use { func.valueEnvir(inval, i) }; inval = localEvent.yield; }; ^inval } storeArgs { ^[func, event, repeats] } } SuperCollider-Source/SCClassLibrary/Common/Streams/Pproto.sc000644 000765 000024 00000004700 12756534417 025174 0ustar00crucialstaff000000 000000 Pfpar : ListPattern { initStreams { arg priorityQ; list.do({ arg pattern, i; priorityQ.put(0.0, pattern.asStream); }); } embedInStream { arg inval; var assn; var priorityQ = PriorityQueue.new; var cleanup = EventStreamCleanup.new; repeats.value(inval).do({ arg j; var outval, stream, nexttime, now = 0.0; this.initStreams(priorityQ); // if first event not at time zero if (priorityQ.notEmpty and: { (nexttime = priorityQ.topPriority) > 0.0 }, { inval = Event.silent(nexttime, inval).yield; now = nexttime; }); while({ priorityQ.notEmpty },{ stream = priorityQ.pop; outval = stream.next(inval).asEvent; if (outval.isNil, { priorityQ.clear; ^cleanup.exit(inval); },{ cleanup.update(outval); // requeue stream priorityQ.put(now + outval.delta, stream); nexttime = priorityQ.topPriority; outval.put(\delta, nexttime - now); inval = outval.yield; // inval ?? { this.purgeQueue(priorityQ); ^nil.yield }; now = nexttime; }); }); }); ^inval; } } Pproto : Pattern { var <>makeFunction, <>pattern, <>cleanupFunc; *new { | makeFunction, pattern, cleanupFunc| ^super.newCopyArgs( makeFunction, pattern, cleanupFunc) } storeArgs { ^[makeFunction,pattern,cleanupFunc] } embedInStream { | event | var stream, ev, evType; var cleanup, cleanupList, eventCleanupFunc; var proto; // temporary proto event used in allocation var makeRoutine; // routine wrapper for function that makes protoEvent var protoEvent; // protoEvent created by function // Step 1: generate resources from function proto = ( delta: 0, // events occur simultaneously finish: { ev = currentEnvironment} // get copy of event object actually played ); protoEvent = (); makeRoutine = Routine({ protoEvent.make (makeFunction) }); while { (ev = makeRoutine.next(ev)).notNil; } { event = ev.proto_(proto).yield; ev.proto = nil; cleanupList = cleanupList.add(ev) }; cleanup = EventStreamCleanup.new; eventCleanupFunc = { | flag | cleanupList.do { | ev | EventTypesWithCleanup.cleanup(ev, flag) } }; cleanupFunc = eventCleanupFunc ?? { { | flag | eventCleanupFunc.value(proto, flag) } }; cleanup.addFunction(event, cleanupFunc); stream = Pfpar(pattern.asArray).asStream; loop { ev = event.copy.putAll(protoEvent); ev = stream.next(ev) ?? { ^cleanup.exit(event) }; event = ev.yield; }; ^event } } SuperCollider-Source/SCClassLibrary/Common/Streams/Prewrite.sc000644 000765 000024 00000003140 12756534417 025507 0ustar00crucialstaff000000 000000 Prewrite : FilterPattern { var <>dict, <>levels; *new { arg pattern, dict, levels=1; ^super.new(pattern).dict_(dict).levels_(levels) } storeArgs { ^[ pattern, dict, levels ] } rewriteList { arg list, inval, level; var newlist; if (level == 0, { // if at bottom level, then embed all items in the stream if (list.isSequenceableCollection, { // isKindOf is necessary because Integer.do would do the wrong thing.. list.do({ arg item; inval = item.embedInStream(inval); }); },{ inval = list.embedInStream(inval); }); },{ if (list.isSequenceableCollection, { // isKindOf is necessary because Integer.do would do the wrong thing.. list.do({ arg item; // lookup item in rewrite dictionary newlist = dict.at(item); // found an entry ? if (newlist.notNil, { // do another level of rewriting inval = this.rewriteList( newlist, inval, level - 1 ); },{ // has no dictionary entry, so embed in stream inval = item.embedInStream(inval); }); }); },{ // lookup item in rewrite dictionary newlist = dict.at(list); // found an entry ? if (newlist.notNil, { // do another level of rewriting inval = this.rewriteList( newlist, inval, level - 1 ); },{ // has no dictionary entry, so embed in stream inval = list.embedInStream(inval); }); }); }); ^inval; } embedInStream { arg inval; var outval; var stream; stream = pattern.asStream; while({ outval = stream.next(inval); outval.notNil; },{ inval = this.rewriteList(outval, inval, levels); }); ^inval } } SuperCollider-Source/SCClassLibrary/Common/Streams/Pseed.sc000644 000765 000024 00000001076 12756534417 024754 0ustar00crucialstaff000000 000000 // allows to reproduce enclosed randomized pattern // by setting the random seed of the resulting routine Pseed : FilterPattern { var <>randSeed; *new { arg randSeed, pattern; ^super.new(pattern).randSeed_(randSeed) } storeArgs { ^[randSeed,pattern] } embedInStream { arg inval; var seedStream; var seed, thread; seedStream = randSeed.asStream; while { seed = seedStream.next(inval); seed.notNil }{ thread = Routine { |inval| pattern.embedInStream(inval) }; thread.randSeed = seed; inval = thread.embedInStream(inval); }; ^inval } } SuperCollider-Source/SCClassLibrary/Common/Streams/Pspawner.sc000644 000765 000024 00000006620 12756534417 025513 0ustar00crucialstaff000000 000000 Spawner : Pattern { var <>genStream; var <>priorityQ; var <>now; var <>event; *new { | func, stackSize=64 | ^super.new.init( func, stackSize) } suspend { | stream | priorityQ.removeValue(stream); } suspendAll { priorityQ.clear } init { | func, stackSize | priorityQ = PriorityQueue.new; genStream = Routine({func.value(this) }, stackSize); now = 0; priorityQ.put(now, genStream); } par { | pattern, delta = 0 | var stream = pattern.asStream; priorityQ.put(now + delta, stream); ^stream; } seq { | pat | pat.embedInStream(event) } wait { | dur | Event.silent(dur, event).yield } embedInStream { | inevent| var outevent, stream, nexttime, cleanup; event = inevent; // gives genStream access to the event cleanup = EventStreamCleanup.new; while({ priorityQ.notEmpty },{ stream = priorityQ.pop; outevent = stream.next(event).asEvent; if (outevent.isNil, { nexttime = priorityQ.topPriority; if (nexttime.notNil, { // that child stream ended, so rest until next one outevent = Event.silent(nexttime - now, event); cleanup.update(outevent); event = outevent.yield; now = nexttime; },{ priorityQ.clear; ^cleanup.exit(event); }); },{ cleanup.update(outevent); // requeue stream priorityQ.put(now + outevent.delta, stream); nexttime = priorityQ.topPriority; outevent.put(\delta, nexttime - now); event = outevent.yield; now = nexttime; }); }); ^event; } } Pspawner : Prout { asStream { ^Routine({ | inval | this.embedInStream(inval) }) } embedInStream { | inevent | ^Spawner(routineFunc).embedInStream(inevent) } } Pspawn : FilterPattern { var <>spawnProtoEvent; *new { |pattern, spawnProtoEvent| ^super.new(pattern) .spawnProtoEvent_(spawnProtoEvent ?? { Event.default }); } embedInStream { |inevent| ^Spawner({ |sp| var event, stream = pattern.asStream, child; while { (event = stream.next(spawnProtoEvent.copy.put(\spawner, sp))).notNil } { case { event.method == \wait } { event.spawner.wait(event.delta) } { #[seq, par].includes(event.method) } { child = event[\pattern]; if(child.isKindOf(Symbol)) { child = (event[\dict] ? Pdef).at(child); }; event.spawner.perform(event.method, child.value(event)); if(event.delta > 0) { event.spawner.wait(event.delta) } } // suspend requires access to the specific stream // don't know how to get it... maybe implement later { event.method == \suspendAll } { event.spawner.suspendAll } { "Unrecognized method % in spawner event." .format(event.method.asCompileString).warn; } }; }).embedInStream(inevent) } } /* ( Pseq([ Pspawner({ | sp | sp.postln; sp.par(Pbind(*[degree: Pwhite(0,12), dur: 0.1, db: -30]) ); sp.seq(Pbind(*[degree: Pseq((0..4).mirror.mirror, 1) + [-3, 0,2], ctranspose: -12, dur: 0.2 ]) ); "hi".postln; sp.wait(1); "bye".postln; sp.suspendAll; }), Pspawner({ | sp | sp.postln; sp.par(Pbind(*[degree: Pwhite(0,12), dur: 0.2, ctranspose: -12]) ); "hi".postln; sp.wait(4); "bye".postln; sp.suspendAll }), ]).play; ) a = Spawner({ |sp | 100.do{ sp.wait(1) } }); a.play; b = a.par(Pbind(*[degree: Pwhite(0, 10), dur: 0.2])); a.suspend(b) a.par(b) ( Pspawner({ | sp | 5.do { sp.par(Pbind(*[ octave: (5.rand + 3).postln, degree: Pwhite(0,12), dur: 0.1, db: -30 ]) ); sp.wait(1); sp.clear; } }).play ) */ SuperCollider-Source/SCClassLibrary/Common/Streams/Quant.sc000644 000765 000024 00000001770 12756534417 025005 0ustar00crucialstaff000000 000000 // This class is used to encapsulate quantization issues associated with EventStreamPlayer and TempoClock // quant and phase determine the starting time of something scheduled by a TempoClock // timingOffset is an additional timing factor that allows an EventStream to compute "ahead of time" enough to allow // negative lags for strumming a chord, etc Quant { classvar default; var <>quant, <>phase, <>timingOffset; *default { ^default ?? { Quant.new } } *default_ { |quant| default = quant.asQuant } *new { |quant = 0, phase, timingOffset| ^super.newCopyArgs(quant, phase, timingOffset) } nextTimeOnGrid { | clock | ^clock.nextTimeOnGrid(quant, (phase ? 0) - (timingOffset ? 0)); } asQuant { ^this.copy } printOn { |stream| stream << "Quant(" << quant; if(phase.notNil) { stream << ", " << phase }; if(timingOffset.notNil) { stream << ", "; if(phase.isNil) { stream << "nil, "; }; stream << timingOffset }; stream << ")" } storeArgs { ^[quant, phase, timingOffset] } } SuperCollider-Source/SCClassLibrary/Common/Streams/RandomDistPatterns.sc000644 000765 000024 00000006761 12756534417 027507 0ustar00crucialstaff000000 000000 Plprand : Pwhite { embedInStream { |inval| var localLength = length.value(inval), pat = Pwhite(lo, hi, localLength); ^min(pat, pat).embedInStream(inval) } } Phprand : Pwhite { embedInStream { |inval| var localLength = length.value(inval), pat = Pwhite(lo, hi, localLength); ^max(pat, pat).embedInStream(inval) } } Pmeanrand : Pwhite { embedInStream { |inval| var localLength = length.value(inval), pat = Pwhite(lo, hi, localLength); ^((pat + pat) * 0.5).embedInStream(inval) } } Pbeta : Pattern { var <>lo, <>hi, <>prob1, <>prob2, <>length; *new{ arg lo = 0.0, hi = 1.0, prob1 = 1, prob2 = 1, length = inf; ^super.newCopyArgs(lo, hi, prob1, prob2, length); } storeArgs { ^[lo, hi, prob1, prob2, length] } embedInStream { arg inval; var loStr = lo.asStream; var hiStr = hi.asStream; var prob1Str = prob1.asStream; var prob2Str = prob2.asStream; var loVal, hiVal; length.value(inval).do({ var sum = 2, temp, rprob1, rprob2; rprob1 = prob1Str.next(inval); rprob2 = prob2Str.next(inval); if(rprob1.isNil or: { rprob2.isNil }) { ^inval }; rprob1 = rprob1.reciprocal; rprob2 = rprob2.reciprocal; loVal = loStr.next(inval); hiVal = hiStr.next(inval); if(loVal.isNil or: { hiVal.isNil }) { ^inval }; while ({ temp = 1.0.rand ** rprob1; sum = temp + (1.0.rand ** rprob2); sum > 1; }); inval = (((temp/sum) * (hiVal - loVal)) + loVal).yield; }); ^inval; } } Pcauchy : Pattern { var <>mean, <>spread, <>length; *new{arg mean = 0.0, spread = 1.0, length = inf; ^super.newCopyArgs(mean, spread, length); } storeArgs{ ^[mean, spread, length] } embedInStream { arg inval; var meanStr = mean.asStream; var spreadStr = spread.asStream; var meanVal, spreadVal; length.value(inval).do({ var ran = 0.5; meanVal = meanStr.next(inval); spreadVal = spreadStr.next(inval); if(meanVal.isNil or: { spreadVal.isNil }) { ^inval }; while({ ran = 1.0.rand; ran == 0.5 }); inval = ((spreadVal * (ran * pi).tan) + meanVal).yield; }); ^inval; } } Pgauss : Pattern { var <>mean, <>dev, <>length; *new{ arg mean = 0.0, dev = 1, length = inf; ^super.newCopyArgs(mean, dev, length); } storeArgs{ ^[mean, dev, length] } embedInStream{arg inval; var meanStr = mean.asStream; var devStr = dev.asStream; var devVal, meanVal; length.value(inval).do({ devVal = devStr.next(inval); meanVal = meanStr.next(inval); if(meanVal.isNil or: { devVal.isNil }) { ^inval }; inval = ((((-2*log(1.0.rand)).sqrt * sin(2pi.rand)) * devVal) + meanVal).yield; }); ^inval; } } Ppoisson : Pattern { var <>mean, <>length; *new{arg mean = 1, length = inf; ^super.newCopyArgs(mean, length); } storeArgs{ ^[mean, length] } embedInStream{ arg inval; var meanStr = mean.asStream; length.value(inval).do({ var inc, test, temp, meanVal = meanStr.next(inval); if(meanVal.isNil) { ^inval }; inc = 0; test = 1.0.rand; temp = exp(meanVal.neg); while({ test > temp; }, { inc = inc + 1; test = test * 1.0.rand; }); inval = inc.yield; }); ^inval; } } Pexprand : Pwhite { *new { arg lo=0.0001, hi=1.0, length=inf; ^super.newCopyArgs(lo, hi, length) } storeArgs { ^[ lo, hi, length ] } embedInStream { arg inval; var loStr = lo.asStream; var hiStr = hi.asStream; var hiVal, loVal; length.value(inval).do({ hiVal = hiStr.next(inval); loVal = loStr.next(inval); if(hiVal.isNil or: { loVal.isNil }) { ^inval }; inval = exprand(loVal, hiVal).yield; }); ^inval; } } SuperCollider-Source/SCClassLibrary/Common/Streams/Rest.sc000644 000765 000024 00000002372 12756534417 024631 0ustar00crucialstaff000000 000000 Rest { var <>dur = 1; *new { |dur(1)| ^super.newCopyArgs(dur) } // for use by Pfunc and Pfuncn *processRest { |inval| inval.put(\isRest, true); ^1 } processRest { |inval| inval.put(\isRest, true); ^dur.value(inval) } // for use e.g. in ListPatterns *embedInStream { |inval| ^this.processRest(inval).yield; // the actual return value is the next inval } embedInStream { |inval| ^this.processRest(inval).yield; } *asStream { ^Routine({ |inval| loop { inval = this.embedInStream(inval); } }) } asStream { ^Routine({ |inval| loop { inval = this.embedInStream(inval); } }) } value { ^dur } storeOn { |stream| stream << "Rest(" << dur << ")" } } + Object { processRest { ^this } } + Collection { processRest { |inval| this.do(_.processRest(inval)) } } + SimpleNumber { // Some patterns call .delta on the eventstream's yield value // since a SimpleNumber is a valid rest, it must answer 'delta' with itself delta {} // but Ppar and several other patterns do "put(\delta, ...)" // so they need to convert the simplenumber into a real rest event asEvent { ^Event.silent(this) } } + Event { asEvent {} } + Nil { // Ppar etc. need stream.next(event).asEvent to be nil when the stream ends asEvent {} } SuperCollider-Source/SCClassLibrary/Common/Streams/Stream.sc000644 000765 000024 00000025414 12766171707 025151 0ustar00crucialstaff000000 000000 Stream : AbstractFunction { // 'reset' is defined in class Object to do nothing. // reading parent { ^nil } next { ^this.subclassResponsibility(thisMethod) } iter { ^this } streamArg { ^this } value { arg inval; ^this.next(inval) } valueArray { ^this.next } all { arg inval; // don't do this on infinite streams. var array; this.do({|item| array = array.add(item) }, inval); ^array } // writing put { arg item; ^this.subclassResponsibility(thisMethod) } putN { arg n, item; n.do({ this.put(item); }); } putAll { arg aCollection; aCollection.do {|item| this.put(item); }; } do { arg function, inval; var item, i=0; while { item = this.next(inval); item.notNil }{ function.value(item, i); i = i + 1; }; } subSample {| offset= 0, skipSize = 0| ^Routine { offset.do{ this.next }; loop { this.next.yield; skipSize.do { this.next } } } } generate { arg function, item; var i=0; while { item = this.next(item); item.notNil }{ function.value(item, i); i = i + 1; }; } // combination collect { arg argCollectFunc; // modify a stream var nextFunc = { arg inval; var nextval = this.next(inval); if ( nextval.notNil, { argCollectFunc.value(nextval, inval) }) }; var resetFunc = { this.reset }; ^FuncStream.new(nextFunc, resetFunc); } reject { arg function; // reject elements from a stream var nextFunc = { arg inval; var nextval = this.next(inval); while { nextval.notNil and: { function.value(nextval, inval) } }{ nextval = this.next(inval); }; nextval }; var resetFunc = { this.reset }; ^FuncStream.new(nextFunc, resetFunc); } select { arg function; // select elements from a stream var nextFunc = { arg inval; var nextval = this.next(inval); while { nextval.notNil and: { function.value(nextval, inval).not } }{ nextval = this.next(inval); }; nextval }; var resetFunc = { this.reset }; ^FuncStream.new(nextFunc, resetFunc); } dot { arg function, stream; // combine item by item with another stream ^FuncStream.new( { arg inval; var x = this.next(inval); var y = stream.next(inval); if ( x.notNil and: { y.notNil }, { function.value(x, y, inval) }); }, { this.reset; stream.reset; } ); } interlace { arg function, stream; // interlace with another stream var nextx = this.next; var nexty = stream.next; ^FuncStream.new({ |inval| var val; if ( nextx.isNil ) { if ( nexty.isNil) {nil}{ val = nexty; nexty = stream.next(inval); val }; }{ if ( nexty.isNil or: { function.value(nextx, nexty, inval) }, { val = nextx; nextx = this.next(inval); val }, { val = nexty; nexty = stream.next(inval); val } ); }; }, { this.reset; stream.reset; nextx = this.next; nexty = stream.next; }); } ++ { arg stream; ^this.appendStream(stream) } appendStream { arg stream; var reset = false; ^Routine({ arg inval; if (reset) { this.reset; stream.reset; }; reset = true; inval = this.embedInStream(inval); stream.embedInStream(inval); }); } collate { arg stream; // ascending order merge of two streams ^this.interlace({|x y| x < y }, stream); } <> { arg obj; ^Pchain(this, obj).asStream } // function composition composeUnaryOp { arg argSelector; ^UnaryOpStream.new(argSelector, this) } composeBinaryOp { arg argSelector, argStream, adverb; if(adverb.isNil) { ^BinaryOpStream.new(argSelector, this, argStream.asStream) } { if (adverb == 'x') { ^BinaryOpXStream.new(argSelector, this, argStream.asStream); }; }; ^nil } reverseComposeBinaryOp { arg argSelector, argStream, adverb; if(adverb.isNil) { ^BinaryOpStream.new(argSelector, argStream.asStream, this) } { if (adverb == 'x') { ^BinaryOpXStream.new(argSelector, argStream.asStream, this); }; }; ^nil } composeNAryOp { arg argSelector, anArgList; ^NAryOpStream.new(argSelector, this, anArgList.collect(_.asStream)); } embedInStream { arg inval; var outval; while { outval = this.value(inval); outval.notNil }{ inval = outval.yield; }; ^inval } asEventStreamPlayer { arg protoEvent; ^EventStreamPlayer(this, protoEvent); } play { arg clock, quant; clock = clock ? TempoClock.default; clock.play(this, quant.asQuant); } trace { arg key, printStream, prefix=""; ^Ptrace(this, key, printStream, prefix).asStream } // constrain { arg sum, tolerance=0.001; // ^Pconst(sum, tolerance).asStream // } repeat { arg repeats = inf; ^r { arg inval; repeats.value(inval).do { inval = this.reset.embedInStream(inval) } } } } OneShotStream : Stream { var value, once = true; *new { arg value; ^super.newCopyArgs(value) } next { ^if (once) {once = false; value} } reset { once = true } storeArgs { ^[value] } } EmbedOnce : Stream { var nextFunc; // Func is evaluated for each next state var <>resetFunc; // Func is evaluated on reset var <>envir; *new { |nextFunc, resetFunc| ^super.new.nextFunc_(nextFunc).resetFunc_(resetFunc).envir_(currentEnvironment) } next { arg inval; ^envir.use({ nextFunc.value(inval).processRest(inval) }) } reset { ^envir.use({ resetFunc.value }) } storeArgs { ^[nextFunc, resetFunc] } } StreamClutch : Stream { var <>stream, <>connected, value, >reset=true; *new { arg pattern, connected = true; ^super.newCopyArgs(pattern.asStream, connected) } next { arg inval; if(reset) { reset = false; value = stream.next(inval) }; if(connected.value(inval)) { value = stream.next(inval); }; ^value } lastValue { ^value } reset { stream.reset; reset = true } step { arg inval; value = stream.next(inval ? Event.default) } } CleanupStream : Stream { var cleanup; *new { arg stream, cleanup; ^super.newCopyArgs(stream, cleanup) } next { arg inval; var outval = stream.next(inval); if (outval.isNil) { cleanup.value(this, inval); cleanup = nil; } ^outval } reset { stream.reset } } // PauseStream is a stream wrapper that can be started and stopped. PauseStream : Stream { var streamHasEnded=false; var isWaiting = false, era=0; *new { arg argStream, clock; ^super.newCopyArgs(nil, argStream, clock ? TempoClock.default) } isPlaying { ^stream.notNil } play { arg argClock, doReset = (false), quant; if (stream.notNil, { "already playing".postln; ^this }); if (doReset, { this.reset }); clock = argClock ? clock ? TempoClock.default; streamHasEnded = false; this.refresh; //stream = originalStream; stream.clock = clock; isWaiting = true; // make sure that accidental play/stop/play sequences // don't cause memory leaks era = CmdPeriod.era; clock.play({ if(isWaiting and: { nextBeat.isNil }) { clock.sched(0, this); isWaiting = false; this.changed(\playing) }; nil }, quant.asQuant); this.changed(\userPlayed); ^this } reset { originalStream.reset } stop { this.prStop; this.changed(\userStopped); } prStop { stream = nil; isWaiting = false; } removedFromScheduler { nextBeat = nil; this.prStop; this.changed(\stopped); } streamError { this.removedFromScheduler; streamHasEnded = true; } wasStopped { ^streamHasEnded.not and: { stream.isNil } // stopped by clock or stop-message or: { CmdPeriod.era != era } // stopped by cmd-period, after stream has ended } canPause { ^this.streamHasEnded.not } pause { this.stop; } resume { arg argClock, quant; ^this.play(clock ? argClock, false, quant) } refresh { stream = originalStream.threadPlayer_(this) } start { arg argClock, quant; ^this.play(argClock, true, quant) } stream_ { arg argStream; originalStream.threadPlayer_(nil); // not owned any more originalStream = argStream.threadPlayer_(this); if (stream.notNil, { stream = argStream; streamHasEnded = argStream.isNil; }); } next { arg inval; var nextTime = stream.next(inval); if (nextTime.isNil) { streamHasEnded = stream.notNil; this.removedFromScheduler; } { nextBeat = inval + nextTime }; // inval is current logical beat ^nextTime } awake { arg beats, seconds, inClock; stream.beats = beats; ^this.next(beats) } threadPlayer { ^this } } // Task is a PauseStream for wrapping a Routine Task : PauseStream { *new { arg func, clock; ^super.new(Routine(func), clock) } storeArgs { ^originalStream.storeArgs ++ if(clock != TempoClock.default) { clock } } } //////////////////////////////////////////////////////////////////////// EventStreamPlayer : PauseStream { var <>event, <>muteCount = 0, <>cleanup, <>routine; *new { arg stream, event; ^super.new(stream).event_(event ? Event.default).init; } init { cleanup = EventStreamCleanup.new; routine = Routine{ | inTime | loop { inTime = this.prNext(inTime).yield } }; } // freeNodes is passed as false from //TempoClock:cmdPeriod removedFromScheduler { | freeNodes = true | nextBeat = nil; cleanup.terminate(freeNodes); this.prStop; this.changed(\stopped); } prStop { stream = nextBeat = nil; isWaiting = false; } stop { cleanup.terminate; this.prStop; this.changed(\userStopped); } reset { routine.reset; super.reset } mute { muteCount = muteCount + 1; } unmute { muteCount = muteCount - 1; } canPause { ^this.streamHasEnded.not and: { cleanup.functions.isEmpty } } next { | inTime | ^routine.next(inTime) } prNext { arg inTime; var nextTime; var outEvent = stream.next(event.copy); if (outEvent.isNil) { streamHasEnded = stream.notNil; cleanup.clear; this.removedFromScheduler; ^nil }{ nextTime = outEvent.playAndDelta(cleanup, muteCount > 0); if (nextTime.isNil) { this.removedFromScheduler; ^nil }; nextBeat = inTime + nextTime; // inval is current logical beat ^nextTime }; } asEventStreamPlayer { ^this } play { arg argClock, doReset = (false), quant; if (stream.notNil, { "already playing".postln; ^this }); if (doReset, { this.reset }); clock = argClock ? clock ? TempoClock.default; streamHasEnded = false; stream = originalStream; stream.clock = clock; isWaiting = true; // make sure that accidental play/stop/play sequences // don't cause memory leaks era = CmdPeriod.era; quant = quant.asQuant; event = event.synchWithQuant(quant); clock.play({ if(isWaiting and: { nextBeat.isNil }) { clock.sched(0, this ); isWaiting = false; this.changed(\playing) }; nil }, quant); this.changed(\userPlayed); ^this } } SuperCollider-Source/SCClassLibrary/Common/Streams/TabFileReader.sc000644 000765 000024 00000003610 12756534417 026341 0ustar00crucialstaff000000 000000 FileReader : Stream { // a class to read text files automatically classvar 0 }) { record = record.add(string); string = String.new; } } { if (c == $\n or: { c == $\r }) { record = record.add(string); string = String.new; if (skipEmptyLines.not or: { (record != [ "" ]) }) { ^record }; record = nil; }{ string = string.add(c); } } }; if (string.notEmpty) { ^record.add(string) }; ^record; } read { ^this.all } *read { | path, skipEmptyLines=false, skipBlanks=false, func, delimiter, startRow = 0, skipSize = 0 | var fr, table; fr = this.new(path, skipEmptyLines, skipBlanks, delimiter) ?? { ^nil }; if (func.notNil) { table = fr.subSample(startRow, skipSize).collect(_.collect(func)).all; } { table = fr.subSample(startRow, skipSize).all; }; fr.close; ^table } *readInterpret { | path, skipEmptyLines=false, skipBlanks=false, delimiter, startRow = 0, skipSize = 0 | ^this.read(path, skipEmptyLines, skipBlanks, _.interpret, delimiter, startRow, skipSize ) } } TabFileReader : FileReader { classvar list, <>durs, <>repeats; *new { arg levels, durs = 1, repeats = 1; ^super.newCopyArgs(levels, durs, repeats).init } init { if (list.isKindOf(Collection)) { list = Pseq(list); } } embedInStream { arg inval; var stream, val,dur; thisThread.endBeat = thisThread.endBeat ? thisThread.beats; // endBeat > beats only if Pfindur ended something early thisThread.endBeat = thisThread.endBeat min: thisThread.beats; repeats.value(inval).do { | i | stream = Ptuple([list, durs]).asStream; while ( { #val, dur = stream.next(inval) ?? { #[nil, nil] }; val.notNil; }, { thisThread.endBeat = thisThread.endBeat + dur; while( { thisThread.endBeat > thisThread.beats }, { inval = val.embedInStream(inval) } ) }); }; ^inval; } storeArgs { ^[list, durs, repeats] } } Pseg : Pstep { var <>curves; *new { arg levels, durs = 1, curves = \lin, repeats = 1 ; ^super.new(levels, durs, repeats).curves_(curves) } embedInStream { arg inval; var valStream, durStream, curveStream, startVal, val, dur, curve; var env; var startTime, curTime; repeats.value(inval).do { valStream = list.asStream; durStream = durs.asStream; curveStream = curves.asStream; val = valStream.next(inval) ?? {^inval}; thisThread.endBeat = thisThread.endBeat ? thisThread.beats min: thisThread.beats; while { startVal = val; val = valStream.next(inval); dur = durStream.next(inval); curve = curveStream.next(inval); val.notNil and: { dur.notNil and: { curve.notNil } } } { startTime = thisThread.endBeat; thisThread.endBeat = thisThread.endBeat + dur; if (startVal.isArray) { env = [startVal,val, dur, curve].flop.collect { | args | Env([args[0], args[1]], [args[2]], args[3]) }; while { thisThread.endBeat > curTime = thisThread.beats } { inval = yield(env.collect{ | e | e.at(curTime - startTime)}) } } { env = Env([startVal, val], [dur], curve); while { thisThread.endBeat > curTime = thisThread.beats } { inval = yield(env.at(curTime - startTime)) } } } } } storeArgs { ^[list, durs, curves, repeats] } } SuperCollider-Source/SCClassLibrary/Common/Quarks/Git.sc000644 000765 000024 00000005475 12756534417 024276 0ustar00crucialstaff000000 000000 Git { var <>localPath, >url, tag, sha, remoteLatest, tags; classvar gitIsInstalled; *isGit { |localPath| ^File.exists(localPath +/+ ".git") } *new { |localPath| ^super.new.localPath_(localPath) } clone { |url| this.git([ "clone", url, localPath.escapeChar($ ) ], false); this.url = url; } pull { this.git(["pull", "origin", "master"]) } checkout { |refspec| this.git(["checkout", refspec]) } fetch { tags = remoteLatest = nil; this.git(["fetch"]); } isDirty { ^this.git(["--no-pager diff HEAD --"]).size != 0 } url { ^url ?? { url = this.remote; } } remote { // detect origin of repo or nil // origin git://github.com/supercollider-quarks/MathLib (fetch) // origin git://github.com/supercollider-quarks/MathLib (push) // problem: if more than one remote then this will just detect the first // should favor 'origin' if more than one var out = this.git(["remote -v"]), match = out.findRegexp("^[a-zA-Z0-9]+\t([^ ]+) \\(fetch\\)"); if(match.size > 0, { ^match[1][1] }); ^nil } refspec { ^this.tag ?? { this.sha } } tag { // find what tag is currently checked out var out, match; ^tag ?? { out = this.git(["--no-pager log --pretty=format:'%d' --abbrev-commit --date=short -1"]); match = out.findRegexp("tag: ([^ ,\)]+)"); if(match.size > 0, { tag = "tags/" ++ match[1][1] }); tag } } sha { // find what hash is currently checked out ^sha ?? { sha = this.git(["rev-parse HEAD"]); } } remoteLatest { // find what the latest commit on the remote is ^remoteLatest ?? { remoteLatest = this.git(["rev-parse origin/master"]); } } tags { var raw; // all tags // only includes ones that have been fetched from remote ^tags ?? { if(thisProcess.platform.name !== 'windows', { raw = this.git(["for-each-ref --format='%(refname)' --sort=taggerdate refs/tags"]); }, { raw = this.git(["for-each-ref --format=%(refname) --sort=taggerdate refs/tags"]); }); tags = raw.split(Char.nl) .select({ |t| t.size != 0 }) .reverse() .collect({ |t| t.copyToEnd(10) }); } } shaForTag { |tag| var out = this.git(["rev-list", tag, "--max-count=1"]); ^out.copyFromStart(39) } git { |args, cd=true| var cmd, result=""; if(cd, { cmd = ["cd", localPath.escapeChar($ ), "&&", "git"]; },{ cmd = ["git"]; }); cmd = (cmd ++ args).join(" "); // this blocks the app thread Pipe.callSync(cmd, { |res| result = res; }, { Git.checkForGit(); }); ^result; } *checkForGit { var gitFind; if(gitIsInstalled.isNil, { if(thisProcess.platform.name !== 'windows', { gitFind = "which git"; }, { gitFind = "where git"; }); Pipe.callSync(gitFind, { gitIsInstalled = true; }, { arg error; "Quarks requires git to be installed".error; gitIsInstalled = false; }); }) } } SuperCollider-Source/SCClassLibrary/Common/Quarks/packages.sc000644 000765 000024 00000006434 12756534417 025325 0ustar00crucialstaff000000 000000 + Main { *packages { // a package is either a quark or a folder in SCClassLibrary or extensions folders // a class is in a 'package' determined by where its Class file is // all folders in class library: // Common // JITlib // crucial // your own // all folders in system extension // all folders in user extension // all quarks // any loose files are placed in a packaged calle SCClassLibrary or Extensions // possiblity for error: if you have loose files in user extensions and system extensions // they will both be placed in the same package: Extensions // [ name -> folderPath, name -> folderPath ... ] var platform; var packages, f; // cache packages = Library.at(Quarks, \packages); if(packages.notNil,{ ^packages }); platform = thisProcess.platform; f = { arg dir; var folders, packages, paths, files, slash = platform.pathSeparator; dir = dir.withTrailingSlash; paths = (dir ++ "*").pathMatch; folders = paths.reject({ |p| p.last != slash or: {p.basename == "quarks"} }); files = paths.select({ |p| p.last != slash }); packages = folders.collect({ |p| p.basename.asSymbol -> p }); if(files.notEmpty, { // collect any loose files in a package called dir packages = packages.add(dir.basename.asSymbol -> dir) }); packages }; packages = ( f.value(platform.classLibraryDir) ++ f.value(platform.systemExtensionDir) ++ Quarks.installed.collect({ |q| q.name.asSymbol -> q.localPath.withTrailingSlash }) ).sort({ |a, b| a.value.size > b.value.size }) // sort longer paths first ++ f.value(platform.userExtensionDir); Library.put(Quarks, \packages, packages); ^packages } } + Class { package { var path = this.filenameSymbol.asString; Main.packages.do({ |namepath| if(path.copyRange(0, namepath.value.size - 1) == namepath.value, { ^namepath.key }) }); Error("Discrepancy: Package not found for class !").throw; } } + Method { package { var path; path = this.filenameSymbol.asString; Main.packages.do({ |namepath| if(path.copyRange(0,namepath.value.size-1) == namepath.value,{ ^namepath.key }) }); Error("Discrepancy: Package not found for method !").throw; } } + Quark { definesClasses { var localPath = this.localPath; ^Class.allClasses.select({ |class| class.isMetaClass.not and: { class.filenameSymbol.asString.beginsWith(localPath) } }) } definesExtensionMethods { // all methods whose path is in this quark folder // where the class is not in this quark var localPath = this.localPath; ^Class.allClasses.collect({ |c| c.methods }).reject(_.isNil).flat .select({ |method| method.filenameSymbol.asString.beginsWith(localPath) and: { method.ownerClass.filenameSymbol.asString.beginsWith(localPath).not } }) } } + Quarks { *classesInPackage { |packageName| // the equivalent to Quark-definesClasses // but works for non-quarks like Quarks.classesInPackage("JITlib") var myPath, end, package; package = Main.packages.detect({ |pk| pk.key == packageName }); if(package.isNil,{ Error("Package not found:"+packageName).throw }); myPath = package.value; end = myPath.size - 1; ^Class.allClasses.select({ |class| class.isMetaClass.not and: { class.filenameSymbol.asString.copyRange(0, end) == myPath } }) } } SuperCollider-Source/SCClassLibrary/Common/Quarks/Quark.sc000644 000765 000024 00000015201 12766171707 024622 0ustar00crucialstaff000000 000000 Quark { var refspec, data, version if(dep.isKindOf(Association), { ^Quark.prMakeDep(dep.key.asString) }); // (3) [name, version, url] // url is svn repo and should be ignored now if(dep.isSequenceableCollection, { ^Quark.prMakeDep(dep.first) }); ("Cannot parse dependency:" + dep + (forQuark ? "")).error; ^nil } *prMakeDep { |name, refspec| // protected make dependency // if not found then posts error and returns nil var args = Quark.parseQuarkName(name, refspec); if(args.isNil, { ^nil }); ^super.new.init(*args) } *parseQuarkName { |name, refspec, url, localPath| // determine which quark the string 'name' refers to // name is one of: quarkname, url, localPath // returns: [name, url, refspec, localPath] var directoryEntry; if(name.contains("://"), { ^[PathName(name).fileNameWithoutExtension(), name, refspec, localPath] }); if(Quarks.isPath(name), { // if not provided then url can be determined later by the Quark ^[name.basename, url, refspec, name] }); // search Quarks folders (Quarks.additionalFolders ++ [Quarks.folder]).do({ |f| var lp = localPath ?? {f +/+ name}; if(File.existsCaseSensitive(lp), { ^[name, url, refspec, lp] }); }); // lookup url in directory directoryEntry = Quarks.findQuarkURL(name); if(directoryEntry.notNil, { directoryEntry = directoryEntry.split($@); ^[name, url ? directoryEntry[0], refspec ? directoryEntry[1], localPath] }); // not found ^nil } parseQuarkFile { var qfp = this.localPath +/+ name ++ ".quark", result; if(File.exists(qfp), { result = thisProcess.interpreter.compileFile(qfp).value; if(result.isNil, { ("Failed to parse %".format(qfp)).warn; }); }); ^result } printOn { arg stream; var v = this.version ? this.refspec; stream << "Quark: " << name; if(v.notNil,{ stream << "[" << v << "]" }); } help { var p = this.data['schelp']; // explicit pointer to a help file in quark data if(p.notNil, { ^HelpBrowser.openHelpFor(p); }); // old html help doc p = this.data['helpdoc']; if(p.notNil, { (this.localPath +/+ p).openOS; // ^HelpBrowser.goTo(URI.fromLocalPath(this.localPath +/+ p).asString); }); HelpBrowser.openBrowsePage("Quarks>" ++ name); } } SuperCollider-Source/SCClassLibrary/Common/Quarks/Quarks.sc000644 000765 000024 00000023741 12766171707 025015 0ustar00crucialstaff000000 000000 Quarks { classvar additionalFolders, directory, <>directoryUrl="https://github.com/supercollider-quarks/quarks.git", fetched=false, cache, regex, installedPaths; *install { |name, refspec| var path, quark; if(Quarks.isPath(name).not, { quark = Quark(name, refspec); this.installQuark(quark); ^quark }, { // local path / ~/ ./ path = this.asAbsolutePath(name); if(File.exists(path).not, { ("Quarks-install: path does not exist" + path).error; ^nil }); quark = Quark.fromLocalPath(path); this.installQuark(quark); ^quark }); } *uninstall { |name| // by quark name or local path this.installed.do { |q| if(q.name == name, { this.unlink(q.localPath) }); }; } *uninstallQuark { |quark| this.unlink(quark.localPath); this.clearCache; } *clear { this.installed.do({ |quark| LanguageConfig.removeIncludePath(quark.localPath); }); LanguageConfig.store(LanguageConfig.currentPath); this.clearCache; } *clearCache { cache = Dictionary.new; installedPaths = nil; } *load { |path, done| // install a list of quarks from a text file var file, line, dir,re, nameRe; var match, localPath, url, name, refspec, q; // localPath=url[@refspec] re = "^([^=]+)=?([^@]+)@?(.*)$"; // quarkname[@refspec] nameRe = "^([^@]+)@?(.*)$"; path = this.asAbsolutePath(path); dir = path.dirname; if(File.exists(path).not, { ^("Quark set file does not exist:" + path).error; }); this.clear(); Routine.run({ file = File.open(path, "r"); while({ line = file.getLine(); line.notNil }, { 0.05.wait; // resolve any paths relative to the quark file match = line.findRegexp(re); if(match.size > 0, { localPath = match[1][1]; name = localPath.basename; localPath = this.asAbsolutePath(localPath, dir); url = match[2][1]; refspec = match[3]; if(refspec.notNil, { refspec = refspec[1]; }); q = Quark(name, refspec, url, localPath); q.install(); }, { match = line.findRegexp(nameRe); if(match.size > 0, { name = match[1][1]; refspec = match[2]; if(refspec.notNil, { refspec = refspec[1]; }); if(Quarks.isPath(name), { this.install(this.asAbsolutePath(name, dir), refspec); }, { this.install(name, refspec); }); }, { "Unreadable line: %".format(line).error; }); }); }); this.clearCache(); done.value(); }, clock: AppClock); } *save { |path| // save currently installed quarks to a text file // localPath=url[@refspec] var file, dir, lines; path = this.asAbsolutePath(path); dir = path.dirname; lines = this.installed.collect({ |quark| var localPath, url="", refspec; localPath = this.asRelativePath(quark.localPath, dir); if(Git.isGit(quark.localPath), { url = quark.url; if(Git(quark.localPath).isDirty, { ("Working copy is dirty" + quark.localPath).warn; }, { refspec = quark.refspec; }); }); if(refspec.notNil, { "%=%@%".format(localPath, url, refspec) }, { "%=%".format(localPath, url) }); }); file = File.open(path, "w"); lines = lines.join(Char.nl); file.write(lines); file.close(); ^lines } *update { |name| // by quark name or by supplying a local path // resolving / ~/ ./ // is it a git var quark, localPath; if(name.isNil, { ("Missing required argument: quark name").throw; }); localPath = this.quarkNameAsLocalPath(name); if(Git.isGit(localPath), { Quark.fromLocalPath(localPath).update(); }, { ("Quark" + name + "was not installed using git, cannot update.").warn; }); } *installed { ^LanguageConfig.includePaths .collect(Quark.fromLocalPath(_)) } *installedPaths { ^installedPaths ?? { installedPaths = LanguageConfig.includePaths.collect({ |apath| apath.withoutTrailingSlash }); } } *isInstalled { |name| ^this.installedPaths.any({ |path| path.endsWith(name) }) } *pathIsInstalled { |path| ^this.installedPaths.includesEqual(path.withoutTrailingSlash) } *openFolder { this.folder.openOS; } *gui { ^QuarksGui.new } *installQuark { |quark| var deps, incompatible = { arg name; (quark.name + "reports an incompatibility with this SuperCollider version" + "or with other already installed quarks." ).inform; false }, prev = this.installed.detect({ |q| q.name == quark.name }); if(prev.notNil and: {prev.localPath != quark.localPath}, { ("A version of % is already installed at %".format(quark, prev.localPath)).error; ^false }); "Installing %".format(quark.name).inform; quark.checkout(); if(quark.isCompatible().not, { ^incompatible.value(quark.name); }); quark.dependencies.do { |dep| var ok = dep.install(); if(ok.not, { ("Failed to install" + quark.name).error; ^false }); }; this.link(quark.localPath); (quark.name + "installed").inform; this.clearCache(); ^true } *link { |path| path = path.withoutTrailingSlash; if(LanguageConfig.includePaths.includesEqual(path).not, { path.debug("Adding path"); LanguageConfig.addIncludePath(path); LanguageConfig.store(LanguageConfig.currentPath); installedPaths = installedPaths.add(path.withoutTrailingSlash); ^true }); ^false } *unlink { |path| path = path.withoutTrailingSlash; if(LanguageConfig.includePaths.includesEqual(path), { path.debug("Removing path"); LanguageConfig.removeIncludePath(path); LanguageConfig.store(LanguageConfig.currentPath); installedPaths.remove(path.withoutTrailingSlash); ^true }); ^false } *initClass { folder = Platform.userAppSupportDir +/+ "downloaded-quarks"; additionalFolders = additionalFolders ? []; if(File.exists(folder).not, { folder.mkdir(); }); this.clearCache; if(thisProcess.platform.name !== 'windows', { regex = ( isPath: "^[~\\.]?/", isAbsolutePath: "^/" ); }, { regex = ( isPath: "\\\\|/", isAbsolutePath: "^[A-Za-z]:\\\\", isURL: "://" ); }); } *at { |name| var q; ^cache[name] ?? { q = Quark(name); cache.put(name, q); q } } *findQuarkURL { |name| ^this.directory[name] } *directory { // just urls if(directory.isNil, { this.fetchDirectory(false); }); ^directory } *addFolder { |path| // in addition to the default downloaded-quarks // add folders that contain quarks to offer on the menu for installation // these may be private quarks, cloned working copies or folders where you // have manually downloaded quarks additionalFolders = additionalFolders.add(path.standardizePath); } *all { // all known quarks var all = Dictionary.new, f; // those in index this.directory.keysValuesDo({ |name, quarkURL| var q = Quark.fromDirectoryEntry(name, quarkURL); all[q.localPath] = q; }); f = { |path| // \directory or \not_found, but not a file var downloadedQuarks = "downloaded-quarks" +/+ "quarks"; if(File.type(path) !== \regular, { path = path.withoutTrailingSlash; // ignore the directory if(path.endsWith(downloadedQuarks).not, { all[path] = Quark.fromLocalPath(path); }); }); }; (Quarks.folder +/+ "*").pathMatch.do(f); additionalFolders.do({ |folder| (folder +/+ "*").pathMatch.do(f); }); LanguageConfig.includePaths.do(f); ^all.atAll(all.order) } *fetchDirectory { |force=true| // will only pull every 15 minutes unless force is true var dirTxtPath = Quarks.folder +/+ "quarks" +/+ "directory.txt", fetch = true; if(File.exists(dirTxtPath), { fetch = force // or: fetched.not }); { if(fetch, { this.prFetchDirectory }); this.prReadDirectoryFile(dirTxtPath); }.try({ arg err; ("Failed to read quarks directory listing: % %".format(if(fetch, directoryUrl, dirTxtPath), err)).error; if(fetch, { // if fetch failed, try read from cache if(File.exists(dirTxtPath), { this.prReadDirectoryFile(dirTxtPath); }); }, { // if read from cache failed, try fetching if(fetch, { this.prFetchDirectory }); this.prReadDirectoryFile(dirTxtPath); }); }); } *checkForUpdates { |done| Routine.run({ this.all.do { arg quark; if(quark.isGit, { quark.checkForUpdates(); }); 0.05.wait; }; done.value(); }); } *prReadDirectoryFile { |dirTxtPath| var file; directory = Dictionary.new; file = File.open(dirTxtPath, "r"); { var line, kv; while({ line = file.getLine(); line.notNil; }, { kv = line.split($=); directory[kv[0]] = kv[1]; }); }.protect({ file.close; }); } *prFetchDirectory { // clone or pull // unless existing non-git copy exists var git, localPath; if(fetched, { ^this }); ("Fetching" + directoryUrl).debug; localPath = Quarks.folder +/+ "quarks"; git = Git(localPath); if(Git.isGit(localPath), { git.pull }, { // check for manually downloaded copy // that exists but is not a git repo if(File.exists(localPath +/+ "directory.txt").not, { git.clone(directoryUrl) }) }); fetched = true; } *quarkNameAsLocalPath { |name| ^if(this.isPath(name), { this.asAbsolutePath(name) }, { Quark(name).localPath }); } *isPath { |string| if(thisProcess.platform.name !== 'windows', { ^string.findRegexp(regex.isPath).size != 0 }, { ^(string.findRegexp(regex.isPath).size != 0).and(string.findRegexp(regex.isURL).size == 0) }); } *asAbsolutePath { |path, relativeTo| ^if(path.findRegexp(regex.isAbsolutePath).size != 0, { path }, { if(path.at(0) == $~, { ^path.standardizePath }); // scroot is the cwd at startup if(path.beginsWith("." ++ Platform.pathSeparator), { ^(relativeTo ?? {PathName.scroot}) +/+ path.copyToEnd(2) }); (relativeTo ?? {PathName.scroot}) +/+ path }) } *asRelativePath { |path, relativeToDir| var d; if(path.beginsWith(relativeToDir), { ^"." ++ path.copyToEnd(relativeToDir.size) }); d = Platform.userHomeDir; // ~/path if in home if(path.beginsWith(d), { ^"~" ++ path.copyToEnd(d.size) }); ^path } // quarks fetch all available quark specs // directory.json } SuperCollider-Source/SCClassLibrary/Common/Quarks/QuarksGui.sc000644 000765 000024 00000036235 12756534417 025464 0ustar00crucialstaff000000 000000 QuarksGui { var model, quarks, window, treeView, quarkRows, palette, lblMsg, btnRecompile, detailView, 64) { path = "..." + path.keep(-64) }; this.pushRow("Local path", makeBtn.value("Open Folder:" + path, { this.openLocalPath; })); }); if(isInstalled and: { File.exists(model.localPath).not }, { this.pushRow("ERROR", model.localPath + "does not exist"); }); dependencies = model.dependencies; if(dependencies.notEmpty) { this.pushRow("Dependencies", dependencies.collect(_.asString).join(Char.nl)); }; if(isInstalled or: { isDownloaded and: {model.data['helpdoc'].isString} }, { this.pushRow("Help", makeBtn.value("Open help", { model.help })); }); if(isDownloaded, { if(isInstalled, { this.pushRow("Classes", makeBtn.value("Show classes", { this.showClasses }) ); this.pushRow("Extensions", makeBtn.value("Show extension methods", { this.showExtensionMethods }) ); }); }, { if(model.url.notNil, { this.pushRow("", makeBtn.value("Fetch", { model.checkout(); quarksGui.update(); this.update(); })); }); }); model.data.keysValuesDo({ |k, v| if(#[\name, \summary, \url, \path, \dependencies, \version].includes(k).not) { this.pushRow(k.asString, v.value().asString); } }); // versions if(isDownloaded and: {model.git.notNil}, { this.pushRow("Versions", this.makeVersionTree()); }); view.visible = true; }, { view.visible = false; }); } pushRow { |caption, obj| if(obj.isString, { details.addItem([caption, obj]); }, { details.addItem([caption, nil]).setView(1, obj); }); } model_ { |quark| model = quark; this.update; } visible_ { |bool| view.visible = bool; } openWebpage { var url = model.data['url']; if(url.notNil, { openOS(url); }); } openGithub { var url = model.url; if(url.notNil, { if(url.beginsWith("git:"), { url = "https:" ++ url.copyToEnd(4) }); openOS(url); }); } openLocalPath { model.localPath.openOS; } showClasses { var cls = model.definesClasses; var tree, item, buts = [ Button().states_([["Browse"]]).action_({ cls[item.index].browse; }), Button().states_([["Help"]]).action_({ cls[item.index].help; }), Button().states_([["Open File"]]).action_({ cls[item.index].openCodeFile; }) ]; buts.do(_.enabled_(false)); Window("% Classes".format(model.name)).layout_( VLayout( tree = TreeView() .setProperty(\rootIsDecorated, false) .columns_(["Classes"]) .onItemChanged_({|v| item = v.currentItem}), HLayout(*buts) ) ).front; if(cls.size > 0) { cls.do {|c| tree.addItem([c.name.asString])}; tree.itemPressedAction = { buts.do(_.enabled_(true)) } } { tree.addItem(["No classes"]); }; tree.invokeMethod(\resizeColumnToContents, 0); } showExtensionMethods { var mets = model.definesExtensionMethods; var tree, item, buts = [ Button().states_([["Browse"]]).action_({ mets[item.index].ownerClass.browse; }), Button().states_([["Help"]]).action_({ mets[item.index].help; }), Button().states_([["Source"]]).action_({ mets[item.index].openCodeFile; }) ]; buts.do(_.enabled_(false)); Window("% Extension Methods".format(model.name)).layout_( VLayout( tree = TreeView() .setProperty(\rootIsDecorated, false) .columns_(["Class", "Method"]) .onItemChanged_({|v| item = v.currentItem }), HLayout(*buts) ) ).front; if(mets.size > 0) { mets.collect { |m| var x = m.ownerClass.name, it = if(x.isMetaClassName, {[x.asString[5..], "*" ++ m.name]}, {[x.asString, "-" ++ m.name]}); tree.addItem(it); }; tree.itemPressedAction = { buts.do(_.enabled_(true)) } } { tree.addItem([nil,"No extension methods"]); }; tree.invokeMethod(\resizeColumnToContents, 0); tree.invokeMethod(\resizeColumnToContents, 1); } makeVersionTree { var versions, tags, remoteLatest, currentRefspec, currentSha, isDirty, tree; versions = List.new; tags = model.tags; // add LATEST iff remoteLatest != sha of most recent tag remoteLatest = model.git.remoteLatest; if(tags.size == 0 or: { remoteLatest != model.git.shaForTag(tags.first); }, { versions.add([remoteLatest, "LATEST"]); }); // working copy currentRefspec = model.refspec; if(currentRefspec.size != 40, { if(currentRefspec.beginsWith("tags/"), { currentSha = model.git.shaForTag(currentRefspec.copyToEnd(5)); }, { currentSha = model.git.shaForTag(currentRefspec); }); }, { currentSha = currentRefspec; }); tags.do { |tag| var refspec = "tags/" ++ tag; versions.add([refspec, tag]); }; isDirty = model.git.isDirty; if(isDirty, { currentRefspec = "DIRTY"; versions.insert(0, ["DIRTY", "DIRTY"]); }); tree = TreeView() .setProperty(\rootIsDecorated, false) .columns_(["Version", "Checkout"]); versions.do({ |tagRefspec| var tag, refspec, btn, row, isCurrent, btnText, enabled; # refspec, tag = tagRefspec; isCurrent = refspec == currentRefspec; row = tree.addItem([tag, nil]); // if installed then you can switch versions // else you can install any including current if(model.isInstalled, { btnText = if(isCurrent, "INSTALLED", "Install"); enabled = isCurrent.not; }, { btnText = "Install"; enabled = true; }); if(isDirty, { enabled = false; }); btn = Button() .fixedSize_(Size(100, 20)) .states_([[btnText]]); btn.enabled = enabled; if(enabled, { btn.action = { this.checkout(refspec) }; }); row.setView(1, btn); if(refspec == currentRefspec, { row.colors = [quarksGui.colors.installed.bg, quarksGui.colors.installed.bg]; row.setTextColor(0, quarksGui.colors.installed.text); }); }); tree.invokeMethod(\resizeColumnToContents, 0); ^tree } checkout { |refspec| { quarksGui.setMsg("Installing" + model.name); if(model.isInstalled, { // reinstall possibly with different dependencies model.uninstall; }); model = Quarks.install(model.url, refspec); }.protect({ |err| this.update; quarksGui.update; if(err.isNil, { quarksGui.setMsg(model.name + "has checked out" + refspec, \success); }, { quarksGui.setMsg(model.name + "failed to checkout" + refspec, \error); }); }); } } QuarkRowView { var 0); }; this.update; } install { |bool| quarksGui.runCancellable({ var prev, ok; if(bool, { // if any other is installed by same name // then just uinstall that first prev = Quarks.installed.detect({ |q| q.name == quark.name }); if(prev.notNil, { "Uninstalling other version % %".format(prev, prev.localPath).warn; prev.uninstall; }); ok = quark.install; if(ok, { quarksGui.setMsg("Installed" + quark, \success); }, { quarksGui.setMsg("Error while installing" + quark, \error); }); }, { quark.uninstall; quarksGui.setMsg("Uninstalled" + quark, \success); }); }, { quarksGui.update; }, { quarksGui.setMsg("Cancelled" + quark, \info); quarksGui.update; }); } update { var isInstalled; btn.states = [ ["+", nil, nil], ["✓", quarksGui.colors.primary.text, quarksGui.colors.primary.bg], ]; isInstalled = quark.isInstalled; btn.value = isInstalled.binaryValue; // this column has invisible text // its used to sort the rows so that installed quarks are at the top treeItem.setString(0, isInstalled.if("Y", { quark.isDownloaded.if("N", "") })); // 1 is the install button. its not possible to sort by this column treeItem.setString(2, quark.name ? ""); treeItem.setString(3, (quark.version ? "").asString); treeItem.setString(4, (quark.summary ? "").replace(Char.nl.asString," ").replace(Char.tab.asString, "")); } } SuperCollider-Source/SCClassLibrary/Common/Math/Complex.sc000644 000765 000024 00000007041 12756534417 024574 0ustar00crucialstaff000000 000000 Complex : Number { var <>real, <>imag; *new { arg real, imag; ^super.newCopyArgs(real, imag); } + { arg aNumber, adverb; if ( aNumber.isNumber, { ^Complex.new(real + aNumber.real, imag + aNumber.imag) },{ ^aNumber.performBinaryOpOnComplex('+', this, adverb) }); } - { arg aNumber, adverb; if ( aNumber.isNumber, { ^Complex.new(real - aNumber.real, imag - aNumber.imag) },{ ^aNumber.performBinaryOpOnComplex('-', this, adverb) }); } * { arg aNumber, adverb; if ( aNumber.isNumber, { ^Complex.new( // these are implemented as additional message sends so that UGens can // optimize the 6 operations down to 2 UGen instances. (real * aNumber.real) - (imag * aNumber.imag), (real * aNumber.imag) + (imag * aNumber.real) ) },{ ^aNumber.performBinaryOpOnComplex('*', this, adverb) }); } / { arg aNumber, adverb; var denom, yr, yi; if ( aNumber.isNumber, { yr = aNumber.real; yi = aNumber.imag; denom = 1.0 / (yr * yr + (yi * yi)); ^Complex.new( ((real * yr) + (imag * yi)) * denom, ((imag * yr) - (real * yi)) * denom) },{ ^aNumber.performBinaryOpOnComplex('/', this, adverb) }); } < { arg aNumber, adverb; if ( aNumber.isNumber, { ^real < aNumber.real },{ ^aNumber.performBinaryOpOnComplex('<', this, adverb) }); } == { arg aNumber, adverb; if ( aNumber.isNumber, { ^real == aNumber.real and: { imag == aNumber.imag } },{ ^aNumber.performBinaryOpOnComplex('==', this, adverb) }); } hash { ^real.hash << 1 bitXor: imag.hash } // double dispatch performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; ^aNumber.asComplex.perform(aSelector, this, adverb) } performBinaryOpOnSignal { arg aSelector, aSignal, adverb; ^aSignal.asComplex.perform(aSelector, this) } performBinaryOpOnComplex { arg aSelector, aNumber, adverb; BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw; } performBinaryOpOnUGen { arg aSelector, aUGen, adverb; ^aUGen.asComplex.perform(aSelector, this, adverb) } neg { ^Complex.new(real.neg, imag.neg) } conjugate { ^Complex.new(real, imag.neg) } squared { ^this * this } cubed { ^this * this * this } exp { ^exp(real) * Complex.new(cos(imag), sin(imag)) } pow { arg aNumber; // return(this ** aNumber) // Notation below: // t=this, p=power, i=sqrt(-1) // Derivation: // t ** p = exp(p*log(t)) = ... = r*exp(i*a) var p_real, p_imag, t_mag, t_phase, t_maglog; var mag, phase; aNumber = aNumber.asComplex; p_real = aNumber.real; p_imag = aNumber.imag; if(p_real == 0.0 and: { p_imag == 0 }) { ^Complex(1.0, 0.0) }; if(p_imag == 0.0 and: { imag == 0.0 } and: { real > 0.0 }) { ^Complex(real ** p_real, 0.0) }; t_mag = this.magnitude; if(t_mag == 0.0) { ^Complex(0.0, 0.0) }; t_maglog = log(t_mag); t_phase = this.phase; mag = exp((p_real * t_maglog) - (p_imag * t_phase)); phase = (p_imag * t_maglog) + (p_real * t_phase); ^Complex(mag * cos(phase), mag * sin(phase)) } magnitude { ^hypot(real, imag) } abs { ^hypot(real, imag) } rho { ^hypot(real, imag) } magnitudeApx { ^hypotApx(real, imag) } angle { ^atan2(imag, real) } phase { ^atan2(imag, real) } theta { ^atan2(imag, real) } coerce { arg aNumber; ^aNumber.asComplex } round { arg aNumber = 1.0; ^Complex(real.round(aNumber), imag.round(aNumber)) } asInteger { ^real.asInteger } asFloat { ^real.asFloat } asComplex { ^this } asPolar { ^Polar.new(this.rho, this.theta) } asPoint { ^Point.new(this.real, this.imag) } printOn { arg stream; stream << "Complex( " << real << ", " << imag << " )"; } } SuperCollider-Source/SCClassLibrary/Common/Math/Date.sc000644 000765 000024 00000003331 12756534417 024040 0ustar00crucialstaff000000 000000 Date { var <>year=2000, <>month=1, <>day=1, <>hour=0, <>minute=0, <>second=0, <>dayOfWeek=6, <>rawSeconds=0; *getDate { ^this.localtime } *localtime { ^this.new.localtime } *gmtime { ^this.new.gmtime } *new { arg year, month, day, hour, minute, second, dayOfWeek, rawSeconds; ^super.newCopyArgs(year, month, day, hour, minute, second, dayOfWeek, rawSeconds); } storeArgs { ^[year, month, day, hour, minute, second, dayOfWeek, rawSeconds] } localtime { _LocalTime ^this.primitiveFailed } gmtime { _GMTime ^this.primitiveFailed } *seed { // return a value suitable for seeding a random number generator. _TimeSeed } // strings for time stamping things like filenames. dayStamp { var s; s = (((year % 100) * 100 + month) * 100 + day + 1000000).asString; s.removeAt(0); // get rid of the leading '1' char that was put there to force leading zeroes. ^s } secStamp { var s; s = ((hour * 100 + minute) * 100 + second + 1000000).asString; s.removeAt(0); // get rid of the leading '1' char that was put there to force leading zeroes. ^s } stamp { ^this.dayStamp ++ "_" ++ this.secStamp } hourStamp { ^hour.asString ++ ":" ++ minute ++ ":" ++ (rawSeconds % 60).round(0.0001) } asSortableString { // standard database format, alphabetically sortable ^String.streamContents({ arg s; s << year; if(month < 10,{ s << 0 }); s << month; if(day < 10,{ s << 0 }); s << day; if(hour < 10,{ s << 0 }); s << hour; if(minute < 10, { s << 0 }); s << minute; if(second < 10, { s << 0 }); s << second; }) } asctime { _AscTime ^this.primitiveFailed } asString { ^this.asctime } format { arg format; _prStrFTime; ^this.primitiveFailed } } SuperCollider-Source/SCClassLibrary/Common/Math/Float.sc000644 000765 000024 00000004521 12756534417 024232 0ustar00crucialstaff000000 000000 Float : SimpleNumber { isFloat { ^true } asFloat { ^this } + { arg aNumber, adverb; _AddFloat; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) } - { arg aNumber, adverb; _SubFloat; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) } * { arg aNumber, adverb; _MulFloat; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) } clip { arg lo, hi; _ClipFloat; ^this.primitiveFailed } wrap { arg lo, hi; _WrapFloat; ^this.primitiveFailed } fold { arg lo, hi; _FoldFloat; ^this.primitiveFailed } coin { ^1.0.rand < this } xrand2 { ^this.rand2 } // returns an Integer which is the bit pattern of this as a // 32bit single precision float as32Bits { _As32Bits } // returns an Integer which is the bit pattern of high // 32 bits of the 64 bit double precision floating point value high32Bits { _High32Bits } low32Bits { _Low32Bits } *from32Bits { arg word; _From32Bits ^this.primitiveFailed } *from64Bits { arg hiWord, loWord; _From64Bits ^this.primitiveFailed } // iteration do { arg function; // iterates function from 0 to this-1 // special byte codes inserted by compiler for this method var i = 0.0; while ({ (i + 0.5) < this }, { function.value(i, i); i = i + 1.0; }); } reverseDo { arg function; // iterates function from this-1 to 0 // special byte codes inserted by compiler for this method var i, j=0.0; i = this - 1.0; while ({ (i + 0.5) >= 0.0 }, { function.value(i, j); i = i - 1.0; j = j + 1.0; }); } asStringPrec { arg precision; _Float_AsStringPrec ^this.primitiveFailed } archiveAsCompileString { ^true } // the correct place to implement compileString for Float is in DumpParseNode.cpp // int asCompileString(PyrSlot *slot, char *str) // for now, solve it here. storeOn { |stream| var str; if(this == inf) { stream << "inf"; ^this }; if(this == -inf) { stream << "-inf"; ^this }; str = super.asString; stream << str; // if it doesn't already have a . or is 1e-05 then add a .0 to force it to Float if(str.find(".").isNil and: { str.find("e").isNil }) { stream << ".0"; } } asCompileString { // do not rely on _ObjectCompileString, because precision is too low ^String.streamContents { |stream| this.storeOn(stream) } } switch { | ... cases| "Float:switch is unsafe, rounding via Float:asInteger:switch".warn; ^this.asInteger.switch(*cases) } } SuperCollider-Source/SCClassLibrary/Common/Math/Integer.sc000644 000765 000024 00000013431 12766171707 024562 0ustar00crucialstaff000000 000000 Integer : SimpleNumber { isInteger { ^true } hash { ^this.asFloat.hash } + { arg aNumber, adverb; _AddInt; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) } - { arg aNumber, adverb; _SubInt; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) } * { arg aNumber, adverb; _MulInt; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) } clip { arg lo, hi; _ClipInt; ^this.primitiveFailed } wrap { arg lo, hi; _WrapInt; ^this.primitiveFailed } fold { arg lo, hi; _FoldInt; ^this.primitiveFailed } even { ^this.bitAnd(1) == 0 } odd { ^this.bitAnd(1) == 1 } xrand { arg exclude=0; ^(exclude + (this - 1).rand + 1) % this; } xrand2 { arg exclude=0; var res; res = (2 * this).rand - this; if (res == exclude, { ^this },{ ^res }); } degreeToKey { arg scale, stepsPerOctave = 12; ^scale.performDegreeToKey(this, stepsPerOctave) } // iteration do { arg function; // iterates function from 0 to this-1 // special byte codes inserted by compiler for this method var i = 0; while ({ i < this }, { function.value(i, i); i = i + 1; }); } // override 'do' generate { arg function; function.value(this) } collectAs { arg function, class; var res = (class ? Array).new(this); this.do {|i| res.add(function.value(i)) } ^res; } collect { arg function; ^this.collectAs(function, Array) } reverseDo { arg function; // iterates function from 0 to this-1 // special byte codes inserted by compiler for this method var i=0, j=0; i = this - 1; while ({ i >= 0 }, { function.value(i, j); i = i - 1; j = j + 1; }); } for { arg endval, function; // iterates function from this to endval (inclusive) // special byte codes inserted by compiler for this method var i, j=0, stepval=1; i = this; while ({ i <= endval }, { function.value(i, j); i = i + 1; j = j + 1; }); } forBy { arg endval, stepval, function; // iterates function from this to endval (inclusive) by step // special byte codes inserted by compiler for this method var i, j=0; i = this; while ({ i <= endval }, { function.value(i, j); i = i + stepval; j = j + 1; }); } to { arg hi, step=1; ^Interval.new(this, hi, step) } // conversions to Char asAscii { // must be 0 <= this <= 255 _AsAscii ^this.primitiveFailed } asUnicode { ^this } asDigit { // must be 0 <= this <= 35 _AsDigit ^this.primitiveFailed } asBinaryDigits { arg numDigits = 8; var array; array = Array.new(numDigits); numDigits.do({ arg i; array.addFirst(this.rightShift(i).bitAnd(1)) }); ^array } asDigits { arg base=10, numDigits; var array, num = this; numDigits = numDigits ?? { (this.log / base.log + 1e-10).asInteger + 1 }; array = Array.new(numDigits); numDigits.do { array = array.addFirst(num % base); num = num div: base } ^array } nextPowerOfTwo { _NextPowerOfTwo } isPowerOfTwo { _IsPowerOfTwo } leadingZeroes { _CLZ } trailingZeroes { _CTZ } numBits { _NumBits } log2Ceil { _Log2Ceil } grayCode { _BinaryGrayCode } setBit { arg bitNumber, bool = true; _SetBit ^this.primitiveFailed } nthPrime { _NthPrime } prevPrime { _PrevPrime } nextPrime { _NextPrime } indexOfPrime { _IndexOfPrime } isPrime { _IsPrime /* var sqrtThis; if ( this <= 2, { if (this == 2, { ^true }, { ^false }); }); sqrtThis = this.sqrt.asInteger; 256.do({ arg i; var p; p = i.nthPrime; if (this % p == 0, { ^false }); if (p >= sqrtThis, { ^true }); }); ^nil */ } // exit the program and return the result code to unix shell exit { _Exit } asStringToBase { | base=10, width=8 | var rest = this, string, mask; if (base.inclusivelyBetween(2, 36).not) { base = clip(base, 2, 36); warn(thisMethod + ": base not between 2 and 36"); }; string = String.newClear(width); if (base.isPowerOfTwo) { mask = base - 1; base = base.trailingZeroes; width.do { | i | string.put(width-i-1, rest.bitAnd(mask).asDigit); rest = rest.rightShift(base); }; } { width.do { | i | string.put(width-i-1, (rest mod: base).asDigit); rest = rest div: base; }; }; ^string } asBinaryString { | width=8 | ^this.asStringToBase(2, width) } asHexString { | width=8 | ^this.asStringToBase(16, width) } asIPString { ^this.rightShift(24).bitAnd(255).asString ++ "." ++ this.rightShift(16).bitAnd(255).asString ++ "." ++ this.rightShift(8).bitAnd(255).asString ++ "." ++ this.bitAnd(255).asString } archiveAsCompileString { ^true } geom { arg start, grow; ^Array.geom(this, start, grow); } fib { arg a=0.0, b=1.0; ^Array.fib(this, a, b); } factors { var num, array, prime; if(this <= 1) { ^[] }; // no prime factors exist below the first prime num = this.abs; // there are 6542 16 bit primes from 2 to 65521 6542.do {|i| prime = i.nthPrime; while { (num mod: prime) == 0 }{ array = array.add(prime); num = num div: prime; if (num == 1) {^array} }; if (prime.squared > num) { array = array.add(num); ^array }; }; // because Integer is 32 bit, and we have tested all 16 bit primes, // any remaining number must be a prime. array = array.add(num); ^array } pidRunning { _PidRunning; ^this.primitiveFailed } factorial { ^#[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600] @ this.max(0) ?? { Error("integer resolution too low for this factorial:" + this).throw }; /*var product = 1; if(this <= 1) { ^1 } { this.do { |x| product = product * (x+1) }; ^product }*/ } // support for modifiers keys isCaps { ^this.bitAnd(65536) == 65536} isShift { ^this.bitAnd(131072) == 131072 } isCtrl { ^this.bitAnd(262144) == 262144 } isAlt { ^this.bitAnd(524288) == 524288 } isCmd { ^this.bitAnd(1048576) == 1048576 } isNumPad { ^this.bitAnd(2097152) == 2097152 } isHelp { ^this.bitAnd(4194304) == 4194304 } isFun { ^this.bitAnd(8388608) == 8388608 } } SuperCollider-Source/SCClassLibrary/Common/Math/Magnitude.sc000644 000765 000024 00000001633 12756534417 025103 0ustar00crucialstaff000000 000000 Magnitude : Object { // Magnitudes are objects which represent a linear measure == { arg aMagnitude; ^this.subclassResponsibility(thisMethod) } != { arg aMagnitude; ^(this == aMagnitude).not } hash { ^this.subclassResponsibility(thisMethod) } // all of the other compare operations are built upon < < { arg aMagnitude; ^this.subclassResponsibility(thisMethod) } > { arg aMagnitude; ^aMagnitude < this } <= { arg aMagnitude; ^(aMagnitude < this).not } >= { arg aMagnitude; ^(this < aMagnitude).not } exclusivelyBetween { arg lo, hi; ^(lo < this) and: { this < hi } } inclusivelyBetween { arg lo, hi; ^(lo <= this) and: { this <= hi } } min { arg aMagnitude; if (this < aMagnitude, {^this}, {^aMagnitude}) } max { arg aMagnitude; if (this < aMagnitude, {^aMagnitude}, {^this}) } clip { arg lo, hi; // clip the receiver to the range lo, hi ^if (this < lo, {^lo}, { if (hi < this, {^hi}, {^this}) }) } } SuperCollider-Source/SCClassLibrary/Common/Math/Number.sc000644 000765 000024 00000003431 12756534417 024414 0ustar00crucialstaff000000 000000 Number : Magnitude { isNumber { ^true } + { arg aNumber; ^this.subclassResponsibility(thisMethod) } - { arg aNumber; ^this.subclassResponsibility(thisMethod) } * { arg aNumber; ^this.subclassResponsibility(thisMethod) } / { arg aNumber; ^this.subclassResponsibility(thisMethod) } mod { arg aNumber; ^this.subclassResponsibility(thisMethod) } div { arg aNumber; ^this.subclassResponsibility(thisMethod) } pow { arg aNumber; ^this.subclassResponsibility(thisMethod) } performBinaryOpOnSeqColl { arg aSelector, aSeqColl, adverb; ^aSeqColl.collect({ arg item; item.perform(aSelector, this, adverb) }) } performBinaryOpOnPoint { arg op, aPoint, adverb; ^Point.new(this.perform(op, aPoint.x, adverb), this.perform(op, aPoint.y, adverb)); } // polar support rho { ^this } theta { ^0.0 } // complex support real { ^this } imag { ^0.0 } // conversion @ { arg aNumber; ^Point.new(this, aNumber) } complex { arg imaginaryPart; ^Complex.new(this, imaginaryPart) } polar { arg angle; ^Polar.new(this, angle) } // iteration for { arg endValue, function; var i, j = 0; i = this; while ({ i <= endValue }, { function.value(i, j); i = i + 1; j = j + 1 }); } forBy { arg endValue, stepValue, function; var i, j=0; i = this; (stepValue > 0).if({ while ({ i <= endValue }, { function.value(i,j); i = i + stepValue; j=j+1; }); }, { while ({ i >= endValue }, { function.value(i,j); i = i + stepValue; j=j+1; }); }); } forSeries { arg second, last, function; // called by generator expression // compiler replaces this with special byte codes. var step, j=0; if (second.isNil) { last = last ? inf; step = if (this < last, 1, -1); }{ last ?? { last = if (second < this, -inf, inf) }; step = second - this; }; ^this.forBy(last, step, function) } } SuperCollider-Source/SCClassLibrary/Common/Math/Polar.sc000644 000765 000024 00000002372 12756534417 024244 0ustar00crucialstaff000000 000000 Polar : Number { var <>rho, <>theta; *new { arg rho, theta; ^super.newCopyArgs(rho, theta) } magnitude { ^rho } angle { ^theta } phase { ^theta } real { ^rho * cos(theta) } imag { ^rho * sin(theta) } asPolar { ^this } asComplex { ^Complex.new(this.real, this.imag) } asPoint { ^Point.new(this.real, this.imag) } scale { arg scale; ^Polar.new(rho * scale, theta) } rotate { arg angle; // in radians ^Polar.new(rho, theta + angle) } // do math as Complex + { arg aNumber; ^this.asComplex + aNumber } - { arg aNumber; ^this.asComplex - aNumber } * { arg aNumber; ^this.asComplex * aNumber } / { arg aNumber; ^this.asComplex / aNumber } == { arg aPolar; ^aPolar respondsTo: #[\rho, \theta] and: { rho == aPolar.rho and: { theta == aPolar.theta } } } hash { ^rho.hash bitXor: theta.hash } neg { ^Polar.new(rho, theta + pi) } performBinaryOpOnSomething { |aSelector, thing, adverb| ^thing.asComplex.perform(aSelector, this, adverb) } performBinaryOpOnUGen { arg aSelector, aUGen; ^Complex.new( BinaryOpUGen.new(aSelector, aUGen, this.real), BinaryOpUGen.new(aSelector, aUGen, this.imag) ); } printOn { arg stream; stream << "Polar( " << rho << ", " << theta << " )"; } storeArgs { ^[rho,theta] } } SuperCollider-Source/SCClassLibrary/Common/Math/Signal.sc000644 000765 000024 00000025442 12756534417 024407 0ustar00crucialstaff000000 000000 Signal[float] : FloatArray { *sineFill { arg size, amplitudes, phases; ^Signal.newClear(size).sineFill(amplitudes, phases).normalize } *chebyFill { arg size, amplitudes, normalize=true, zeroOffset=false; ^Signal.newClear(size).chebyFill(amplitudes, normalize, zeroOffset); } *hammingWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).fill(0.5).addSine(1, 0.39, -0.5pi); },{ ^this.newClear(size-pad).fill(0.5).addSine(1, 0.39, -0.5pi) ++ this.newClear(pad); }); } *hanningWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).fill(0.5).addSine(1, 0.5, -0.5pi); },{ ^this.newClear(size-pad).fill(0.5).addSine(1, 0.5, -0.5pi) ++ this.newClear(pad); }); } *welchWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).addSine(0.5, 1, 0); },{ ^this.newClear(size-pad).addSine(0.5, 1, 0) ++ this.newClear(pad); }); } *rectWindow { arg size, pad=0; if (pad == 0, { ^this.newClear(size).fill(1.0); },{ ^this.newClear(size-pad).fill(1.0) ++ this.newClear(pad); }); } *readNew { arg file; ^file.readAllSignal; } // operations fill { arg val; _SignalFill ^this.primitiveFailed } scale { arg scale; _SignalScale ^this.primitiveFailed } offset { arg offset; _SignalOffset ^this.primitiveFailed } asWavetable { // Interpolating oscillators require wavetables in a special format. // This method returns a wavetable in that format. _SignalAsWavetable; ^this.primitiveFailed } asWavetableNoWrap { // Shaper requires wavetables without wrap. // This method returns a wavetable in that format. //To generate size N wavetable need N/2+1 signal values rather than N/2 //because Buffer's add_wchebyshev calculates N/2+1 values whilst //Signal's _SignalAddChebyshev calculates N/2! var newsig = Signal.newClear((this.size-1)*2); var next, cur; cur= this[0]; (this.size-1).do{|i| var index= 2*i; next= this[i+1]; newsig[index]= 2*cur -next; newsig[index+1]= next-cur; cur=next; }; ^newsig } peak { _SignalPeak; ^this.primitiveFailed } normalize { arg beginSamp=0, endSamp; _SignalNormalize; ^this.primitiveFailed } normalizeTransfer { _SignalNormalizeTransferFn; ^this.primitiveFailed } invert { arg beginSamp=0, endSamp; _SignalInvert; ^this.primitiveFailed } reverse { arg beginSamp=0, endSamp; _SignalReverse; ^this.primitiveFailed } fade { arg beginSamp=0, endSamp, beginLevel=0.0, endLevel=1.0; _SignalFade; ^this.primitiveFailed } rotate { arg n=1; _SignalRotate ^this.primitiveFailed } zeroPad { arg minSize; var size = max(minSize ? 0, this.size).nextPowerOfTwo; ^this ++ Signal.newClear(size - this.size); } integral { _SignalIntegral; ^this.primitiveFailed } overDub { arg aSignal, index=0; _SignalOverDub // add a signal to myself starting at the index // if the other signal is too long only the first part is overdubbed ^this.primitiveFailed } overWrite { arg aSignal, index=0; _SignalOverWrite // write a signal to myself starting at the index // if the other signal is too long only the first part is overwritten ^this.primitiveFailed } play { arg loop=false, mul=0.2, numChannels=1, server; var buf; buf = Buffer.sendCollection(server ? Server.default, this, numChannels, -1, { buf.play(loop, mul); }); ^buf } waveFill { arg function, start = 0.0, end = 1.0; var i = 0, step, size, val, x; // evaluate a function for every sample over the interval from // start to end. size = this.size; if (size <= 0, { ^this }); x = start; step = (end - start) / size; while ({ i < size }, { val = function.value(x, this.at(i), i); this.put(i, val); x = x + step; i = i + 1; }); ^this } addSine { arg harmonicNumber = 1, amplitude = 1.0, phase = 0.0; _SignalAddHarmonic ^this.primitiveFailed } sineFill { arg amplitudes, phases; this.fill(0.0); if (phases.isNil, { phases = #[0]; }); amplitudes.do({ arg amp, i; this.addSine(i+1, amp, phases @@ i) }); } sineFill2 { arg list; this.fill(0.0); list.do({ arg item, i; var harm, amp, phase; # harm, amp, phase = item; this.addSine(harm, amp ? 1.0, phase ? 0.0); }); } addChebyshev { arg harmonicNumber = 1, amplitude = 1.0; _SignalAddChebyshev ^this.primitiveFailed } chebyFill { arg amplitudes, normalize=true, zeroOffset=false; this.fill(0.0); amplitudes.do({ arg amp, i; this.addChebyshev(i+1, amp); if (zeroOffset) { if(i%4==1,{this.offset(amp)}); if(i%4==3,{this.offset(-1*amp)}); } //corrections for JMC DC offsets, as per Buffer:cheby }); if (normalize) { if (zeroOffset) { this.normalizeTransfer } { this.normalize } }; } //old version chebyFill_old { arg amplitudes; this.fill(0.0); amplitudes.do({ arg amp, i; this.addChebyshev(i+1, amp) }); this.normalizeTransfer } *fftCosTable { arg fftsize; ^this.newClear((fftsize/4) + 1).fftCosTable } fftCosTable { var harm; harm = this.size / ((this.size - 1) * 4); this.addSine(harm, 1, 0.5pi); } fft { arg imag, cosTable; // argCosTable must contain 1/4 cycle of a cosine (use fftCosTable) // fftsize is the next greater power of two than the receiver's length _Signal_FFT ^this.primitiveFailed } ifft { arg imag, cosTable; // argCosTable must contain 1/4 cycle of a cosine (use fftCosTable) // fftsize is the next greater power of two than the receiver's length _Signal_IFFT ^this.primitiveFailed } neg { _Neg; ^this.primitiveFailed } abs { _Abs; ^this.primitiveFailed } sign { _Sign; ^this.primitiveFailed } squared { _Squared; ^this.primitiveFailed } cubed { _Cubed; ^this.primitiveFailed } sqrt { _Sqrt; ^this.primitiveFailed } exp { _Exp; ^this.primitiveFailed } //reciprocal { _Recip; ^this.primitiveFailed } //midicps { _MIDICPS; ^this.primitiveFailed } //cpsmidi { _CPSMIDI; ^this.primitiveFailed } //midiratio { _MIDIRatio; ^this.primitiveFailed } //ratiomidi { _RatioMIDI; ^this.primitiveFailed } //ampdb { _AmpDb; ^this.primitiveFailed } //dbamp { _DbAmp; ^this.primitiveFailed } //octcps { _OctCPS; ^this.primitiveFailed } //cpsoct { _CPSOct; ^this.primitiveFailed } log { _Log; ^this.primitiveFailed } log2 { _Log2; ^this.primitiveFailed } log10 { _Log10; ^this.primitiveFailed } sin { _Sin; ^this.primitiveFailed } cos { _Cos; ^this.primitiveFailed } tan { _Tan; ^this.primitiveFailed } asin { _ArcSin; ^this.primitiveFailed } acos { _ArcCos; ^this.primitiveFailed } atan { _ArcTan; ^this.primitiveFailed } sinh { _SinH; ^this.primitiveFailed } cosh { _CosH; ^this.primitiveFailed } tanh { _TanH; ^this.primitiveFailed } distort { _Distort; ^this.primitiveFailed } softclip { _SoftClip; ^this.primitiveFailed } rectWindow { _RectWindow; ^this.primitiveFailed } hanWindow { _HanWindow; ^this.primitiveFailed } welWindow { _WelchWindow; ^this.primitiveFailed } triWindow { _TriWindow; ^this.primitiveFailed } scurve { _SCurve; ^this.primitiveFailed } ramp { _Ramp; ^this.primitiveFailed } + { arg aNumber; _Add; ^aNumber.performBinaryOpOnSignal('+', this) } - { arg aNumber; _Sub; ^aNumber.performBinaryOpOnSignal('-', this) } * { arg aNumber; _Mul; ^aNumber.performBinaryOpOnSignal('*', this) } / { arg aNumber; _FDiv; ^aNumber.performBinaryOpOnSignal('/', this) } mod { arg aNumber; _Mod; ^aNumber.performBinaryOpOnSignal('mod', this) } div { arg aNumber; _IDiv; ^aNumber.performBinaryOpOnSignal('div', this) } pow { arg aNumber; _Pow; ^aNumber.performBinaryOpOnSignal('pow', this) } min { arg aNumber; _Min; ^aNumber.performBinaryOpOnSignal('min', this) } max { arg aNumber; _Max; ^aNumber.performBinaryOpOnSignal('max', this) } ring1 { arg aNumber; _Ring1; ^aNumber.performBinaryOpOnSignal('ring1', this) } ring2 { arg aNumber; _Ring2; ^aNumber.performBinaryOpOnSignal('ring2', this) } ring3 { arg aNumber; _Ring3; ^aNumber.performBinaryOpOnSignal('ring3', this) } ring4 { arg aNumber; _Ring4; ^aNumber.performBinaryOpOnSignal('ring4', this) } difsqr { arg aNumber; _DifSqr; ^aNumber.performBinaryOpOnSignal('difsqr', this) } sumsqr { arg aNumber; _SumSqr; ^aNumber.performBinaryOpOnSignal('sumsqr', this) } sqrsum { arg aNumber; _SqrSum; ^aNumber.performBinaryOpOnSignal('sqrsum', this) } sqrdif { arg aNumber; _SqrDif; ^aNumber.performBinaryOpOnSignal('sqrdif', this) } absdif { arg aNumber; _AbsDif; ^aNumber.performBinaryOpOnSignal('absdif', this) } thresh { arg aNumber; _Thresh; ^aNumber.performBinaryOpOnSignal('thresh', this) } amclip { arg aNumber; _AMClip; ^aNumber.performBinaryOpOnSignal('amclip', this) } scaleneg { arg aNumber; _ScaleNeg; ^aNumber.performBinaryOpOnSignal('scaleneg', this) } clip2 { arg aNumber=1; _Clip2; ^aNumber.performBinaryOpOnSignal('clip2', this) } fold2 { arg aNumber; _Fold2; ^aNumber.performBinaryOpOnSignal('fold2', this) } wrap2 { arg aNumber; _Wrap2; ^aNumber.performBinaryOpOnSignal('wrap2', this) } excess { arg aNumber; _Excess; ^aNumber.performBinaryOpOnSignal('excess', this) } firstArg { arg aNumber; _FirstArg; ^aNumber.performBinaryOpOnSignal('firstArg', this) } == { arg aNumber; _EQ; ^aNumber.performBinaryOpOnSignal('==', this) } != { arg aNumber; _NE; ^aNumber.performBinaryOpOnSignal('!=', this) } clip { arg lo, hi; _ClipSignal; ^this.primitiveFailed } wrap { arg lo, hi; _WrapSignal; ^this.primitiveFailed } fold { arg lo, hi; _FoldSignal; ^this.primitiveFailed } blend { arg that, blendFrac = 0.5; ^this + (blendFrac * (that - this)); } asInteger { _AsInt; ^this.primitiveFailed } asFloat { _AsFloat; ^this.primitiveFailed } asComplex { ^Complex.new(this, 0.0) } asSignal { ^this } // complex support real { ^this } imag { ^0.0 } //PRIVATE: performBinaryOpOnSignal { arg aSelector, aNumber, adverb; BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw; } } Wavetable[float] : FloatArray { // the only way to make a Wavetable is by Signal::asWavetable *new { ^this.shouldNotImplement(thisMethod) } *newClear { ^this.shouldNotImplement(thisMethod) } *sineFill { arg size, amplitudes, phases; ^Signal.sineFill(size, amplitudes, phases).asWavetable } //size must be N/2+1 for N power of two; N is eventual size of wavetable *chebyFill { arg size, amplitudes, normalize=true, zeroOffset=false; ^Signal.chebyFill(size, amplitudes, normalize, zeroOffset).asWavetableNoWrap; //asWavetable causes wrap here, problem } *chebyFill_old { arg size, amplitudes; //this.deprecated(thisMethod, Buffer.findRespondingMethodFor(\cheby)); ^Signal.chebyFill(size, amplitudes).asWavetable; //asWavetable causes wrap here, problem } asSignal { _WavetableAsSignal ^this.primitiveFailed } blend { arg anotherWavetable, blendFrac=0.5; ^this.asSignal.blend(anotherWavetable.asSignal, blendFrac).asWavetable; } *readNew { arg file; ^file.readAllSignal.asWavetable; } write { arg path; var file; file = File.new(path, "wb"); if (file.notNil, { file.write(this.asSignal); file.close; }); } //libMenuAction { arg names; // this.plot(names.last); //} } SuperCollider-Source/SCClassLibrary/Common/Math/SimpleNumber.sc000644 000765 000024 00000042520 12766171707 025570 0ustar00crucialstaff000000 000000 SimpleNumber : Number { *new { ^this.shouldNotImplement(thisMethod) } isValidUGenInput { ^this.isNaN.not } numChannels { ^1 } magnitude { ^this.abs } angle { if (this >= 0, {^0.0}, {^pi} ) } neg { _Neg; ^this.primitiveFailed } bitNot { _BitNot; ^this.primitiveFailed } abs { _Abs; ^this.primitiveFailed } ceil { _Ceil; ^this.primitiveFailed } floor { _Floor; ^this.primitiveFailed } frac { _Frac; ^this.primitiveFailed } sign { _Sign; ^this.primitiveFailed } squared { _Squared; ^this.primitiveFailed } cubed { _Cubed; ^this.primitiveFailed } sqrt { _Sqrt; ^this.primitiveFailed } exp { _Exp; ^this.primitiveFailed } reciprocal { _Recip; ^this.primitiveFailed } midicps { _MIDICPS; ^this.primitiveFailed } cpsmidi { _CPSMIDI; ^this.primitiveFailed } midiratio { _MIDIRatio; ^this.primitiveFailed } ratiomidi { _RatioMIDI; ^this.primitiveFailed } ampdb { _AmpDb; ^this.primitiveFailed } dbamp { _DbAmp; ^this.primitiveFailed } octcps { _OctCPS; ^this.primitiveFailed } cpsoct { _CPSOct; ^this.primitiveFailed } log { _Log; ^this.primitiveFailed } log2 { _Log2; ^this.primitiveFailed } log10 { _Log10; ^this.primitiveFailed } sin { _Sin; ^this.primitiveFailed } cos { _Cos; ^this.primitiveFailed } tan { _Tan; ^this.primitiveFailed } asin { _ArcSin; ^this.primitiveFailed } acos { _ArcCos; ^this.primitiveFailed } atan { _ArcTan; ^this.primitiveFailed } sinh { _SinH; ^this.primitiveFailed } cosh { _CosH; ^this.primitiveFailed } tanh { _TanH; ^this.primitiveFailed } rand { _Rand; ^this.primitiveFailed } rand2 { _Rand2; ^this.primitiveFailed } linrand { _LinRand; ^this.primitiveFailed } bilinrand { _BiLinRand; ^this.primitiveFailed } sum3rand { _Sum3Rand; ^this.primitiveFailed } distort { _Distort; ^this.primitiveFailed } softclip { _SoftClip; ^this.primitiveFailed } coin { _Coin; ^this.primitiveFailed } isPositive { ^this >= 0 } isNegative { ^this < 0 } isStrictlyPositive { ^this > 0 } isNaN { ^(this >= 0 or: { this <= 0 }).not } asBoolean { ^this > 0 } booleanValue { ^this > 0 } // TODO in the long-run, deprecate for asBoolean binaryValue { ^this.sign.max(0) } // TODO in the long-run, deprecate for asInteger rectWindow { _RectWindow; ^this.primitiveFailed } hanWindow { _HanWindow; ^this.primitiveFailed } welWindow { _WelchWindow; ^this.primitiveFailed } triWindow { _TriWindow; ^this.primitiveFailed } scurve { _SCurve; ^this.primitiveFailed } ramp { _Ramp; ^this.primitiveFailed } + { arg aNumber, adverb; _Add; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) } - { arg aNumber, adverb; _Sub; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) } * { arg aNumber, adverb; _Mul; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) } / { arg aNumber, adverb; _FDiv; ^aNumber.performBinaryOpOnSimpleNumber('/', this, adverb) } mod { arg aNumber, adverb; _Mod; ^aNumber.performBinaryOpOnSimpleNumber('mod', this, adverb) } div { arg aNumber, adverb; _IDiv; ^aNumber.performBinaryOpOnSimpleNumber('div', this, adverb) } pow { arg aNumber, adverb; _Pow; ^aNumber.performBinaryOpOnSimpleNumber('pow', this, adverb) } min { arg aNumber, adverb; _Min; ^aNumber.performBinaryOpOnSimpleNumber('min', this, adverb) } max { arg aNumber=0.0, adverb; _Max; ^aNumber.performBinaryOpOnSimpleNumber('max', this, adverb) } bitAnd { arg aNumber, adverb; _BitAnd; ^aNumber.performBinaryOpOnSimpleNumber('bitAnd', this, adverb) } bitOr { arg aNumber, adverb; _BitOr; ^aNumber.performBinaryOpOnSimpleNumber('bitOr', this, adverb) } bitXor { arg aNumber, adverb; _BitXor; ^aNumber.performBinaryOpOnSimpleNumber('bitXor', this, adverb) } bitHammingDistance { arg aNumber, adverb; _HammingDistance ^aNumber.performBinaryOpOnSimpleNumber('hammingDistance', this, adverb) } bitTest { arg bit; ^( (this.bitAnd(1.leftShift(bit))) != 0) } lcm { arg aNumber, adverb; _LCM; ^aNumber.performBinaryOpOnSimpleNumber('lcm', this, adverb) } gcd { arg aNumber, adverb; _GCD; ^aNumber.performBinaryOpOnSimpleNumber('gcd', this, adverb) } round { arg aNumber=1.0, adverb; _Round; ^aNumber.performBinaryOpOnSimpleNumber('round', this, adverb) } roundUp { arg aNumber=1.0, adverb; _RoundUp; ^aNumber.performBinaryOpOnSimpleNumber('roundUp', this, adverb) } trunc { arg aNumber=1.0, adverb; _Trunc; ^aNumber.performBinaryOpOnSimpleNumber('trunc', this, adverb) } atan2 { arg aNumber, adverb; _Atan2; ^aNumber.performBinaryOpOnSimpleNumber('atan2', this, adverb) } hypot { arg aNumber, adverb; _Hypot; ^aNumber.performBinaryOpOnSimpleNumber('hypot', this, adverb) } hypotApx { arg aNumber, adverb; _HypotApx; ^aNumber.performBinaryOpOnSimpleNumber('hypotApx', this, adverb) } leftShift { arg aNumber=1, adverb; _ShiftLeft; ^aNumber.performBinaryOpOnSimpleNumber('leftShift', this, adverb) } rightShift { arg aNumber=1, adverb; _ShiftRight; ^aNumber.performBinaryOpOnSimpleNumber('rightShift', this, adverb) } unsignedRightShift { arg aNumber, adverb; _UnsignedShift; ^aNumber.performBinaryOpOnSimpleNumber('unsignedRightShift', this, adverb) } ring1 { arg aNumber, adverb; _Ring1; ^aNumber.performBinaryOpOnSimpleNumber('ring1', this, adverb) } ring2 { arg aNumber, adverb; _Ring2; ^aNumber.performBinaryOpOnSimpleNumber('ring2', this, adverb) } ring3 { arg aNumber, adverb; _Ring3; ^aNumber.performBinaryOpOnSimpleNumber('ring3', this, adverb) } ring4 { arg aNumber, adverb; _Ring4; ^aNumber.performBinaryOpOnSimpleNumber('ring4', this, adverb) } difsqr { arg aNumber, adverb; _DifSqr; ^aNumber.performBinaryOpOnSimpleNumber('difsqr', this, adverb) } sumsqr { arg aNumber, adverb; _SumSqr; ^aNumber.performBinaryOpOnSimpleNumber('sumsqr', this, adverb) } sqrsum { arg aNumber, adverb; _SqrSum; ^aNumber.performBinaryOpOnSimpleNumber('sqrsum', this, adverb) } sqrdif { arg aNumber, adverb; _SqrDif; ^aNumber.performBinaryOpOnSimpleNumber('sqrdif', this, adverb) } absdif { arg aNumber, adverb; _AbsDif; ^aNumber.performBinaryOpOnSimpleNumber('absdif', this, adverb) } thresh { arg aNumber, adverb; _Thresh; ^aNumber.performBinaryOpOnSimpleNumber('thresh', this, adverb) } amclip { arg aNumber, adverb; _AMClip; ^aNumber.performBinaryOpOnSimpleNumber('amclip', this, adverb) } scaleneg { arg aNumber, adverb; _ScaleNeg; ^aNumber.performBinaryOpOnSimpleNumber('scaleneg', this, adverb) } clip2 { arg aNumber, adverb; _Clip2; ^aNumber.performBinaryOpOnSimpleNumber('clip2', this, adverb) } fold2 { arg aNumber, adverb; _Fold2; ^aNumber.performBinaryOpOnSimpleNumber('fold2', this, adverb) } wrap2 { arg aNumber, adverb; _Wrap2; ^aNumber.performBinaryOpOnSimpleNumber('wrap2', this, adverb) } excess { arg aNumber, adverb; _Excess; ^aNumber.performBinaryOpOnSimpleNumber('excess', this, adverb) } firstArg { arg aNumber, adverb; _FirstArg; ^aNumber.performBinaryOpOnSimpleNumber('firstArg', this, adverb) } rrand { arg aNumber, adverb; _RandRange; ^aNumber.performBinaryOpOnSimpleNumber('rrand', this, adverb) } exprand { arg aNumber, adverb; _ExpRandRange; ^aNumber.performBinaryOpOnSimpleNumber('exprand', this, adverb) } == { arg aNumber, adverb; _EQ; ^aNumber.perform('==', this, adverb) } != { arg aNumber, adverb; _NE; ^aNumber.perform('!=', this, adverb) } < { arg aNumber, adverb; _LT; ^aNumber.performBinaryOpOnSimpleNumber('<', this, adverb) } > { arg aNumber, adverb; _GT; ^aNumber.performBinaryOpOnSimpleNumber('>', this, adverb) } <= { arg aNumber, adverb; _LE; ^aNumber.performBinaryOpOnSimpleNumber('<=', this, adverb) } >= { arg aNumber, adverb; _GE; ^aNumber.performBinaryOpOnSimpleNumber('>=', this, adverb) } equalWithPrecision { arg that, precision=0.0001, relativePrecision=0; ^if(relativePrecision > 0) { absdif(this, that) < max(precision, relativePrecision * min(abs(this), abs(that))) } { absdif(this, that) < precision } } hash { _ObjectHash; ^this.primitiveFailed } asInteger { _AsInt; ^this.primitiveFailed } asFloat { _AsFloat; ^this.primitiveFailed } asComplex { ^Complex.new(this, 0.0) } asRect { ^Rect(this, this, this, this) } degrad { ^this*pi/180 } raddeg { ^this*180/pi } performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw; } performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^aComplex.perform(aSelector, this.asComplex, adverb) } performBinaryOpOnSignal { arg aSelector, aSignal, adverb; BinaryOpFailureError(this, aSelector, [aSignal, adverb]).throw; } nextPowerOfTwo { ^this.nextPowerOf(2) } nextPowerOf { arg base; ^pow(base, ceil(log(this) / log(base))) } nextPowerOfThree { ^pow(3, ceil(log(this) / log(3))) } previousPowerOf { arg base; ^pow(base, ceil(log(this) / log(base)) - 1) } quantize { arg quantum = 1.0, tolerance = 0.05, strength = 1.0; var round = round(this, quantum); var diff = round - this; if (abs(diff) < tolerance) { ^this + (strength * diff) }{ ^this } } linlin { arg inMin, inMax, outMin, outMax, clip=\minmax; // linear to linear mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin; } linexp { arg inMin, inMax, outMin, outMax, clip=\minmax; // linear to exponential mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^pow(outMax/outMin, (this-inMin)/(inMax-inMin)) * outMin } explin { arg inMin, inMax, outMin, outMax, clip=\minmax; // exponential to linear mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^(log(this/inMin)) / (log(inMax/inMin)) * (outMax-outMin) + outMin; } expexp { arg inMin, inMax, outMin, outMax, clip=\minmax; // exponential to exponential mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^pow(outMax/outMin, log(this/inMin) / log(inMax/inMin)) * outMin; } lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled; switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); if (abs(curve) < 0.001) { // If the value should be clipped, it has already been clipped (above). // If we got this far, then linlin does not need to do any clipping. // Inlining the formula here makes it even faster. ^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin; }; grow = exp(curve); a = outMax - outMin / (1.0 - grow); b = outMin + a; scaled = (this - inMin) / (inMax - inMin); ^b - (a * pow(grow, scaled)); } curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled; switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); if (abs(curve) < 0.001) { // If the value should be clipped, it has already been clipped (above). ^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin; }; grow = exp(curve); a = inMax - inMin / (1.0 - grow); b = inMin + a; ^log((b - this) / a) * (outMax - outMin) / curve + outMin } bilin { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; // triangular linear mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^if (this >= inCenter) { this.linlin(inCenter, inMax, outCenter, outMax, \none); } { this.linlin(inMin, inCenter, outMin, outCenter, \none); } } biexp { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; // triangular exponential mapping switch(clip, \minmax, { if (this <= inMin, { ^outMin }); if (this >= inMax, { ^outMax }); }, \min, { if (this <= inMin, { ^outMin }); }, \max, { if (this >= inMax, { ^outMax }); } ); ^if (this >= inCenter) { this.explin(inCenter, inMax, outCenter, outMax, \none); } { this.explin(inMin, inCenter, outMin, outCenter, \none); } } moddif { arg aNumber = 0.0, mod = 1.0; var diff = absdif(this, aNumber) % mod; var modhalf = mod * 0.5; ^modhalf - absdif(diff, modhalf) } lcurve { arg a = 1.0, m = 0.0, n = 1.0, tau = 1.0; var rTau, x = this.neg; ^if(tau == 1.0) { a * (m * exp(x) + 1) / (n * exp(x) + 1) } { rTau = tau.reciprocal; a * (m * exp(x) * rTau + 1) / (n * exp(x) * rTau + 1) } } gauss { arg standardDeviation; ^((((-2*log(1.0.rand)).sqrt * sin(2pi.rand)) * standardDeviation) + this) } gaussCurve { arg a = 1.0, b = 0.0, c = 1.0; ^a * (exp(squared(this - b) / (-2.0 * squared(c)))) } asPoint { ^Point.new(this, this) } asWarp { arg spec; ^CurveWarp.new(spec, this) } // scheduled Routine support wait { ^this.yield } waitUntil { ^(this - thisThread.beats).max(0).yield } sleep { var thread = thisThread; thread.clock.sched(this, { thread.next; nil }); nil.yield; } printOn { arg stream; stream.putAll(this.asString); } storeOn { arg stream; stream.putAll(this.asString); } rate { ^'scalar' } // scalarRate constant asAudioRateInput { ^if(this == 0) { Silent.ar } { DC.ar(this) } } madd { arg mul, add; ^(this * mul) + add; } lag { ^this } lag2 { ^this } lag3 { ^this } lagud { ^this } lag2ud { ^this } lag3ud { ^this } varlag { ^this } slew { ^this } poll { arg trig = 10, label, trigid = -1; ^Poll(trig, this, label, trigid) } // support for writing synth defs writeInputSpec { arg file, synth; var constIndex = synth.constants.at(this.asFloat); if (constIndex.isNil) { Error("SimpleNumber-writeInputSpec constant not found: " ++ this.asFloat).throw; }; file.putInt32(-1); file.putInt32(constIndex); } series { arg second, last; _SimpleNumberSeries ^this.primitiveFailed /* var step, size; second = second ?? { if (this < last) { this + 1 } { this - 1 } }; step = second - this; size = floor((last - this) / step + 0.001).asInteger + 1; ^Array.series(size, this, step) */ } seriesIter { arg second, last; var step, size; if (second.isNil) { last = last ? inf; step = if (this < last, 1, -1); }{ last ?? { last = if (second < this, -inf, inf) }; step = second - this; }; ^if (step < 0) { r { var val = this; while { val >= last; }{ val.yield; val = val + step; }; } }{ r { var val = this; while { val <= last; }{ val.yield; val = val + step; }; } } } degreeToKey { arg scale, stepsPerOctave = 12; var scaleDegree = this.round.asInteger; var accidental = (this - scaleDegree) * 10.0; ^scale.performDegreeToKey(scaleDegree, stepsPerOctave, accidental) } keyToDegree { arg scale, stepsPerOctave=12; ^scale.performKeyToDegree(this, stepsPerOctave) } nearestInList { arg list; // collection is sorted ^list.performNearestInList(this); } nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted ^scale.performNearestInScale(this, stepsPerOctave); } partition { arg parts=2, min=1; // randomly partition a number into parts of at least min size : var n = this - (min - 1 * parts); ^(1..n-1).scramble.keep(parts-1).sort.add(n).differentiate + (min - 1) } nextTimeOnGrid { arg clock; ^clock.nextTimeOnGrid(this, 0); } playAndDelta {} asQuant { ^Quant(this) } // a clock format inspired by ISO 8601 time interval display (truncated representation) // receiver is a time in seconds, returns string "ddd:hh:mm:ss:ttt" where t is milliseconds // see String:asSecs for complement asTimeString { arg precision = 0.001, maxDays = 365, dropDaysIfPossible = true; var decimal, days, hours, minutes, seconds, mseconds; decimal = this.asInteger; days = decimal.div(86400).min(maxDays); days = if(dropDaysIfPossible and: { days == 0 }) { days = "" } { days.asString.padLeft(3, "0").add($:); }; hours = (decimal.div(3600) % 24).asString.padLeft(2, "0").add($:); minutes = (decimal.div(60) % 60).asString.padLeft(2, "0").add($:); seconds = (decimal % 60).asString.padLeft(2, "0").add($:); mseconds = (this.frac / precision).round(precision).asInteger.asString.padLeft(3, "0"); ^days ++ hours ++ minutes ++ seconds ++ mseconds } asFraction {|denominator=100, fasterBetter=true| _AsFraction // asFraction will return a fraction that is the best approximation up to the given // denominator. // if fasterBetter is true it may find a much closer approximation and do it faster. ^this.primitiveFailed } prSimpleNumberSeries { arg second, last; _SimpleNumberSeries ^this.primitiveFailed } asBufWithValues { ^this } schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency| clock.sched(this, { if (lag != 0) { SystemClock.sched(lag, { server.sendBundle(latency ? server.latency, *bundleArray) }) } { server.sendBundle(latency ? server.latency, *bundleArray) } }) } } SuperCollider-Source/SCClassLibrary/Common/GUI/backwardsCompatibility/000755 000765 000024 00000000000 13007315613 027043 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/Base/000755 000765 000024 00000000000 13007315613 023222 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/000755 000765 000024 00000000000 13007315613 023640 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/tools/000755 000765 000024 00000000000 13007315613 023510 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/tools/guicrucial/000755 000765 000024 00000000000 13007315613 025637 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/tools/HelpBrowser.sc000644 000765 000024 00000020071 12766171707 026312 0ustar00crucialstaff000000 000000 HelpBrowser { classvar singleton; classvar <>defaultHomeUrl; classvar <>openNewWindows = false; var <>homeUrl; var "], [\Reload, "Reload"]].do { |item| var str = item[1]; var w = str.bounds.width + hPad; toolbar[item[0]] = Button( window, Rect(x,y,w,h) ).states_([[str]]); x = x + w + 2; }; x = x + 10; str = "Quick lookup:"; w = str.bounds.width + 5; StaticText(window, Rect(x,y,w,h)).string_(str); x = x + w; w = 200; srchBox = TextField.new( window, Rect(x,y,w,h) ).resize_(1); if(GUI.current.id == \qt) { srchBox.toolTip = "Smart quick help lookup. Prefix with # to just search."; }; srchBox.action = {|x| if(x.string.notEmpty) { this.goTo(if(x.string.first==$#) {SCDoc.helpTargetUrl ++ "/Search.html" ++ x.string} {SCDoc.findHelpFile(x.string)} ); } }; openNewWin = aNewWin; x = x + w + 10; if(GUI.current.respondsTo(\checkBox)) { str = "Open links in new window"; w = str.bounds.width + 50; CheckBox.new (window, Rect(x, y, w, h) ) .resize_(1) .string_(str) .value_(openNewWin) .action_({ |b| openNewWin = b.value }); } { str = "Open links in same window"; w = str.bounds.width + 5; Button.new( window, Rect(x, y, w, h) ) .resize_(1) .states_([[str],["Open links in new window"]]) .value_(openNewWin.asInteger) .action_({ |b| openNewWin = b.value.asBoolean }); }; x = 0; y = marg + h + 5; w = winRect.width; findView = CompositeView(window, Rect(x,y,w,h+10)).visible_(false).resize_(2); y = marg; w = 200; x = winRect.width - marg - w; txtFind = TextField.new( findView, Rect(x,y,w,h) ).resize_(3); str = "Find text in document:"; w = str.bounds.width + 5; x = x - w - 5; lblFind = StaticText.new( findView, Rect(x, y, w, h) ) .string_(str) .resize_(3); x = 5; y = marg + h + 5; w = winRect.width - 10; h = winRect.height - y - marg; webView = WebView.new( window, Rect(x,y,w,h) ).resize_(5); webView.html = "Please wait while initializing Help... (This might take several seconds the first time)"; if(webView.respondsTo(\setFontFamily)) { webView.setFontFamily(\fixed, Platform.case( \osx, { "Monaco" }, \linux, { "Andale Mono" }, { "Monospace" } )) }; webView.onLoadFinished = { this.stopAnim; window.name = "SuperCollider Help: %".format(webView.title); }; webView.onLoadFailed = { this.stopAnim }; webView.onLinkActivated = {|wv, url| var redirected, newPath, oldPath; redirected = this.redirectTextFile(url); if (not(redirected)) { if(openNewWin) { #newPath, oldPath = [url,webView.url].collect {|x| if(x.notEmpty) {x.findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1]} }; }; if(newPath!=oldPath) { HelpBrowser.new(newWin:true).goTo(url); } { this.goTo(url); }; } }; if(webView.respondsTo(\onReload_)) { webView.onReload = {|wv, url| WebView.clearCache; this.goTo(url); }; }; if(webView.respondsTo(\onJavaScriptMsg_)) { webView.onJavaScriptMsg = {|wv, err, type| "JavaScript %: %".format(if(type==0,"Error","Message"),err).postln; }; }; toggleFind = { if(findView.visible.not) { saveSize = webView.bounds; h = findView.bounds.height + marg; webView.bounds = Rect(saveSize.left,saveSize.top+h,saveSize.width,saveSize.height-h); findView.visible = true; txtFind.focus; } { webView.bounds = saveSize; findView.visible = false; }; }; webView.enterInterpretsSelection = true; webView.keyDownAction = { arg view, char, mods; if( (char.ascii == 13) && (mods.isCtrl || mods.isCmd || mods.isShift) ) { view.tryPerform(\evaluateJavaScript,"selectLine()"); }; }; window.view.keyDownAction = { arg view, char, mods, uni, kcode, key; if( ((key == 70) && mods.isCtrl) || (char == $f && mods.isCmd) ) { toggleFind.value; }; if(char.ascii==27) { if(findView.visible) {toggleFind.value}; } }; toolbar[\Back].action = { this.goBack }; toolbar[\Forward].action = { this.goForward }; toolbar[\Reload].action = { this.goTo( webView.url ) }; txtFind.action = { |x| webView.findText( x.string ) }; } redirectTextFile {|url| var plainTextExts = #[".sc",".scd",".txt",".schelp",".rtf"]; plainTextExts.do {|x| var path; if(url.endsWith(x)) { path = url.replace("%20"," ") .findRegexp("(^\\w+://)?([^#]+)(#.*)?")[1..].flop[1][1]; if(File.exists(path)) { path.openDocument; } { webView.url = SCDoc.helpTargetUrl++"/BrokenLink.html#"++path; window.front; }; ^true } }; ^false } startAnim { var progress = [">---","->--","-->-","--->"]; if(loading.not) { loading = true; Routine { block {|break| loop { progress.do {|p| window.name = ("Loading"+p); 0.3.wait; if(loading.not) {break.value}; }; }; }; // lblStatus.string_(""); }.play(AppClock); }; } stopAnim { loading = false; } } SuperCollider-Source/SCClassLibrary/Common/GUI/tools/Inspector.sc000644 000765 000024 00000014546 12756534417 026036 0ustar00crucialstaff000000 000000 Inspector { classvar index, 0) { // ins StaticText(view, Rect(10, 5, 100, 15)) .font_(Font.sansSerif(10).boldVariant) .string_("Inputs"); inmeters = Array.fill( numIns, { arg i; var comp; comp = CompositeView(innerView, Rect(0, 0, meterWidth, 195)).resize_(5); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font.sansSerif(9).boldVariant) .string_(i.asString); levelIndic = LevelIndicator( comp, Rect(0, 0, meterWidth, 180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); }; if((numIns > 0) && (numOuts > 0)) { // divider UserView(innerView, Rect(0, 0, meterWidth, 180)).drawFunc_( { try { Pen.color = \QPalette.asClass.new.windowText; } { Pen.color = Color.white; }; Pen.line(((meterWidth + gapWidth) * 0.5)@0, ((meterWidth + gapWidth) * 0.5)@180); Pen.stroke; }); }; // outs if(numOuts > 0) { StaticText(view, Rect(10 + if(numIns > 0) { (numIns + 2) * (meterWidth + gapWidth) } { 0 }, 5, 100, 15)) .font_(Font.sansSerif(10).boldVariant) .string_("Outputs"); outmeters = Array.fill( numOuts, { arg i; var comp; comp = CompositeView(innerView, Rect(0, 0, meterWidth, 195)); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font.sansSerif(9).boldVariant) .string_(i.asString); levelIndic = LevelIndicator( comp, Rect(0, 0, meterWidth, 180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); }; this.setSynthFunc(inmeters, outmeters); startResponderFunc = {this.startResponders}; this.start; } setSynthFunc { var numRMSSamps, numRMSSampsRecip; synthFunc = { //responders and synths are started only once per server var numIns = server.options.numInputBusChannels; var numOuts = server.options.numOutputBusChannels; numRMSSamps = server.sampleRate / updateFreq; numRMSSampsRecip = 1 / numRMSSamps; server.bind( { var insynth, outsynth; if(numIns > 0, { insynth = SynthDef(server.name ++ "InputLevels", { var in = In.ar(NumOutputBuses.ir, numIns); SendPeakRMS.kr(in, updateFreq, 3, "/" ++ server.name ++ "InLevels") }).play(RootNode(server), nil, \addToHead); }); if(numOuts > 0, { outsynth = SynthDef(server.name ++ "OutputLevels", { var in = In.ar(0, numOuts); SendPeakRMS.kr(in, updateFreq, 3, "/" ++ server.name ++ "OutLevels") }).play(RootNode(server), nil, \addToTail); }); if (serverCleanupFuncs.isNil) { serverCleanupFuncs = IdentityDictionary.new; }; serverCleanupFuncs.put(server, { insynth.free; outsynth.free; ServerTree.remove(synthFunc, server); }); }); }; } startResponders { var numRMSSamps, numRMSSampsRecip; //responders and synths are started only once per server numRMSSamps = server.sampleRate / updateFreq; numRMSSampsRecip = 1 / numRMSSamps; if(numIns > 0) { inresp = OSCFunc( {|msg| { try { var channelCount = min(msg.size - 3 / 2, numIns); channelCount.do {|channel| var baseIndex = 3 + (2*channel); var peakLevel = msg.at(baseIndex); var rmsValue = msg.at(baseIndex + 1); var meter = inmeters.at(channel); if (meter.notNil) { if (meter.isClosed.not) { meter.peakLevel = peakLevel.ampdb.linlin(dBLow, 0, 0, 1, \min); meter.value = rmsValue.ampdb.linlin(dBLow, 0, 0, 1); } } } } { |error| if(error.isKindOf(PrimitiveFailedError).not) { error.throw } }; }.defer; }, ("/" ++ server.name ++ "InLevels").asSymbol, server.addr).fix; }; if(numOuts > 0) { outresp = OSCFunc( {|msg| { try { var channelCount = min(msg.size - 3 / 2, numOuts); channelCount.do {|channel| var baseIndex = 3 + (2*channel); var peakLevel = msg.at(baseIndex); var rmsValue = msg.at(baseIndex + 1); var meter = outmeters.at(channel); if (meter.notNil) { if (meter.isClosed.not) { meter.peakLevel = peakLevel.ampdb.linlin(dBLow, 0, 0, 1, \min); meter.value = rmsValue.ampdb.linlin(dBLow, 0, 0, 1); } } } } { |error| if(error.isKindOf(PrimitiveFailedError).not) { error.throw } }; }.defer; }, ("/" ++ server.name ++ "OutLevels").asSymbol, server.addr).fix; }; } start { if(serverMeterViews.isNil) { serverMeterViews = IdentityDictionary.new; }; if(serverMeterViews[server].isNil) { serverMeterViews.put(server, List()); }; if(serverMeterViews[server].size == 0) { ServerTree.add(synthFunc, server); if(server.serverRunning, synthFunc); // otherwise starts when booted }; serverMeterViews[server].add(this); if (server.serverRunning) { this.startResponders } { ServerBoot.add (startResponderFunc, server) } } stop { serverMeterViews[server].remove(this); if(serverMeterViews[server].size == 0 and: (serverCleanupFuncs.notNil)) { serverCleanupFuncs[server].value; serverCleanupFuncs.removeAt(server); }; (numIns > 0).if( { inresp.free; }); (numOuts > 0).if( { outresp.free; }); ServerBoot.remove(startResponderFunc, server) } remove { view.remove } } ServerMeter { var smallSize, <>largeSize; // runtime (mutable at runtime) var screenBounds.width) { x = floor(right % screenBounds.width / (w + 10)) * (w + 10) + 10 }; x = x + screenBounds.left; ^Rect(x, y, w, h) } *new { arg server, numChannels = 2, index = 0, bufsize = 4096, zoom = 1.0, rate = \audio, view, bufnum; var bus; if(server.isNil) {server = Server.default}; if(server.isLocal.not) {Error("Can not scope on remote server.").throw}; bus = Bus(rate, index, numChannels, server); ^super.new.initStethoscope( server, view, bus, bufsize, 1024 * zoom.asFloat.reciprocal ); } initStethoscope { arg server_, parent, bus_, bufsize_, cycle_; var singleBus; server = server_; synth = BusScopeSynth(server); maxBufSize = max(bufsize_, 128); bus = bus_; singleBus = bus.class === Bus; aBusSpec = ControlSpec(0, server.options.numAudioBusChannels, step:1); cBusSpec = ControlSpec(0, server.options.numControlBusChannels, step:1); if( singleBus ) { busSpec = if(bus.rate===\audio){aBusSpec}{cBusSpec}; }; cycleSpec = ControlSpec( maxBufSize, 64, \exponential ); yZoomSpec = ControlSpec( 0.125, 16, \exponential ); cycle = cycleSpec.constrain(cycle_); yZoom = 1.0; smallSize = Size(250,250); largeSize = Size(500,500); makeGui = { arg parent; var gizmo; // WINDOW, WRAPPER VIEW if( window.notNil ) {window.close}; if( parent.isNil ) { view = window = Window( bounds: (smallSize).asRect.center_(Window.availableBounds.center) ).name_("Stethoscope"); }{ view = View( parent, Rect(0,0,250,250) ); window = nil; }; // WIDGETS scopeView = ScopeView(); scopeView.server = server; scopeView.canFocus = true; cycleSlider = Slider().orientation_(\horizontal).value_(cycleSpec.unmap(cycle)); yZoomSlider = Slider().orientation_(\vertical).value_(yZoomSpec.unmap(yZoom)); rateMenu = PopUpMenu().items_(["Audio","Control"]).enabled_(singleBus); idxNumBox = NumberBox().decimals_(0).step_(1).scroll_step_(1).enabled_(singleBus); chNumBox = NumberBox().decimals_(0).step_(1).scroll_step_(1) .clipLo_(1).clipHi_(128).enabled_(singleBus); if( singleBus ) { rateMenu.value_(if(bus.rate===\audio){0}{1}); idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index); chNumBox.value_(bus.numChannels); }; styleMenu = PopUpMenu().items_(["Tracks","Overlay","X/Y"]); // LAYOUT gizmo = "999".bounds( idxNumBox.font ).width + 20; idxNumBox.fixedWidth = gizmo; chNumBox.fixedWidth = gizmo; idxNumBox.align = \center; chNumBox.align = \center; view.layout = GridLayout() .add( HLayout( rateMenu, idxNumBox, chNumBox, nil, styleMenu ).margins_(0).spacing_(2), 0, 0 ) .add(scopeView,1,0) .add(yZoomSlider.maxWidth_(15), 1,1) .add(cycleSlider.maxHeight_(15), 2,0) .margins_(2).spacing_(2); // ACTIONS cycleSlider.action = { |me| setCycle.value(cycleSpec.map(me.value)) }; yZoomSlider.action = { |me| setYZoom.value(yZoomSpec.map(me.value)) }; idxNumBox.action = { |me| setIndex.value(me.value) }; chNumBox.action = { |me| setNumChannels.value(me.value) }; rateMenu.action = { |me| setRate.value(me.value) }; styleMenu.action = { |me| setStyle.value(me.value) }; view.asView.keyDownAction = { |v, char, mod| this.keyDown(char, mod) }; view.onClose = { view = nil; this.quit; }; // LAUNCH scopeView.focus; if( window.notNil ) { window.front }; }; setCycle = { arg val; cycle = val; synth.setCycle(val); }; setYZoom = { arg val; yZoom = val; scopeView.yZoom = val; }; // NOTE: assuming a single Bus setIndex = { arg i; bus = Bus(bus.rate, i, bus.numChannels, bus.server); synth.setBusIndex(i); }; // NOTE: assuming a single Bus setNumChannels = { arg n; // we have to restart the whole thing: bus = Bus(bus.rate, bus.index, n, bus.server); updateColors.value; this.run; }; // NOTE: assuming a single Bus setRate = { arg val; val.switch ( 0, { bus = Bus(\audio, bus.index, bus.numChannels, bus.server); busSpec = aBusSpec; }, 1, { bus = Bus(\control, bus.index, bus.numChannels, bus.server); busSpec = cBusSpec; } ); synth.setRate(val); idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index); this.index = bus.index; // ensure conformance with busSpec; updateColors.value; }; setStyle = { arg val; if(this.numChannels < 2 and: { val == 2 }) { "Stethoscope: x/y scoping with one channel only; y will be a constant 0".warn; }; scopeView.style = val; }; updateColors = { var colors; bus.do { |b| var c = if(b.rate === \audio){Color.new255(255, 218, 000)}{Color.new255(125, 255, 205)}; colors = colors ++ Array.fill(b.numChannels, c); }; scopeView.waveColors = colors; }; makeGui.value(parent); updateColors.value; ServerTree.add(this, server); ServerQuit.add(this, server); this.run; } doOnServerTree { this.run; } doOnServerQuit { this.stop; } run { synth.play(maxBufSize, bus, cycle); if( view.notNil && synth.bufferIndex.notNil) { scopeView.bufnum = synth.bufferIndex; scopeView.start; }; } stop { if( view.notNil ) { {scopeView.stop}.defer }; synth.stop; } quit { var win; this.stop; synth.free; if( window.notNil and: { window.isClosed.not } ) { win = window; window = nil; { win.close }.defer; }; ServerTree.remove(this, server); ServerQuit.remove(this, server); } setProperties { arg numChannels, index, bufsize, zoom, rate; var new_bus; // process args if(index.notNil || numChannels.notNil || rate.notNil) { bus = if(bus.class === Bus) { Bus ( rate ? bus.rate, index ? bus.index, numChannels ? bus.numChannels, server ) }{ Bus ( rate ? \audio, index ? 0, numChannels ? 2, server ) }; }; if(bufsize.notNil) { maxBufSize = max(bufsize, 128) }; // set other vars related to args busSpec = if(bus.rate === \audio) {aBusSpec} {cBusSpec}; cycleSpec = ControlSpec( maxBufSize, 64, \exponential ); if(zoom.notNil) { cycle = cycleSpec.constrain( 1024 * zoom.asFloat.reciprocal ) }; // update GUI cycleSlider.value = cycleSpec.unmap(cycle); rateMenu.value_(if(bus.rate === \audio){0}{1}).enabled_(true); idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index).enabled_(true); chNumBox.value_(bus.numChannels).enabled_(true); updateColors.value; if (synth.isRunning) { synth.play(maxBufSize, bus, cycle) }; } bufsize { ^maxBufSize } bus_ { arg b; var isSingle = b.class === Bus; bus = b; if( isSingle ) { busSpec = if(bus.rate === \audio) {aBusSpec} {cBusSpec}; rateMenu.value = if(b.rate===\audio){0}{1}; idxNumBox.clipLo_(busSpec.minval).clipHi_(busSpec.maxval).value_(bus.index); chNumBox.value = b.numChannels; }{ busSpec = nil; rateMenu.value = nil; idxNumBox.string = "-"; chNumBox.string = "-"; }; rateMenu.enabled = isSingle; idxNumBox.enabled = isSingle; chNumBox.enabled = isSingle; updateColors.value; if (synth.isRunning) { synth.play(maxBufSize, bus, cycle); }; } numChannels { var num; if( bus.class === Bus ) { ^bus.numChannels; }{ num = 0; bus.do { |b| num = num + b.numChannels }; ^num; } } // will always be clipped between 0 and the amount of channels // at the beginning of the current run numChannels_ { arg n; if( (bus.class === Bus).not ) { ^this }; setNumChannels.value(n); chNumBox.value = n; } index { if( bus.class === Bus ) { ^bus.index } { nil } } index_ { arg i; if( (bus.class === Bus).not ) { ^this }; setIndex.value( busSpec.constrain(i) ); idxNumBox.value = i; } rate { if( bus.class === Bus ) { ^bus.rate } { nil } } rate_ { arg argRate=\audio; var val; if( (bus.class === Bus).not ) { ^this }; val = if(argRate===\audio){0}{1}; setRate.value(val); rateMenu.value = val; } switchRate { if( bus.class === Bus ) { this.rate = if(bus.rate === \control) {\audio} {\control}; } } // [0, 1] -> [64, 8192] frames cycle_ { arg val; setCycle.value( cycleSpec.constrain(val) ); cycleSlider.value = cycleSpec.unmap(val); } xZoom_ { arg val; this.cycle = 1024 * val.asFloat.reciprocal } xZoom { ^(1024 * cycle.reciprocal) } zoom { ^this.xZoom } zoom_ { arg val; this.xZoom_(val ? 1) } // [0, 1] -> [0.125, 16] y scaling factor yZoom_ { arg val; setYZoom.value( yZoomSpec.constrain(val) ); yZoomSlider.value = yZoomSpec.unmap(val); } style_ { arg val; setStyle.value(val); styleMenu.value = val; } size_ { arg value; var sz = value.asSize; if( window.notNil ) { window.setInnerExtent(sz.width,sz.height) }; } toggleSize { if(window.notNil) { sizeToggle = sizeToggle.not; if(sizeToggle) { this.size = largeSize } { this.size = smallSize }; } } toInputBus { var i = server.options.numOutputBusChannels; var c = server.options.numInputBusChannels; this.bus = Bus(\audio, i, c, server); } toOutputBus { var c = server.options.numOutputBusChannels; this.bus = Bus(\audio, 0, c, server); } keyDown { arg char, mod; if (mod != 0) { ^false }; case ( { char === $i }, { this.toInputBus }, { char === $o }, { this.toOutputBus }, { char === $ }, { this.run }, { char === $s }, { this.style = (scopeView.style + 1).wrap(0,2) }, { char === $S }, { this.style = 2 }, { char === $j }, { if(this.index.notNil) {this.index = this.index - 1} }, { char === $k }, { this.switchRate; }, { char === $l }, { if(this.index.notNil) {this.index = this.index + 1} }, { char === $- }, { cycleSlider.increment; cycleSlider.doAction }, { char === $+ }, { cycleSlider.decrement; cycleSlider.doAction }, { char === $* }, { yZoomSlider.increment; yZoomSlider.doAction }, { char === $_ }, { yZoomSlider.decrement; yZoomSlider.doAction }, { char === $m }, { this.toggleSize }, { char === $.}, { this.stop }, { ^false } ); ^true; } } BusScopeSynth { // Encapsulate management of server resources var server, buffer, synthDefName, synth; var playThread; *new { arg server; var instance; server = server ? Server.default; instance = super.newCopyArgs(server); ServerQuit.add(instance); ^instance; } play { arg bufSize, bus, cycle; var synthDef; var synthArgs; var bufIndex; var busChannels; if(server.serverRunning.not) { ^this }; this.stop; if (buffer.isNil) { buffer = ScopeBuffer.alloc(server); synthDefName = "stethoscope" ++ buffer.index.asString; }; bufIndex = buffer.index.asInteger; if( bus.class === Bus ) { busChannels = bus.numChannels.asInteger; synthDef = SynthDef(synthDefName, { arg busIndex, rate, cycle; var z; z = Select.ar(rate, [ In.ar(busIndex, busChannels), K2A.ar(In.kr(busIndex, busChannels))] ); ScopeOut2.ar(z, bufIndex, bufSize, cycle ); }); synthArgs = [\busIndex, bus.index.asInteger, \rate, if('audio' === bus.rate, 0, 1), \cycle, cycle]; }{ synthDef = SynthDef(synthDefName, { arg cycle; var z = Array(); bus.do { |b| z = z ++ b.ar }; ScopeOut2.ar(z, bufIndex, bufSize, cycle); }); synthArgs = [\cycle, cycle]; }; playThread = fork { synthDef.send(server); server.sync; synth = Synth.tail(RootNode(server), synthDef.name, synthArgs); } } stop { if (playThread.notNil) { playThread.stop; playThread = nil }; if (synth.notNil) { // avoid node not found if stoppedby cmd-period already server.sendBundle(nil, ['/error', -1], [11, synth.nodeID], ['/error', -2]); synth = nil }; } isRunning { ^playThread.notNil } bufferIndex { ^ buffer !? { buffer.index } } setBusIndex { arg index; if( synth.notNil ) { synth.set(\busIndex, index) }; } setRate { arg rate; // 0 = audio, 1 = control if( synth.notNil ) { synth.set(\rate, rate) }; } setCycle { arg frames; if( synth.notNil ) { synth.set(\cycle, frames) }; } free { this.stop; if (buffer.notNil) { buffer.free; buffer = nil; }; ServerQuit.remove(this, server); } doOnServerQuit { buffer = nil; synth = nil; } } SuperCollider-Source/SCClassLibrary/Common/GUI/tools/guicrucial/gui.sc000644 000765 000024 00000001106 12766171707 026767 0ustar00crucialstaff000000 000000 + Object { gui { arg parent,bounds ... args; ^this.guiClass.new(this).performList(\gui,[parent,bounds] ++ args); } guiClass { ^ObjectGui } } // just a label with the name + String { guiClass { ^StringGui } } + Symbol { guiClass { ^StringGui } } + SimpleNumber { guiClass { ^StringGui } } + Boolean { guiClass { ^StringGui } } + Nil { guiClass { ^StringGui } // create a window/FlowView if you don't supply a parent to: thing.gui asPageLayout { arg name,bounds; ^PageLayout(name.asString,bounds ).front } asFlowView { arg bounds; ^FlowView(nil,bounds) } } SuperCollider-Source/SCClassLibrary/Common/GUI/tools/guicrucial/ObjectGui.sc000644 000765 000024 00000005322 12756534417 030062 0ustar00crucialstaff000000 000000 ObjectGui : SCViewHolder { /* this is a controller class: it creates the views and implements the relationship between them and the model model: the object for which this is a graphical user interface view: this.view is the flow view (aka the arg layout) that is passed to guiBody individual views/widgets are placed in it and their actions talk to either this object or the model */ var 40,{ string = string.copyRange(0,40) ++ "..."; }); dragSource = GUI.dragSource.new(layout,Rect(0,0,(string.bounds(font).width + 10).max(70),GUI.skin.buttonHeight)) .stringColor_(Color.new255(70, 130, 200)) .font_(font) .background_(Color.white) .align_(\left) .beginDragAction_({ model }) .object_(string); } } SuperCollider-Source/SCClassLibrary/Common/GUI/tools/guicrucial/PageLayout.sc000644 000765 000024 00000007621 12766171707 030265 0ustar00crucialstaff000000 000000 PageLayout { // a Window with a FlowView on it // it also manages onClose handlers for use by ObjectGui's MVC model, var isClosed=false,boundsWereExplicit=false,<>onClose; var autoRemoves; *new { arg title,bounds,margin,background,scroll=true,front=true; ^super.new.init(title,bounds,margin,background,scroll,front) } init { arg title,bounds,argMargin,background,argScroll=true,front=true; var w,v; if(bounds.notNil,{ boundsWereExplicit = true; bounds = bounds.asRect },{ bounds = Window.screenBounds.insetAll(10,20,0,25) }); window = Window.new("< " ++ title.asString ++ " >",bounds, border: true, scroll: argScroll ); window.onClose_({ this.close }); if(background.isKindOf(Boolean),{ // bwcompat : metal=true/false background = background.if(nil,{Color(0.88, 0.94, 0.87, 1)}) }); if(background.notNil,{ window.view.background_(background); }); isClosed = false; view = FlowView.new( window, window.view.bounds.insetAll(4,4,0,0) ); view.decorator.margin_(argMargin ?? {GUI.skin.margin}); autoRemoves = []; if(front,{ window.front }); } *on { arg window,bounds,margin,background; ^super.new.initOn(window,bounds,margin,background) } initOn { arg argWindow,bounds,argMargin,background; window = argWindow; view = FlowView.new(window,bounds); if(argMargin.notNil,{ view.decorator.margin_(argMargin); }); autoRemoves = []; } asView { ^this.view.asView } asFlowView { arg bounds; ^if(bounds.notNil,{ FlowView(this,bounds) },{ this.view }) } bounds { ^this.view.bounds } add { arg view; this.view.add(view); } asPageLayout { arg name,bounds; if(isClosed,{ ^this.class.new(name,bounds) },{ ^this }) } startRow { this.view.startRow; } indentedRemaining { ^this.view.indentedRemaining } *guify { arg parent,title,width,height,background; ^parent ?? { this.new(title,width@height,background: background ) } } // act like a GUI window checkNotClosed { ^isClosed.not } front { window.front } hide { window.alpha = 0.0; } show { window.alpha = 1.0; } close { // called when the GUI.window closes if(isClosed.not,{ isClosed = true; autoRemoves.do({ arg updater; updater.remove(false) }); autoRemoves = nil; window.close; onClose.value; NotificationCenter.notify(window,\didClose); window=view=nil; }); } refresh { window.refresh } hr { arg color,height=8,borderStyle=1; this.view.hr; } focus { arg index=0; var first; first = this.window.views.at(index); if(first.notNil,{first.focus }); } background_ { arg c; this.view.background_(c) } removeOnClose { arg dependant; autoRemoves = autoRemoves.add(dependant); } resizeToFit { arg reflow=false,center=false; var fs, b,wb,wbw,wbh; b = this.view.resizeToFit(reflow); wbw = b.width + 11; wbh = b.height + 15; window.setInnerExtent(wbw,wbh); if(center and: {window.respondsTo(\setTopLeftBounds)}) { // this should be a window method fs = GUI.window.screenBounds; wb = window.bounds; // bounds are inaccurate until the end of the code cycle/refresh wb.width = wbw; wb.height = wbh; // if height is less than 60% of full screen if(wbh <= (fs.height * 0.6),{ // then move its top to be level at golden ratio wb.top = fs.height - (fs.height / 1.6180339887); },{ wb.top = 0; }); // center it horizontally wb.left = (fs.width - wbw) / 2; window.setTopLeftBounds(wb); } } reflowAll { view.reflowAll; } fullScreen { window.bounds = GUI.window.screenBounds.insetAll(10,20,0,25); } endFullScreen { window.endFullScreen } flow { arg func,bounds; ^this.view.flow(func,bounds) } vert { arg func,bounds,spacing; ^this.view.vert(func,bounds,spacing) } horz { arg func,bounds,spacing; ^this.view.horz(func,bounds,spacing) } comp { arg func,bounds; ^this.view.comp(func,bounds) } scroll { arg ... args; ^this.view.performList(\scroll,args) } } SuperCollider-Source/SCClassLibrary/Common/GUI/tools/guicrucial/StringGui.sc000644 000765 000024 00000001565 12766171707 030127 0ustar00crucialstaff000000 000000 // just a label with the name of the object StringGui : ObjectGui { writeName {} gui { arg parent, bounds ... args; var layout,string,font; var width,height; layout=this.guify(parent,bounds); font = Font.new(*GUI.skin.fontSpecs); if(model.isString,{ string = " "++model; },{ // floats, integers, symbols will show more clearly what they are string = " "++model.asCompileString; }); if(string.size > 1024,{ string = string.copyRange(0,1024) ++ "..."; }); if(bounds.notNil,{ bounds = bounds.asRect; },{ bounds = Rect(0,0, string.bounds.width(font).max(30), GUI.skin.buttonHeight); }); this.view = StaticText.new(layout,bounds) .stringColor_(GUI.skin.fontColor) .font_(font) .background_(GUI.skin.background) .align_(\left) .object_(string); if(parent.isNil,{ layout.resizeToFit; layout.front }); } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Collections/000755 000765 000024 00000000000 13007315613 026116 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/000755 000765 000024 00000000000 13007315613 025260 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Core/000755 000765 000024 00000000000 13007315613 024530 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Files/000755 000765 000024 00000000000 13007315613 024702 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Math/000755 000765 000024 00000000000 13007315613 024531 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Math/PlotView.sc000644 000765 000024 00000052673 12756534417 026665 0ustar00crucialstaff000000 000000 Plot { var <>plotter, drawGrid; var plotColor, <>backgroundColor; var labelX, <>labelY; var valueCache; *initClass { StartUp.add { GUI.skin.put(\plot, ( gridColorX: QtGUI.palette.highlight, gridColorY: QtGUI.palette.highlight, fontColor: QtGUI.palette.windowText, plotColor: [QtGUI.palette.windowText, Color.blue.valueBlend(QtGUI.palette.windowText), Color.red.valueBlend(QtGUI.palette.windowText), Color.green(0.7).valueBlend(QtGUI.palette.windowText)], background: QtGUI.palette.base, gridLinePattern: nil, gridLineSmoothing: false, labelX: "", labelY: "", expertMode: false, gridFont: Font( Font.defaultSansFace, 9 ) )); } } *new { |plotter| ^super.newCopyArgs(plotter).init } init { var fontName; var gui = plotter.gui; var skin = GUI.skin.at(\plot); drawGrid = DrawGrid(bounds ? Rect(0,0,1,1),nil,nil); drawGrid.x.labelOffset = Point(0,4); drawGrid.y.labelOffset = Point(-10,0); skin.use { font = ~gridFont ?? { Font.default }; this.gridColorX = ~gridColorX; this.gridColorY = ~gridColorY; plotColor = ~plotColor; this.fontColor = ~fontColor; backgroundColor = ~background; this.gridLineSmoothing = ~gridLineSmoothing; this.gridLinePattern = ~gridLinePattern !? {~gridLinePattern.as(FloatArray)}; labelX = ~labelX; labelY = ~labelY; }; } bounds_ { |rect| var size = (try { "foo".bounds(font).height } ?? { font.size } * 1.5); plotBounds = if(rect.height > 40) { rect.insetBy(size, size) } { rect }; bounds = rect; valueCache = nil; drawGrid.bounds = plotBounds; } value_ { |array| value = array; valueCache = nil; } spec_ { |sp| spec = sp; if(gridOnY and: spec.notNil,{ drawGrid.vertGrid = spec.grid; },{ drawGrid.vertGrid = nil }) } domainSpec_ { |sp| domainSpec = sp; if(gridOnX and: domainSpec.notNil,{ drawGrid.horzGrid = domainSpec.grid; },{ drawGrid.horzGrid = nil }) } gridColorX_ { |c| drawGrid.x.gridColor = c; gridColorX = c; } gridColorY_ { |c| drawGrid.y.gridColor = c; gridColorY = c; } font_ { |f| font = f; drawGrid.font = f; } fontColor_ { |c| fontColor = c; drawGrid.fontColor = c; } gridLineSmoothing_ { |bool| drawGrid.smoothing = bool; } gridLinePattern_ { |pattern| drawGrid.linePattern = pattern; } gridOnX_ { |bool| gridOnX = bool; drawGrid.horzGrid = if(gridOnX,{domainSpec.grid},{nil}); } gridOnY_ { |bool| gridOnY= bool; drawGrid.vertGrid = if(gridOnY,{spec.grid},{nil}); } draw { this.drawBackground; drawGrid.draw; this.drawLabels; this.drawData; plotter.drawFunc.value(this); // additional elements } drawBackground { Pen.addRect(bounds); Pen.fillColor = backgroundColor; Pen.fill; } drawLabels { var sbounds; if(gridOnX and: { labelX.notNil }) { sbounds = try { labelX.bounds(font) } ? 0; Pen.font = font; Pen.strokeColor = fontColor; Pen.stringAtPoint(labelX, plotBounds.right - sbounds.width @ plotBounds.bottom ) }; if(gridOnY and: { labelY.notNil }) { sbounds = try { labelY.bounds(font) } ? 0; Pen.font = font; Pen.strokeColor = fontColor; Pen.stringAtPoint(labelY, plotBounds.left - sbounds.width - 3 @ plotBounds.top ) }; } domainCoordinates { |size| var val = this.resampledDomainSpec.unmap(plotter.domain ?? { (0..size-1) }); ^plotBounds.left + (val * plotBounds.width); } dataCoordinates { var val = spec.warp.unmap(this.prResampValues); ^plotBounds.bottom - (val * plotBounds.height); // measures from top left (may be arrays) } resampledSize { ^min(value.size, plotBounds.width / plotter.resolution) } resampledDomainSpec { var offset = if(this.hasSteplikeDisplay) { 0 } { 1 }; ^domainSpec.copy.maxval_(this.resampledSize - offset) } drawData { var mode = plotter.plotMode; var ycoord = this.dataCoordinates; var xcoord = this.domainCoordinates(ycoord.size); Pen.use { Pen.width = 1.0; Pen.joinStyle = 1; plotColor = plotColor.as(Array); Pen.addRect(plotBounds); Pen.clip; // clip curve to bounds. if(ycoord.at(0).isSequenceableCollection) { // multi channel expansion ycoord.flop.do { |y, i| Pen.beginPath; this.perform(mode, xcoord, y); Pen.strokeColor = plotColor.wrapAt(i); Pen.stroke; } } { Pen.beginPath; Pen.strokeColor = plotColor.at(0); this.perform(mode, xcoord, ycoord); Pen.stroke; }; Pen.joinStyle = 0; }; } // modes linear { |x, y| Pen.moveTo(x.first @ y.first); y.size.do { |i| Pen.lineTo(x[i] @ y[i]); } } points { |x, y| var size = min(bounds.width / value.size * 0.25, 4); y.size.do { |i| Pen.addArc(x[i] @ y[i], 0.5, 0, 2pi); if(size > 2) { Pen.addArc(x[i] @ y[i], size, 0, 2pi); }; } } plines { |x, y| var size = min(bounds.width / value.size * 0.25, 3); Pen.moveTo(x.first @ y.first); y.size.do { |i| var p = x[i] @ y[i]; Pen.lineTo(p); Pen.addArc(p, size, 0, 2pi); Pen.moveTo(p); } } levels { |x, y| Pen.smoothing_(false); y.size.do { |i| Pen.moveTo(x[i] @ y[i]); Pen.lineTo(x[i + 1] ?? { plotBounds.right } @ y[i]); } } steps { |x, y| Pen.smoothing_(false); Pen.moveTo(x.first @ y.first); y.size.do { |i| Pen.lineTo(x[i] @ y[i]); Pen.lineTo(x[i + 1] ?? { plotBounds.right } @ y[i]); } } // editing editDataIndex { |index, x, y, plotIndex| // WARNING: assuming index is in range! var val = this.getRelativePositionY(y); plotter.editFunc.value(plotter, plotIndex, index, val, x, y); value.put(index, val); valueCache = nil; } editData { |x, y, plotIndex| var index = this.getIndex(x); this.editDataIndex( index, x, y, plotIndex ); } editDataLine { |pt1, pt2, plotIndex| var ptLeft, ptRight, ptLo, ptHi; var xSpec, ySpec; var i1, i2, iLo, iHi; var val; // get indexes related to ends of the line i1 = this.getIndex(pt1.x); i2 = this.getIndex(pt2.x); // if both ends at same index, simplify if( i1 == i2 ) { ^this.editDataIndex( i2, pt2.x, pt2.y, plotIndex ); }; // order points and indexes if( i1 < i2 ) { iLo = i1; iHi = i2; ptLeft = pt1; ptRight = pt2; }{ iLo = i2; iHi = i1; ptLeft = pt2; ptRight = pt1; }; // if same value all over, simplify if( ptLeft.y == ptRight.y ) { val = this.getRelativePositionY(ptLeft.y); while( {iLo <= iHi} ) { value.put( iLo, val ); iLo = iLo + 1; }; // trigger once for second end of the line plotter.editFunc.value(plotter, plotIndex, i2, val, pt2.x, pt2.y); valueCache = nil; ^this; }; // get actual points corresponding to indexes xSpec = ControlSpec( ptLeft.x, ptRight.x ); ySpec = ControlSpec( ptLeft.y, ptRight.y ); ptLo = Point(); ptHi = Point(); ptLo.x = domainSpec.unmap(iLo) * plotBounds.width + plotBounds.left; ptHi.x = domainSpec.unmap(iHi) * plotBounds.width + plotBounds.left; ptLo.y = ySpec.map( xSpec.unmap(ptLo.x) ); ptHi.y = ySpec.map( xSpec.unmap(ptHi.x) ); // interpolate and store ySpec = ControlSpec( this.getRelativePositionY(ptLo.y), this.getRelativePositionY(ptHi.y) ); xSpec = ControlSpec( iLo, iHi ); while( {iLo <= iHi} ) { val = ySpec.map( xSpec.unmap(iLo) ); value.put( iLo, val ); iLo = iLo+1; }; // trigger once for second end of the line plotter.editFunc.value(plotter, plotIndex, i2, val, pt2.x, pt2.y); valueCache = nil; } getRelativePositionX { |x| ^this.resampledDomainSpec.map((x - plotBounds.left) / plotBounds.width) } getRelativePositionY { |y| ^spec.map((plotBounds.bottom - y) / plotBounds.height) } hasSteplikeDisplay { ^#[\levels, \steps].includes(plotter.plotMode) } getIndex { |x| var offset = if(this.hasSteplikeDisplay) { 0.5 } { 0.0 }; // needs to be fixed. ^(this.getRelativePositionX(x) - offset).round.asInteger } getDataPoint { |x| var index = this.getIndex(x).clip(0, value.size - 1); ^[index, value.at(index)] } // settings zoomFont { |val| font = font.copy; font.size = max(1, font.size + val); this.font = font; drawGrid.clearCache; } copy { ^super.copy.drawGrid_(drawGrid.copy) } prResampValues { ^if(value.size <= (plotBounds.width / plotter.resolution)) { value } { valueCache ?? { valueCache = value.resamp1(plotBounds.width / plotter.resolution) } } } } Plotter { var <>name, <>bounds, <>parent; var domain; var plotMode = \linear, <>editMode = false, <>normalized = false; var <>resolution = 1, <>findSpecs = true, drawFunc, <>editFunc; var 1 ) { 4.0 } { 0.0 }; var distY = bounds.height / data.size; var height = distY - deltaY; plots.do { |plot, i| plot.bounds_( Rect(bounds.left, distY * i + bounds.top, bounds.width, height) ) } } makePlots { var template = if(plots.isNil) { Plot(this) } { plots.last }; plots !? { plots = plots.keep(data.size.neg) }; plots = plots ++ template.dup(data.size - plots.size); plots.do { |plot, i| plot.value = data.at(i) }; this.updatePlotSpecs; this.updatePlotBounds; } updatePlots { if(plots.size != data.size) { this.makePlots; } { plots.do { |plot, i| plot.value = data.at(i) } } } updatePlotSpecs { specs !? { plots.do { |plot, i| plot.spec = specs.clipAt(i) } }; domainSpecs !? { plots.do { |plot, i| plot.domainSpec = domainSpecs.clipAt(i) } } } setProperties { |... pairs| pairs.pairsDo { |selector, value| selector = selector.asSetter; plots.do { |x| x.perform(selector, value) } } } // specs specs_ { |argSpecs| specs = argSpecs.asArray.clipExtend(data.size).collect(_.asSpec); this.updatePlotSpecs; } domainSpecs_ { |argSpecs| domainSpecs = argSpecs.asArray.clipExtend(data.size).collect(_.asSpec); this.updatePlotSpecs; } minval_ { |val| val = val.asArray; specs.do { |x, i| x.minval = val.wrapAt(i) }; this.updatePlotSpecs; } maxval_ { |val| val = val.asArray; specs.do { |x, i| x.maxval = val.wrapAt(i) }; this.updatePlotSpecs; } calcSpecs { |separately = true, minval, maxval, defaultRange| var ranges = [minval, maxval].flop; var newSpecs = ranges.collect(_.asSpec).clipExtend(data.size); if(separately) { newSpecs = newSpecs.collect { |spec, i| var list = data.at(i); if(list.notNil) { spec = spec.looseRange(list, defaultRange, *ranges.wrapAt(i)); } { spec }; } } { newSpecs = newSpecs.first.looseRange(data.flat, defaultRange, *ranges.at(0)); }; this.specs = newSpecs; } calcDomainSpecs { // for now, a simple version domainSpecs = data.collect { |val| [0, val.size - 1, \lin, 1].asSpec } } // interaction pointIsInWhichPlot { |point| var res; if(plots.isNil) { ^nil }; res = plots.detectIndex { |plot| point.y.exclusivelyBetween(plot.bounds.top, plot.bounds.bottom) }; ^res ?? { if(point.y < bounds.center.y) { 0 } { plots.size - 1 } } } getDataPoint { |x, y| var plotIndex = this.pointIsInWhichPlot(x @ y); ^plotIndex !? { plots.at(plotIndex).getDataPoint(x) } } postCurrentValue { |x, y| this.getDataPoint(x, y).postln } editData { |x, y| var plotIndex = this.pointIsInWhichPlot(x @ y); plotIndex !? { plots.at(plotIndex).editData(x, y, plotIndex); }; } refresh { parent !? { parent.refresh } } prReshape { |item| var size, array = item.asArray; if(item.first.isSequenceableCollection.not) { ^array.bubble; }; if(superpose) { if(array.first.first.isSequenceableCollection) { ^array }; size = array.maxItem { |x| x.size }.size; // for now, just extend data: ^array.collect { |x| x.asArray.clipExtend(size) }.flop.bubble }; ^array } } + ArrayedCollection { plot { |name, bounds, discrete=false, numChannels, minval, maxval, separately = true| var array, plotter; array = this.as(Array); if(array.maxDepth > 3) { "Cannot currently plot an array with more than 3 dimensions".warn; ^nil }; plotter = Plotter(name, bounds); if(discrete) { plotter.plotMode = \points }; numChannels !? { array = array.unlace(numChannels) }; array = array.collect {|elem| if (elem.isKindOf(Env)) { elem.asMultichannelSignal.flop } { elem } }; plotter.setValue( array, findSpecs: true, separately: separately, refresh: true, minval: minval, maxval: maxval ); ^plotter } } + Collection { plotHisto { arg steps = 100, min, max; var histo = this.histo(steps, min, max); var plotter = histo.plot; plotter.domainSpecs = [[min ?? { this.minItem }, max ?? { this.maxItem }].asSpec]; plotter.specs = [[0, histo.maxItem, \linear, 1].asSpec]; plotter.plotMode = \steps; ^plotter } } + Function { loadToFloatArray { arg duration = 0.01, server, action; var buffer, def, synth, name, numChannels, val, rate; server = server ? Server.default; if(server.serverRunning.not) { "Server not running!".warn; ^nil }; name = this.hash.asString; def = SynthDef(name, { |bufnum| var val = this.value; if(val.isValidUGenInput.not) { val.dump; Error("loadToFloatArray failed: % is no valid UGen input".format(val)).throw }; val = UGen.replaceZeroesWithSilence(val.asArray); rate = val.rate; if(rate == \audio) { // convert mixed rate outputs: val = val.collect { |x| if(x.rate != \audio) { K2A.ar(x) } { x } } }; if(val.size == 0) { numChannels = 1 } { numChannels = val.size }; RecordBuf.perform(RecordBuf.methodSelectorForRate(rate), val, bufnum, loop:0); Line.perform(Line.methodSelectorForRate(rate), dur: duration, doneAction: 2); }); Routine.run({ var c, numFrames; c = Condition.new; numFrames = duration * server.sampleRate; if(rate == \control) { numFrames = numFrames / server.options.blockSize }; buffer = Buffer.new(server, numFrames, numChannels); server.sendMsgSync(c, *buffer.allocMsg); server.sendMsgSync(c, "/d_recv", def.asBytes); synth = Synth(name, [\bufnum, buffer], server); OSCFunc({ buffer.loadToFloatArray(action: { |array, buf| action.value(array, buf); buffer.free; server.sendMsg("/d_free", name); }); }, '/n_end', server.addr, nil, [synth.nodeID]).oneShot; }); } plot { |duration = 0.01, server, bounds, minval, maxval, separately = false| var name = this.asCompileString, plotter; if(name.size > 50 or: { name.includes(Char.nl) }) { name = "function plot" }; plotter = Plotter(name, bounds); plotter.value = [0.0]; server = server ? Server.default; server.waitForBoot { this.loadToFloatArray(duration, server, { |array, buf| var numChan = buf.numChannels; { plotter.setValue( array.unlace(numChan).collect(_.drop(-1)), findSpecs: true, separately: separately, refresh: false, minval: minval, maxval: maxval ); plotter.domainSpecs = ControlSpec(0, duration, units: "s"); plotter.refresh; }.defer }) }; ^plotter } plotAudio { |duration = 0.01, minval = -1, maxval = 1, server, bounds| ^this.plot(duration, server, bounds, minval, maxval) } } + Bus { plot { |duration = 0.01, bounds, minval, maxval, separately = false| ^{ InFeedback.ar(this.index, this.numChannels) }.plot(duration, this.server, bounds, minval, maxval, separately) } plotAudio { |duration = 0.01, minval = -1, maxval = 1, bounds| ^this.plot(duration, bounds, minval, maxval) } } + Wavetable { plot { |name, bounds, minval, maxval, separately = false| ^this.asSignal.plot(name, bounds, minval: minval, maxval: maxval, separately: separately) } } + Buffer { plot { |name, bounds, minval, maxval, separately = false| var plotter; if(server.serverRunning.not) { "Server % not running".format(server).warn; ^nil }; if(numFrames.isNil) { "Buffer not allocated, can't plot data".warn; ^nil }; plotter = [0].plot( name ? "Buffer plot (bufnum: %)".format(this.bufnum), bounds, minval: minval, maxval: maxval ); this.loadToFloatArray(action: { |array, buf| { plotter.setValue( array.unlace(buf.numChannels), findSpecs: true, separately: separately, refresh: false, minval: minval, maxval: maxval ); plotter.domainSpecs = ControlSpec(0.0, buf.numFrames, units:"frames"); plotter.refresh; }.defer }); ^plotter } } + Env { plot { |size = 400, bounds, minval, maxval, name| var plotLabel = if (name.isNil) { "envelope plot" } { name }; var plotter = [this.asMultichannelSignal(size).flop] .plot(name, bounds, minval: minval, maxval: maxval); var duration = this.duration.asArray; var channelCount = duration.size; var totalDuration = if (channelCount == 1) { duration } { duration.maxItem ! channelCount }; plotter.domainSpecs = totalDuration.collect(ControlSpec(0, _, units: "s")); plotter.setProperties(\labelX, "time"); plotter.refresh; ^plotter } } + AbstractFunction { plotGraph { arg n=500, from = 0.0, to = 1.0, name, bounds, discrete = false, numChannels, minval, maxval, separately = true; var array = Array.interpolation(n, from, to); var res = array.collect { |x| this.value(x) }; res.plot(name, bounds, discrete, numChannels, minval, maxval, separately) } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Files/FilePlusGUI.sc000644 000765 000024 00000000341 12756534417 027336 0ustar00crucialstaff000000 000000 + File { *openDialog { arg prompt, successFunc, cancelFunc; Dialog.openPanel(successFunc, cancelFunc); } *saveDialog { arg prompt, defaultName, successFunc, cancelFunc; Dialog.savePanel(successFunc, cancelFunc); } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Core/ClassBrowser.sc000644 000765 000024 00000054351 12756534417 027517 0ustar00crucialstaff000000 000000 // A thorough refactoring of JMc's original class browser // Previously a state was a Class or an array representing a search result // Now it's an Environment holding more info // James Harkins ClassBrowser { classvar updateProtos, searchMenuKeys, viewList, buttonSet, gray; var 0) { historyPos = historyPos - 1; this.restoreHistory; } }; ~fwdButton = Button.new(~window, Rect(0,0, 24, 24)); ~fwdButton.states = [[">"]]; ~fwdButton.action = { if (historyPos < (history.size - 1)) { historyPos = historyPos + 1; this.restoreHistory; } }; ~superButton = Button.new(~window, Rect(0,0, 50, 24)); ~superButton.states = [["super"]]; ~superButton.action = { if(currentState.currentClass.notNil) { this.makeState( currentState.currentClass.superclass ); } }; ~metaButton = Button.new(~window, Rect(0,0, 50, 24)); ~metaButton.states = [["meta"]]; ~metaButton.action = { if(currentState.currentClass.notNil) { this.makeState( currentState.currentClass.class ); }; }; ~helpButton = Button.new(~window, Rect(0,0, 50, 24)); ~helpButton.states = [["help"]]; ~helpButton.action = { if(currentState.currentClass.notNil) { currentState.currentClass.help; } }; ~classSourceButton = Button.new(~window, Rect(0,0, 90, 24)); ~classSourceButton.states = [["class source"]]; ~classSourceButton.action = { if(currentState.currentClass.notNil) { currentState.currentClass.openCodeFile; } }; ~methodSourceButton = Button.new(~window, Rect(0,0, 90, 24)); ~methodSourceButton.states = [["method source"]]; ~methodSourceButton.action = { if(currentState.currentMethod.notNil) { currentState.currentMethod.openCodeFile; }; }; ~implementationButton = Button.new(~window, Rect(0,0, 100, 24)); ~implementationButton.states = [["implementations"]]; ~implementationButton.action = { if(currentState.currentMethod.notNil) { thisProcess.interpreter.cmdLine = currentState.currentMethod.name.asString; thisProcess.methodTemplates; }; }; ~refsButton = Button.new(~window, Rect(0,0, 70, 24)); ~refsButton.states = [["references"]]; ~refsButton.action = { if(currentState.currentMethod.notNil) { thisProcess.interpreter.cmdLine = currentState.currentMethod.name.asString; thisProcess.methodReferences; }; }; ~window.view.decorator.nextLine; StaticText.new(~window, Rect(0, 0, 65, 20)).string_("Search for"); ~searchField = TextField.new(~window, Rect(0, 0, 235, 20)) .action_({ this.searchClasses(views.searchField.string, views.searchMenu.value, views.matchCaseButton.value); }); StaticText.new(~window, Rect(0, 0, 15, 20)).string_("in").align_(\center); ~searchMenu = PopUpMenu.new(~window, Rect(0, 0, 200, 20)); ~matchCaseButton = Button.new(~window, Rect(0, 0, 100, 20)) .states_([["Case insensitive"], ["Match case"]]); ~searchButton = Button.new(~window, Rect(0, 0, 40, 20)) .states_([["GO"]]) .action_({ this.searchClasses(views.searchField.string, views.searchMenu.value, views.matchCaseButton.value); }); ~window.view.decorator.nextLine; ~filenameView = StaticText.new(~window, Rect(0,0, 600, 18)); ~filenameView.font = Font.sansSerif( 10 ); ~window.view.decorator.nextLine; StaticText.new(~window, Rect(0,0, 180, 24)) .font_(hvBold12).align_(\center).string_("class vars"); StaticText.new(~window, Rect(0,0, 180, 24)) .font_(hvBold12).align_(\center).string_("instance vars"); ~window.view.decorator.nextLine; ~classVarView = ListView.new(~window, Rect(0,0, 180, 130)); ~instVarView = ListView.new(~window, Rect(0,0, 180, 130)); ~classVarView.value = 0; ~instVarView.value = 0; ~window.view.decorator.nextLine; ~subclassTitle = StaticText.new(~window, Rect(0,0, 220, 24)) .font_(hvBold12).align_(\center).string_("subclasses (press return)"); ~methodTitle = StaticText.new(~window, Rect(0,0, 240, 24)) .font_(hvBold12).align_(\center).string_("methods"); StaticText.new(~window, Rect(0,0, 200, 24)) .font_(hvBold12).align_(\center).string_("arguments"); ~window.view.decorator.nextLine; ~subclassView = ListView.new(~window, Rect(0,0, 220, 260)); ~methodView = ListView.new(~window, Rect(0,0, 240, 260)); ~argView = ListView.new(~window, Rect(0,0, 200, 260)); ~subclassView.resize = 4; ~methodView.resize = 4; ~argView.resize = 4; ~window.view.decorator.nextLine; [~classVarView, ~instVarView, ~subclassView, ~methodView, ~argView].do ( _.beginDragAction_({nil}) ); }; this.addInstanceActions .makeState(class, \class); views.window.front; } makeState { |result, state = \class, addHistory = true, extraValuesDict| currentState = Environment(proto: views, parent: updateProtos, know: true).make { ~result = result; if(~result.isNil or: { result.isArray and: { result.isEmpty } }) { ~state = ("empty" ++ state).asSymbol } { ~state = state; }; if(extraValuesDict.respondsTo(\keysValuesDo)) { currentEnvironment.putAll(extraValuesDict); }; ~state.envirGet[\init].value; ~subclassViewIndex = ~subclassViewIndex.value ? 0; ~methodViewIndex = ~methodViewIndex.value ? 0; ~argView.value = 0; }; if (addHistory) { if (history.size > 1000) { history = history.drop(1) }; historyPos = historyPos + 1; history = history.extend(historyPos).add(currentState); }; this.updateViews; } restoreHistory { // note, don't use makeState because we already have the complete state saved currentState = history[historyPos]; this.updateViews; } updateViews { var updaters, bstate, view; currentState.use { updaters = ~state.envirGet; viewList.do { |viewname| updaters[viewname].value(viewname.envirGet); }; buttonSet.do { |viewname| viewname.envirGet.tryPerform(\enabled_, updaters[\buttonsDisabled].includes(viewname).not); }; ~window.refresh; } } close { if(views.window.isClosed.not) { views.window.close }; currentState = history = views = nil; // dump garbage } // workaround for the fact that you can't get a non-metaclass from a metaclass *getClass { |method| var class; if(method.isNil) { ^nil }; ^if((class = method.ownerClass).isMetaClass) { class.name.asString[5..].asSymbol.asClass; } { class } } getClass { |method| ^this.class.getClass(method) } searchClasses { |string, rootNumber, matchCase, addHistory = true| var pool, rootdir, result, searchType = searchMenuKeys[rootNumber] ? \classSearch, isClassSearch, warning = { var w; w = Window("Invalid search", Rect.aboutPoint(Window.screenBounds.center, 170, 60)) .layout_(VLayout( StaticText().align_(\center) .string_("This search requires a class to be selected"), HLayout( StaticText(), // padding to push button to horiz. center Button().states_([["OK"]]) .action_({ w.close }) .maxWidth_(80), StaticText() ) )) .endFrontAction_({ w.endFrontAction_(nil).close; }) .front; }; string = string ?? { "" }; matchCase = matchCase > 0; switch(rootNumber) { 0 } { isClassSearch = true; pool = Class.allClasses } { 1 } { isClassSearch = false; pool = Class.allClasses; } { 2 } { if(this.currentClass.notNil) { isClassSearch = true; pool = this.currentClass.allSubclasses.asArray } { ^warning.value }; // early exit } { 3 } { if(this.currentClass.notNil) { isClassSearch = false; pool = this.currentClass.allSubclasses ++ [this.currentClass]; if(this.currentClass.isMetaClass.not) { pool = pool ++ pool.collect(_.class); }; } { ^warning.value }; // early exit } { 4 } { if(this.currentClass.notNil) { isClassSearch = true; rootdir = PathName(currentState.currentClass.filenameSymbol.asString).pathOnly; pool = Class.allClasses.select({ |class| PathName(class.filenameSymbol.asString).pathOnly == rootdir }); if(string.isEmpty) { this.makeState( pool.reject(_.isMetaClass).sort({ |a, b| a.name < b.name }), searchType ); ^this // early exit }; } { ^warning.value }; // early exit }; if (isClassSearch) { result = case ( {string.isEmpty}, pool, {matchCase}, { pool.select({ |class| class.isMetaClass.not and: { class.name.asString.contains(string) } }) }, //else { pool.select({ |class| class.isMetaClass.not and: { class.name.asString.containsi(string) } }) } ).sort({ |a, b| a.name < b.name }); } { // else - method search result = Array.new; case ( {string.isEmpty}, { pool.do { |class| result = result.addAll(class.methods); } }, {matchCase}, { pool.do({ |class| result = result.addAll(class.methods.select({ |method| method.name.asString.contains(string) })); }); }, { pool.do({ |class| result = result.addAll(class.methods.select({ |method| method.name.asString.containsi(string) })); }); } ); result = result.sort({ |a, b| if(a.name == b.name) { a.ownerClass.name < b.ownerClass.name } { a.name < b.name }; }); }; this.makeState(result, searchType, addHistory, extraValuesDict: ( searchString: string, searchMenuValue: rootNumber, caseButtonValue: matchCase.binaryValue )); } *initGUI { updateProtos ?? { gray = Color.grey(0.5); searchMenuKeys = #[classSearch, methodSearch, classSearch, methodSearch, classSearch]; viewList = #[currentClassNameView, superClassNameView, filenameView, classVarView, instVarView, subclassTitle, methodTitle, subclassView, methodView, argView, searchMenu]; buttonSet = IdentitySet[\superButton, \metaButton, \helpButton, \classSourceButton, \methodSourceButton, \implementationButton, \refsButton]; // updateProtos holds instructions to update the GUI // for each kind of browser result to display updateProtos = ( class: ( init: { ~setSubclassArray.value; ~setMethodArray.value; ~setCurrentClass.value(~result); ~setCurrentMethod.value(~methodArray[0]); }, // ~result must be a Class currentClassNameView: { |v| v.string = ~currentClass.name.asString }, superClassNameView: { |v| v.string = "superclass: " ++ ~currentClass.superclass.tryPerform(\name).asString }, filenameView: { |v| v.string = ~currentClass.filenameSymbol.asString }, classVarView: { |v| v.items = ~currentClass.classVarNames.asArray.collectAs ({|name| name.asString }, Array).sort }, instVarView: { |v| v.items = ~currentClass.instVarNames.asArray.collectAs ({|name| name.asString }, Array).sort }, subclassTitle: { |v| v.string_("subclasses (press return)") }, subclassView: { |v| ~subclassView.items_(~subclassArray.collect({|class| class.name.asString })) .value_(~subclassViewIndex ? 0) .action_(~subclassViewNormalAction) .enterKeyAction_(~navigateToSubclassAction) .mouseDownAction_(~listViewDoubleClickAction); }, methodTitle: { |v| v.string_("methods") }, methodView: { |v| var colorFunc = { |class, name| if(class.findOverriddenMethod(name.asSymbol).isNil) { nil } { Color.grey(0.5, 0.8) } }; var classMethodColors = ~classMethodNames.collect { |name| colorFunc.value(~currentClass.class, name) }; var methodColors = ~methodNames.collect { |name| colorFunc.value(~currentClass, name) }; var methodNames = ~classMethodNames ++ ~methodNames; var colors = classMethodColors ++ methodColors; ~methodView.items_(methodNames) .value_(~methodViewIndex ? 0) .action_(~displayCurrentMethodArgsAction) .mouseDownAction_(~listViewDoubleClickAction) .tryPerform(\colors_, colors) }, argView: { |v| if (~currentMethod.isNil or: { ~currentMethod.argNames.isNil }) { ~argView.items = ["this"]; } { ~argView.items = ~currentMethod.argNames.collectAs( {|name, i| var defval; defval = ~currentMethod.prototypeFrame[i]; if (defval.isNil) { name.asString }{ name.asString ++ " = " ++ defval.asString } }, Array); }; }, searchMenu: { |v| v.items = ["All classes", "All methods", "Subclasses of " ++ ~currentClass.name, "% + subclass methods".format(~currentClass.name), "Classes in folder " ++ PathName(~currentClass.filenameSymbol.asString) .allFolders.last ]; }, buttonsDisabled: IdentitySet.new // all buttons OK ), // this could happen if the user types a wrong class name into the class name box emptyclass: ( currentClassNameView: { |v| v.string = "Class does not exist" }, superClassNameView: { |v| v.string = "" }, filenameView: { |v| v.string = "" }, classVarView: { |v| v.items_(#[]) }, instVarView: { |v| v.items_(#[]) }, subclassTitle: { |v| v.string = "no subclasses" }, methodTitle: { |v| v.string = "no methods" }, subclassView: { |v| v.items_(#[]) }, methodView: { |v| v.items_(#[]) }, argView: { |v| v.items_(#[]) }, buttonsDisabled: buttonSet // all buttons disabled ), classSearch: ( // init: set current class and current method init: { ~currentClass = ~result[0]; ~subclassArray = ~result; ~setMethodArray.value(~currentClass); ~currentMethod = ~methodArray[0]; }, // result must be an array of classes currentClassNameView: { |v| v.string = "Class Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "" }, filenameView: { |v| ~class[\filenameView].value(v) }, classVarView: { |v| ~class[\classVarView].value(v) }, instVarView: { |v| ~class[\instVarView].value(v) }, subclassTitle: { |v| v.string = "matching classes (press return)" }, methodTitle: { |v| v.string = "methods" }, subclassView: { |v| v.items_(~result.collect(_.name)) .value_(~subclassViewIndex ? 0) .action_(~classSearchSubclassViewAction) .enterKeyAction_(~navigateToCurrentClassAction); }, methodView: { |v| ~class[\methodView].value(v) }, argView: { |v| ~class[\argView].value(v) }, buttonsDisabled: #[] // all buttons OK ), emptyclassSearch: ( currentClassNameView: { |v| v.string = "Class Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "No results found!" }, filenameView: { |v| v.string = "" }, classVarView: { |v| v.items_(#[]) }, instVarView: { |v| v.items_(#[]) }, subclassTitle: { |v| v.string = "no classes" }, methodTitle: { |v| v.string = "no methods" }, subclassView: { |v| v.items_(#[]) }, methodView: { |v| v.items_(#[]) }, argView: { |v| v.items_(#[]) }, buttonsDisabled: buttonSet // all buttons disabled ), methodSearch: ( init: { ~methodArray = ~result; ~currentMethod = ~methodArray[0]; ~methodViewIndex = 0; ~setClassArrayFromMethodSearch.value(~result); ~currentClass = this.getClass(~currentMethod); ~subclassViewIndex = ~subclassArray.indexOf(~currentClass); }, // result must be an array of methods currentClassNameView: { |v| v.string = "Method Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "" }, filenameView: { |v| v.string = ~currentMethod.filenameSymbol }, classVarView: { |v| ~class[\classVarView].value(v) }, instVarView: { |v| ~class[\instVarView].value(v) }, subclassTitle: { |v| v.string = "classes (press return)" }, methodTitle: { |v| v.string = "matching methods (press return)" }, subclassView: { |v| v.items_(~subclassArray.collect({ |class| class.name })) .value_(~subclassViewIndex ? 0) .action_(nil) .enterKeyAction_(~navigateToSubclassAction); }, methodView: { |v| v.items_(~methodArray.collect({ |method| method.name ++ " (" ++ method.ownerClass ++ ")" })).action_(~methodSearchMethodViewAction) .value_(~methodViewIndex ? 0) .enterKeyAction_(~navigateToCurrentClassAction) }, argView: { |v| ~class[\argView].value(v) }, buttonsDisabled: #[] // all buttons OK ), emptymethodSearch: ( currentClassNameView: { |v| v.string = "Method Search: " ++ ~searchString }, superClassNameView: { |v| v.string = "No results found!" }, filenameView: { |v| v.string = "" }, classVarView: { |v| v.items_(#[]) }, instVarView: { |v| v.items_(#[]) }, subclassTitle: { |v| v.string = "no classes" }, methodTitle: { |v| v.string = "no methods" }, subclassView: { |v| v.items_(#[]) }, methodView: { |v| v.items_(#[]) }, argView: { |v| v.items_(#[]) }, buttonsDisabled: buttonSet // all buttons disabled ), // support funcs shared in common setCurrentClass: { |class| ~currentClass = class ?? { ~subclassArray[~subclassView.value ? 0] }; }, setCurrentMethod: { |method| ~currentMethod = method ?? { ~methodArray[~methodView.value ? 0] }; }, setSubclassArray: { |class| class = class ? ~result; if (class.subclasses.isNil) { ~subclassArray = []; } { ~subclassArray = class.subclasses.copy.sort {|a,b| a.name <= b.name }; }; }, setMethodArray: { |class| class = class ? ~result; if (class.class.methods.isNil) { ~classMethodArray = []; ~classMethodNames = []; } { ~classMethodArray = class.class.methods.asArray.copy.sort {|a,b| a.name <= b.name }; ~classMethodNames = ~classMethodArray.collect {|method| "*" ++ method.name.asString }; }; if (class.methods.isNil) { ~methodArray = []; ~methodNames = []; } { ~methodArray = class.methods.asArray.copy.sort {|a,b| a.name <= b.name }; ~methodNames = ~methodArray.collect {|method| method.name.asString }; }; ~methodArray = ~classMethodArray ++ ~methodArray; }, setClassArrayFromMethodSearch: { |result| var classSet = IdentitySet.new, class; ~result.do({ |method| classSet.add(this.getClass(method)); }); ~subclassArray = classSet.asArray.sort({ |a, b| a.name < b.name }); } ); } } // because these use instance variables, they cannot be defined in the above class method // each ClassBrowser instance gets a separate dictionary with the proper object scope addInstanceActions { views.putAll(( // these are called from GUI, cannot assume currentState is already in force navigateToSubclassAction: { var prevState = currentState, prevMethod = prevState.currentMethod; this.makeState(currentState.subclassArray[currentState.subclassView.value], \class, // methodViewIndex func runs in context // of the new state environment // might be nil unless subclass also implements extraValuesDict: (methodViewIndex: { if(prevMethod.isNil) { 0 } { ~methodArray.detectIndex({ |item| item.name == prevMethod.name }) }; })); }, navigateToCurrentClassAction: { var prevState = currentState; this.makeState(currentState.currentClass, \class, extraValuesDict: (methodViewIndex: { ~methodArray.indexOf(prevState.currentMethod) })); }, subclassViewNormalAction: { |view| currentState.subclassViewIndex = view.value; }, displayCurrentMethodArgsAction: { |view| currentState.use { ~methodViewIndex = view.value; ~setCurrentMethod.value; ~class[\argView].value(~argView) } }, methodEnterKeyAction: { currentState.currentMethod !? { currentState.currentMethod.openCodeFile }; }, classSearchSubclassViewAction: { |view| currentState.use { ~subclassViewIndex = view.value; ~setCurrentClass.value; ~setMethodArray.value(~currentClass); ~methodViewIndex = 0; ~class[\filenameView].value(~filenameView); ~class[\methodView].value(~methodView); ~class[\argView].value(~argView); ~class[\classVarView].value(~classVarView); ~class[\instVarView].value(~instVarView); } }, methodSearchMethodViewAction: { |view| currentState.use { var index; ~methodViewIndex = view.value; ~currentMethod = ~methodArray[~methodView.value ? 0]; ~currentClass = this.getClass(~currentMethod); ~methodSearch[\filenameView].value(~filenameView); ~class[\argView].value(~argView); ~class[\classVarView].value(~classVarView); ~class[\instVarView].value(~instVarView); if((index = ~subclassArray.indexOf(~currentClass)).notNil) { ~subclassView.value = index; ~subclassViewIndex = index; }; }; }, listViewDoubleClickAction: { |view, x, y, mods, buttonNumber, clickCount| if(clickCount == 2) { view.enterKeyAction.value } } )); } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Core/HistoryGui.sc000644 000765 000024 00000022002 12766171707 027200 0ustar00crucialstaff000000 000000 /* // tests // History.start; h = HistoryGui(History.current); 1 + 2; 3 + 4; 12 + 14; 1 + 2; History.current.lines h.postDoc(1); h.alignDoc; h.docFlag = \newDoc; // not working yet. */ HistoryGui : JITGui { classvar <>docTitle = "History repeats", <>docHeight=120; var stickMode=0; var 0); if (filtering) { this.filterLines }; object.hasMovedOn = true; }); keyPop = PopUpMenu(zone, Rect(0, 0, 50, 20)) .items_([\all]).value_(0) .action_({ |pop| this.setKeyFilter(pop.items[pop.value]) }); filTextV = TextView(zone, Rect(0,0, 88 + 12, 20)).string_("") .enterInterpretsSelection_(false) .resize_(2) .keyDownAction_({ |txvw, char, mod, uni, keycode| defer ({ this.setStrFilter(txvw.string); if (this.filtering) { this.updateLines; }; }, 0.01) }); topBut = Button(zone, Rect(0, 0, 32, 20)) .states_([["top"], ["keep"]]).value_(0) .resize_(3) .canFocus_(false) .action_({ |but| this.stickMode_(but.value) }); Button(zone, Rect(0, 0, 32, 20)) //// .states_([["rip"]]) .resize_(3) .canFocus_(false) .action_({ |btn| this.rip(textV.string) }); // // not sure that this still works in Qt as intended // Button(zone, Rect(0,0, 16, 20)) // .states_([["v"], ["^"]]) // .resize_(3) // .action_ { |btn| // var views = zone.children; // var resizes = [ // [2, 1, 1, 1, 2, 3, 3, 3, 5], // [5, 7, 7, 7, 8, 9, 9, 9, 8] // ][btn.value.asInteger]; // // views.postln.do { |v, i| v.resize_(resizes[i]) }; // // }; listV = ListView(zone, bounds.copy.insetBy(2).height_(listViewHeight)) .font_(font) .items_([]) .resize_(5) .background_(Color.grey(0.62)) .action_({ |lview| var index = lview.value; if (lview.items.isEmpty) { "no entries yet.".postln; } { lastLineSelected = listV.items[index]; if (filtering.not) { this.postInlined(index) } { this.postInlined(filteredIndices[index]) } } }) .enterKeyAction_({ |lview| var index = lview.value; if (filtering) { index = filteredIndices[index] }; try { object.lines[index][2].postln.interpret.postln; // "did execute.".postln; } { "execute line from history failed.".postln; }; }); this.checkUpdate; } getState { var newState; if (object.isNil) { ^(hasMovedOn: false) }; newState = ( object: object, hasMovedOn: object.hasMovedOn, isCurrent: object.isCurrent, started: History.started, filtStr: filTextV.string, numLines: object.lines.size, filtering: filtering ); ^newState } resetViews { [startBut, filtBut, keyPop].do(_.value_(0)); textV.string = ""; filTextV.string = ""; listV.items = []; } // these three should move to JITGui in general, // to simplify the checkUpdate methods updateFunc { |newState, key, func, post = false| var val = newState[key]; if (val != prevState[key]) { func.value(val) } } updateVal { |newState, key, guiThing, post = false| var val = newState[key]; if (val != prevState[key]) { guiThing.value_(val).refresh } } updateBinVal { |newState, key, guiThing, post = false| var val = newState[key]; if (val != prevState[key]) { guiThing.value_(val.binaryValue).refresh } } updateLines { var linesToShow, newIndex, selectedLine; // remember old selection if (stickMode == 1) { selectedLine = (lastLinesShown ? [])[listV.value]; } { // something else here? }; linesToShow = if (filtering.not) { object.lineShorts.array } { this.filterLines; filteredShorts; } ? []; listV.items_(linesToShow); lastLinesShown = linesToShow; newIndex = if (selectedLine.isNil) { 0 } { linesToShow.indexOf(selectedLine) }; listV.value_(newIndex ? 0); if(stickMode == 0) { listV.action.value(listV) }; this.postInlined(newIndex); } checkUpdate { var newState = this.getState; var keys; /// if (newState == prevState) { ^this }; this.updateFunc(newState, \object, { |obj| zone.enabled_(obj.notNil) }); if (newState[\object].isNil) { this.resetViews; prevState = newState; ^this }; this.updateFunc(newState, \isCurrent, { |val| startBut.enabled_(val.binaryValue) }); this.updateBinVal(newState, \started, startBut); this.updateBinVal(newState, \filtering, filtBut); // // clumsy, but filTextV has no usable action... // if (filTextV.hasFocus and: (newState[\filtStr] != filters[1])) { // this.setStrFilter(newState[\filtStr]); // }; // could be factored a bit more if (newState[\hasMovedOn] or: { newState[\numLines] != prevState[\numLines] }) { keys = [\all] ++ object.keys.asArray.sort; keyPop.items_(keys); keyPop.value_(keys.indexOf(filters[0]) ? 0); this.updateLines; object.hasMovedOn = false; }; prevState = newState; } setKeyFilter { |key| filters.put(0, key); object.hasMovedOn_(true); if (filtering) { this.filterLines; }; } setStrFilter { |str| filters.put(1, str); object.hasMovedOn_(true); if (filtering) { this.filterLines; }; } filtering_ { |flag=true| filtering = flag; object.hasMovedOn_(true); if (filtering) { this.filterLines; }; this.updateLines; } filterOn { this.filtering_(true) } filterOff { this.filtering_(false) } filterLines { filteredIndices = object.indicesFor(*filters); filteredShorts = object.lineShorts[filteredIndices]; defer { keyPop.value_(keyPop.items.indexOf(filters[0] ? 0)); // filTextV.string_(filters[1]); }; if (filtering) { object.hasMovedOn = true; }; } postInlined { |index| var line; if (object.lines.isNil) { "no history lines yet.".postln; ^this }; line = object.lines[index]; if (line.isNil) { "history: no line found!".inform; ^this }; textV.string_(line[2]); } postDoc { |index| var line; if (object.lines.isNil) { "no history lines yet.".postln; ^this }; line = object.lines[index]; if (line.isNil) { "history: no line found!".inform; ^this }; this.setDocStr(line[2]); doc.front; try { this.alignDoc }; // w.front; } setDocStr { |str| this.findDoc; doc.view.children.first.string_(str); } alignDoc { var docbounds, winbounds; this.findDoc; docbounds = doc.bounds; winbounds = parent.bounds; doc.bounds_( Rect( winbounds.left, winbounds.top + winbounds.height + 24, winbounds.width, docHeight ) ) } rip { this.setDocStr(textV.string); doc.front; try { doc.align }; } findDoc { if (docFlag == \newDoc) { oldDocs = oldDocs.add(doc) }; if (docFlag == \newDoc or: doc.isNil or: { Window.allWindows.includes(doc).not }) { doc = Window(docTitle, Rect(300, 500, 314, 114)); doc.addFlowLayout; TextView(doc, doc.bounds.resizeBy(-8, -8)).resize_(5); }; oldDocs = oldDocs.select {|d| d.notNil and: { d.dataptr.notNil } }; } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Core/KernelPlusGUI.sc000644 000765 000024 00000000252 12756534417 027526 0ustar00crucialstaff000000 000000 + Process{ //this called when the menu item file-new or file-open is called addDocument { Document.prGetLast; } } + Class { browse { ^ClassBrowser.new(this) } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Core/NilPlusGUI.sc000644 000765 000024 00000000147 12756534417 027033 0ustar00crucialstaff000000 000000 + Nil { // nil parent view asView {} // graphical support asRect { ^Rect.new } asArray { ^[] } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Core/ObjectPlusGUI.sc000644 000765 000024 00000000102 12756534417 027506 0ustar00crucialstaff000000 000000 + Object { mouseDown { ^nil } mouseOver { ^nil } keyDown { } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/FreqScope.sc000644 000765 000024 00000036120 12756534417 027517 0ustar00crucialstaff000000 000000 FreqScopeView { var specialSynthDef, 2/dbRange // linear SynthDef("system_freqScope0", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr]).add; SynthDef("system_freqScope0_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr]).add; // logarithmic SynthDef("system_freqScope1", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr]).add; SynthDef("system_freqScope1_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, fftbufnum, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr]).add; // These next two are based on the original two, but adapted by Dan Stowell // to calculate the frequency response between two channels SynthDef("system_freqScope0_magresponse", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; SynthDef("system_freqScope0_magresponse_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, numSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; numSamples = (BufSamples.ir(fftbufnum) - 2) * 0.5; // 1023 (bufsize=2048) signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); // -1023 to 1023, 0 to 2046, 2 to 2048 (skip first 2 elements DC and Nyquist) phasor = LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, numSamples, numSamples + 2); phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; SynthDef("system_freqScope1_magresponse", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; SynthDef("system_freqScope1_magresponse_shm", { arg in=0, fftBufSize = 2048, scopebufnum=1, rate=4, dbFactor = 0.02, in2=1; var phase = 1 - (rate * fftBufSize.reciprocal); var signal, chain, result, phasor, halfSamples, mul, add; var signal2, chain2, divisionbuf; var fftbufnum = LocalBuf(fftBufSize, 1); mul = 0.00285; halfSamples = BufSamples.ir(fftbufnum) * 0.5; signal = In.ar(in); signal2 = In.ar(in2); chain = FFT(fftbufnum, signal, hop: 0.75, wintype:1); divisionbuf = LocalBuf(BufFrames.ir(fftbufnum)); chain2 = FFT(divisionbuf, signal2, hop: 0.75, wintype:1); // Here we perform complex division to estimate the freq response chain = PV_Div(chain2, chain); chain = PV_MagSmear(chain, 1); phasor = halfSamples.pow(LFSaw.ar(rate/BufDur.ir(fftbufnum), phase, 0.5, 0.5)) * 2; // 2 to bufsize phasor = phasor.round(2); // the evens are magnitude ScopeOut2.ar( ((BufRd.ar(1, divisionbuf, phasor, 1, 1) * mul).ampdb * dbFactor) + 1, scopebufnum, fftBufSize/rate); }, [\kr, \ir, \ir, \ir, \kr, \ir]).add; } initFreqScope { arg parent, bounds, argServer; server = argServer ? Server.default; if (this.shmScopeAvailable) { scope = ScopeView.new(parent, bounds); scope.server = server; scope.fill = false; } { scope = SCScope(parent, bounds); }; active = false; inBus = 0; dbRange = 96; dbFactor = 2/dbRange; rate = 4; freqMode = 0; bufSize = 2048; ServerQuit.add(this, server); ^this; } allocBuffers { if (this.shmScopeAvailable) { scopebuf = ScopeBuffer.alloc(server); scope.bufnum = scopebuf.bufnum; } { Buffer.alloc(server, bufSize/4, 1, { |sbuf| scope.bufnum = sbuf.bufnum; scopebuf = sbuf; }); }; } freeBuffers { if (scopebuf.notNil) { scopebuf.free; scopebuf = nil; }; } start { var defname, args; if (synth.notNil) { synth.free }; if (scopebuf.isNil) { this.allocBuffers }; defname = specialSynthDef ?? { "system_freqScope" ++ freqMode.asString ++ if (this.shmScopeAvailable) {"_shm"} {""} }; args = [\in, inBus, \dbFactor, dbFactor, \rate, 4, \fftBufSize, bufSize, \scopebufnum, scopebuf.bufnum] ++ specialSynthArgs; synth = Synth.tail(RootNode(server), defname, args); if (scope.isKindOf(ScopeView)) { scope.start }; } kill { this.active_(false); this.freeBuffers; ServerQuit.remove(this, server); } active_ { arg activate; if (activate) { ServerTree.add(this, server); if (server.serverRunning) { active=activate; this.doOnServerTree; ^this } } { ServerTree.remove(this, server); if (server.serverRunning and: active) { if (scope.isKindOf(ScopeView)) { scope.stop }; synth.free; synth = nil; }; }; active=activate; ^this } doOnServerTree { synth = nil; if (active) { this.start; } } doOnServerQuit { var thisScope = scope; defer { thisScope.stop; }; scopebuf = synth = nil; } inBus_ { arg num; inBus = num; if(active, { synth.set(\in, inBus); }); ^this } dbRange_ { arg db; dbRange = db; dbFactor = 2/db; if(active, { synth.set(\dbFactor, dbFactor); }); } freqMode_ { arg mode; freqMode = mode.asInteger.clip(0,1); if(active, { this.start; }); } specialSynthArgs_ {|args| specialSynthArgs = args; if(args.notNil and:{active}){ synth.set(*specialSynthArgs); } } special { |defname, extraargs| this.specialSynthDef_(defname); this.specialSynthArgs_(extraargs); if(active, { this.start; }); } *response{ |parent, bounds, bus1, bus2, freqMode=1| var scope = this.new(parent, bounds, bus1.server).inBus_(bus1.index); var synthDefName = "system_freqScope%_magresponse%".format(freqMode, if (scope.shmScopeAvailable) {"_shm"} {""}); ^scope.special(synthDefName, [\in2, bus2]) } doesNotUnderstand { arg selector ... args; ^scope.performList(selector, args); } shmScopeAvailable { ^server.isLocal // and: { server.inProcess.not } } } FreqScope { classvar 1.0, { freqLabel[i].string_( kfreq.asString.keep(4) ++ "k" ) },{ freqLabel[i].string_( (kfreq*1000).asInteger.asString) }); }); }; setDBLabelVals = { arg db; dbLabel.size.do({ arg i; dbLabel[i].string = (i * db/(dbLabel.size-1)).asInteger.neg.asString; }); }; window = Window("Freq Analyzer", rect.resizeBy(pad[0] + pad[1] + 4, pad[2] + pad[3] + 4), false); freqLabel.size.do({ arg i; freqLabel[i] = StaticText(window, Rect(pad[0] - (freqLabelDist*0.5) + (i*freqLabelDist), pad[2] - 10, freqLabelDist, 10)) .font_(font) .align_(\center) ; StaticText(window, Rect(pad[0] + (i*freqLabelDist), pad[2], 1, rect.height)) .string_("") ; }); dbLabel.size.do({ arg i; dbLabel[i] = StaticText(window, Rect(0, pad[2] + (i*dbLabelDist), pad[0], 10)) .font_(font) .align_(\left) ; StaticText(window, Rect(pad[0], dbLabel[i].bounds.top, rect.width, 1)) .string_("") ; }); scope = FreqScopeView(window, rect.moveBy(pad[0], pad[2]), server); scope.xZoom_((scope.bufSize*0.25) / width); setFreqLabelVals.value(scope.freqMode, 2048); setDBLabelVals.value(scope.dbRange); Button(window, Rect(pad[0] + rect.width, pad[2], pad[1], 16)) .states_([["stop", Color.white, Color.green(0.5)], ["start", Color.white, Color.red(0.5)]]) .action_({ arg view; if(view.value == 0, { scope.active_(true); },{ scope.active_(false); }); }) .font_(font) .canFocus_(false) ; StaticText(window, Rect(pad[0] + rect.width, pad[2]+20, pad[1], 10)) .string_("BusIn") .font_(font) ; NumberBox(window, Rect(pad[0] + rect.width, pad[2]+30, pad[1], 14)) .action_({ arg view; view.value_(view.value.asInteger.clip(0, server.options.numAudioBusChannels)); scope.inBus_(view.value); }) .value_(busNum) .font_(font) ; StaticText(window, Rect(pad[0] + rect.width, pad[2]+48, pad[1], 10)) .string_("FrqScl") .font_(font) ; PopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+58, pad[1], 16)) .items_(["lin", "log"]) .action_({ arg view; scope.freqMode_(view.value); setFreqLabelVals.value(scope.freqMode, 2048); }) .canFocus_(false) .font_(font) .valueAction_(1) ; StaticText(window, Rect(pad[0] + rect.width, pad[2]+76, pad[1], 10)) .string_("dbCut") .font_(font) ; PopUpMenu(window, Rect(pad[0] + rect.width, pad[2]+86, pad[1], 16)) .items_(Array.series(12, 12, 12).collect({ arg item; item.asString })) .action_({ arg view; scope.dbRange_((view.value + 1) * 12); setDBLabelVals.value(scope.dbRange); }) .canFocus_(false) .font_(font) .value_(7) ; scope .inBus_(busNum) .active_(true) .style_(1) .waveColors_([scopeColor.alpha_(1)]) .canFocus_(false) ; if (bgColor.notNil) { scope.background_(bgColor) }; window.onClose_({ scope.kill; scopeOpen = false; }).front; ^super.newCopyArgs(scope, window) }); } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/scopeResponse.sc000644 000765 000024 00000004457 12756534417 030470 0ustar00crucialstaff000000 000000 /* Server.default.boot; {|in| MoogFF.ar(in, freq: LFCub.kr(0.2).exprange(10, 10000))}.scopeResponse {|in| MoogFF.ar(in)}.scopeResponse LPF.scopeResponse HPF.scopeResponse MoogFF.scopeResponse BLowPass.scopeResponse BBandPass.scopeResponse BLowShelf.scopeResponse // by default BLowShelf doesn't mangle much Resonz.scopeResponse BRF.scopeResponse Integrator.scopeResponse Formlet.scopeResponse Median.scopeResponse // nonlinear, and therefore interesting Slew.scopeResponse */ + Function { scopeResponse{ |server, freqMode=1, label="Empirical Frequency response", mute = false| var bus1, bus2, synth, win, fs; server = server ? Server.default; if (server.serverRunning.not) { Error("Function-scopeResponse: server not running").throw }; // Create two private busses bus1 = Bus.audio(server, 1); bus2 = Bus.audio(server, 1); // Create the SCFreqScope.response using the same simple window as in the helpfile // Also, onClose must free the synth and the busses win = Window.new(label, Rect(100, 100, 511, 300)); fs = FreqScopeView.response(win, win.view.bounds, bus1, bus2, freqMode); win.onClose_ { fs.kill; synth.release; }; win.front; fs.active_(true); // Create a synth using this function and the busses synth = { |gate = 1| var noise = PinkNoise.ar; var filtered = this.value(noise); var env = EnvGen.kr(Env.asr(0.1, 1, 0.1, \sine), gate, 0.1, doneAction: 2); if (not(mute)) { Out.ar(0, (filtered * env) ! 2); // filter only }; Out.ar(bus1, noise); Out.ar(bus2, filtered); }.play(server.defaultGroup); synth.register; synth.onFree { { [bus1, bus2].do(_.free); fs.active_(false); win.close; }.defer; } ^fs } } + Filter { *scopeResponse { |server, freqMode=1, label, args| var argNames = this.class.findRespondingMethodFor(\ar).argNames; var hasFreqInput = argNames.includes(\freq); ^if(hasFreqInput){ {|in| this.ar(in: in, freq:MouseX.kr(10, SampleRate.ir / 4, 1)) * Line.ar(0,1,0.1) } .scopeResponse(server, freqMode, label ?? {"%: empirical frequency response (move mouse to change freq)".format(this.asString)} ) }{ // no freq input {|in| this.ar(in: in) * Line.ar(0,1,0.1) } .scopeResponse(server, freqMode, label ?? {"%: empirical frequency response".format(this.asString)} ) } } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/server-meter.sc000644 000765 000024 00000000310 12756534417 030240 0ustar00crucialstaff000000 000000 + Server { meter { |numIns, numOuts| ^if( GUI.id == \swing and: { \JSCPeakMeter.asClass.notNil }, { \JSCPeakMeter.asClass.meterServer( this ); }, { ServerMeter(this, numIns, numOuts) }); } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/server-scope.sc000644 000765 000024 00000003273 12756534417 030250 0ustar00crucialstaff000000 000000 + Server { scope { arg numChannels, index = 0, bufsize = 4096, zoom = (1), rate = \audio; numChannels = numChannels ?? { if (index == 0) { options.numOutputBusChannels } { 2 } }; if(scopeWindow.isNil) { scopeWindow = Stethoscope(this, numChannels, index, bufsize, zoom, rate, nil, this.options.numBuffers); // prevent buffer conflicts by using reserved bufnum scopeWindow.window.onClose = scopeWindow.window.onClose.addFunc({ scopeWindow = nil }); ServerTree.add(this, this); } { scopeWindow.setProperties(numChannels, index, bufsize, zoom, rate); scopeWindow.run; scopeWindow.window.front; }; ^scopeWindow } freqscope { ^FreqScope.new(server: this); } } + Bus { scope { arg bufsize = 4096, zoom; ^server.scope(numChannels, index, bufsize, zoom, rate); } } + Function { scope { arg numChannels, outbus = 0, fadeTime = 0.05, bufsize = 4096, zoom; var synth, synthDef, bytes, synthMsg, outUGen, server; server = Server.default; if(server.serverRunning.not) { (server.name.asString ++ " server not running!").postln; ^nil }; synthDef = this.asSynthDef(name: SystemSynthDefs.generateTempName, fadeTime:fadeTime); outUGen = synthDef.children.detect { |ugen| ugen.class === Out }; numChannels = numChannels ?? { if(outUGen.notNil) { (outUGen.inputs.size - 1) } { 1 } }; synth = Synth.basicNew(synthDef.name, server); bytes = synthDef.asBytes; synthMsg = synth.newMsg(server, [\i_out, outbus, \out, outbus], \addToHead); server.sendMsg("/d_recv", bytes, synthMsg); server.scope(numChannels, outbus, bufsize, zoom, outUGen.rate); ^synth } freqscope { var server = Server.default; this.play(server); ^FreqScope.new(server: server) } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/ServerPlusGUI.sc000644 000765 000024 00000032645 12766171707 030317 0ustar00crucialstaff000000 000000 + Server { // splitting makeWindow and makeGui, makes sure that makeWindow can be overridden // while maintaining the availability of the GUI server window makeWindow { arg w; if (Platform.makeServerWindowAction.notNil) { ^Platform.makeServerWindowAction.value(this, w) } { ^this.makeGui( w ); } } calculateViewBounds { var width = 288, height = 98, taskBarHeight = 27; // the latter should be in SCWindow var keys = set.asArray.collect(_.name).sort; ^Rect(5, keys.indexOf(name) * (height + taskBarHeight) + 5, width, height) } makeGui { arg w; var active, booter, killer, makeDefault, running, booting, stopped, bundling, showDefault; var startDump, stopDump, blockAliveThread, dumping = false; var recorder, scoper; var countsViews, serverController, serverStatusController; var label, gui, font, volumeNum; var buttonColor, faintGreen, faintRed; if (window.notNil) { ^window.front }; gui = GUI.current; font = Font.sansSerif(10); if (gui.id == \qt) { buttonColor = gui.palette.button; faintGreen = buttonColor.blend(Color.green, 0.2); faintRed = buttonColor.blend(Color.red, 0.25); } { faintGreen = Color.green.alpha_(0.2); faintRed = Color.red.alpha_(0.3) }; if(w.isNil) { label = name.asString + "server"; w = window = gui.window.new(label, this.calculateViewBounds, resizable: false); w.view.decorator = FlowLayout(w.view.bounds); } { label = w.name }; if(isLocal) { booter = gui.button.new(w, Rect(0,0, 44, 18)); booter.canFocus = false; booter.font = font; booter.states = [["Boot"], ["Quit", nil, faintGreen]]; booter.action = { arg view; if(view.value == 1, { booting.value; this.boot; }); if(view.value == 0,{ this.quit; }); }; booter.setProperty(\value, this.serverRunning.binaryValue); killer = gui.button.new(w, Rect(0,0, 20, 18)); killer.states = [["K"]]; killer.font = font; killer.canFocus = false; killer.action = { Server.killAll; stopped.value; }; }; active = gui.staticText.new(w, Rect(0,0, 78, 18)); active.string = this.name.asString; active.align = \center; active.font = Font.sansSerif( 12 ).boldVariant; if(this.serverRunning, running, stopped); makeDefault = gui.button.new(w, Rect(0,0, 54, 18)); makeDefault.font = font; makeDefault.canFocus = false; makeDefault.states = [["-> default"], ["-> default", nil, faintGreen]]; makeDefault.value_((this == Server.default).binaryValue); makeDefault.action = { Server.default_(this) }; //w.view.decorator.nextLine; if(isLocal){ recorder = gui.button.new(w, Rect(0,0, 66, 18)); recorder.font = font; recorder.states = [ ["record >"], ["stop []", nil, faintGreen] ]; recorder.action = { if (recorder.value == 1) { this.record } { this.stopRecording }; }; recorder.enabled = false; }; w.view.keyDownAction = { arg view, char, modifiers; // if any modifiers except shift key are pressed, skip action if(modifiers & 16515072 == 0) { case {char === $n } { this.queryAllNodes(false) } {char === $N } { this.queryAllNodes(true) } {char === $l } { this.tryPerform(\meter) } {char === $p} { if(this.serverRunning) { this.plotTree } } {char === $ } { if(this.serverRunning.not) { this.boot } } {char === $s } { if( (this.isLocal and: (GUI.id == \qt)) or: ( this.inProcess )) {this.scope(options.numOutputBusChannels)} {warn("Scope not supported")} } {char === $f } { if( (this.isLocal and: (GUI.id == \qt)) or: ( this.inProcess )) {this.freqscope} {warn("FreqScope not supported")} } {char == $d } { if(this.isLocal or: { this.inProcess }) { if(dumping, stopDump, startDump) } { "cannot dump a remote server's messages".inform } } {char === $m } { if(this.volume.isMuted) { this.unmute } { this.mute } } {char === $0 and: {volumeNum.hasFocus.not}} { this.volume = 0.0; }; }; }; if (isLocal) { running = { active.stringColor_(Color.new255(74, 120, 74)); active.string = "running"; booter.setProperty(\value,1); recorder.enabled = true; }; stopped = { active.stringColor_(Color.grey(0.3)); active.string = "inactive"; stopDump.value; booter.setProperty(\value,0); recorder.setProperty(\value,0); recorder.enabled = false; countsViews.do(_.string = ""); }; booting = { active.stringColor_(Color.new255(255, 140, 0)); active.string = "booting"; //booter.setProperty(\value,0); }; bundling = { active.stringColor_(Color.new255(237, 157, 196)); booter.setProperty(\value,1); recorder.enabled = false; }; blockAliveThread = { SystemClock.sched(0.2, { this.stopAliveThread }); }; startDump = { this.dumpOSC(1); this.stopAliveThread; dumping = true; w.name = "dumping osc: " ++ name.asString; CmdPeriod.add(blockAliveThread); }; stopDump = { this.dumpOSC(0); if(this.serverRunning) { this.startAliveThread }; dumping = false; w.name = label; CmdPeriod.remove(blockAliveThread); }; w.onClose = { window = nil; serverController.remove; serverStatusController.remove; }; } { running = { active.stringColor_(Color.new255(74, 120, 74)); active.string = "running"; active.background = Color.clear; }; stopped = { active.stringColor_(Color.grey(0.5)); active.string = "inactive"; }; booting = { active.stringColor_(Color.new255(255, 140, 0)); active.string = "booting"; }; bundling = { active.stringColor = Color.new255(237, 157, 196); active.background = Color.red(0.5); booter.setProperty(\value,1); }; w.onClose = { // but do not remove other responders this.stopAliveThread; window = nil; serverController.remove; serverStatusController.remove; }; }; showDefault = { makeDefault.value = (Server.default == this).binaryValue; }; if(this.serverRunning, running, stopped); w.view.decorator.nextLine; countsViews = #[ "Avg CPU:", "Peak CPU:", "UGens:", "Synths:", "Groups:", "SynthDefs:" ].collect { arg name, i; var label,numView, pctView; label = gui.staticText.new(w, Rect(0,0, 80, 12)); label.string = name; label.font = font; label.align = \right; if (i < 2, { numView = gui.staticText.new(w, Rect(0,0, 34, 12)); numView.font = font; numView.align = \left; pctView = gui.staticText.new(w, Rect(0,0, 12, 12)); pctView.string = "%"; pctView.font = font; pctView.align = \left; },{ numView = gui.staticText.new(w, Rect(0,0, 50, 12)); numView.font = font; numView.align = \left; }); numView }; if(isLocal or: { options.remoteControlVolume }) { { var volSpec, currentVolume; var volumeSlider, muteButton, muteActions, volController; currentVolume = this.volume.volume; muteActions = [{this.unmute}, {this.mute}]; volSpec = [volume.min, volume.max, \db].asSpec; gui.staticText.new(w, Rect(0,0, 44, 18)) .font_(font) .string_("volume:"); muteButton = gui.button.new(w, Rect(0, 0, 20, 18)) .font_(font) .canFocus_(false) .states_([ ["M"], ["M", nil, faintRed] ]) .action_({arg me; if(this.serverRunning) { muteActions[me.value].value; } { "The server must be booted to mute it".warn; me.value_(0); } }); volumeNum = gui.numberBox.new(w, Rect(0, 0, 28, 18)) .font_(font) .value_(currentVolume) .align_(\center) .action_({arg me; var newdb; newdb = me.value.clip(-90, 6); this.volume_(newdb); volumeSlider.value_(volSpec.unmap(newdb)); }); volumeSlider = gui.slider.new(w, Rect(0, 0, 172, 18)) .value_(volSpec.unmap(currentVolume).round(0.1)) .onClose_{volController.remove} .action_({arg me; var newdb; newdb = volSpec.map(me.value).round(0.1); this.volume_(newdb); volumeNum.value_(newdb); }) .keyDownAction_({arg slider, char, modifiers, unicode, keycode; if (char == $], { slider.increment; }); if (char == $[, { slider.decrement; }); if (unicode == 16rF700, { slider.increment; }); if (unicode == 16rF703, { slider.increment; }); if (unicode == 16rF701, { slider.decrement; }); if (unicode == 16rF702, { slider.decrement; }); nil; }) ; volController = SimpleController(volume) .put(\amp, {|changer, what, vol| { volumeNum.value_(vol.round(0.01)); volumeSlider.value_(volSpec.unmap(vol)); }.defer }) .put(\mute, {|changer, what, flag| { muteButton.value_(flag.binaryValue); }.defer }) .put(\ampRange, {|changer, what, min, max| volSpec = [min, max, \db].asSpec; volumeSlider.value_(volSpec.unmap(volume.volume)); }) }.value; }; w.front; serverStatusController = SimpleController(statusWatcher) .put(\serverRunning, { if(this.serverRunning, running, stopped) }) .put(\counts,{ countsViews.at(0).string = statusWatcher.avgCPU.round(0.1); countsViews.at(1).string = statusWatcher.peakCPU.round(0.1); countsViews.at(2).string = statusWatcher.numUGens; countsViews.at(3).string = statusWatcher.numSynths; countsViews.at(4).string = statusWatcher.numGroups; countsViews.at(5).string = statusWatcher.numSynthDefs; }); serverController = SimpleController(this) .put(\bundling, bundling) .put(\default, showDefault); if(isLocal){ serverController.put(\cmdPeriod, { recorder.setProperty(\value, 0) }) }; this.startAliveThread; } plotTree {|interval=0.5| var onClose, window = Window.new(name.asString + "Node Tree", Rect(128, 64, 400, 400), scroll:true ).front; window.view.hasHorizontalScroller_(false).background_(Color.grey(0.9)); onClose = this.plotTreeView(interval, window.view, { defer {window.close}; }); window.onClose = { onClose.value; }; } plotTreeView {|interval=0.5, parent, actionIfFail| var resp, done = false; var collectChildren, levels, countSize; var view, bounds; var updater, updateFunc; var tabSize = 25; var pen, font; pen = GUI.current.pen; font = Font.sansSerif(10); view = UserView.new(parent, Rect(0,0,400,400)); view.drawFunc = { var xtabs = 0, ytabs = 0, drawFunc; drawFunc = {|group| var thisSize, rect, endYTabs; xtabs = xtabs + 1; ytabs = ytabs + 1; pen.font = font; group.do({|node| if(node.value.isArray, { thisSize = countSize.value(node); endYTabs = ytabs + thisSize + 0.2; rect = Rect(xtabs * tabSize + 0.5, ytabs * tabSize + 0.5, parent.bounds.width - (xtabs * tabSize * 2), thisSize * tabSize; ); pen.fillColor = Color.grey(0.8); pen.fillRect(rect); pen.strokeRect(rect); pen.color = Color.black; pen.stringInRect( " Group" + node.key.asString + (node.key == 1).if("- default group", ""), rect ); drawFunc.value(node.value); ytabs = endYTabs; },{ rect = Rect(xtabs * tabSize + 0.5, ytabs * tabSize + 0.5, 7 * tabSize, 0.8 * tabSize ); pen.fillColor = Color.white; pen.fillRect(rect); pen.strokeRect(rect); pen.color = Color.black; pen.stringInRect( " " ++ node.key.asString + node.value.asString, rect ); ytabs = ytabs + 1; }); }); xtabs = xtabs - 1; }; drawFunc.value(levels); }; // msg[1] controls included // msg[2] nodeID of queried group // initial number of children resp = OSCFunc({ arg msg; var finalEvent; var i = 2, j, controls, printControls = false, dumpFunc; if(msg[1] != 0, {printControls = true}); dumpFunc = {|numChildren| var event, children; event = ().group; event.id = msg[i]; event.instrument = nil; // need to know it's a group i = i + 2; children = Array.fill(numChildren, { var id, child; // i = id // i + 1 = numChildren // i + 2 = def (if synth) id = msg[i]; if(msg[i+1] >=0, { child = dumpFunc.value(msg[i+1]); }, { j = 4; child = ().synth.instrument_(msg[i+2]); if(printControls, { controls = (); msg[i+3].do({ controls[msg[i + j]] = msg[i + j + 1]; j = j + 2; }); child.controls = controls; i = i + 4 + (2 * controls.size); }, {i = i + 3 }); }); child.id = id; }); event.children = children; event; }; finalEvent = dumpFunc.value(msg[3]); done = true; collectChildren = {|group| group.children.collect({|child| if(child.children.notNil,{ child.id -> collectChildren.value(child); }, { child.id -> child.instrument; }); }); }; levels = collectChildren.value(finalEvent); countSize = {|array| var size = 0; array.do({|elem| if(elem.value.isArray, { size = size + countSize.value(elem.value) + 2}, {size = size + 1;}); }); size }; defer { view.bounds = Rect(0, 0, 400, max(400, tabSize * (countSize.value(levels) + 2))); view.refresh; } }, '/g_queryTree.reply', addr).fix; updateFunc = { fork { loop { this.sendMsg("/g_queryTree", 0, 0); interval.wait; } } }; updater = updateFunc.value; CmdPeriod.add(updateFunc); SystemClock.sched(3, { if(done.not, { actionIfFail.value(); "Server failed to respond to Group:queryTree!".warn; }); }); //action to be executed when enclosing window closes ^{ updater.stop; CmdPeriod.remove(updateFunc); resp.free; } } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/SynthDescLibPlusGUI.sc000644 000765 000024 00000011233 12756534417 031372 0ustar00crucialstaff000000 000000 + SynthDescLib { browse { var w; var synthDescLib; var synthDescLibListView; var synthDescListView; var ugensListView; var controlsListView; var inputsListView; var outputsListView; var synthDescList; var hvBold12; var updateSynthDefs; var updateSynthDefData; var btn, testFn; var fntMono, gui; hvBold12 = Font.sansSerif( 12 ).boldVariant; fntMono = Font.monospace( 10 ); w = Window.new("SynthDef browser", Rect(128, (Window.screenBounds.height - 638).clip(0, 320), 700, 608)); w.view.decorator = FlowLayout(w.view.bounds); w.view.decorator.shift(220); testFn = { var synth, item; item = this[synthDescListView.item.asSymbol]; if (item.notNil) { synth = Synth(item.name); synth.postln; synth.play; SystemClock.sched(3, { if (item.hasGate) { synth.release } { synth.free }; }); }; }; btn = Button.new(w, 48 @ 20); btn.states = [["test"]]; btn.action = testFn; btn = Button.new(w, 48 @ 20); btn.states = [["window"]]; btn.action = { var item; item = this[synthDescListView.item.asSymbol]; if (item.notNil) { item.makeWindow }; }; w.view.decorator.nextLine; StaticText.new(w, Rect(0,0,220,24)).string_("SynthDescLibs").font_(hvBold12); StaticText.new(w, Rect(0,0,220,24)).string_("SynthDefs").font_(hvBold12); StaticText.new(w, Rect(0,0,220,24)).string_("UGens").font_(hvBold12); w.view.decorator.nextLine; synthDescLibListView = ListView.new(w, Rect(0,0, 220, 320)).focus; synthDescListView = ListView.new(w, Rect(0,0, 220, 320)); synthDescListView.beginDragAction_({arg v; v.items[v.value].asSymbol; }); ugensListView = ListView.new(w, Rect(0,0, 220, 320)); w.view.decorator.nextLine; StaticText.new(w, Rect(0,0,240,24)).string_("SynthDef Controls") .font_(hvBold12).align_(\center); StaticText.new(w, Rect(0,0,200,24)).string_("SynthDef Inputs") .font_(hvBold12).align_(\center); StaticText.new(w, Rect(0,0,200,24)).string_("SynthDef Outputs") .font_(hvBold12).align_(\center); w.view.decorator.nextLine; controlsListView = ListView.new(w, Rect(0,0, 240, 160)); inputsListView = ListView.new(w, Rect(0,0, 200, 160)); outputsListView = ListView.new(w, Rect(0,0, 200, 160)); controlsListView.resize = 4; inputsListView.resize = 4; outputsListView.resize = 4; [controlsListView, inputsListView, outputsListView].do { |listview| listview.selectionMode = \none }; controlsListView.font = fntMono; inputsListView.font = fntMono; outputsListView.font = fntMono; w.view.decorator.nextLine; synthDescLibListView.items_(SynthDescLib.all.keys.asArray.sort) .value_(synthDescLibListView.items.indexOf(name) ? 0); synthDescLibListView.action = { synthDescListView.value = 0; updateSynthDefs.value; }; synthDescListView.items = []; synthDescListView.action = { updateSynthDefData.value; }; synthDescListView.enterKeyAction = testFn; updateSynthDefs = { var libName; libName = synthDescLibListView.item; synthDescLib = SynthDescLib.all[libName]; synthDescList = synthDescLib.synthDescs.values.sort {|a,b| a.name <= b.name }; synthDescListView.items = synthDescList.collect {|desc| desc.name.asString }; updateSynthDefData.value; }; updateSynthDefData = { var synthDesc; synthDesc = synthDescList[synthDescListView.value]; if (synthDesc.isNil) { ugensListView.items = []; inputsListView.items = []; outputsListView.items = []; controlsListView.items = []; }{ ugensListView.items = synthDesc.def.children.collect { |x, i| i.asString.copy.extend(7, $ ) ++ x.class.name.asString; }; inputsListView.items = synthDesc.inputs.collect { |x| var string; string = x.rate.asString.copy; string = string.extend(9, $ ) ++ " " ++ x.startingChannel; string = string.extend(19, $ ) ++ " " ++ x.numberOfChannels; }; outputsListView.items = synthDesc.outputs.collect { |x| var string; string = x.rate.asString.copy; string = string.extend(9, $ ) ++ " " ++ x.startingChannel; string = string.extend(19, $ ) ++ " " ++ x.numberOfChannels; }; controlsListView.items = synthDesc.controls.reject {|a| a.name == '?' }.collect { |x| var string; string = if (x.name.notNil) { x.name.asString.copy; }{ "" }; if (x.rate.notNil) { string = string.extend(12, $ ) ++ " " ++ x.rate; }; if (x.defaultValue.notNil) { if (x.defaultValue.isArray) { string = string.extend(22, $ ) ++ " " ++ x.defaultValue.collect(_.asStringPrec(6)); } { string = string.extend(22, $ ) ++ " " ++ x.defaultValue.asStringPrec(6); } }; }; }; }; updateSynthDefs.value; w.front; } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/SynthDescPlusGUI.sc000644 000765 000024 00000007135 12756534417 030751 0ustar00crucialstaff000000 000000 +SynthDesc { makeWindow{ if (Platform.makeSynthDescWindowAction.notNil) { ^Platform.makeSynthDescWindowAction.value(this) } { ^this.makeGui; } } makeGui { var w, startButton, sliders; var synth, cmdPeriodFunc; var usefulControls, numControls; var getSliderValues, gui; gui = GUI.current; usefulControls = controls.select {|controlName, i| var ctlname; ctlname = controlName.name.asString; (ctlname != "?") && (msgFuncKeepGate or: { ctlname != "gate" }) }; numControls = usefulControls.collect(_.defaultValue).flatten.size; sliders = IdentityDictionary(numControls); // make the window w = gui.window.new("another control panel", Rect(20, 400, 440, numControls * 28 + 32)); w.view.decorator = FlowLayout(w.view.bounds); w.view.background = Color.rand(0.5, 1.0); // add a button to start and stop the sound. startButton = gui.button.new(w, 75 @ 24); startButton.states = [ ["Start", Color.black, Color.green], ["Stop", Color.white, Color.red] ]; getSliderValues = { var envir; envir = (); usefulControls.do {|controlName, i| var ctlname = controlName.name.asString; var sliderEntry = sliders[controlName.name]; if(ctlname[1] == $_ and: { "ti".includes(ctlname[0]) }) { ctlname = ctlname[2..]; }; if (sliderEntry.isArray) { envir.put(controlName.name, sliderEntry.collect(_.value)); } { envir.put(controlName.name, sliderEntry.value); } }; envir.use { msgFunc.valueEnvir }; }; startButton.action = { |view| var synthEndWatcher, localSynth; if (view.value == 1) { synth = Synth(name, getSliderValues.value).register; localSynth = synth; synthEndWatcher = SimpleController(synth).put(\n_end, { synthEndWatcher.remove; // 'synth' may have changed in the interim -- // clear 'synth' only if n_end is for the current synth if(localSynth === synth) { synth = nil; defer { view.value = 0 }; }; }); } { if(synth.isPlaying) { if (this.hasGate) { synth.release; } { synth.free }; }; }; }; // create controls for all parameters usefulControls.do {|controlName| var ctlname, ctlname2, capname, spec, controlIndex, slider; ctlname = controlName.name; capname = ctlname.asString; capname[0] = capname[0].toUpper; w.view.decorator.nextLine; ctlname = ctlname.asSymbol; if((spec = metadata.tryPerform(\at, \specs).tryPerform(\at, ctlname)).notNil) { spec = spec.asSpec } { spec = ctlname.asSpec; }; if (spec.isKindOf(ControlSpec)) { slider = EZSlider(w, 400 @ 24, capname, spec, { |ez| if(synth.isPlaying) { synth.set(ctlname, ez.value) } }, controlName.defaultValue); } { spec = ControlSpec(-1e10, 1e10); if (controlName.defaultValue.isNumber) { slider = EZNumber(w, 400 @ 24, capname, spec, { |ez| if(synth.isPlaying) { synth.set(ctlname, ez.value) } }, controlName.defaultValue) } { slider = Array(controlName.defaultValue.size); controlName.defaultValue.do {|value, i| slider.add(EZNumber(w, 96 @ 24, "%[%]".format(capname, i), spec, { |ez| if(synth.isPlaying) { synth.set(controlName.index + i, ez.value) } }, value)) } } }; sliders.put(ctlname, slider) }; // set start button to zero upon a cmd-period cmdPeriodFunc = { startButton.value = 0; }; CmdPeriod.add(cmdPeriodFunc); // stop the sound when window closes and remove cmdPeriodFunc. w.onClose = { synth.release; CmdPeriod.remove(cmdPeriodFunc); }; ^w.front; // make window visible and front window. } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/UGen-scope.sc000644 000765 000024 00000002742 12756534417 027600 0ustar00crucialstaff000000 000000 + UGen { scope { arg name = "UGen Scope", bufsize = 4096, zoom = 1.0; var server = Server.default; ^SynthDef.wrap({ var bus, numChannels, rate, scope; numChannels = this.numChannels; rate = this.rate; bus = Bus.perform(rate, server, numChannels); switch(rate, \audio, {Out.ar(bus.index, this)}, \control, {Out.kr(bus.index, this)} ); { scope = Stethoscope.new( server, numChannels, bus.index, bufsize, zoom, rate ); scope.window.name_(name.asString).bounds_( Stethoscope.tileBounds); Stethoscope.ugenScopes.add(scope); scope.window.onClose = { scope.free; bus.free; Stethoscope.ugenScopes.remove(scope) }; CmdPeriod.doOnce({ {scope.window.close}.defer }); }.defer(0.001); this; }) } } + Array { scope { arg name = "UGen Scope", bufsize = 4096, zoom = 1.0; var server = Server.default; ^SynthDef.wrap({ var bus, numChannels, rate, scope; numChannels = this.numChannels; rate = this.rate; bus = Bus.perform(rate, server, numChannels); switch(rate, \audio, {Out.ar(bus.index, this)}, \control, {Out.kr(bus.index, this)} ); { scope = Stethoscope.new( server, numChannels, bus.index, bufsize, zoom, rate ); scope.window.name_(name.asString).bounds_( Stethoscope.tileBounds); Stethoscope.ugenScopes.add(scope); scope.window.onClose = { scope.free; bus.free; Stethoscope.ugenScopes.remove(scope) }; CmdPeriod.doOnce({ {scope.window.close}.defer }); }.defer(0.001); this; }) } } SuperCollider-Source/SCClassLibrary/Common/GUI/PlusGUI/Control/WiiMoteGUI.sc000644 000765 000024 00000011660 12756534417 027554 0ustar00crucialstaff000000 000000 /* class to display wiimote data as a gui */ WiiMoteGUI { classvar <>xposScreen=0, <>yposScreen=20; classvar w, <>wiimote, 700, { yposScreen = 20; xposScreen = xposScreen + xsize + 10; if ( xposScreen > 900, { xposScreen = 0; }); }); StaticText.new(w, Rect(0, 0, xsize - 2, 20)).string_("WiiMote" + wiimote.id + wiimote.address ) .align_(0); //.background_(labelColor); rmview = CompositeView.new( w, Rect( 5, 30, 205, 130 )); rm = WiiRemoteGUI.new( rmview, wiimote, 0 ); //30 ); ncview = CompositeView.new( w, Rect( 5, 160, 205, 105 )); nc = WiiNunchukGUI.new( ncview, wiimote, 0 ); // 160 ); watcher = SkipJack.new( { this.updateVals }, 0.1, { w.isClosed }, (\wiimote_gui_ ++ counter)); watcher.start; } updateVals { { rm.updateVals; if (wiimote.ext_type == 1, { nc.updateVals }); }.defer; } hide { w.close; watcher.stop; } show { watcher.start; } } WiiRemoteGUI{ var <>wiimote; var <>w; var " ).background_(onColor).align_( 0 ); xpos = xpos + 25; sliders = wiimote.remote_motion.collect{ |it,i| xpos = xpos + 25; Slider.new( w, Rect( xpos-25, ypos, 20, 70 ) ); }; sliders = sliders.add( Slider.new( w, Rect( xpos, ypos, 20, 70 ) ) ); ypos = ypos + 75; xpos = 5; led = wiimote.remote_led.collect{ |it,i| xpos = xpos + 25; Button.new( w, Rect( xpos-25, ypos, 20, 20 ) ) .states_( [ [ "X", Color.black, Color.yellow ],["O", Color.yellow, Color.black ] ] ) .action_( { |but| wiimote.setLEDState( i, but.value ) } ); }; rumble = Button.new( w, Rect( xpos, ypos, 70, 20 ) ) .states_( [ [ "rumble", Color.black, Color.yellow ],["RUMBLING", Color.yellow, Color.black ] ] ) .action_( { |but| wiimote.rumble( but.value ) } ); } updateVals{ led.do{ |it,i| it.value = wiimote.remote_led[i] }; //rumble.value = wiimote.rumble; wiimote.remote_motion.do{ |it,i| sliders[i].value = it }; //sliders[3].value = wiimote.remote_motion[3]/3; sliders[4].value = wiimote.battery; wiimote.remote_buttons.do{ |it,i| if ( it == 1 , { buttons[i].background = onColor; },{ buttons[i].background = offColor; }); }; } } WiiNunchukGUI{ var <>wiimote; var <>w; var setBoth = true; var finishedFunc, <>errorFunc, <>progressFunc; var error = false, started = false; *new {|requestedURL, localPath, finishedFunc, errorFunc, progressFunc| ^super.new.init(requestedURL, localPath, finishedFunc, errorFunc, progressFunc); } *qtClass { ^'QtDownload' } init {|requestedURL, localPath, argfinFunc, argerrFunc, argprogFunc| localPath = localPath ?? { Platform.defaultTempDir +/+ "download" }; finishedFunc = argfinFunc; errorFunc = argerrFunc; progressFunc = argprogFunc; if(requests.isNil, { requests = Set.new; }); requests.add(this); this.startDownload(requestedURL, localPath); } cancel { "Download of % cancelled\n".postf(this.getProperty(\source)); this.invokeMethod(\cancel); this.cleanup; } *cancelAll { requests.do({|dl| dl.cancel }); } // private doOnShutDown { this.cancel } startDownload { |requestedURL, localPath| if(started.not, { started = true; ShutDown.add(this); this.setProperty(\source, requestedURL); this.setProperty(\destination, localPath); this.connectMethod('doFinished()', 'doFinished'); this.connectMethod('doError()', 'doError'); this.connectMethod('doProgress(int, int)', 'doProgress'); this.invokeMethod(\download); }); } doFinished { "Download of % finished\n".postf(this.getProperty(\source)); this.cleanup; if(error.not, { finishedFunc.value; }); } cleanup { requests.remove(this); heap.remove(this); ShutDown.remove(this); } doError { error = true; this.cleanup; errorFunc.value; } doProgress {|bytesReceived, bytesTotal| if(error.not, { progressFunc.value(bytesReceived, bytesTotal); }); } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/DragView.sc000644 000765 000024 00000001751 12756534416 025303 0ustar00crucialstaff000000 000000 DragView : TextField { *new { arg parent, bounds; ^super.new(parent,bounds).initQDragView } initQDragView { var plt = this.palette; plt.base = plt.window; this.palette = plt; this.setProperty(\readOnly, true); } // override View.mouseDownEvent to initiate drag without keyboard modifier mouseDownEvent { arg x, y, modifiers, buttonNumber, clickCount; // Try to get drag obj and start a drag. // If successful, block further processing of this event. if( this.beginDrag( x, y ) ) { ^true }; // else continue to handle mouse down event modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseDown( x, y, modifiers, buttonNumber, clickCount ); } defaultGetDrag { ^nil } defaultCanReceiveDrag { ^false } defaultReceiveDrag { } } DragSource : DragView { defaultGetDrag { ^object } } DragSink : DragView { defaultCanReceiveDrag { ^true } defaultReceiveDrag { this.object = View.currentDrag; action.value(this); } } DragBoth : DragSink { defaultGetDrag { ^object } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/enums.sc000644 000765 000024 00000005205 12756534417 024721 0ustar00crucialstaff000000 000000 QAlignment { classvar dict; *initClass { dict = IdentityDictionary.new; dict.put( \left, 16r1 | 16r80 ); dict.put( \center, 16r4 | 16r80 ); dict.put( \right, 16r2 | 16r80 ); dict.put( \topLeft, 16r1 | 16r20 ); dict.put( \top, 16r4 | 16r20 ); dict.put( \topRight, 16r2 | 16r20 ); dict.put( \bottomLeft, 16r1 | 16r40 ); dict.put( \bottom, 16r4 | 16r40 ); dict.put( \bottomRight, 16r2 | 16r40 ); } *new { arg alignment; ^dict[alignment]; } } QOrientation { classvar dict; *initClass { dict = IdentityDictionary.new; dict.put( \horizontal, 1 ); dict.put( \vertical, 2 ); } *new { arg alignment; ^dict[alignment]; } } QLimits { classvar dict; *initClass { dict = IdentityDictionary.new; dict.put( \maxWidgetSize, 16777215 ); } *new { arg limit; ^dict[limit]; } } QKey { classvar 0) {cmods = cmods | 131072}; if (mods & QKeyModifiers.alt > 0 ) {cmods = cmods | 524288}; Platform.case ( \osx, { if (mods & QKeyModifiers.control > 0) {cmods = cmods | 1048576}; // Cmd if (mods & QKeyModifiers.meta > 0) {cmods = cmods | 262144}; // Ctrl }, { if (mods & QKeyModifiers.control > 0) {cmods = cmods | 262144} } // Ctrl ); if (mods & QKeyModifiers.keypad > 0) {cmods = cmods | 2097152}; // TODO: caps-lock, func, help ^cmods; } } QWebFontFamily { classvar labelView, action, globalAction; *new { arg parentView, bounds, label,items, globalAction, initVal=0, initAction=false, labelWidth,labelHeight=20, layout, gap, margin; ^super.new.init(parentView, bounds, label, items, globalAction, initVal, initAction, labelWidth,labelHeight,layout, gap, margin); } init { arg parentView, bounds, label, argItems, argGlobalAction, initVal, initAction, labelWidth, labelHeight, layout, argGap, argMargin; // try to use the parent decorator gap this.prMakeMarginGap(parentView, argMargin, argGap); // init the views (handled by subclasses) this.initViews( parentView, bounds, label, labelWidth,labelHeight,layout ); this.items=argItems ? []; globalAction=argGlobalAction; widget.action={arg obj; items.at(obj.value).value.value(this); globalAction.value(this); }; this.value_(initVal); items.notNil.if{ if(initAction){ items.at(initVal).value.value(this); // You must do this like this globalAction.value(this); // since listView's array is not accessible yet }; this.value_(initVal); }; } initViews{} // override this for your subclass views value{ ^widget.value} value_{|val| widget.value=val} valueAction_{|val| widget.value_(val); this.doAction} doAction {widget.doAction;} items_{ arg assocArray; assocArray = assocArray.collect({ |it| if (it.isKindOf(Association), { it }, { it -> nil }) }); items=assocArray; widget.items=assocArray.collect({|item| item.key}); } item {^items.at(this.value).key} itemFunc {^items.at(this.value).value} addItem{arg name, action; this.insertItem(nil, name, action); } insertItem{ arg index, name, action; var temp; index = index ? items.size; this.items=items.insert(index, name.asSymbol -> action); } removeItemAt{ arg index; var temp; items.removeAt(index); this.items_(items) } replaceItemAt{ arg index, name, action; var temp; name = name ? items.at(index).key; action = action ? items.at(index).value; this.removeItemAt(index); this.insertItem(index, name, action); } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZKnob.sc000644 000765 000024 00000021413 12766171707 024721 0ustar00crucialstaff000000 000000 EZKnob : EZGui { classvar <>compactRatio=0.87; var controlSpec, knobSize, unitWidth; var <>round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, knobSize, unitWidth=0, labelHeight=20, layout=\vert, gap, margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, knobSize, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argKnobSize,argUnitWidth, labelHeight, argLayout, argGap, argMargin; var labelBounds, numBounds, unitBounds,knobBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; layout=argLayout; bounds.isNil.if{bounds = 50@90}; knobSize = argKnobSize ; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); labelSize=labelWidth@labelHeight; // calculate bounds of all subviews # labelBounds,numBounds,knobBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); // instert the views label.notNil.if{ //only add a label if desired labelView = StaticText.new(view, labelBounds); labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = StaticText.new(view, unitBounds); }; knobView = Knob.new(view, knobBounds); numberView = NumberBox.new(view, numBounds); // set view parameters and actions controlSpec = argControlSpec.asSpec; (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString}; initVal = initVal ? controlSpec.default; action = argAction; numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep }{ // controlSpec wants a step, so zooming in with alt is disabled. numberView.alt_scale = 1.0; knobView.alt_scale = 1.0; }; numberView.step = numberStep; numberView.scroll_step = numberStep; if((controlSpec.minval + controlSpec.maxval)==0){knobView.centered=true}; knobView.action = { this.valueActionIfChanged_(controlSpec.map(knobView.value)); }; if (controlSpec.step != 0) { knobView.step = (controlSpec.step / (controlSpec.maxval - controlSpec.minval)); }; knobView.receiveDragHandler = { arg slider; slider.valueAction = controlSpec.unmap(View.currentDrag); }; knobView.beginDragAction = { arg slider; controlSpec.map(slider.value) }; numberView.action = { this.valueActionIfChanged_(numberView.value) }; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; this.prSetViewParams; } // just set, no action value_ { arg val; value = controlSpec.constrain(val); numberView.value = value.round(round); knobView.value = controlSpec.unmap(value); } // set and do action valueAction_ { arg val; this.value_(val); this.doAction; } doAction { action.value(this) } set { arg label, spec, argAction, initVal, initAction = false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? value ? controlSpec.default; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } centered_ { arg bool; knobView.centered_(bool) } centered{ ^knobView.centered } setColors{arg stringBackground,stringColor,numBackground, numStringColor,numNormalColor,numTypingColor,knobColors,background; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; numBackground.notNil.if{ numberView.background_(numBackground);}; numNormalColor.notNil.if{ numberView.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ numberView.typingColor_(numTypingColor);}; numStringColor.notNil.if{ numberView.stringColor_(numStringColor);}; knobColors.notNil.if{ knobView.color_(knobColors);}; background.notNil.if{ view.background=background;}; numberView.refresh; knobView.refresh; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; numberView.font=font; } ///////Private methods /////// prSetViewParams{ // sets resize and alignment for different layouts switch (layout, \line2, { labelView.notNil.if{ labelView.resize_(5); unitView.notNil.if{unitView.resize_(9)}; numberView.resize_(8); }{ unitView.notNil.if{ unitView.resize_(6); numberView.resize_(5); }{ numberView.resize_(5); }; }; knobView.resize_(9); popUp.if{view.resize_(2)}; }, \vert, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); popUp.if{view.resize_(2)}; }, \vert2, { labelView.notNil.if{labelView.resize_(2).align_(\center)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); popUp.if{view.resize_(2)}; }, \horz, { labelView.notNil.if{labelView.resize_(4).align_(\right)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); knobView.resize_(9); popUp.if{view.resize_(2)}; }); } prSubViewBounds{arg rect, hasLabel, hasUnit; // calculate subview bounds var numBounds,labelBounds,knobBounds, unitBounds,knobHeight, numHeight; var gap1, gap2, gap3, tmp, labelH, unitH; gap1 = gap.copy; gap2 = gap.copy; gap3 = gap.copy; (rect.height<= (labelSize.y*2)).if{labelSize.y=rect.height/2}; numHeight=labelSize.y; switch (layout, \line2, { knobSize.isNil.if{knobSize=( ((rect.height/compactRatio)-margin.x)@(rect.height))}; knobSize=(knobSize.x-margin.x)@(knobSize.y.min(rect.height)); hasUnit.not.if{ gap2 = 0@0; unitWidth = 0}; labelBounds = Rect(0,0,rect.width-knobSize.x-gap3.x,labelSize.y); //to left hasLabel.if{ unitBounds = Rect(labelBounds.width-unitWidth,labelSize.y+gap1.y, unitWidth, rect.height-labelSize.y-gap1.y); numBounds = Rect(0,labelSize.y+gap1.y, labelBounds.width-gap2.x-unitBounds.width,rect.height-labelSize.y-gap1.y); }{ unitBounds = Rect(labelBounds.width-unitWidth,0, unitWidth, rect.height); numBounds = Rect(0,0, labelBounds.width-gap2.x-unitBounds.width,rect.height); }; knobBounds=knobSize.asRect.moveTo(rect.width-knobSize.x,0); }, \horz, { knobSize.isNil.if{knobSize=( ((rect.height/compactRatio)-margin.x)@(rect.height))}; knobSize=(knobSize.x-margin.x)@(knobSize.y.min(rect.height)); knobBounds=knobSize.asRect.moveTo(rect.width-knobSize.x,0); hasUnit.not.if{ gap2 = 0@0; unitWidth = 0}; hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0}; labelBounds = (labelSize.x@rect.height).asRect; unitBounds = (unitWidth@rect.height).asRect .moveTo(rect.width-knobBounds.width-gap2.x-unitWidth,0); numBounds = Rect.newSides(labelSize.x+gap1.x,0,unitBounds.left-gap2.x,rect.height); }, \vert , { hasUnit.not.if{ gap3 = 0@0; unitWidth = 0}; hasLabel.not.if{ gap1 = 0@0; labelSize.y = 0}; knobSize.isNil.if{ knobSize=( ((rect.height-labelSize.y-numHeight-gap1.y-gap2.y)/compactRatio) @(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)) }; knobSize=((knobSize.x).min(rect.width)) @(knobSize.y.min(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)); labelBounds = (rect.width@labelSize.y).asRect; knobBounds=knobSize.asRect.moveTo(0,labelSize.y+gap1.y); numBounds = Rect(0,rect.height-numHeight,rect.width-unitWidth-gap3.x, numHeight); unitBounds = Rect(rect.width-unitWidth,rect.height-numHeight,unitWidth,numHeight); }, \vert2 , { hasUnit.not.if{ gap3 = 0@0; unitWidth = 0}; hasLabel.not.if{ gap1 = 0@0; labelSize.y = 0}; knobSize.isNil.if{ knobSize=( ((rect.height-labelSize.y-numHeight-gap1.y-gap2.y)/compactRatio) @(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)) }; knobSize=((knobSize.x).min(rect.width)) @(knobSize.y.min(rect.height-labelSize.y-numHeight-gap1.y-gap2.y)); labelBounds = (rect.width@labelSize.y).asRect; knobBounds=knobSize.asRect.moveTo(0,labelSize.y+gap1.y); knobBounds=knobBounds.moveBy((rect.width-knobBounds.width)/2,0); numBounds = Rect(0,rect.height-numHeight,rect.width-unitWidth-gap3.x, numHeight); unitBounds = Rect(rect.width-unitWidth,rect.height-numHeight,unitWidth,numHeight); } ); ((knobBounds.height<0)||(knobBounds.width<0)).if{knobBounds=knobBounds.height_(0).width_(0)}; ^[labelBounds, numBounds, knobBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZListView.sc000644 000765 000024 00000003051 12766171707 025574 0ustar00crucialstaff000000 000000 EZListView : EZLists{ initViews{ arg parentView, bounds, label, labelWidth,labelHeight,arglayout; var labelBounds, listBounds; labelWidth = labelWidth ? 80; layout=arglayout ? \vert; labelSize=labelWidth@labelHeight; bounds.isNil.if{bounds= 160@200}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); // calcualate bounds # labelBounds,listBounds = this.prSubViewBounds(innerBounds, label.notNil); // insert the views label.notNil.if{ //only add a label if desired if (layout==\vert){ labelView = StaticText.new(view, labelBounds).resize_(2); labelView.align = \left; }{ labelView = StaticText.new(view, labelBounds).resize_(4); labelView.align = \right; }; labelView.string = label; }; widget = ListView.new(view, listBounds).resize_(5); } listView{^widget} setColors{arg stringBackground, stringColor, listBackground, listStringColor, selectedStringColor,hiliteColor, background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)};}; listBackground.notNil.if{ this.listview.background_(listBackground);}; listStringColor.notNil.if{ this.listview.stringColor_(listStringColor);}; selectedStringColor.notNil.if{ this.listview.selectedStringColor_(selectedStringColor);}; hiliteColor.notNil.if{ this.listview.hiliteColor_(hiliteColor);}; background.notNil.if{ view.background=background;}; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZNumber.sc000644 000765 000024 00000013154 12766171707 025263 0ustar00crucialstaff000000 000000 EZNumber : EZGui{ var controlSpec, numSize,numberWidth,unitWidth, gap2; var <>round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, numberWidth, unitWidth=0, labelHeight=20, layout=\horz, gap, margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, numberWidth, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argNumberWidth,argUnitWidth, labelHeight, argLayout, argGap, argMargin; var labelBounds, numBounds, unitBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; numberWidth = argNumberWidth; layout=argLayout; bounds.isNil.if {bounds= 160@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); numberWidth.isNil.if{numberWidth=45}{ labelWidth=bounds.width-unitWidth-numberWidth; //override the labelWidth if (layout==\line2){unitWidth=bounds.width-numberWidth}; //override the unitWidth }; labelSize=labelWidth@labelHeight; numSize = numberWidth@labelHeight; // calcualate bounds # labelBounds,numBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); // insert the views label.notNil.if{ //only add a label if desired labelView = StaticText.new(view, labelBounds); if (layout==\line2) {labelView.align = \left;} {labelView.align = \right;}; labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = StaticText.new(view, unitBounds); }; // set view parameters and actions controlSpec = argControlSpec.asSpec; // let default to nil.asSpec! (unitWidth>0).if{ unitView.string = " "++controlSpec.units.asString}; initVal = initVal ? controlSpec.default; action = argAction; numberView = NumberBox.new(view, numBounds).resize_(2); numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep; }{ // controlSpec wants a step, so zooming in with alt is disabled. numberView.alt_scale = 1.0 }; numberView.step = numberStep; numberView.scroll_step = numberStep; numberView.scroll=true; numberView.action = { this.valueActionIfChanged_(numberView.value); }; if (initAction) { this.valueAction = initVal; }{ this.value = initVal; }; this.prSetViewParams; } value_{ arg val; value = controlSpec.constrain(val); numberView.value = value.round(round); } valueAction_ { arg val; this.value_(val); this.doAction; } doAction { action.value(this) } set { arg label, spec, argAction, initVal, initAction=false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? value ? controlSpec.default; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } setColors{ arg stringBackground, stringColor,numBackground,numStringColor, numNormalColor, numTypingColor, background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; numBackground.notNil.if{ numberView.background_(numBackground); }; numNormalColor.notNil.if{ numberView.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ numberView.typingColor_(numTypingColor);}; numStringColor.notNil.if{ numberView.stringColor_(numStringColor);}; background.notNil.if{ view.background=background;}; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; numberView.font=font; } /////// Private methods ///////// prSetViewParams{ // sets resize and alignment for different layouts switch (layout, \line2, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(5); }, \horz, { labelView.notNil.if{ labelView.resize_(4).align_(\right); numberView.resize_(5); unitView.notNil.if{unitView.resize_(6)}; }{ unitView.notNil.if{ unitView.resize_(6)}; numberView.resize_(5); }; }); popUp.if{view.resize_(2)}; } prSubViewBounds{arg rect, hasLabel, hasUnit; var numBounds,labelBounds,sliderBounds; var unitBounds, gap1, gap2, numY; gap1 = gap.copy; gap2 = gap.copy; hasLabel.not.if{ gap1 = 0@0; labelSize=0@0}; hasUnit.not.if{gap2 = 0@0}; switch (layout, \line2, { labelBounds = Rect( // fill the line 0, 0, rect.width, labelSize.y; ); numSize.y=numSize.y-gap1.y; numY=labelBounds.height+gap1.y; unitBounds = Rect( rect.width - unitWidth, // //adjust to fit numY, unitWidth, rect.height-labelSize.y-gap1.y); numBounds = Rect(0, numY, rect.width-unitWidth-gap2.x, rect.height-labelSize.y-gap1.y); // to right }, \horz, { labelSize.y=rect.height; labelBounds = (labelSize.x@labelSize.y).asRect; // to left unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); // to right numBounds = Rect( //adjust to fit labelBounds.width+gap1.x, 0, rect.width - labelBounds.width - unitBounds.width - gap1.x - gap2.x , labelBounds.height ); }); ^[labelBounds, numBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZPopUpMenu.sc000644 000765 000024 00000002511 12756534416 025715 0ustar00crucialstaff000000 000000 EZPopUpMenu : EZLists{ initViews{ arg parentView, bounds, label, labelWidth,labelHeight,arglayout; var labelBounds, listBounds; labelWidth = labelWidth ? 80; layout=arglayout ? \horz; labelSize=labelWidth@labelHeight; bounds.isNil.if{bounds= 160@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); // calcualate bounds # labelBounds,listBounds = this.prSubViewBounds(innerBounds, label.notNil); // insert the views label.notNil.if{ //only add a label if desired if (layout==\vert){ labelView = StaticText.new(view, labelBounds).resize_(2); labelView.align = \left; }{ labelView = StaticText.new(view, labelBounds); labelView.align = \right; }; labelView.string = label; }; widget = PopUpMenu.new(view, listBounds).resize_(5); } menu {^ widget} setColors{arg stringBackground, stringColor, menuBackground, menuStringColor,background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)};}; menuBackground.notNil.if{ this.menu.background_(menuBackground);}; menuStringColor.notNil.if{ this.menu.stringColor_(menuStringColor);}; background.notNil.if{ view.background=background;}; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZRangerSC.sc000644 000765 000024 00000020722 12766171707 025476 0ustar00crucialstaff000000 000000 EZRanger : EZGui { var controlSpec, round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, numberWidth=45, unitWidth=0, labelHeight=20, layout=\horz, gap,margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, numberWidth, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argNumberWidth,argUnitWidth, labelHeight, argLayout, argGap,argMargin; var labelBounds, hiBounds,loBounds, unitBounds,rangerBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; numberWidth = argNumberWidth; layout=argLayout; bounds.isNil.if{bounds = 350@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); labelSize=labelWidth@labelHeight; numSize = numberWidth@labelHeight; // calcualate bounds # labelBounds,hiBounds,loBounds,rangerBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); label.notNil.if{ //only add a label if desired labelView = StaticText.new(view, labelBounds); labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = StaticText.new(view, unitBounds); }; loBox = NumberBox.new(view, loBounds); rangeSlider = RangeSlider.new(view, rangerBounds); hiBox = NumberBox.new(view, hiBounds); controlSpec = argControlSpec.asSpec; (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString}; action = argAction; loBox.action_({ |box| this.lo_(box.value).doAction; }); rangeSlider.action_({ |sl| this.lo_(controlSpec.map(sl.lo)); this.hi_(controlSpec.map(sl.hi)); this.doAction; }); hiBox.action_({ |box| this.hi_(box.value).doAction; }); if (initVal.notNil) { this.value_(initVal) }; if (initAction) { this.doAction }; // if (controlSpec.step != 0) { // rangeSlider.step = (controlSpec.step / (controlSpec.maxval - controlSpec.minval)); // }; numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep; }{ // controlSpec wants a step, so zooming in with alt is disabled. hiBox.alt_scale = 1.0; loBox.alt_scale = 1.0; rangeSlider.alt_scale = 1.0; }; hiBox.step=numberStep; loBox.step=numberStep; hiBox.scroll_step=numberStep; loBox.scroll_step=numberStep; rangeSlider.receiveDragHandler = { arg slider; slider.valueAction = controlSpec.unmap(View.currentDrag); }; rangeSlider.beginDragAction = { arg slider; controlSpec.map(slider.value) }; this.prSetViewParams; } doAction { action.value(this); } set { arg label, spec, argAction, initVal, initAction = false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? this.value ? controlSpec.default.dup(2); if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } value { ^[lo, hi] } value_ { |vals| this.lo_(vals[0]).hi_(vals[1]) } valueAction_ { |vals| this.value_(vals).doAction } lo_ { |val| lo = controlSpec.constrain(val); loBox.value_(lo.round(round)); rangeSlider.lo_(controlSpec.unmap(lo)); } hi_ { |val| hi = controlSpec.constrain(val); hiBox.value_(hi.round(round)); rangeSlider.hi_(controlSpec.unmap(hi)); } setColors{arg stringBackground, stringColor, sliderColor, numBackground,numStringColor, numNormalColor, numTypingColor, knobColor,background ; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; sliderColor.notNil.if{ rangeSlider.background_(sliderColor);}; numBackground.notNil.if{ hiBox.background_(numBackground); loBox.background_(numBackground);}; numNormalColor.notNil.if{ hiBox.normalColor_(numNormalColor); loBox.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ hiBox.typingColor_(numTypingColor); loBox.typingColor_(numTypingColor);}; numStringColor.notNil.if{ hiBox.stringColor_(numStringColor); loBox.stringColor_(numStringColor);}; knobColor.notNil.if{ rangeSlider.knobColor_(knobColor);}; background.notNil.if{ view.background=background;}; hiBox.refresh; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; hiBox.font=font; loBox.font=font; } prSetViewParams{ switch (layout, \line2, { labelView.notNil.if{ labelView.resize_(2); unitView.notNil.if{unitView.resize_(3)}; hiBox.resize_(3); loBox.resize_(3); }{ unitView.notNil.if{ unitView.resize_(2).align_(\left)}; hiBox.resize_(1); loBox.resize_(1); }; rangeSlider.resize_(5); popUp.if{view.resize_(2)}; }, \vert, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(8)}; loBox.resize_(8); hiBox.resize_(2); rangeSlider.resize_(5); popUp.if{view.resize_(4)}; }, \horz, { labelView.notNil.if{labelView.resize_(4).align_(\right)}; unitView.notNil.if{unitView.resize_(6)}; loBox.resize_(4); hiBox.resize_(6); rangeSlider.resize_(5); popUp.if{view.resize_(2)}; }); } prSubViewBounds{arg rect, hasLabel, hasUnit; var hiBounds,loBounds,labelBounds,rangerBounds; var unitBounds, gap1, gap2, gap3,gap4, tmp, labelH, unitH; gap1 = gap.copy; // use copy to make sure these are unique gap2 = gap.copy; // since you later set the .x or .y gap3 = gap.copy; gap4 = gap.copy; labelH=labelSize.y;// needed for \vert unitH=labelSize.y; // needed for \vert switch (layout, \line2, { hasLabel.not.if{ gap2 = 0@0; labelSize.x = 0 ;}; hasUnit.not.if{ gap4 = 0@0; unitWidth = 0}; hasLabel.if{ // with label unitBounds = (unitWidth@labelSize.y) .asRect.left_(rect.width-unitWidth);// view to right hiBounds = (numSize.x@labelSize.y) .asRect.left_(rect.width-unitBounds.width-numberWidth-gap4.x); // view to right loBounds = (numSize.x@labelSize.y) .asRect.left_(rect.width-unitBounds.width-numberWidth -gap3.x-hiBounds.width-gap4.x); // view to right labelBounds = (labelSize.x@labelSize.y) .asRect.width_(loBounds.left-gap2.x); //adjust width }{ // no label labelBounds = (0@labelSize.y).asRect; //just a dummy loBounds = (numberWidth@labelSize.y).asRect; //view to left hiBounds = (numberWidth@labelSize.y).asRect.moveTo(loBounds.width+gap3.x,0); //view to left (unitWidth>0).if{ unitBounds = Rect.newSides (hiBounds.right+gap4.x, 0,rect.width, labelSize.y); //adjust width }{ unitBounds = Rect (0, 0,0,0); //no unitView }; }; rangerBounds = Rect( 0, labelSize.y+gap1.y, rect.width, rect.height-numSize.y-gap1.y; ); }, \vert, { hasLabel.not.if{labelH=0; gap1.y=0}; labelBounds = (rect.width@labelH).asRect; // to top hasUnit.not.if{unitH=0; gap4 = 0@0;}; unitBounds = (rect.width@unitH) .asRect.top_(rect.height-unitH); // to bottom hiBounds = (rect.width@labelSize.y) .asRect.top_(labelBounds.height+gap1.y); // to bottom loBounds = (rect.width@labelSize.y) .asRect.top_(rect.height-unitBounds.height-numSize.y-gap4.y); // to bottom rangerBounds = Rect.newSides( 0, hiBounds.bottom+gap2.y, rect.width, loBounds.top-gap3.y ); }, \horz, { hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;}; hasUnit.not.if{ gap4 = 0@0; unitWidth = 0}; labelSize.y=rect.height; labelBounds = (labelSize.x@labelSize.y).asRect; unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); loBounds = (numSize.x@labelSize.y).asRect .left_(labelBounds.width+gap1.x); hiBounds = (numSize.x@labelSize.y).asRect .left_(rect.width-unitBounds.width-numSize.x-gap4.x); rangerBounds = Rect.newSides( loBounds.right+gap2.x , 0, rect.width-hiBounds.width-unitBounds.width -gap3.x-gap4.x, labelSize.y); }); ^[labelBounds, hiBounds, loBounds, rangerBounds, unitBounds] .collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZScroller.sc000644 000765 000024 00000003371 12756534416 025617 0ustar00crucialstaff000000 000000 EZScroller { var action, controlSpec; var numSize,numberWidth,unitWidth; var <>round = 0.001; *new { arg parent, bounds, label, controlSpec, action, initVal, initAction=false, labelWidth=60, numberWidth=45, unitWidth=0, labelHeight=20, layout=\horz, gap, margin; ^super.new.init(parent, bounds, label, controlSpec, action, initVal, initAction, labelWidth, numberWidth, unitWidth, labelHeight, layout, gap, margin) } init { arg parentView, bounds, label, argControlSpec, argAction, initVal, initAction, labelWidth, argNumberWidth,argUnitWidth, labelHeight, argLayout, argGap, argMargin; var labelBounds, numBounds, unitBounds,sliderBounds; var numberStep; // Set Margin and Gap this.prMakeMarginGap(parentView, argMargin, argGap); unitWidth = argUnitWidth; numberWidth = argNumberWidth; layout=argLayout; bounds.isNil.if{bounds = 350@20}; // if no parent, then pop up window # view,bounds = this.prMakeView( parentView,bounds); labelSize=labelWidth@labelHeight; numSize = numberWidth@labelHeight; // calculate bounds of all subviews # labelBounds,numBounds,sliderBounds, unitBounds = this.prSubViewBounds(innerBounds, label.notNil, unitWidth>0); // instert the views label.notNil.if{ //only add a label if desired labelView = StaticText.new(view, labelBounds); labelView.string = label; }; (unitWidth>0).if{ //only add a unitLabel if desired unitView = StaticText.new(view, unitBounds); }; sliderView = Slider.new(view, sliderBounds); numberView = NumberBox.new(view, numBounds); // set view parameters and actions controlSpec = argControlSpec.asSpec; controlSpec.addDependant(this); this.onClose = { controlSpec.removeDependant(this) }; (unitWidth>0).if{unitView.string = " "++controlSpec.units.asString}; initVal = initVal ? controlSpec.default; action = argAction; sliderView.action = { this.valueActionIfChanged_(controlSpec.map(sliderView.value)); }; sliderView.receiveDragHandler = { arg slider; slider.valueAction = controlSpec.unmap(View.currentDrag); }; sliderView.beginDragAction = { arg slider; controlSpec.map(slider.value) }; numberView.action = { this.valueActionIfChanged_(numberView.value) }; numberStep = controlSpec.step; if (numberStep == 0) { numberStep = controlSpec.guessNumberStep }{ // controlSpec wants a step, so zooming in with alt is disabled. numberView.alt_scale = 1.0; sliderView.alt_scale = 1.0; }; numberView.step = numberStep; numberView.scroll_step = numberStep; //numberView.scroll=true; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; if (labelView.notNil) { labelView.mouseDownAction = {|view, x, y, modifiers, buttonNumber, clickCount| if(clickCount == 2, {this.editSpec}); } }; this.prSetViewParams; } value_ { arg val; value = controlSpec.constrain(val); numberView.value = value.round(round); sliderView.value = controlSpec.unmap(value); } valueAction_ { arg val; this.value_(val); this.doAction; } doAction { action.value(this) } set { arg label, spec, argAction, initVal, initAction = false; labelView.notNil.if { labelView.string = label.asString }; spec.notNil.if { controlSpec = spec.asSpec }; argAction.notNil.if { action = argAction }; initVal = initVal ? value ? controlSpec.default; if (initAction) { this.valueAction_(initVal); }{ this.value_(initVal); }; } setColors{arg stringBackground,stringColor,sliderBackground,numBackground, numStringColor,numNormalColor,numTypingColor,knobColor,background; stringBackground.notNil.if{ labelView.notNil.if{labelView.background_(stringBackground)}; unitView.notNil.if{unitView.background_(stringBackground)};}; stringColor.notNil.if{ labelView.notNil.if{labelView.stringColor_(stringColor)}; unitView.notNil.if{unitView.stringColor_(stringColor)};}; numBackground.notNil.if{ numberView.background_(numBackground);}; numNormalColor.notNil.if{ numberView.normalColor_(numNormalColor);}; numTypingColor.notNil.if{ numberView.typingColor_(numTypingColor);}; numStringColor.notNil.if{ numberView.stringColor_(numStringColor);}; sliderBackground.notNil.if{ sliderView.background_(sliderBackground);}; knobColor.notNil.if{ sliderView.knobColor_(knobColor);}; background.notNil.if{ view.background=background;}; numberView.refresh; } font_{ arg font; labelView.notNil.if{labelView.font=font}; unitView.notNil.if{unitView.font=font}; numberView.font=font; } ///////Private methods /////// prSetViewParams{ // sets resize and alignment for different layouts switch (layout, \line2, { labelView.notNil.if{ labelView.resize_(2); unitView.notNil.if{unitView.resize_(3)}; numberView.resize_(3); }{ unitView.notNil.if{ unitView.resize_(2); numberView.resize_(1); }{ numberView.resize_(2); }; }; sliderView.resize_(5); popUp.if{view.resize_(2)}; }, \vert, { labelView.notNil.if{labelView.resize_(2)}; unitView.notNil.if{unitView.resize_(8)}; numberView.resize_(8); sliderView.resize_(5); popUp.if{view.resize_(4)}; }, \horz, { labelView.notNil.if{labelView.resize_(4).align_(\right)}; unitView.notNil.if{unitView.resize_(6)}; numberView.resize_(6); sliderView.resize_(5); popUp.if{view.resize_(2)}; }); } prSubViewBounds{arg rect, hasLabel, hasUnit; // calculate subview bounds var numBounds,labelBounds,sliderBounds, unitBounds; var gap1, gap2, gap3, tmp, labelH, unitH; gap1 = gap.copy; gap2 = gap.copy; gap3 = gap.copy; labelH=labelSize.y;// needed for \vert unitH=labelSize.y; // needed for \vert hasUnit.not.if{ gap3 = 0@0; unitWidth = 0}; switch (layout, \line2, { hasLabel.if{ // with label unitBounds = (unitWidth@labelSize.y) .asRect.left_(rect.width-unitWidth);// view to right numBounds = (numSize.x@labelSize.y) .asRect.left_(rect.width-unitBounds.width-numberWidth-gap3.x); // view to right labelBounds = (labelSize.x@labelSize.y) .asRect.width_(numBounds.left-gap2.x); //adjust width }{ // no label labelBounds = (0@labelSize.y).asRect; //just a dummy numBounds = (numberWidth@labelSize.y).asRect; //view to left (unitWidth>0).if{ unitBounds = Rect (numBounds.width+gap3.x, 0, rect.width-numBounds.width-gap3.x,labelSize.y); //adjust to fit }{ unitBounds = Rect (0, 0,0,0); //no unitView numBounds = (rect.width@labelSize.y).asRect; //view to left }; }; sliderBounds = Rect( //adjust to fit 0, labelSize.y+gap1.y, rect.width, rect.height-numSize.y-gap1.y; ); }, \vert, { hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;}; hasLabel.not.if{labelH=0}; labelBounds = (rect.width@labelH).asRect; // to top hasUnit.not.if{unitH=0}; unitBounds = (rect.width@unitH) .asRect.top_(rect.height-labelSize.y); // to bottom numBounds = (rect.width@labelSize.y) .asRect.top_(rect.height-unitBounds.height-numSize.y-gap3.y); // to bottom sliderBounds = Rect( //adjust to fit 0, labelBounds.height+gap1.y, rect.width, rect.height - labelBounds.height - unitBounds.height - numBounds.height - gap1.y - gap2.y - gap3.y ); }, \horz, { hasLabel.not.if{ gap1 = 0@0; labelSize.x = 0 ;}; labelSize.y = rect.height; labelBounds = (labelSize.x@labelSize.y).asRect; //to left unitBounds = (unitWidth@labelSize.y).asRect.left_(rect.width-unitWidth); // to right numBounds = (numSize.x@labelSize.y).asRect .left_(rect.width-unitBounds.width-numSize.x-gap3.x);// to right sliderBounds = Rect( // adjust to fit labelBounds.width+gap1.x, 0, rect.width - labelBounds.width - unitBounds.width - numBounds.width - gap1.x - gap2.x - gap3.x, labelBounds.height ); }); ^[labelBounds, numBounds, sliderBounds, unitBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } update {arg changer, what ...moreArgs; var oldValue; if(changer === controlSpec, { oldValue = this.value; this.value = oldValue; if(this.value != oldValue, { this.doAction }); }); } editSpec { var ezspec, val; val = this.value; [labelView, sliderView, numberView, unitView].do({|view| view.notNil.if({ view.enabled_(false).visible_(false)}); }); ezspec = EZControlSpecEditor(view, view.bounds.moveTo(0,0), controlSpec: controlSpec.copy, layout: layout); ezspec.labelView.mouseDownAction = {|view, x, y, modifiers, buttonNumber, clickCount| if(clickCount == 2, { controlSpec = ezspec.controlSpec; ezspec.remove; [labelView, sliderView, numberView, unitView].do({|view| view.notNil.if({ view.enabled_(true).visible_(true)}); }); this.value = val; }); }; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZSpecEditor.sc000644 000765 000024 00000007351 12766171707 026076 0ustar00crucialstaff000000 000000 EZControlSpecEditor : EZGui { var 0).if{ //only add a unitLabel if desired // unitView = StaticText.new(view, unitBounds); // }; minView = NumberBox.new(view, minBounds); maxView = NumberBox.new(view, maxBounds); warpView = TextField.new(view, warpBounds); stepView = NumberBox.new(view, stepBounds); // set view parameters and actions controlSpec = argControlSpec.asSpec; minView.value = controlSpec.minval; maxView.value = controlSpec.maxval; warpView.value = controlSpec.warp.asSpecifier.asCompileString; stepView.value = controlSpec.step; minView.action = { controlSpec.minval = minView.value }; maxView.action = { controlSpec.maxval = maxView.value }; warpView.action = { try { controlSpec.warp = warpView.value.interpret.asWarp(controlSpec) } }; stepView.action = { controlSpec.step = stepView.value }; //this.prSetViewParams; } prSubViewBounds{arg rect; // calculate subview bounds var labelBounds, minBounds, maxBounds, warpBounds, stepBounds; var gap1, gap2, gap3, tmp, labelH, componentSize; gap1 = gap.copy; gap2 = gap.copy; gap3 = gap.copy; labelH=labelSize.y;// needed for \vert switch (layout, \line2, { componentSize = ((rect.width - (3 * gap.x) - labelSize.x) / 4)@labelH; stepBounds = componentSize.asRect.left_(rect.width - componentSize.x); warpBounds = componentSize.asRect.left_(stepBounds.left-componentSize.x-gap.x); maxBounds = componentSize.asRect.left_(warpBounds.left-componentSize.x-gap.x); minBounds = componentSize.asRect.left_(maxBounds.left-componentSize.x-gap.x); labelBounds = (labelSize.x@labelSize.y).asRect.width_(minBounds.left-gap.x); //adjust width }, \vert, { componentSize = labelSize.x@((rect.height - (3 * gap.y) - labelH) / 4); labelBounds = (rect.width@labelH).asRect; // to top minBounds = (rect.width@componentSize.y) .asRect.top_(labelBounds.bottom + gap.y); maxBounds = (rect.width@componentSize.y) .asRect.top_(minBounds.bottom + gap.y); warpBounds = (rect.width@componentSize.y) .asRect.top_(maxBounds.bottom + gap.y); stepBounds = (rect.width@componentSize.y) .asRect.top_(warpBounds.bottom + gap.y); }, \horz, { componentSize = ((rect.width - (3 * gap.x) - labelSize.x) / 4)@labelH; stepBounds = componentSize.asRect.left_(rect.width - componentSize.x); warpBounds = componentSize.asRect.left_(stepBounds.left-componentSize.x-gap.x); maxBounds = componentSize.asRect.left_(warpBounds.left-componentSize.x-gap.x); minBounds = componentSize.asRect.left_(maxBounds.left-componentSize.x-gap.x); labelBounds = (labelSize.x@labelSize.y).asRect.width_(minBounds.left-gap.x); //adjust width } ); ^[labelBounds, minBounds, maxBounds, warpBounds, stepBounds].collect{arg v; v.moveBy(margin.x,margin.y)} } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/EZText.sc000644 000765 000024 00000006261 12766171707 024760 0ustar00crucialstaff000000 000000 // value can be any object, // display is asCompileString EZText : EZGui { var margin, <>gap; var <>left, <>top, <>maxHeight,<>maxRight; var <>owner; *new { arg bounds, margin, gap; ^super.newCopyArgs(bounds, margin, gap).init } init { gap = gap ? Point(4,4); margin = margin ? Point(4,4); this.reset; } clear { this.reset; } reset { maxRight = left = bounds.left + margin.x; top = bounds.top + margin.y; maxHeight = 0; } place { arg view; var height, width,vbounds; vbounds = view.bounds; width = vbounds.width; height = vbounds.height; if ((left + width) > (bounds.right - margin.x), { this.nextLine; }); view.bounds = Rect(left, top, width, height); maxRight = max(maxRight,left + width); left = left + width + gap.x; maxHeight = max(maxHeight, height); } remove { } nextLine { left = bounds.left + margin.x; top = top + maxHeight + gap.y; maxHeight = 0; } shift { arg x=0, y=0; left = left + x; top = top + y; } innerBounds { ^bounds.insetBy(margin.x * 2,margin.y * 2) } bounds_ { arg b; var d; left = left + ( d = (b.left - bounds.left)); maxRight = maxRight + (d); top = top + (d = (b.top - bounds.top)); maxHeight = maxHeight + (d); bounds = b; // and then you need to re-place all views // but nextLine will be broken, see FlowView } currentBounds { var currentBounds; currentBounds = bounds; currentBounds.height = top + maxHeight; ^currentBounds } // rounded out to the nearest rect + margin used { ^Rect(bounds.left,bounds.top, maxRight + margin.x - bounds.left, (top + maxHeight + margin.y ) - bounds.top) } // largest allocatable rect starting in the current row // going down as far as possible indentedRemaining { var inb; inb = this.innerBounds; ^Rect(left,top, inb.width - (left - inb.left - margin.x), inb.height - (top - inb.top - margin.y)) } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/Gradient.sc000644 000765 000024 00000000756 12756534416 025334 0ustar00crucialstaff000000 000000 Gradient { var color1, color2, direction, steps; *new { arg color1, color2, direction=\h, steps=64; ^super.newCopyArgs(color1, color2, direction, steps) } at { |pos| ^blend(color1, color2, pos.round(steps.reciprocal)) } } HiliteGradient { var color1, color2, direction, steps, frac; *new { arg color1, color2, direction=\v, steps=64, frac = 0.33; ^super.newCopyArgs(color1, color2, direction, steps, frac) } at { |pos| ^blend(color1, color2, pos.round(steps.reciprocal)) } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/Grid.sc000644 000765 000024 00000014126 12756534416 024460 0ustar00crucialstaff000000 000000 DrawGrid { var x,<>y; var <>opacity=0.7,<>smoothing=false,<>linePattern; *new { |bounds,horzGrid,vertGrid| ^super.new.init(bounds, horzGrid, vertGrid) } *test { arg horzGrid,vertGrid,bounds; var w,grid; bounds = bounds ?? {Rect(0,0,500,400)}; grid = DrawGrid(bounds,horzGrid,vertGrid); w = Window("Grid",bounds).front; UserView(w,bounds ?? {w.bounds.moveTo(0,0)}) .resize_(5) .drawFunc_({ arg v; grid.bounds = v.bounds; grid.draw }) .background_(Color.white) ^grid } init { arg bounds,h,v; var w; x = DrawGridX(h); y = DrawGridY(v); this.bounds = bounds; this.font = Font( Font.defaultSansFace, 9 ); this.fontColor = Color.grey(0.3); this.gridColors = [Color.grey(0.7),Color.grey(0.7)]; } bounds_ { arg b; bounds = b; x.bounds = b; y.bounds = b; } draw { Pen.push; Pen.alpha = opacity; Pen.smoothing = smoothing; if(linePattern.notNil) {Pen.lineDash_(linePattern)}; x.commands.do({ arg cmd; Pen.perform(cmd) }); y.commands.do({ arg cmd; Pen.perform(cmd) }); Pen.pop; } font_ { arg f; x.font = f; y.font = f; } fontColor_ { arg c; x.fontColor = c; y.fontColor = c; } gridColors_ { arg colors; x.gridColor = colors[0]; y.gridColor = colors[1]; } horzGrid_ { arg g; x.grid = g; } vertGrid_ { arg g; y.grid = g; } copy { ^DrawGrid(bounds,x.grid,y.grid).x_(x.copy).y_(y.copy).opacity_(opacity).smoothing_(smoothing).linePattern_(linePattern) } clearCache { x.clearCache; y.clearCache; } } DrawGridX { var range,<>bounds; var <>font,<>fontColor,<>gridColor,<>labelOffset; var commands,cacheKey; *new { arg grid; ^super.newCopyArgs(grid.asGrid).init } init { range = [grid.spec.minval, grid.spec.maxval]; labelOffset = 4 @ -10; } grid_ { arg g; grid = g.asGrid; range = [grid.spec.minval, grid.spec.maxval]; this.clearCache; } setZoom { arg min,max; range = [min,max]; } commands { var p; if(cacheKey != [range,bounds],{ commands = nil }); ^commands ?? { cacheKey = [range,bounds]; commands = []; p = grid.getParams(range[0],range[1],bounds.left,bounds.right); p['lines'].do { arg val; // value, [color] var x; val = val.asArray; x = val[0].linlin(range[0],range[1],bounds.left,bounds.right); commands = commands.add( ['strokeColor_',val[1] ? gridColor] ); commands = commands.add( ['line', Point( x, bounds.top), Point(x,bounds.bottom) ] ); commands = commands.add( ['stroke' ] ); }; if(bounds.width >= 12 ,{ commands = commands.add(['font_',font ] ); commands = commands.add(['color_',fontColor ] ); p['labels'].do { arg val; var x; // value, label, [color, font] if(val[2].notNil,{ commands = commands.add( ['color_',val[2] ] ); }); if(val[3].notNil,{ commands = commands.add( ['font_',val[3] ] ); }); x = val[0].linlin(range[0],range[1],bounds.left,bounds.right); commands = commands.add( ['stringAtPoint', val[1].asString, Point(x, bounds.bottom) + labelOffset ] ); } }); commands } } clearCache { cacheKey = nil; } copy { ^super.copy.clearCache } } DrawGridY : DrawGridX { init { range = [grid.spec.minval, grid.spec.maxval]; labelOffset = 4 @ 4; } commands { var p; if(cacheKey != [range,bounds],{ commands = nil }); ^commands ?? { commands = []; p = grid.getParams(range[0],range[1],bounds.top,bounds.bottom); p['lines'].do { arg val; // value, [color] var y; val = val.asArray; y = val[0].linlin(range[0],range[1],bounds.bottom,bounds.top); commands = commands.add( ['strokeColor_',val[1] ? gridColor] ); commands = commands.add( ['line', Point( bounds.left,y), Point(bounds.right,y) ] ); commands = commands.add( ['stroke' ] ); }; if(bounds.height >= 20 ,{ commands = commands.add(['font_',font ] ); commands = commands.add(['color_',fontColor ] ); p['labels'].do { arg val,i; var y; y = val[0].linlin(range[0],range[1],bounds.bottom,bounds.top); if(val[2].notNil,{ commands = commands.add( ['color_',val[2] ] ); }); if(val[3].notNil,{ commands = commands.add( ['font_',val[3] ] ); }); commands = commands.add( ['stringAtPoint', val[1].asString, Point(bounds.left, y) + labelOffset ] ); } }); commands } } } // DrawGridRadial : DrawGridX {} GridLines { var <>spec; *new { arg spec; ^super.newCopyArgs(spec.asSpec) } asGrid { ^this } niceNum { arg val,round; // http://books.google.de/books?id=fvA7zLEFWZgC&pg=PA61&lpg=PA61 var exp,f,nf,rf; exp = floor(log10(val)); f = val / 10.pow(exp); rf = 10.pow(exp); if(round,{ if(f < 1.5,{ ^rf * 1.0 }); if(f < 3.0,{ ^rf * 2.0 }); if( f < 7.0,{ ^rf * 5.0 }); ^rf * 10.0 },{ if(f <= 1.0,{ ^rf * 1.0; }); if(f <= 2,{ ^rf * 2.0 }); if(f <= 5,{ ^rf * 5.0; }); ^rf * 10.0 }); } ideals { arg min,max,ntick=5; var nfrac,d,graphmin,graphmax,range,x; range = this.niceNum(max - min,false); d = this.niceNum(range / (ntick - 1),true); graphmin = floor(min / d) * d; graphmax = ceil(max / d) * d; nfrac = max( floor(log10(d)).neg, 0 ); ^[graphmin,graphmax,nfrac,d]; } looseRange { arg min,max,ntick=5; ^this.ideals(min,max).at( [ 0,1] ) } getParams { |valueMin,valueMax,pixelMin,pixelMax,numTicks| var lines,p,pixRange; var nfrac,d,graphmin,graphmax,range; pixRange = pixelMax - pixelMin; if(numTicks.isNil,{ numTicks = (pixRange / 64); numTicks = numTicks.max(3).round(1); }); # graphmin,graphmax,nfrac,d = this.ideals(valueMin,valueMax,numTicks); lines = []; if(d != inf,{ forBy(graphmin,graphmax + (0.5*d),d,{ arg tick; if(tick.inclusivelyBetween(valueMin,valueMax),{ lines = lines.add( tick ); }) }); }); p = (); p['lines'] = lines; if(pixRange / numTicks > 9) { p['labels'] = lines.collect({ arg val; [val, this.formatLabel(val,nfrac) ] }); }; ^p } formatLabel { arg val, numDecimalPlaces; ^val.round( (10**numDecimalPlaces).reciprocal).asString + (spec.units?"") } } BlankGridLines : GridLines { getParams { ^() } } + Nil { asGrid { ^BlankGridLines.new } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QDialog.sc000644 000765 000024 00000002533 12766171707 025113 0ustar00crucialstaff000000 000000 FileDialog : QObject { *qtClass { ^'QcFileDialog' } *new { arg okFunc, cancelFunc, fileMode, acceptMode, stripResult = false; /** fileMode: QFileDialog::AnyFile 0 The name of a file, whether it exists or not. QFileDialog::ExistingFile 1 The name of a single existing file. QFileDialog::Directory 2 The name of a directory. Both files and directories are displayed. QFileDialog::ExistingFiles 3 The names of zero or more existing files. acceptMode: QFileDialog::AcceptOpen 0 QFileDialog::AcceptSave 1 stripResult: true: okFunc(path1, path2, path3) false: okFunc(paths) **/ var me = super.new( [fileMode, acceptMode] ); if( okFunc.notNil ) { me.connectFunction( 'accepted(QVariantList)', { |me, result| if( stripResult ) { okFunc.performList(\value, result) } { okFunc.value(result) } }); }; if( cancelFunc.notNil ) { me.connectFunction( 'rejected()', { cancelFunc.value() } ); }; me.invokeMethod('show', synchronous:false); ^me; } } Dialog { *openPanel { arg okFunc, cancelFunc, multipleSelection=false; var fileMode; if( multipleSelection ) { fileMode = 3 } { fileMode = 1 }; ^FileDialog.new( okFunc, cancelFunc, fileMode, 0, stripResult:multipleSelection.not ); } *savePanel { arg okFunc, cancelFunc; ^FileDialog.new( okFunc, cancelFunc, 0, 1, stripResult:true ); } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QEnvelopeView.sc000644 000765 000024 00000010461 12756534416 026322 0ustar00crucialstaff000000 000000 EnvelopeView : View { var 0) { [curves.collect{|c| QCurve(c)}] } { QCurve(curves) } ); } setEnv { arg env; var times = [0] ++ env.times.integrate; if( times.last > 0 ) {times = times / times.last}; this.value = [times, env.levels]; this.curves = env.curves; } grid_ { arg aPoint; grid = aPoint; this.setProperty( \grid, aPoint ); } gridOn_ { arg aBool; gridOn = aBool; this.setProperty( \gridOn, aBool ); } connect { arg source, targets; this.invokeMethod( \connectElements, [source, targets] ); } gridColor { ^this.getProperty(\gridColor) } gridColor_ { arg color; this.setProperty( \gridColor, color ) } selectionColor { ^this.getProperty(\selectionColor) } selectionColor_ { arg color; this.setProperty(\selectionColor, color) } strokeColor { ^this.getProperty(\strokeColor) } strokeColor_ { arg color; this.setProperty( \strokeColor, color ) } fillColor_ { arg aColor; fillColor = aColor; this.setProperty( \fillColor, aColor ); } setFillColor { arg index, color; this.invokeMethod( \setFillColorAt, [index, color] ); } colors_ { arg strokeColor, fillColor; this.strokeColor_( strokeColor ); this.fillColor_( fillColor ); } drawLines_ { arg aBool; drawLines = aBool; this.setProperty( \drawLines, aBool ); } drawRects_ { arg aBool; drawRects = aBool; this.setProperty( \drawRects, aBool ); } style { ^this.getProperty(\style) } style_ { arg style; if (style.isNumber.not) { style = style.switch ( \dots, 0, \rects, 1, 0 ); }; style = style.clip(0,1).asInteger; this.setProperty(\style, style) } thumbWidth_ { arg width; this.setProperty( \thumbWidth, width.asInteger; ); } thumbHeight_ { arg height; this.setProperty( \thumbHeight, height.asInteger; ); } thumbSize_ { arg size; this.setProperty( \thumbSize, size.asInteger; ); } setThumbWidth { arg index, width; this.invokeMethod(\setThumbWidthAt, [index, width.asInteger]) } setThumbHeight { arg index, height; this.invokeMethod(\setThumbHeightAt, [index, height.asInteger]) } setThumbSize { arg index, size; this.invokeMethod(\setThumbSizeAt, [index, size.asInteger]) } metaAction_ { arg function; this.manageMethodConnection( metaAction, function, 'metaAction()', \doMetaAction ); metaAction = function; } doMetaAction { metaAction.value(this); } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^true; } defaultReceiveDrag { this.value = View.currentDrag; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QFont.sc000644 000765 000024 00000004056 12756534416 024623 0ustar00crucialstaff000000 000000 Font { classvar name, bold, <>italic, name, scalesWhenResized=false; *initClass { compositingOperations = [ 'sourceOver', // 0 'destinationOver', // 1 'clear', // 2 'copy', // 3 'destination', // 4 qt name 'sourceIn', // 5 'destinationIn', // 6 'sourceOut', // 7 'destinationOut', // 8 'sourceATop', // 9 'destinationATop', // 10 'xor', // 11 'plus', // 12 qt name 'multiply', // 13 qt name 'screen', // 14 qt name 'overlay', // 15 qt name 'plusDarker', // 16 CompositionMode_Darken + plus? 'plusLighter', // 17 CompositionMode_Lighten + plus? 'highlight', // 18 CompositionMode_ColorDodge? 'colorBurn', // 19 qt name 'hardLight', // 20 qt name 'softLight', // 21 qt name 'difference', // 22 qt name 'exclusion', // 23 qt name // 24-32 RasterOp ]; resizeModes = [ 'doNotScale', 'ignoreAspectRatio', 'keepAspectRatio', 'keepAspectRatioByExpanding' ]; } *new { arg multiple, height = nil; var ret; case { multiple.isKindOf(Point) } { ret = this.newEmpty(multiple.x, multiple.y); } { multiple.isKindOf(Number) } { ret = this.newEmpty(multiple, height ? multiple); } { multiple.isKindOf(String) } { if (multiple.beginsWith("http://").not and:{ multiple.beginsWith("file://").not } and:{ multiple.beginsWith("ftp://").not }, { ret = this.open(multiple); }, { ret = this.openURL(multiple); }); } { Error("Image: wrong arguments to constructor").throw }; ^ret; } *newEmpty { arg width, height; ^super.new.prNewEmpty(width, height); } *color { arg ...args; var ret, color; ret = this.new(*args); color = args.last; if(color.isKindOf(Color).not, { color = Color.black; }); ret.fill(color); ^ret; } *open { arg path; path = path.standardizePath; ^super.new.prNewPath(path); } *openURL { arg url, timeout = 60; ^super.new.prNewURL(url, timeout).url_(url); } *fromImage { arg image; if(image.isKindOf(this), { ^image.copy; }); "Image: invalid instance to copy from.".error; ^nil } *fromWindow { arg window, rect; ^super.new.prNewFromWindow( window.asView, rect ?? { window.asView.bounds } ); } // Class variables attributes *formats { arg rw = "r"; case( { rw.asSymbol == \r }, { rw = 0 }, { rw.asSymbol == \w }, { rw = 1 }, { true }, { Error("Image.formats(rw) must be either 'r' or 'w'").throw } ); ^this.prFormats(rw); } *interpolations { ^[\fast, \smooth]; // TODO } *colorToPixel { arg color; _QImage_ColorToPixel; ^this.primitiveFailed; } *pixelToColor { arg pixel; _QImage_PixelToColor; ^this.primitiveFailed; } // Instance methods isValid { ^dataptr.notNil; } interpolation { ^if(this.smooth, \smooth, \fast); } interpolation_ { arg mode; switch (mode, \smooth, { this.smooth = true }, \fast, { this.smooth = false }, { Error("Image: Interpolation mode invalid").throw } ); } smooth { _QImage_HasSmoothTransformation; ^this.primitiveFailed } smooth_ { arg smooth; _QImage_SetSmoothTransformation; ^this.primitiveFailed } url_ { arg newURL; if(newURL.isKindOf(String), { url = newURL.standardizePath.replace(" ", "%20"); }, { url = ""; }); } bounds { ^Rect(0, 0, this.width, this.height); } width { _QImage_Width ^this.primitiveFailed } width_ { arg w; this.setSize(w, this.height); } height { _QImage_Height ^this.primitiveFailed } height_ { arg h; this.setSize(this.width, h); } setSize { arg width, height, resizeMode; if (resizeMode.isNil) { resizeMode = if (scalesWhenResized, \ignoreAspectRatio, \doNotScale); }; resizeMode = resizeModes.indexOf(resizeMode); if (resizeMode.isNil) { Error("Image: invalid resize mode.").throw; }; this.prSetSize(width, height, resizeMode); } // pixel manipulation setPixel { arg rgbaInteger, x, y; _QImage_SetPixel ^this.primitiveFailed } getPixel { arg x, y; _QImage_GetPixel ^this.primitiveFailed } setColor { arg color, x, y; _QImage_SetColor ^this.primitiveFailed } getColor { arg x, y; _QImage_GetColor ^this.primitiveFailed; } pixels { var pixelArray; if(this.width == 0 or: { this.height == 0 }, { ^nil }); pixelArray = Int32Array.newClear(this.width * this.height); this.loadPixels(pixelArray); ^pixelArray; } loadPixels {arg array, region = nil, start = 0; this.prTransferPixels(array, region, start, false); ^this; } pixels_ {arg array; this.setPixels(array); } setPixels { arg array, region = nil, start = 0; this.prTransferPixels(array, region, start, true); } fill { arg color; _QImage_Fill ^this.primitiveFailed } free { _QImage_Free ^this.primitiveFailed } // TODO: make a primitive copy { var new, rect; rect = Rect(0, 0, this.width, this.height); new = this.class.newEmpty(rect.width, rect.height); new.name_(this.name); new.url_(this.url); new.draw({ Pen.drawImage(rect, this, rect); }); ^new } draw { arg aFunction; this.prSetPainter; protect({ aFunction.value(this); }, { this.prUnsetPainter; }); } drawAtPoint { arg point, fromRect, operation = 'sourceOver', fraction = 1.0; Pen.drawImage( point, this, fromRect, operation, fraction ); } drawInRect { arg rect, fromRect, operation = 'sourceOver', fraction = 1.0; // TODO: check stretch behavior Pen.drawImage(rect, this, fromRect, operation, fraction); } tileInRect { arg rect, fromRect, operation = 'sourceOver', opacity = 1.0; Pen.tileImage(rect, this, fromRect, operation, opacity); } drawStringAtPoint { arg string, point, font, color; this.draw({ Pen.stringAtPoint(string, point, font, color); }); } plot { arg name, bounds, freeOnClose = false, background = nil, showInfo = true; var uview, window, nw, nh, ratio = this.width / this.height, info = ""; nw = this.width.min(600).max(200); nh = nw / ratio; window = Window.new(name ? "plot", bounds ? Rect(400, 400, nw, nh)); allPlotWindows = allPlotWindows.add(window); if(background.notNil, { window.view.background_(background); }); window.acceptsMouseOver = true; uview = UserView(window, window.view.bounds) .resize_(5) .focusColor_(Color.clear); window.onClose_({ allPlotWindows.remove(window); if(freeOnClose, { this.free }); }); uview.drawFunc_({ Pen.drawImage(window.view.bounds, this, this.bounds); if(showInfo, { Pen.use { Pen.width_(0.5); Color.black.alpha_(0.4).setFill; Color.white.setStroke; Pen.fillRect(Rect(5.5, 5.5, 100, 20)); Pen.strokeRect(Rect(5.5, 5.5, 100, 20)); info.drawAtPoint(10@10, Font.default, Color.white); } }); }); uview.mouseOverAction_({ arg v, x, y; if(showInfo, { if(this.isValid, { info = format("X: %, Y: %", ((x / window.view.bounds.width) * this.width).floor.min(this.width-1), ((y / window.view.bounds.height) * this.height).floor.min(this.height-1) ); }, { info = "invalid image"; }); //window.view.refreshInRect(Rect(5.5,5.5,100,20)); window.view.refresh; }); }); ^window.front; } *closeAllPlotWindows { allPlotWindows.do(_.close); } storeOn { arg stream; stream << this.class.name << ".openURL(" << url.asCompileString << ")"; } archiveAsCompileString { ^true } // saving and archiving write { arg path, format, quality = -1; _QImage_Write ^this.primitiveFailed } // private primitives prNewPath { arg path; _QImage_NewPath ^this.primitiveFailed } prNewURL { arg path, timeout; _QImage_NewURL ^this.primitiveFailed } prNewFromWindow { arg window, rect; _QImage_NewFromWindow ^this.primitiveFailed } prNewEmpty { arg width, height; _QImage_NewEmpty ^this.primitiveFailed } prSetPainter { _QImage_SetPainter ^this.primitiveFailed } prUnsetPainter { _QImage_UnsetPainter ^this.primitiveFailed } *prFormats { arg rw; _QImage_Formats ^this.primitiveFailed } prSetSize { arg width, height, resizeMode; _QImage_SetSize ^this.primitiveFailed } prTransferPixels { arg array, region, start, store = false; _QImage_TransferPixels ^this.primitiveFailed } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QKnob.sc000644 000765 000024 00000005337 12756534416 024611 0ustar00crucialstaff000000 000000 // blackrain at realizedsound dot net - 05/2006 // fix key modidiers bug by Stephan Wittwer 08/2006 - thanks! // Knob updates only on value changes - 10/2006 // GUI.cocoa changes - 04/2007 // // 03.10.2008 - new implementation: // - Knob now is a subclass of SCViewHolder // - Relative origin // // 01.20.2009 - SCKnob // - a subclass of SCUserView again. // - isSquare option // // 08.03.2010 - QKnob = SCKnob adjusted for GUI.qt scheme (by Jakob Leben) Knob : QAbstractStepValue { classvar <>defaultMode = \round; var <>keystep = 0.01; *qtClass {^'QcKnob'} *new { arg parent, bounds; var me = super.new(parent,bounds); me.mode = defaultMode; ^me; } value { ^this.getProperty(\value) } value_ { arg val; this.setProperty(\value, val) } valueAction_ { arg val; this.value = val; this.doAction } mode { var m = this.getProperty(\mode); ^ #[\round, \horiz, \vert].at(m); } mode_ { arg inputMode; var iMode; switch ( inputMode, \round, { iMode = 0}, \horiz, { iMode = 1}, \vert, { iMode = 2 }, { ^this } ); this.setProperty( \mode, iMode ); } centered_ { arg bool; this.setProperty( \centered, bool ); } centered { ^this.getProperty( \centered ); } background { ^this.palette.button; } background_ { arg color; this.palette = this.palette.button_(color); } // FIXME: find better alternatives to set colors separately. color_ { arg colors; var p; p = this.palette; p.button = colors[0]; p.windowText = colors[1]; p.window = colors[2]; p.buttonText = colors[3]; this.palette = p; } color { var p; p = this.palette; ^[p.button, p.windowText, p.window, p.buttonText]; } getScale { |modifiers| ^case { modifiers.isShift } { this.shift_scale } { modifiers.isCtrl } { this.ctrl_scale } { modifiers.isAlt } { this.alt_scale } { 1 }; } defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; var zoom = this.getScale(modifiers); // standard keydown switch( char, $r, { this.valueAction = 1.0.rand }, $n, { this.valueAction = 0.0 }, $x, { this.valueAction = 1.0 }, $c, { this.valueAction = 0.5 }, { switch( key, 16r5b, { this.decrement(zoom) }, 16r5d, { this.increment(zoom) }, 16r1000013, { this.increment(zoom) }, 16r1000014, { this.increment(zoom) }, 16r1000015, { this.decrement(zoom) }, 16r1000012, { this.decrement(zoom) }, {^this} // propagate on if the key is a no-op ) } ); ^true; } increment { |zoom=1| ^this.valueAction = (this.value + (keystep * zoom)) } decrement { |zoom=1| ^this.valueAction = (this.value - (keystep * zoom)) } defaultGetDrag { ^this.value } defaultCanReceiveDrag { ^View.currentDrag.isNumber } defaultReceiveDrag { this.valueAction = View.currentDrag } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QLayout.sc000644 000765 000024 00000011760 12766171724 025172 0ustar00crucialstaff000000 000000 Layout : QObject { spacing_ { arg spacing; this.setProperty( \spacing, spacing ); } margins_ { arg margins; this.setProperty( \margins, margins + [0,0,0,0] ); } asLayoutElement { ^this } } // LINE LAYOUTS /////////////////////////////////////////////////// LineLayout : Layout { *new { arg ...items; var serializedItems = items.collect( { |x| this.parse(x) } ); ^super.new( [serializedItems] ); } *parse { arg in; var out = [nil,0,0]; var key; var i; if( in.isKindOf(Array) ) { out[0] = in[0].asLayoutElement; i = 1; while { i + 1 < in.size } { key = in[i]; case ( { (key === \stretch) || (key === \s) }, { out[1] = in[i+1] }, { (key === \align) || (key === \a) }, { out[2] = QAlignment(in[i+1]) } ); i = i + 2; }; }{ out[0] = in.asLayoutElement; }; ^out; } add { arg item, stretch = 0, align; this.invokeMethod( \addItem, [[item.asLayoutElement, stretch, QAlignment(align)]], true ); } insert { arg item, index=0, stretch = 0, align; this.invokeMethod( \insertItem, [[item.asLayoutElement, index, stretch, QAlignment(align)]], true ); } setStretch { arg item, stretch; this.invokeMethod( \setStretch, [item.asLayoutElement, stretch], true ); } setAlignment { arg item, align; this.invokeMethod( \setAlignment, [item.asLayoutElement, QAlignment(align)], true ); } } HLayout : LineLayout { *qtClass { ^'QcHBoxLayout' } } VLayout : LineLayout { *qtClass { ^'QcVBoxLayout' } } // GRID LAYOUT /////////////////////////////////////////////////// GridLayout : Layout { *new { // get rid of QObject's arguments ^super.new; } *qtClass { ^'QcGridLayout' } *parse { arg in, row, col; var out = [nil,row,col,1,1,nil]; var key; var i; if( in.isKindOf(Array) ) { out[0] = in[0].asLayoutElement; i = 1; while { i + 1 < in.size } { key = in[i]; case ( { (key === \rows) || (key === \r) }, { out[3] = in[i+1] }, { (key === \columns) || (key === \c) }, { out[4] = in[i+1] }, { (key === \align) || (key === \a) }, { out[5] = QAlignment(in[i+1]) } ); i = i + 2; }; }{ out[0] = in.asLayoutElement; }; ^out; } *rows { arg ...rows ; var grid; var data; grid = this.new; rows.do { |row, r| var offset = 0; if( row.size > 0 ) { row.do { |item, c| var colSpan; if( item.notNil ) { data = this.parse( item, r, c ); colSpan = data[4]; data[2] = data[2] + offset; grid.invokeMethod( \addItem, [data], true ); // If there's spanning, store offset for next elements column if (colSpan > 1) { offset = offset + (colSpan - 1) }; }; }; }; } ^grid; } *columns { arg ...cols; var grid; var data; grid = this.new; cols.do { |col, c| var offset = 0; if( col.size > 0 ) { col.do { |item, r| var rowSpan; if( item.notNil ) { data = this.parse( item, r, c ); rowSpan = data[3]; data[1] = data[1] + offset; grid.invokeMethod( \addItem, [data], true ); // If there's spanning, store offset for next elements row if (rowSpan > 1) { offset = offset + (rowSpan - 1) }; }; }; }; } ^grid; } add { arg item, row, column, align; this.invokeMethod( \addItem, [[item.asLayoutElement, row, column, 1, 1, QAlignment(align)]], true ); } addSpanning { arg item, row, column, rowSpan=1, columnSpan=1, align; this.invokeMethod( \addItem, [[item.asLayoutElement, row, column, rowSpan, columnSpan, QAlignment(align) ]], true ); } hSpacing_ { arg spacing; this.setProperty( \horizontalSpacing, spacing ); } vSpacing_ { arg spacing; this.setProperty( \verticalSpacing, spacing ); } setRowStretch{ arg row, factor; this.invokeMethod( 'setRowStretch', [row, factor], true ); } setColumnStretch{ arg column, factor; this.invokeMethod( 'setColumnStretch', [column, factor], true ); } setAlignment { arg item, align; var args = if( item.class === Point ) { [item.y, item.x, QAlignment(align)] } { [item, QAlignment(align)] }; this.invokeMethod( \setAlignment, args, true ); } minRowHeight { arg row; ^this.invokeMethod( \minRowHeight, row ); } setMinRowHeight { arg row, height; this.invokeMethod( \setMinRowHeight, [row, height] ); } minColumnWidth { arg column; ^this.invokeMethod( \minColumnWidth, column ); } setMinColumnWidth { arg column, width; this.invokeMethod( \setMinColumnWidth, [column, width] ); } } StackLayout : Layout { *qtClass { ^'QcStackLayout' } *new { arg ...views; ^super.new([views.collect(_.asLayoutElement)]) } add { arg view; this.insert(view.asLayoutElement, -1) } insert { arg view, index = 0; this.invokeMethod( \insertWidget, [index, view.asLayoutElement] ) } index { ^this.getProperty(\currentIndex) } index_ { arg value; this.setProperty(\currentIndex, value) } count { ^this.getProperty(\count) } mode { ^this.getProperty(\stackingMode) } mode_ { arg value; value = value.switch( \stackOne, 0, \stackAll, 1, value ); value = value.clip(0, 1).asInteger; this.setProperty(\stackingMode, value) } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QLevelIndicator.sc000644 000765 000024 00000013226 12756534416 026620 0ustar00crucialstaff000000 000000 LevelIndicator : View { *qtClass {^'QcLevelIndicator'} value { ^this.getProperty(\value) } value_ { arg val; this.setProperty(\value, val); } valueAction_ { arg val; this.setProperty(\value, val); this.doAction; } warning_ {arg val; this.setProperty(\warning, val); } critical_ {arg val; this.setProperty(\critical, val); } style_ {arg val; this.setProperty(\style, QLevelIndicatorStyle(val)); } stepWidth_{arg val; this.setProperty(\stepWidth, val); } background { ^this.getProperty(\grooveColor) } background_ { arg color; this.setProperty(\grooveColor, color) } meterColor_{ |color| this.setProperty(\meterColor, color) } warningColor_{ |color| this.setProperty(\warningColor, color) } criticalColor_{ |color| this.setProperty(\criticalColor, color) } numSteps_ {arg val; var stepWidth, length = max(this.bounds.width, this.bounds.height); stepWidth = length / val; stepWidth = stepWidth - (stepWidth < 3).if(1, 2); this.stepWidth = stepWidth; } image_ {arg image; this.nonimpl("image"); } numTicks_ {arg number; this.setProperty(\ticks, number); } numMajorTicks_ {arg number; this.setProperty(\majorTicks, number); } drawsPeak_ {arg bool; this.setProperty(\drawPeak, bool); } peakLevel_ { arg val; this.setProperty(\peak, val); } *meterServer { arg server; var window, inmeters, outmeters, inresp, outresp, insynth, outsynth, func; var numIns, numOuts; var view, viewWidth, meterWidth = 15, gapWidth = 4; var updateFreq = 10, dBLow = -80; var numRMSSamps, numRMSSampsRecip; numIns = server.options.numInputBusChannels; numOuts = server.options.numOutputBusChannels; viewWidth = (numIns + numOuts + 2) * (meterWidth + gapWidth); window = Window.new(server.name ++ " levels (dBFS)", Rect(5, 305, viewWidth + 20, 230)); window.view.background = Color.grey(0.4); view = CompositeView(window, Rect(10,25, viewWidth, 180) ); view.addFlowLayout(0@0, gapWidth@gapWidth); // dB scale UserView(view, Rect(0,0,meterWidth,195)).drawFunc_({ Pen.color = Color.white; Pen.font = Font("Helvetica", 10, true); Pen.stringCenteredIn("0", Rect(0, 0, meterWidth, 12)); Pen.stringCenteredIn("-80", Rect(0, 170, meterWidth, 12)); }); (numIns > 0).if({ // ins StaticText(window, Rect(10, 5, 100, 15)) .font_(Font("Helvetica", 10, true)) .stringColor_(Color.white) .string_("Inputs"); inmeters = Array.fill( numIns, { arg i; var comp; comp = CompositeView(view, Rect(0,0,meterWidth,195)).resize_(5); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font("Helvetica", 9, true)) .stringColor_(Color.white) .string_(i.asString); LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); // divider UserView(view, Rect(0,0,meterWidth,180)).drawFunc_({ Pen.color = Color.white; Pen.line(((meterWidth + gapWidth) * 0.5)@0, ((meterWidth + gapWidth) * 0.5)@180); Pen.stroke; }); }); // outs StaticText(window, Rect(10 + if(numIns > 0 , ((numIns + 2) * (meterWidth + gapWidth)), 0), 5, 100, 15)) .font_(Font("Helvetica", 10, true)) .stringColor_(Color.white) .string_("Outputs"); outmeters = Array.fill( numOuts, { arg i; var comp; comp = CompositeView(view, Rect(0,0,meterWidth,195)); StaticText(comp, Rect(0, 180, meterWidth, 15)) .font_(Font("Helvetica", 9, true)) .stringColor_(Color.white) .string_(i.asString); LevelIndicator( comp, Rect(0,0,meterWidth,180) ).warning_(0.9).critical_(1.0) .drawsPeak_(true) .numTicks_(9) .numMajorTicks_(3); }); window.front; func = { numRMSSamps = server.sampleRate / updateFreq; numRMSSampsRecip = 1 / numRMSSamps; (numIns > 0).if({ inresp = OSCProxy({ |msg, t| {try { msg.copyToEnd(3).pairsDo({|val, peak, i| var meter; i = i * 0.5; meter = inmeters[i]; meter.value = (val.max(0.0) * numRMSSampsRecip).sqrt.ampdb.linlin(dBLow, 0, 0, 1); meter.peakLevel = peak.ampdb.linlin(dBLow, 0, 0, 1); }) }}.defer; }, ("/" ++ server.name ++ "InLevels").asSymbol, server.addr).fix; }); outresp = OSCProxy({ |msg, t| {try { msg.copyToEnd(3).pairsDo({|val, peak, i| var meter; i = i * 0.5; meter = outmeters[i]; meter.value = (val.max(0.0) * numRMSSampsRecip).sqrt.ampdb.linlin(dBLow, 0, 0, 1); meter.peakLevel = peak.ampdb.linlin(dBLow, 0, 0, 1); }) }}.defer; }, ("/" ++ server.name ++ "OutLevels").asSymbol, server.addr).fix; server.bind({ (numIns > 0).if({ insynth = SynthDef(server.name ++ "InputLevels", { var in, imp; in = In.ar(NumOutputBuses.ir, numIns); imp = Impulse.ar(updateFreq); SendReply.ar(imp, "/" ++ server.name ++ "InLevels", // do the mean and sqrt clientside to save CPU [ RunningSum.ar(in.squared, numRMSSamps), Peak.ar(in, Delay1.ar(imp)).lag(0, 3)] .flop.flat ); }).play(RootNode(server), nil, \addToHead); }); outsynth = SynthDef(server.name ++ "OutputLevels", { var in, imp; in = In.ar(0, numOuts); imp = Impulse.ar(updateFreq); SendReply.ar(imp, "/" ++ server.name ++ "OutLevels", // do the mean and sqrt clientside to save CPU [ RunningSum.ar(in.squared, numRMSSamps), Peak.ar(in, Delay1.ar(imp)).lag(0, 3) ].flop.flat ); }).play(RootNode(server), nil, \addToTail); }); }; window.onClose_({ (server.options.numInputBusChannels > 0).if({ inresp.clear;}); outresp.clear; insynth.free; outsynth.free; ServerTree.remove(func); }); ServerTree.add(func); if(server.serverRunning, func); // otherwise starts when booted } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QListView.sc000644 000765 000024 00000005210 12756534416 025454 0ustar00crucialstaff000000 000000 ListView : ItemViewBase { var 0) ) { if( this.beginDrag( x, y ) ) { ^true }; }; ^super.mouseMoveEvent(x, y, modifiers, buttons); } selectionMode_ { arg mode; var m; m = mode.switch( \none, {0}, \single, {1}, \multi, {2}, \extended, {3}, \contiguous, {4} ); if( m == 0 ) { this.invokeMethod( \clearSelection ); this.setProperty( \currentRow, -1 ); this.setProperty( \focusPolicy, 0 ); }; this.setProperty( \selectionMode, m ); } selectionMode { var modes = [\none, \single, \multi, \extended, \contiguous]; var m = this.getProperty( \selectionMode ); ^modes[m]; } value { var v = this.getProperty( \currentRow ); if( v < 0 ) { ^nil } { ^v }; } value_ { arg val; this.setProperty( \currentRow, val ? -1 ); } selection { ^ this.getProperty(\selection) } selection_ { arg indexes; if (indexes.isNumber) { indexes = [indexes] }; if (indexes.isNil) { indexes = [] }; this.setProperty(\selection, indexes) } background { ^this.palette.base; } background_ { arg color; this.palette = this.palette.base_(color); } stringColor { ^this.palette.baseText; } stringColor_ { arg color; this.palette = this.palette.baseText_(color); } selectedStringColor { ^this.palette.highlightText; } selectedStringColor_ { arg color; this.palette = this.palette.highlightText_(color); } hiliteColor { ^this.palette.highlight; } hiliteColor_ { arg color; this.palette = this.palette.highlight_(color); } enterKeyAction_ { arg func; this.manageMethodConnection( enterKeyAction, func, 'returnPressed()', 'enterKey' ); enterKeyAction = func; } enterKey { enterKeyAction.value( this ); } selectionAction_ { arg func; this.manageFunctionConnection( selectionAction, func, 'itemSelectionChanged()' ); selectionAction = func; } colors_ { arg colorArray; colors = colorArray; this.setProperty( \colors, colorArray ); } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^View.currentDrag.isNumber; } defaultReceiveDrag { this.valueAction = View.currentDrag; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QMultiSliderView.sc000644 000765 000024 00000007470 12756534416 027010 0ustar00crucialstaff000000 000000 MultiSliderView : View { var 1 ) { i = this.index; ^val[i..(i+c-1)]; } ^this.value; } defaultCanReceiveDrag { ^true; } defaultReceiveDrag { arg data = View.currentDrag; if( data.size > 0 ) { if( data[0].size > 0 ) { this.value = data[0]; this.reference = data[1]; }{ this.value = data; } }; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QNumberBox.sc000644 000765 000024 00000005536 12756534416 025622 0ustar00crucialstaff000000 000000 NumberBox : QAbstractStepValue { var setBoth = true; *qtClass { ^'QcNumberBox' } *new { arg parent, bounds; var obj = super.new( parent, bounds ); obj.initNumberBox; ^obj; } initNumberBox { scroll = true; scroll_step = 1; normalColor = Color.black; typingColor = Color.red; } object_ { arg obj; if( setBoth ) { if( obj.isNumber ) { this.value = obj } { this.string = obj.asString } }; object = obj } value { var type = this.getProperty( \valueType ); var val; switch( type, 0 /* Number */, { val = this.getProperty( \value ) }, 1 /* Inf */, { val = inf }, 2 /* -Inf */, { val = -inf }, 3 /* NaN */, { val = 0 }, 4 /* Text */, { val = 0 } ); ^val; } value_ { arg value; case // isNaN has to be on the first plase, because a NaN is also equal to inf and -inf { value.isNaN } { this.invokeMethod( \setNaN ); } { value == inf } { this.invokeMethod( \setInfinite, true ); } { value == -inf } { this.invokeMethod( \setInfinite, false ); } { this.setProperty( \value, value.asFloat ); } ; } valueAction_ { arg val; this.value_(val); action.value(this); } string { ^this.getProperty( \text ); } string_ { arg string; this.setProperty( \text, string ); } clipLo { ^this.getProperty(\minimum) } clipLo_ { arg aFloat; this.setProperty( \minimum, aFloat ) } clipHi { ^this.getProperty(\maximum) } clipHi_ { arg aFloat; this.setProperty( \maximum, aFloat ) } scroll_ { arg aBool; scroll = aBool; this.setProperty( \scroll, aBool ); } scroll_step_ { arg aFloat; scroll_step = aFloat; this.setProperty( \scrollStep, aFloat ); } decimals { ^this.getProperty(\decimals); } minDecimals { ^this.getProperty(\minDecimals); } maxDecimals { ^this.getProperty(\maxDecimals); } decimals_ { arg decimals; this.setProperty( \decimals, decimals ); } minDecimals_ { arg decimals; this.setProperty( \minDecimals, decimals ); } maxDecimals_ { arg decimals; this.setProperty( \maxDecimals, decimals ); } align_ { arg alignment; align = alignment; this.setProperty( \alignment, QAlignment(alignment)); } stringColor { ^this.palette.baseText; } stringColor_ { arg color; this.palette = this.palette.baseText_(color); } normalColor_ { arg aColor; normalColor = aColor; this.setProperty( \normalColor, aColor ); } typingColor_ { arg aColor; typingColor = aColor; this.setProperty( \editingColor, aColor ); } background { ^this.palette.base; } background_ { arg color; this.palette = this.palette.base_(color); } buttonsVisible_ { arg aBool; buttonsVisible = aBool; this.setProperty( \buttonsVisible, aBool ); } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^View.currentDrag.isNumber; } defaultReceiveDrag { this.valueAction = View.currentDrag; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QObject.sc000644 000765 000024 00000006450 12756534416 025123 0ustar00crucialstaff000000 000000 QMetaObject { var className; *new { arg className; ^super.newCopyArgs(className); } properties { _QMetaObject_Properties ^this.primitiveFailed } methods { arg plain = true, signals = false, slots = true; _QMetaObject_Methods ^this.primitiveFailed } } QObject { classvar heap, r.height ) { this.orientation_( \horizontal ); } { this.orientation_( \vertical ); } } } pixelStep { // FIXME for now we are using step instead ^this.step; } orientation_ { arg aSymbol; this.setProperty( \orientation, QOrientation(aSymbol) ); } lo { ^this.getProperty( \loValue ); } lo_ { arg aFloat; this.setProperty( \loValue, aFloat ); } activeLo_ { arg aFloat; this.lo_(aFloat); this.doAction; } hi { ^this.getProperty( \hiValue ); } hi_ { arg aFloat; this.setProperty( \hiValue, aFloat ); } activeHi_ { arg aFloat; this.hi_(aFloat); this.doAction; } range { ^(this.hi - this.lo); } range_ { arg aFloat; this.hi_( this.lo + aFloat; ) } activeRange_ { arg aFloat; this.range_(aFloat); this.doAction; } setSpan { arg lo, hi; this.lo_(lo); this.hi_(hi); } setSpanActive { arg lo, hi; this.setSpan(lo,hi); this.doAction; } setDeviation { arg deviation, average; this.lo_( average - deviation ); this.hi_( average + deviation ); } knobColor { ^this.getProperty(\knobColor) } knobColor_ { arg color; this.setProperty(\knobColor, color) } background { ^this.getProperty(\grooveColor) } background_ { arg color; this.setProperty(\grooveColor, color) } defaultGetDrag { ^Point(this.lo,this.hi); } defaultCanReceiveDrag { ^(View.currentDrag.class === Point); } defaultReceiveDrag { var pt = View.currentDrag; this.setSpanActive( pt.x, pt.y ); } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QSlider.sc000644 000765 000024 00000003653 12756534417 025142 0ustar00crucialstaff000000 000000 Slider : QAbstractStepValue { //compatibility stuff: var r.height ) { this.orientation_( \horizontal ); } { this.orientation_( \vertical ); } } } pixelStep { ^this.getProperty(\pixelStep) } orientation_ { arg aSymbol; orientation = aSymbol; this.setProperty( \orientation, QOrientation(aSymbol) ); } defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; var scale = this.getScale( modifiers ); switch( char, $r, { this.valueAction = 1.0.rand }, $n, { this.valueAction = 0.0 }, $x, { this.valueAction = 1.0 }, $c, { this.valueAction = 0.5 }, { switch( key, 16r5d, { this.increment(scale) }, 16r1000013, { this.increment(scale) }, 16r1000014, { this.increment(scale) }, 16r5b, { this.decrement(scale) }, 16r1000015, { this.decrement(scale) }, 16r1000012, { this.decrement(scale) }, { ^this; } // if unhandled, let Qt process the event ); this.doAction; } ); ^true; // accept the event and stop its processing } defaultGetDrag { ^this.value; } defaultCanReceiveDrag { ^View.currentDrag.isNumber; } defaultReceiveDrag { this.valueAction = View.currentDrag; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QSlider2D.sc000644 000765 000024 00000003100 12756534417 025313 0ustar00crucialstaff000000 000000 Slider2D : QAbstractStepValue { *qtClass { ^'QcSlider2D' } *new { arg parent, bounds; var me = super.new( parent, bounds ); me.connectMethod( 'randomize()', \randomize ); ^me; } pixelStepX { // FIXME for now we are using step instead ^this.step; } pixelStepY { // FIXME for now we are using step instead ^this.step; } x { ^this.getProperty( \xValue ); } x_ { arg aFloat; this.setProperty( \xValue, aFloat ); } activex_ { arg aFloat; this.x_(aFloat); this.doAction; } y { ^this.getProperty( \yValue ); } y_ { arg aFloat; this.setProperty( \yValue, aFloat ); } activey_ { arg aFloat; this.y_(aFloat); this.doAction; } setXY { arg x, y; this.x_(x); this.y_(y); } setXYActive { arg x, y; this.setXY(x,y); this.doAction; } incrementX { arg factor=1.0; this.invokeMethod( \incrementX, factor.asFloat ); } decrementX { arg factor=1.0; this.invokeMethod( \decrementX, factor.asFloat ); } incrementY { arg factor=1.0; this.invokeMethod( \incrementY, factor.asFloat ); } decrementY { arg factor=1.0; this.invokeMethod( \decrementY, factor.asFloat ); } randomize { this.setXYActive( 1.0.rand, 1.0.rand ); } knobColor { ^this.getProperty(\knobColor) } knobColor_ { arg color; this.setProperty(\knobColor, color) } background { ^this.getProperty(\grooveColor) } background_ { arg color; this.setProperty(\grooveColor, color) } defaultGetDrag { ^Point(this.x,this.y); } defaultCanReceiveDrag { ^(View.currentDrag.class === Point); } defaultReceiveDrag { var pt = View.currentDrag; this.setXYActive( pt.x, pt.y ); } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QSoundFileView.sc000644 000765 000024 00000014521 12756534417 026437 0ustar00crucialstaff000000 000000 SoundFileView : View { var <>soundfile; var elasticMode; // NOTE: no-op, only for compatibility var curDoneAction; *qtClass { ^'QcWaveform' } load { arg filename, startFrame, frames, block, doneAction; if( filename.isString && filename != "" ) { if( curDoneAction.notNil ) { this.disconnectFunction( 'loadingDone()', curDoneAction ) }; if( doneAction.notNil ) { this.connectFunction( 'loadingDone()', doneAction ); }; curDoneAction = doneAction; if( startFrame.notNil && frames.notNil ) { this.invokeMethod( \load, [filename, startFrame.asInteger, frames.asInteger] ); }{ this.invokeMethod( \load, filename ); } } } alloc { arg frames, channels=1, samplerate=44100; this.invokeMethod( \allocate, [frames.asInteger, channels.asInteger, samplerate.asInteger] ); } data_ { arg data; this.setData(data); } setData { arg data, block, startFrame=0, channels=1, samplerate=44100; if( data.isKindOf(DoubleArray).not and: {data.isKindOf(FloatArray).not} ) { data = data.as(DoubleArray) }; this.invokeMethod( \load, [data, startFrame, channels, samplerate] ); } set { arg offset=0, data; if( data.isKindOf(DoubleArray).not and: {data.isKindOf(FloatArray).not} ) { data = data.as(DoubleArray) }; this.invokeMethod( \write, [data, offset.asInteger] ); } readFile { arg aSoundFile, startFrame, frames, block, closeFile, doneAction; this.load( aSoundFile.path, startFrame, frames, block, doneAction ); } read { arg startFrame, frames, block, closeFile, doneAction; if( soundfile.notNil ) { this.readFile( soundfile, startFrame, frames, block, nil, doneAction ); }; } readFileWithTask { arg soundFile, startFrame, frames, block, doneAction, showProgress; this.readFile( soundFile, startFrame, frames, block, nil, doneAction ); } readWithTask { arg startFrame, frames, block, doneAction, showProgress; this.read( startFrame, frames, block, nil, doneAction ); } drawsWaveForm { ^this.getProperty( \drawsWaveform ); } drawsWaveForm_ { arg boolean; this.setProperty( \drawsWaveform, boolean ); } waveColors { ^this.getProperty( \waveColors ) } waveColors_ { arg colors; this.setProperty( \waveColors, colors ) } //// Info startFrame { ^this.getProperty( \startFrame ); } numFrames { ^this.getProperty( \frames ); } scrollPos { ^this.getProperty( \scrollPos ); } // a fraction of the full scrolling range viewFrames { ^this.getProperty( \viewFrames ); } readProgress { ^this.getProperty( \readProgress ); } //// Navigation zoom { arg factor; this.invokeMethod( \zoomBy, factor.asFloat ); } zoomToFrac { arg fraction; this.invokeMethod( \zoomTo, fraction.asFloat ); } zoomAllOut { this.invokeMethod( \zoomAllOut ); } zoomSelection { arg selection; if( selection.isNil ) { selection = this.currentSelection }; this.invokeMethod( \zoomSelection, selection ); } scrollTo { arg fraction; // a fraction of the full scrolling range this.setProperty( \scrollPos, fraction ); } scroll { arg fraction; // a fraction of the visible range var frames = this.viewFrames * fraction + this.getProperty(\viewStartFrame); this.setProperty( \viewStartFrame, frames ); } scrollToStart { this.invokeMethod( \scrollToStart ); } scrollToEnd { this.invokeMethod( \scrollToEnd ); } xZoom { ^this.getProperty( \xZoom ); } xZoom_ { arg seconds; this.setProperty( \xZoom, seconds ); } yZoom { ^this.getProperty( \yZoom ); } yZoom_ { arg factor; this.setProperty( \yZoom, factor.asFloat ); } //// Selections selections { ^this.getProperty( \selections ); } currentSelection { ^this.getProperty( \currentSelection ); } currentSelection_ { arg index; this.setProperty( \currentSelection, index ); } selection { arg index; ^this.invokeMethod( \selection, index, true ); } setSelection { arg index, selection; this.invokeMethod( \setSelection, [index, selection] ); } selectionStart { arg index; var sel = this.selection( index ); ^sel.at(0); } setSelectionStart { arg index, frame; var sel = this.selection( index ); sel.put( 0, frame ); this.setSelection( index, sel ); } selectionSize { arg index; var sel = this.selection( index ); ^sel.at(1); } setSelectionSize { arg index, frames; var sel = this.selection( index ); sel.put( 1, frames ); this.setSelection( index, sel ); } selectAll { arg index; this.setSelection( index, [0, this.numFrames] ); } selectNone { arg index; this.setSelection( index, [0, 0] ); } setEditableSelectionStart { arg index, editable; ^this.nonimpl("setEditableSelectionStart"); } setEditableSelectionSize { arg index, editable; ^this.nonimpl("setEditableSelectionSize"); } setSelectionColor { arg index, color; this.invokeMethod( \setSelectionColor, [index,color] ); } selectionStartTime { arg index; ^this.nonimpl("selectionStartTime"); } selectionDuration { arg index; ^this.nonimpl("selectionDuration"); } readSelection { arg block, closeFile; ^this.nonimpl("readSelection"); } readSelectionWithTask { ^this.nonimpl("readSelectionWithTask"); } // cursor timeCursorOn { ^this.getProperty( \cursorVisible ); } timeCursorOn_ { arg flag; this.setProperty( \cursorVisible, flag ) } timeCursorEditable { ^this.getProperty( \cursorEditable ); } timeCursorEditable_ { arg flag; this.setProperty( \cursorEditable, flag ) } timeCursorPosition { ^this.getProperty( \cursorPosition ); } timeCursorPosition_ { arg frame; this.setProperty( \cursorPosition, frame ) } // grid gridOn { ^this.getProperty( \gridVisible ); } gridOn_ { arg flag; this.setProperty( \gridVisible, flag ) } gridResolution { ^this.getProperty( \gridResolution ) } gridResolution_ { arg seconds; this.setProperty( \gridResolution, seconds ) } gridOffset { ^this.getProperty( \gridOffset ) } gridOffset_ { arg seconds; this.setProperty( \gridOffset, seconds ) } // colors peakColor { ^this.getProperty(\peakColor) } peakColor_ { arg color; this.setProperty(\peakColor, color) } rmsColor { ^this.getProperty(\rmsColor) } rmsColor_ { arg color; this.setProperty(\rmsColor, color) } timeCursorColor { ^this.getProperty( \cursorColor ); } timeCursorColor_ { arg color; this.setProperty( \cursorColor, color ) } gridColor { ^this.getProperty( \gridColor ) } gridColor_ { arg color; this.setProperty( \gridColor, color ) } // actions metaAction_ { arg action; this.manageFunctionConnection( metaAction, action, 'metaAction()' ); metaAction = action } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QTextView.sc000644 000765 000024 00000004143 12756534417 025472 0ustar00crucialstaff000000 000000 TextView : QAbstractScroll { var 150 ) { this.dragLabel = text.copyRange(0,149) ++ "..."; }{ this.dragLabel = text; } ^text; } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QtGUI.sc000644 000765 000024 00000006106 12756534417 024524 0ustar00crucialstaff000000 000000 QtGUI { classvar = 0 ) { while { i < n } { id = i.wrap(0,nd); func.value( i, d[id] ); i = i + 1; }; }; } // dummy for convenience in case tree view is invalid prValidItem { ^nil; } } TreeViewItem { var qtObject; var userCanClose=true, <>deleteOnClose = true; // actions var keyTyped; // focus var dragLabel; var 0 ) } canFocus_ { arg bool; var policy; if( bool ) { policy = 16r1 | 16r2 | 16r8 } { policy = 0 }; this.setProperty(\focusPolicy, policy); } focus { arg flag=true; _QWidget_SetFocus ^this.primitiveFailed; } hasFocus { ^this.getProperty( \focus ); } acceptsMouse { _QWidget_AcceptsMouse ^this.primitiveFailed; } acceptsMouse_ { arg bool; _QWidget_SetAcceptsMouse ^this.primitiveFailed; } focusColor_ { arg color; this.setProperty(\focusColor, color); } focusColor { ^this.getProperty(\focusColor) ? Color(); } // ------------------ container stuff ---------------------------- children { arg class = View; var ch = super.children( class ); ^ch.select { |v| (v.tryPerform(\isClosed) ? false).not }; } parent { arg class = View; if (wasRemoved) { ^nil } { ^super.parent(class) }; } parents { var allParents; var p; if (wasRemoved.not) { p = this.parent; while { p.notNil } { allParents = allParents.add( p ); p = p.parent; }; }; ^allParents; } getParents { ^this.parents; } removeAll { var childWidgets = this.children( View ); childWidgets.do { |child| child.remove }; } layout_ { arg newLayout; if( newLayout.notNil && (newLayout != layout) ) { this.prSetLayout( newLayout ); layout = newLayout; }; } addFlowLayout { arg margin, gap; this.decorator_( FlowLayout( this.bounds.moveTo(0, 0), margin, gap ) ); ^this.decorator; } decorator_ { arg decor; decor.bounds = decor.bounds.moveTo(0, 0); decor.reset; decorator = decor; } // ................. top window stuff ............................ name { ^this.getProperty( \windowTitle ); } name_ { arg string; this.setProperty( \windowTitle, string ); } front { _QWidget_BringFront ^this.primitiveFailed; } minimize { if( this.visible ) { this.invokeMethod( \showMinimized, synchronous:false ) }; } unminimize { if( this.getProperty( \minimized ) ) { this.invokeMethod( \showNormal, synchronous:false ) }; } fullScreen { this.invokeMethod( \showFullScreen, synchronous:false ); } endFullScreen { if( this.getProperty( \fullScreen ) ) { this.invokeMethod( \showNormal, synchronous:false ) }; } alpha_ { arg aFloat; alpha = aFloat; this.setProperty( \windowOpacity, aFloat ); } alwaysOnTop { _QWidget_GetAlwaysOnTop ^this.primitiveFailed; } alwaysOnTop_ { arg boolean; _QWidget_SetAlwaysOnTop ^this.primitiveFailed; } close { if( this.getProperty( \fullScreen ) ? false ) { this.invokeMethod( \showNormal, synchronous:false ) }; if( deleteOnClose ) { this.remove; } { this.visible_( false ); } } isClosed { if (wasRemoved) {^true} {^this.isValid.not}; } notClosed { ^this.isClosed.not } // TODO: deprecate acceptsMouseOver and expose 'mouseTracking' property directly acceptsMouseOver { ^this.getProperty(\_qc_win_mouse_tracking) == true } acceptsMouseOver_ { arg flag; this.setProperty(\_qc_win_mouse_tracking, flag == true) } // ----------------- actions ..................................... action_ { arg func; // NOTE: not all widgets have action() signal try { this.manageMethodConnection( action, func, 'action()', \doAction ); }; action = func; } addAction { arg func, selector=\action; this.perform(selector.asSetter, this.perform(selector).addFunc(func)); } removeAction { arg func, selector=\action; this.perform(selector.asSetter, this.perform(selector).removeFunc(func)); } *globalKeyDownAction_ { arg action; globalKeyDownAction = action; this.setGlobalEventEnabled( 16r01 /* KeyPress */, true ); } *globalKeyUpAction_ { arg action; globalKeyUpAction = action; this.setGlobalEventEnabled( 16r02 /* KeyRelease */, true ); } keyDownAction_ { arg aFunction; keyDownAction = aFunction; this.setEventHandlerEnabled( QObject.keyDownEvent, true ); } keyUpAction_ { arg aFunction; keyUpAction = aFunction; this.setEventHandlerEnabled( QObject.keyUpEvent, true ); } keyModifiersChangedAction_ { arg aFunction; keyModifiersChangedAction = aFunction; this.setEventHandlerEnabled( QObject.keyDownEvent, true ); this.setEventHandlerEnabled( QObject.keyUpEvent, true ); } mouseDownAction_ { arg aFunction; mouseDownAction = aFunction; this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true ); this.setEventHandler( QObject.mouseDblClickEvent, \mouseDownEvent, true ); } mouseUpAction_ { arg aFunction; mouseUpAction = aFunction; this.setEventHandler( QObject.mouseUpEvent, \mouseUpEvent, true ); } mouseMoveAction_ { arg aFunction; mouseMoveAction = aFunction; this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true ); } // mouseOverAction responds to same Qt event as mouseMoveAction, // but on different conditions. // See View:-mouseMoveEvent method. mouseOverAction_ { arg aFunction; mouseOverAction = aFunction; this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true ); this.setProperty(\mouseTracking, true); } mouseEnterAction_ { arg aFunction; mouseEnterAction = aFunction; this.setEventHandler( QObject.mouseEnterEvent, \mouseEnterEvent, true ); } mouseLeaveAction_ { arg aFunction; mouseLeaveAction = aFunction; this.setEventHandler( QObject.mouseLeaveEvent, \mouseLeaveEvent, true ); } mouseWheelAction_ { arg aFunction; mouseWheelAction = aFunction; this.setEventHandler( QObject.mouseWheelEvent, \mouseWheelEvent, true ); } beginDragAction_ { arg handler; beginDragAction = handler; this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true ) } canReceiveDragHandler_ { arg handler; canReceiveDragHandler = handler; this.setDragEventsEnabled( true ); } receiveDragHandler_ { arg handler; receiveDragHandler = handler; this.setDragEventsEnabled( true ); } toFrontAction_ { arg aFunction; toFrontAction = aFunction; this.setEventHandler( QObject.windowActivateEvent, \onWindowActivateEvent ); } endFrontAction_ { arg aFunction; endFrontAction = aFunction; this.setEventHandler( QObject.windowDeactivateEvent, \onWindowDeactivateEvent ); } focusGainedAction_ { arg handler; focusGainedAction = handler; this.setEventHandler( 8 /* QEvent::FocusIn */, \focusInEvent ); } focusLostAction_ { arg handler; focusLostAction = handler; this.setEventHandler( 9 /* QEvent::FocusOut */, \focusOutEvent ); } onMove_ { arg aFunction; onMove = aFunction; this.setEventHandler( 13 /* QEvent::Move */, \moveEvent ); } onResize_ { arg aFunction; onResize = aFunction; this.setEventHandler( 14 /* QEvent::Resize */, \resizeEvent ); } onClose_ { arg func; this.manageFunctionConnection( onClose, func, 'destroyed()', false ); onClose = func; } doAction { action.value(this); } defaultKeyDownAction { arg char, modifiers, unicode, keycode, key; } defaultKeyUpAction { arg char, modifiers, unicode, keycode, key; } keyDown { arg char, modifiers, unicode, keycode, key; if( keyDownAction.notNil ) { ^keyDownAction.value( this, char, modifiers, unicode, keycode, key ); } { ^this.defaultKeyDownAction( char, modifiers, unicode, keycode, key ); }; } keyUp { arg char, modifiers, unicode, keycode, key; keyTyped = char; if( keyUpAction.notNil ) { ^keyUpAction.value( this, char, modifiers, unicode, keycode, key ); } { ^this.defaultKeyUpAction( char, modifiers, unicode, keycode, key ); }; } keyModifiersChanged { arg modifiers; keyModifiersChangedAction.value( this, modifiers); } mouseDown { arg x, y, modifiers, buttonNumber, clickCount; ^mouseDownAction.value( this, x, y, modifiers, buttonNumber, clickCount ); } mouseUp { arg x, y, modifiers, buttonNumber; ^mouseUpAction.value( this, x, y, modifiers, buttonNumber ); } mouseMove { arg x, y, modifiers; ^mouseMoveAction.value( this, x, y, modifiers ); } mouseOver { arg x, y; ^mouseOverAction.value( this, x, y ); } mouseEnter { ^mouseEnterAction.value(this); } mouseLeave { ^mouseLeaveAction.value(this); } mouseWheel { arg x, y, modifiers, xDelta, yDelta; ^mouseWheelAction.value( this, x, y, modifiers, xDelta, yDelta ); } /* ---------------- private ----------------------- */ *prSetCurrentDrag { arg obj; currentDrag = obj; currentDragString = obj.asCompileString; } *prClearCurrentDrag { currentDrag = nil; currentDragString = nil; } *setGlobalEventEnabled { arg event, enabled; _QWidget_SetGlobalEventEnabled ^this.primitiveFailed; } initView { arg parent; var handleKeyDown, handleKeyUp, overridesMouseDown, handleDrag; if (parent.notNil) { if( parent.decorator.notNil ) { parent.decorator.place(this) } }; this.setEventHandler( QObject.closeEvent, \onCloseEvent, true ); // key events handleKeyDown = handleKeyUp = this.overrides( \keyModifiersChanged ); if( handleKeyDown.not ) { handleKeyDown = this.overrides( \defaultKeyDownAction ) }; if( handleKeyUp.not ) { handleKeyUp = this.overrides( \defaultKeyUpAction )}; this.setEventHandler( QObject.keyDownEvent, \keyDownEvent, true, enabled: handleKeyDown ); this.setEventHandler( QObject.keyUpEvent, \keyUpEvent, true, enabled: handleKeyUp ); // mouse events overridesMouseDown = this.overrides( \mouseDown ); if( this.respondsTo(\defaultGetDrag) || overridesMouseDown ) {this.setEventHandler( QObject.mouseDownEvent, \mouseDownEvent, true )}; if( overridesMouseDown ) {this.setEventHandler( QObject.mouseDblClickEvent, \mouseDownEvent, true )}; if( this.overrides( \mouseUp ) ) {this.setEventHandler( QObject.mouseUpEvent, \mouseUpEvent, true )}; if( this.overrides( \mouseMove ) || this.overrides( \mouseOver ) ) {this.setEventHandler( QObject.mouseMoveEvent, \mouseMoveEvent, true )}; if( this.overrides( \mouseEnter ) ) {this.setEventHandler( QObject.mouseEnterEvent, \mouseEnterEvent, true )}; if( this.overrides( \mouseLeave ) ) {this.setEventHandler( QObject.mouseLeaveEvent, \mouseLeaveEvent, true )}; if( this.overrides( \mouseWheel ) ) {this.setEventHandler( QObject.mouseWheelEvent, \mouseWheelEvent, true )}; // DnD events handleDrag = this.respondsTo(\defaultCanReceiveDrag) or: {this.respondsTo(\defaultReceiveDrag)}; this.setEventHandler( 60, \dragEnterEvent, true, enabled:handleDrag ); this.setEventHandler( 61, \dragMoveEvent, true, enabled:handleDrag ); this.setEventHandler( 63, \dropEvent, true, enabled:handleDrag ); } onCloseEvent { if( userCanClose != false ) { if( deleteOnClose != false ) { this.remove; ^true }; }{ ^false; }; } onWindowActivateEvent { toFrontAction.value(this); } onWindowDeactivateEvent { endFrontAction.value(this); } focusInEvent { focusGainedAction.value(this) } focusOutEvent { focusLostAction.value(this) } moveEvent { onMove.value(this) } resizeEvent { onResize.value(this) } keyDownEvent { arg char, modifiers, unicode, keycode, key, spontaneous; modifiers = QKeyModifiers.toCocoa(modifiers); if( spontaneous ) { // this event has never been propagated to parent yet View.globalKeyDownAction.value( this, char, modifiers, unicode, keycode, key ); }; if( (key == 16r1000020) || (key == 16r1000021) || (key == 16r1000022) || (key == 16r1000023 ) ) { this.keyModifiersChanged( modifiers ) }; ^this.keyDown( char, modifiers, unicode, keycode, key ); } keyUpEvent { arg char, modifiers, unicode, keycode, key, spontaneous; modifiers = QKeyModifiers.toCocoa(modifiers); if( spontaneous ) { // this event has never been propagated to parent yet View.globalKeyUpAction.value( this, char, modifiers, unicode, keycode, key ); }; if( (key == 16r1000020) || (key == 16r1000021) || (key == 16r1000022) || (key == 16r1000023 ) ) { this.keyModifiersChanged( modifiers ) }; ^this.keyUp( char, modifiers, unicode, keycode, key ); } mouseDownEvent { arg x, y, modifiers, buttonNumber, clickCount; // WARNING: DragView and ListView override this method! if( (modifiers & QKeyModifiers.control) > 0 ) { // if Ctrl / Cmd mod // Try to get drag obj and start a drag. // If successful, block further processing of this event. if( this.beginDrag( x, y ) ) { ^true }; }; // else continue to handle mouse down event modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseDown( x, y, modifiers, buttonNumber, clickCount ); } mouseUpEvent { arg x, y, modifiers, buttonNumber; modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseUp( x, y, modifiers, buttonNumber ); } mouseMoveEvent { arg x, y, modifiers, buttons; // WARNING: Overridden in ListView! if( buttons != 0 ) { modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseMove( x, y, modifiers ); }{ ^this.mouseOver( x, y ) } } mouseEnterEvent { var dummy = 0; // prevent this method from being optimized away ^this.mouseEnter; } mouseLeaveEvent { var dummy = 0; // prevent this method from being optimized away ^this.mouseLeave; } mouseWheelEvent { arg x, y, modifiers, xDelta, yDelta; modifiers = QKeyModifiers.toCocoa(modifiers); ^this.mouseWheel( x, y, modifiers, xDelta, yDelta ); } beginDrag { arg x, y; var obj, str; if( beginDragAction.notNil ) { obj = beginDragAction.value( this, x, y ) } { obj = this.tryPerform( \defaultGetDrag, x, y ) }; if( obj.notNil ) { View.prSetCurrentDrag( obj ); str = obj.asString; this.prStartDrag( dragLabel ?? str, obj, str ); ^true; }; ^false; } canReceiveDrag { arg x, y; if( canReceiveDragHandler.notNil ) { ^this.canReceiveDragHandler.value( this, x, y ) } { ^( this.tryPerform( \defaultCanReceiveDrag, x, y ) ? false ) }; } receiveDrag { arg x, y; if( receiveDragHandler.notNil ) { this.receiveDragHandler.value( this, x, y ) } { this.tryPerform( \defaultReceiveDrag, x, y ) }; } prStartDrag { arg label, data, dataAsString; _QWidget_StartDrag ^this.primitiveFailed; } dragEnterEvent { arg internal, data; if(internal.not) { // dnd incoming from outside SC View.prSetCurrentDrag(data); }; // always accept the event ^true; } dragMoveEvent { arg x, y; // make sure the event is always consumed ^this.canReceiveDrag( x, y ).switch ( true, true, false, false, false ) } dropEvent { arg x, y; this.receiveDrag( x, y ); // always accept the event ^true } setDragEventsEnabled { arg enabled; this.setEventHandlerEnabled( 60, enabled ); this.setEventHandlerEnabled( 61, enabled ); this.setEventHandlerEnabled( 63, enabled ); } prSetLayout { arg layout; _QWidget_SetLayout ^this.primitiveFailed; } manageMethodConnection { arg oldAction, newAction, signal, method, sync=false; if( newAction !== oldAction ) { case { oldAction.isNil && newAction.notNil } {this.connectMethod (signal, method, sync)} { oldAction.notNil && newAction.isNil } {this.disconnectMethod (signal, method)} ; }; } manageFunctionConnection { arg oldAction, newAction, signal, sync=false; if( newAction !== oldAction ) { if( oldAction.notNil ) {this.disconnectFunction (signal, oldAction)}; if( newAction.notNil ) {this.connectFunction (signal, newAction, sync)}; }; } overrides { arg method; ^this.prOverrides(View, method) } prOverrides { arg superclass, method; _Qt_IsMethodOverridden ^this.primitiveFailed } nonimpl { arg methodName; this.class.nonimpl( methodName ); } *nonimpl { arg methodName; this.debug( msg: methodName.asString ++ " is not implemented yet" ) } *debug { arg level = 1, msg = ""; if( QtGUI.debugLevel >= level ) { ("Qt: " ++ this.asString ++ ": " ++ msg).postln } } } SuperCollider-Source/SCClassLibrary/Common/GUI/Base/QWebView.sc000644 000765 000024 00000010337 12756534417 025265 0ustar00crucialstaff000000 000000 WebView : View { var win; doDrawFunc { win.drawFunc.value(win); } } ScrollTopView : ScrollView { var >window; *qtClass {^'QcScrollWindow'} *new { arg win, name, bounds, resizable, border; ^super.newCustom([name, bounds, resizable, border]) .initScrollTopView(win); } initScrollTopView { arg win; var cnv; window = win; // NOTE: The canvas widget must not be a View, so that asking its // children for parent will skip it and hit this view instead. cnv = TopScrollWidget.new; cnv.win = win; this.canvas = cnv; } bounds { var r; r = this.getProperty( \geometry ); ^r.moveTo(0,0); } bounds_ { arg rect; var rNew = rect.asRect; var rOld = this.getProperty( \geometry ); this.setProperty( \geometry, rOld.resizeTo( rNew.width, rNew.height ) ); } drawingEnabled_ { arg bool; canvas.setProperty( \drawingEnabled, bool ); } findWindow { ^window; } } TopView : View { var >window; *qtClass {^'QcWindow'} *new { arg win, name, bounds, resizable, border; ^super.newCustom([name, bounds, resizable, border]) .initTopView(win); } initTopView { arg win; window = win; } bounds { var r; r = this.getProperty( \geometry ); ^r.moveTo(0,0); } bounds_ { arg rect; var rNew = rect.asRect; var rOld = this.getProperty( \geometry ); this.setProperty( \geometry, rOld.resizeTo( rNew.width, rNew.height ) ); } drawingEnabled_ { arg bool; this.setProperty( \drawingEnabled, bool ); } findWindow { ^window; } doDrawFunc { window.drawFunc.value(window) } } Window { classvar initAction; var resizable, acceptsClickThrough=false; var consumeKeyDowns = false;// should the view by default consume keydowns var bounds.bottom } rows { ^rows.copy } prInitFlowViewLayout { fOnViewClose = { |view| this.remove(view); }; } prAddRow { rows = rows.add(List.new); } } FlowView : SCViewHolder { // a CompositeView with a FlowLayout as its decorator // has the advantage that it preserves startRow when the view is resized var x = 0, <>y = 0; *new { arg x=0, y=0; ^super.newCopyArgs(x, y); } @ { arg aPoint; ^Rect.fromPoints(this, aPoint) } set { arg argX=0, argY=0; x = argX; y = argY; } asPoint { ^this } asComplex { ^Complex.new(x,y) } asPolar { ^Polar.new(this.rho, this.theta) } asSize { ^Size(x,y) } asRect { ^Rect.new(0,0,x,y) } asArray { ^[this.x, this.y] } == { arg aPoint; ^this.compareObject(aPoint, #[\x, \y]) } hash { ^this.instVarHash(#[\x, \y]) } performBinaryOpOnSomething { |aSelector, thing, adverb| ^thing.asPoint.perform(aSelector, this, adverb) } + { arg delta; var deltaPoint; deltaPoint = delta.asPoint; ^Point(this.x + deltaPoint.x, this.y + deltaPoint.y) } - { arg delta; var deltaPoint; deltaPoint = delta.asPoint; ^Point(this.x - deltaPoint.x, this.y - deltaPoint.y) } * { arg scale; var scalePoint; scalePoint = scale.asPoint; ^Point(this.x * scalePoint.x, this.y * scalePoint.y) } / { arg scale; var scalePoint; scalePoint = scale.asPoint; ^Point(this.x / scalePoint.x, this.y / scalePoint.y) } div { arg scale; var scalePoint; scalePoint = scale.asPoint; ^Point(this.x div: scalePoint.x, this.y div: scalePoint.y) } translate { arg delta; ^Point(this.x + delta.x, this.y + delta.y) } scale { arg scale; ^Point(this.x * scale.x, this.y * scale.y) } rotate { arg angle; // in radians var sinr, cosr; sinr = angle.sin; cosr = angle.cos; ^Point((x * cosr) - (y * sinr), (y * cosr) + (x * sinr)) } abs { ^Point(x.abs, y.abs) } rho { ^hypot(x, y) } theta { ^atan2(y, x) } dist { arg aPoint; aPoint = aPoint.asPoint; ^hypot(x - aPoint.x, y - aPoint.y) } transpose { ^Point(y, x) } round { arg quant; quant = quant.asPoint; ^Point(x.round(quant.x), y.round(quant.y)) } trunc { arg quant; quant = quant.asPoint; ^Point(x.trunc(quant.x), y.trunc(quant.y)) } mod {|that| var thatPoint; thatPoint = that.asPoint; ^Point(this.x mod: thatPoint.x, this.y mod: thatPoint.y) } printOn { arg stream; stream << this.class.name << "( " << x << ", " << y << " )"; } storeArgs { ^[x,y] } } PointArray : Point { *new { arg n; ^super.new(Signal.new(n), Signal.new(n)) } add { arg point; x = x.add(point.x); y = y.add(point.y); } } //Lines : PointArray //{ // *new { arg n; // ^super.new(2*n) // } //} // //Polygon : PointArray //{ //} // //ZigZag : PointArray //{ //} SuperCollider-Source/SCClassLibrary/Common/Geometry/Rect.sc000644 000765 000024 00000011371 12756534417 024765 0ustar00crucialstaff000000 000000 Rect { var <>left=0, <>top=0, <>width=0, <>height=0; *new { arg left=0, top=0, width=0, height=0; ^super.newCopyArgs(left, top, width, height) } *newSides { arg left=0, top=0, right=0, bottom=0; ^super.newCopyArgs(left, top, right-left, bottom-top) } *fromPoints { arg pt1, pt2; ^super.newCopyArgs( pt1.x min: pt2.x, pt1.y min: pt2.y, absdif(pt1.x, pt2.x), absdif(pt1.y, pt2.y) ) } *fromRect { arg rect; ^this.new(rect.left, rect.top, rect.width, rect.height) } *fromArray {|array| ^this.new(*array) } *aboutPoint { arg point, dx, dy; ^this.new(point.x-dx, point.y-dy, 2*dx, 2*dy) } set { arg argLeft=0, argTop=0, argWidth=0, argHeight=0; left = argLeft; top = argTop; width = argWidth; height = argHeight; } setExtent { arg argWidth=0, argHeight=0; width = argWidth; height = argHeight; } origin { ^Point.new(left, top) } origin_ { | pt | left = pt.x; top = pt.y } extent { ^Point.new(width, height) } extent_ { | pt | width = pt.x; height = pt.y } center { ^Point.new(left + (width * 0.5), top + (height * 0.5)) } center_ { arg center; ^this.class.aboutPoint(center, width * 0.5, height * 0.5) } bottom { ^top + height } bottom_ { |b| top = top - (this.bottom - b) } right { ^left + width } right_ { |r| left = left - (this.right - r) } leftTop { ^Point.new(this.left, this.top) } rightTop { ^Point.new(this.right, this.top) } leftBottom { ^Point.new(this.left, this.bottom) } rightBottom { ^Point.new(this.right, this.bottom) } size { ^Size(width,height) } size_ { |sz| width = sz.width; height = sz.height } moveBy { arg h, v; ^this.class.new(left + h, top + v, width, height) } moveTo { arg h, v; ^this.class.new(h, v, width, height) } moveToPoint { arg aPoint; ^this.class.new(aPoint.x, aPoint.y, width, height) } resizeBy { arg h, v; ^this.class.new(left, top, width + h, height + (v ? h)) } resizeTo { arg h, v; ^this.class.new(left, top, h, v) } insetBy { arg h, v; if(v.isNil){ v = h }; ^this.class.new(left + h, top + v, width - h - h, height - v - v) } insetAll { arg a, b, c, d; ^this.class.new(left + a, top + b, width - a - c, height - b - d) } insetByRect { arg r; ^this.copy.insetAll(r.left, r.top, r.right, r.bottom) } centerSquare { var pos, center; if (width > height, { pos = (width - height) * 0.5 + left; ^Rect(pos, top, height, height) },{ pos = (height - width) * 0.5 + top; ^Rect(left, pos, width, width) }); } centerIn { arg inRect; var pos, spacing; spacing = (inRect.extent - this.extent) * 0.5; ^inRect.origin - this.origin + spacing; } contains{ arg anObject; if ( anObject.isKindOf( Point ), { ^this.containsPoint( anObject ) }); if ( anObject.isKindOf( Rect ), { ^this.containsRect( anObject ) }); ^false; } containsPoint { arg aPoint; ^(aPoint.x.inclusivelyBetween(left, left + width) and: { aPoint.y.inclusivelyBetween(top, top + height) }) } containsRect { arg aRect; ^(this.containsPoint(aRect.leftTop) and: {this.containsPoint(aRect.rightBottom) }) } intersects { arg aRect; if (aRect.right <= this.left, { ^false }); if (aRect.bottom <= this.top, { ^false }); if (aRect.left >= this.right, { ^false }); if (aRect.top >= this.bottom, { ^false }); ^true } & { arg aRect; ^this sect: aRect } | { arg aRect; ^this union: aRect } union { arg aRect; ^this.class.newSides( left min: aRect.left, top min: aRect.top, this.right max: aRect.right, this.bottom max: aRect.bottom) } sect { arg aRect; ^this.class.newSides( left max: aRect.left, top max: aRect.top, this.right min: aRect.right, this.bottom min: aRect.bottom) } storeArgs { ^[left,top,width,height] } printOn { arg stream; stream << this.class.name << "(" <<* [left, top, width, height] << ")"; } // the drawing routine here use Quickdraw. // If you want CoreGraphics drawing, use methods in Pen. draw { arg color, operation=2; _Rect_Draw ^this.primitiveFailed } asRect { ^this } bounds { ^Rect.new(left, top, width, height) } == { arg that; ^this.compareObject(that, #[\left, \top, \width, \height]) } hash { ^this.instVarHash(#[\left, \top, \width, \height]) } // deprec layout { arg argBounds; this.set(argBounds.left, argBounds.top, argBounds.width, argBounds.height); } asArray { ^[this.left, this.top, this.width, this.height] } performBinaryOpOnSomething { |aSelector, thing, adverb| ^thing.asRect.perform(aSelector, this, adverb) } + {|that| var thatRect; thatRect = that.asRect; ^Rect( this.left + thatRect.left, this.top + thatRect.top, this.width + thatRect.width, this.height + thatRect.height ) } - {|that| var thatRect; thatRect = that.asRect; ^Rect( this.left - thatRect.left, this.top - thatRect.top, this.width - thatRect.width, this.height - thatRect.height ) } } SuperCollider-Source/SCClassLibrary/Common/Geometry/Size.sc000644 000765 000024 00000000713 12756534417 025000 0ustar00crucialstaff000000 000000 Size { var <>width = 0, <>height = 0; *new { arg width=0, height=0; ^super.newCopyArgs(width, height); } asSize { ^this } asRect { ^Rect(0, 0, width, height) } asPoint { ^Point(width, height) } == { arg size; ^this.compareObject(size, #[\width, \height]) } hash { ^this.instVarHash(#[\width, \height]) } printOn { |stream| this.storeOn(stream) } storeArgs { ^[width, height] } } + SimpleNumber { asSize { ^Size(this, this) } } SuperCollider-Source/SCClassLibrary/Common/Files/Directory.sc000644 000765 000024 00000002067 12766171707 025305 0ustar00crucialstaff000000 000000 /* Not working, but see String-pathMatch */ /* DirectoryEntry { var pathName; *new { arg pathName; ^super.new.pathName_(pathName); } numFiles { var numFiles = 0; this.scanFiles({ numFiles = numFiles + 1; }); ^numFiles } at { arg index; ^this.prAt(DirectoryEntry.new, index); } scan { arg func; // scan all entries in this Directory var entry, index = 0; while ({ entry = this.at(index); entry.notNil },{ func.value(entry, index); index = index + 1; }); } scanFiles { arg func; var index = 0; // scan only files in this Directory this.scan({ arg entry; if (entry.isDir.not and: { entry.isVisible }, { func.value(entry, index); index = index + 1; }) }); } deepScan { arg func; // recursively scan all files in and below this Directory this.scan({ arg entry; if (entry.isDir, { Directory.new(entry.pathName).scanFiles(func); },{ func.value(entry); }) }); } // PRIVATE prAt { arg entry, index; _Directory_At } } */ SuperCollider-Source/SCClassLibrary/Common/Files/File.sc000644 000765 000024 00000011437 12756534416 024220 0ustar00crucialstaff000000 000000 File : UnixFILE { classvar scroot; classvar <>tmp; *new { | path = "" | ^super.newCopyArgs(path.standardizePath) } *initClass { scroot = File.getcwd; tmp = Platform.defaultTempDir; if(tmp.isNil, { "No valid temp directory found. Please set it manually using PathName.tmp_".warn }) } colonIndices { ^colonIndices ?? { colonIndices = List.new; fullPath.do({ | eachChar, i | if(eachChar.isPathSeparator, { colonIndices.add(i) }) }); colonIndices } } fileName { ^fullPath.copyRange((this.lastColonIndex) + 1, (fullPath.size -1).max(0)) } fileNameWithoutExtension { var fileName = this.fileName; fileName.reverseDo({ | char, i | if(char == $.,{ ^fileName.copyRange(0,fileName.size - (i + 2)) }) }); ^fileName } fileNameWithoutDoubleExtension { var fileName, pathName; fileName = this.fileNameWithoutExtension; pathName = PathName( fileName ); ^pathName.fileNameWithoutExtension } extension { var fileName; fileName = this.fileName; fileName.reverseDo({ | char, i | if(char == $., { ^fileName.copyRange(fileName.size - i,fileName.size - 1) }) }); ^"" } pathOnly { ^fullPath.copyRange(0, this.lastColonIndex) } diskName { ^fullPath.copyRange(0, this.colonIndices.first - 1) } isRelativePath { ^this.isAbsolutePath.not } isAbsolutePath { ^fullPath.at(0).isPathSeparator } absolutePath{ ^fullPath.absolutePath } asRelativePath { |relativeTo| var r, a, b, i, mePath; mePath = this.fullPath.absolutePath; relativeTo = (relativeTo ? scroot ).absolutePath; r = thisProcess.platform.pathSeparator; a = mePath.split(r); b = relativeTo.split(r); i = 0; while { a[i] == b[i] and: { i < a.size } } { i = i + 1; }; ^(".." ++ r).dup(b.size - i).join ++ a[i..].join(r) } asAbsolutePath { if(this.isAbsolutePath,{ ^fullPath },{ // this assumes relative to the sc app ^fullPath.absolutePath }) } allFolders { var folderNames, pathCopy; folderNames = List.new; pathCopy = fullPath; this.colonIndices.doAdjacentPairs({ | startColon, endColon | folderNames.add( fullPath.copyRange(startColon + 1, endColon - 1) ) }); ^folderNames } folderName { var indexBeforeFolder; var ci = this.colonIndices; if (ci.isEmpty, { ^"" }); indexBeforeFolder = if (ci.size == 1, 0, { ci.at(ci.size - 2) + 1 }); ^fullPath.copyRange(indexBeforeFolder, this.lastColonIndex - 1) } lastColonIndex { var ci = this.colonIndices; ^if(ci.isEmpty, { -1 }, { ci.last }) ; } nextName { ^if(fullPath.last.isDecDigit, { this.noEndNumbers ++ (this.endNumber + 1) }, { fullPath ++ "1" }) } noEndNumbers { ^fullPath[..this.endNumberIndex] } endNumber { // turn consecutive digits at the end of fullPath into a number. ^fullPath[this.endNumberIndex + 1..].asInteger } endNumberIndex { var index = fullPath.lastIndex; while({ index > 0 and: { fullPath.at(index).isDecDigit } }, { index = index - 1 }); ^index } /* concatenation */ +/+ { | path | var otherFullPath = path.respondsTo(\fullPath).if({ path.fullPath }, { path.asString }); ^this.class.new(fullPath +/+ otherFullPath) } entries { var path = fullPath; if(path.isEmpty) { ^[] }; ^pathMatch(path +/+ "*").collect({ | item | PathName(item) }) } pathMatch { ^pathMatch(fullPath) } isFolder { var path = this.pathMatch; ^if(path.notEmpty, { path.at(0).last.isPathSeparator }, { false }) } isFile { var path = this.pathMatch; ^if(path.notEmpty, { path.at(0).last.isPathSeparator.not }, { false }) } files { ^this.entries.select({ | item | item.isFile }) } folders { ^this.entries.select({ | item | item.isFolder }) } deepFiles { ^this.entries.collect({ | item | if(item.isFile, { item },{ item.deepFiles }) }).flat } parentPath { var ci = this.colonIndices; ^if((fullPath.last.isPathSeparator) and: { ci.size > 1 }, { fullPath.copyRange(0, ci[ci.size - 2]) }, { fullPath.copyRange(0, this.lastColonIndex) }) } filesDo { | func | this.files.do(func); this.folders.do { | pathname | pathname.filesDo(func) }; } streamTree { | str, tabs = 0 | str << this.fullPath << Char.nl; this.files.do({ | item | tabs.do({ str << Char.tab }); str << item.fileNameWithoutExtension << Char.nl }); this.folders.do({ | item | item.streamTree(str, tabs + 1); }); } dumpTree { this.streamTree(Post) } printOn { | stream | stream << "PathName(" << fullPath << ")" } dumpToDoc { | title="Untitled" | var str, doc; doc = Document.new(title); str = CollStream.new; this.streamTree(str); doc.string = str.collection; ^doc } // deprecated messages *fromOS9 { | path | ^this.deprecated(thisMethod) } foldersWithoutCVS { | path | ^this.deprecated(thisMethod) } isCVS { ^this.deprecated(thisMethod) } foldersWithoutSVN { | path |^this.deprecated(thisMethod) } isSVN { ^this.deprecated(thisMethod) } filesDoNoCVS { | func | ^this.deprecated(thisMethod) } filesDoNoSVN { | func | ^this.deprecated(thisMethod) } streamTreeNoCVS { | str, tabs=0 | ^this.deprecated(thisMethod) } helpFilesDo { |func| ^this.deprecated(thisMethod) } } SuperCollider-Source/SCClassLibrary/Common/Files/SoundFile.sc000644 000765 000024 00000032070 12756534416 025225 0ustar00crucialstaff000000 000000 /* Sound File Format strings: header formats: read/write formats: "AIFF", - Apple's AIFF "WAV","RIFF" - Microsoft .WAV "SD2", - Sound Designer 2 "Sun", - NeXT/Sun "IRCAM", - old IRCAM format "none" - no header = raw data A huge number of other formats are supported read only. sample formats: "int8", "int16", "int24", "int32" "mulaw", "alaw", "float" not all header formats support all sample formats. */ SoundFile { classvar fileptr; var <>headerFormat = "AIFF"; var <>sampleFormat = "float"; var numChannels = 1; // number of channels var <>sampleRate = 44100.0; var <> path; *closeAll { if (openFiles.notNil, { openFiles.copy.do({ arg file; file.close; }); }); } isOpen { ^fileptr.notNil } *new { arg pathName; ^super.new.path_(pathName); } *openRead{ arg pathName; var file; file = SoundFile(pathName); if(file.openRead(pathName)){^file}{^nil} } *openWrite{ arg pathName; var file; file = SoundFile(pathName); if(file.openWrite(pathName)){ ^file}{^nil} } *use { arg path, function; var file = this.new, res; protect { file.openRead(path); res = function.value(file); } { file.close; } ^res } openRead{ arg pathName; path = pathName ? path; ^this.prOpenRead(path); } prOpenRead { arg pathName; // returns true if success, false if file not found or error reading. _SFOpenRead ^this.primitiveFailed; } readData { arg rawArray; // must have called openRead first! // returns true if success, false if file not found or error reading. _SFRead ^this.primitiveFailed; } readHeaderAsString { // must have called openRead first! //returns the whole header as String _SFHeaderInfoString ^this.primitiveFailed; } openWrite{ arg pathName; path = pathName ? path; ^this.prOpenWrite(path) } prOpenWrite { arg pathName; // write the header // format written is that indicated in headerFormat and sampleFormat. // return true if successful, false if not found or error writing. _SFOpenWrite ^this.primitiveFailed; } writeData { arg rawArray; // must have called openWrite first! // format written is that indicated in sampleFormat. // return true if successful, false if not found or error writing. _SFWrite ^this.primitiveFailed; } close { _SFClose ^this.primitiveFailed; } seek { arg offset = 0, origin = 0; // offset is in frames // origin is an integer, one of: // 0 - from beginning of file // 1 - from current position // 2 - from end of file _SFSeek ^this.primitiveFailed; } duration { ^numFrames/sampleRate } // normalizer utility *normalize { |path, outPath, newHeaderFormat, newSampleFormat, startFrame = 0, numFrames, maxAmp = 1.0, linkChannels = true, chunkSize = 4194304, threaded = false| var file, outFile, action = { protect { outFile = file.normalize(outPath, newHeaderFormat, newSampleFormat, startFrame, numFrames, maxAmp, linkChannels, chunkSize, threaded); } { file.close }; file.close; }; (file = SoundFile.openRead(path.standardizePath)).notNil.if({ // need to clean up in case of error if(threaded, { Routine(action).play(AppClock) }, action); ^outFile }, { MethodError("Unable to read soundfile at: " ++ path, this).throw; }); } normalize { |outPath, newHeaderFormat, newSampleFormat, startFrame = 0, numFrames, maxAmp = 1.0, linkChannels = true, chunkSize = 4194304, threaded = false| var peak, outFile; outFile = SoundFile.new.headerFormat_(newHeaderFormat ?? { this.headerFormat }) .sampleFormat_(newSampleFormat ?? { this.sampleFormat }) .numChannels_(this.numChannels) .sampleRate_(this.sampleRate); // can we open soundfile for writing? outFile.openWrite(outPath.standardizePath).if({ protect { "Calculating maximum levels...".postln; peak = this.channelPeaks(startFrame, numFrames, chunkSize, threaded); Post << "Peak values per channel are: " << peak << "\n"; peak.includes(0.0).if({ MethodError("At least one of the soundfile channels is zero. Aborting.", this).throw; }); // if all channels should be scaled by the same amount, // choose the highest peak among all channels // otherwise, retain the array of peaks linkChannels.if({ peak = peak.maxItem }); "Writing normalized file...".postln; this.scaleAndWrite(outFile, maxAmp / peak, startFrame, numFrames, chunkSize, threaded); "Done.".postln; } { outFile.close }; outFile.close; ^outFile }, { MethodError("Unable to write soundfile at: " ++ outPath, this).throw; }); } *groupNormalize { |paths, outDir, newHeaderFormat, newSampleFormat, maxAmp = 1.0, chunkSize = 4194304, threaded = true| var action; action = { var groupPeak = 0.0, files, outFiles; "Calculating maximum levels...".postln; paths.do({|path| var file, peak; (file = SoundFile.openRead(path.standardizePath)).notNil.if({ "Checking levels for file %\n".postf(path.standardizePath); files = files.add(file); peak = file.channelPeaks(0, nil, chunkSize, threaded); Post << "Peak values per channel are: " << peak << "\n"; peak.includes(0.0).if({ MethodError("At least one of the soundfile channels is zero. Aborting.", this).throw; }); groupPeak = max(groupPeak, peak.maxItem); }, { MethodError("Unable to read soundfile at: " ++ path, this).throw; }); }); "Overall peak level: %\n".postf(groupPeak); outDir = outDir.standardizePath.withTrailingSlash; files.do({|file| var outPath, outFile; outPath = outDir ++ file.path.basename; outFile = SoundFile.new.headerFormat_(newHeaderFormat ?? { file.headerFormat }) .sampleFormat_(newSampleFormat ?? { file.sampleFormat }) .numChannels_(file.numChannels) .sampleRate_(file.sampleRate); outFile.openWrite(outPath).if({ protect { "Writing normalized file %\n".postf(outPath); file.scaleAndWrite(outFile, maxAmp / groupPeak, 0, nil, chunkSize, threaded); } { outFile.close }; outFile.close; }, { MethodError("Unable to write soundfile at: " ++ outPath, this).throw; }); }); "////// Group Normalize complete //////".postln; }; if(threaded, { Routine(action).play(AppClock) }, action); } channelPeaks { |startFrame = 0, numFrames, chunkSize = 1048576, threaded = false| var rawData, peak, numChunks, chunksDone, test; peak = 0 ! numChannels; numFrames.isNil.if({ numFrames = this.numFrames }); numFrames = numFrames * numChannels; // chunkSize must be a multiple of numChannels chunkSize = (chunkSize/numChannels).floor * numChannels; if(threaded) { numChunks = (numFrames / chunkSize).roundUp(1); chunksDone = 0; }; this.seek(startFrame, 0); { (numFrames > 0) and: { rawData = FloatArray.newClear(min(numFrames, chunkSize)); this.readData(rawData); rawData.size > 0 } }.while({ rawData.do({ |samp, i| (samp.abs > peak[i % numChannels]).if({ peak[i % numChannels] = samp.abs }); }); numFrames = numFrames - chunkSize; if(threaded) { chunksDone = chunksDone + 1; test = chunksDone / numChunks; (((chunksDone-1) / numChunks) < test.round(0.02) and: { test >= test.round(0.02) }).if({ $..post; }); 0.0001.wait; }; }); if(threaded) { $\n.postln }; ^peak } scaleAndWrite { |outFile, scale, startFrame, numFrames, chunkSize, threaded = false| var rawData, numChunks, chunksDone, test; numFrames.isNil.if({ numFrames = this.numFrames }); numFrames = numFrames * numChannels; scale = scale.asArray; // (scale.size == 0).if({ scale = [scale] }); // chunkSize must be a multiple of numChannels chunkSize = (chunkSize/numChannels).floor * numChannels; if(threaded) { numChunks = (numFrames / chunkSize).roundUp(1); chunksDone = 0; }; this.seek(startFrame, 0); { (numFrames > 0) and: { rawData = FloatArray.newClear(min(numFrames, chunkSize)); this.readData(rawData); rawData.size > 0 } }.while({ rawData.do({ |samp, i| rawData[i] = rawData[i] * scale.wrapAt(i) }); // write, and check whether successful // throwing the error invokes error handling that closes the files (outFile.writeData(rawData) == false).if({ MethodError("SoundFile writeData failed.", this).throw }); numFrames = numFrames - chunkSize; if(threaded) { chunksDone = chunksDone + 1; test = chunksDone / numChunks; (((chunksDone-1) / numChunks) < test.round(0.02) and: { test >= test.round(0.02) }).if({ $..post; }); 0.0001.wait; }; }); if(threaded) { $\n.postln }; ^outFile } info { | path | var flag = this.openRead; if (flag) { this.close; } { ^nil } } *collect { | path = "sounds/*" | var paths, files; paths = path.pathMatch; files = paths.collect { | p | SoundFile(p).info }; files = files.select(_.notNil); ^files; } *collectIntoBuffers { | path = "sounds/*", server | server = server ?? { Server.default }; if (server.serverRunning) { ^SoundFile.collect(path) .collect { | sf | Buffer(server, sf.numFrames, sf.numChannels) .allocRead(sf.path) .sampleRate_(sf.sampleRate); } } { "the server must be running to collect soundfiles into buffers".error } } asBuffer { |server| var buffer, rawData; server = server ? Server.default; if(server.serverRunning.not) { Error("SoundFile:asBuffer - Server not running.").throw }; if(this.isOpen.not) { Error("SoundFile:asBuffer - SoundFile not open.").throw }; if(server.isLocal) { buffer = Buffer.read(server, path) } { forkIfNeeded { buffer = Buffer.alloc(server, numFrames, numChannels); rawData = FloatArray.newClear(numFrames * numChannels); this.readData(rawData); server.sync; buffer.sendCollection(rawData, wait: -1); } }; ^buffer } cue { | ev, playNow = false, closeWhenDone = false | var server, packet, defname = "diskIn" ++ numChannels, condition, onClose; ev = ev ? (); if (this.numFrames == 0) { this.info }; fork { ev.use { server = ~server ?? { Server.default}; if(~instrument.isNil) { SynthDef(defname, { | out, amp = 1, bufnum, sustain, ar = 0, dr = 0.01 gate = 1 | Out.ar(out, VDiskIn.ar(numChannels, bufnum, BufRateScale.kr(bufnum) ) * Linen.kr(gate, ar, 1, dr, 2) * EnvGen.kr(Env.linen(ar, sustain - ar - dr max: 0 ,dr),1, doneAction: 2) * amp) }).add; ~instrument = defname; condition = Condition.new; server.sync(condition); }; ev.synth; // set up as a synth event (see Event) ~bufnum = server.bufferAllocator.alloc(1); ~bufferSize = 0x10000; ~firstFrame = ~firstFrame ? 0; ~lastFrame = ~lastFrame ? numFrames; ~sustain = (~lastFrame - ~firstFrame)/(sampleRate ?? {server.options.sampleRate ? 44100}); ~close = { | ev | server.bufferAllocator.free(ev[\bufnum]); server.sendBundle(server.latency, ["/b_close", ev[\bufnum]], ["/b_free", ev[\bufnum] ] ) }; ~setwatchers = { |ev| OSCFunc({ server.sendBundle(server.latency, ["/b_close", ev[\bufnum]], ["/b_read", ev[\bufnum], path, ev[\firstFrame], ev[\bufferSize], 0, 1]); }, "/n_end", server.addr, nil, ev[\id][0]).oneShot; }; if (playNow) { packet = server.makeBundle(false, {ev.play})[0]; // makeBundle creates an array of messages // need one message, take the first } { packet = []; }; server.sendBundle(server.latency,["/b_alloc", ~bufnum, ~bufferSize, numChannels, ["/b_read", ~bufnum, path, ~firstFrame, ~bufferSize, 0, 1, packet] ]); }; }; if (closeWhenDone) { onClose = SimpleController(ev).put(\n_end, { ev.close; onClose.remove; }); ev.addDependant(onClose) }; ^ev; } play { | ev, playNow = true | ^this.cue(ev, playNow) } asEvent { | type = \allocRead | if (type == \cue) { ^( type: type, path: path, numFrames: numFrames, sampleRate: sampleRate, numChannels: numChannels, bufferSize: 0x10000, firstFileFrame: 0, firstBufferFrame: 0, leaveOpen: 1 ) } { ^( type: type, path: path, numFrames: numFrames, sampleRate: sampleRate, numChannels: numChannels, firstFileFrame: 0 ) } } toCSV { |outpath, headers, delim=",", append=false, func, action| var outfile, dataChunk; // Prepare input if(this.openRead(this.path).not){ ^"SoundFile:toCSV could not open the sound file".error }; dataChunk = FloatArray.newClear(this.numChannels * min(this.numFrames, 1024)); // Prepare output if(outpath.isNil){ outpath = path.splitext.at(0) ++ ".csv" }; outfile = File(outpath, if(append, "a", "w")); if(headers.notNil){ if(headers.isString){ outfile.write(headers ++ Char.nl); }{ outfile.write(headers.join(delim) ++ Char.nl); } }; // Now do it while{this.readData(dataChunk); dataChunk.size > 0}{ dataChunk.clump(this.numChannels).do{|row| outfile.write(if(func.isNil, {row}, {func.value(row)}).join(delim) ++ Char.nl) }; }; outfile.close; this.close; action.value(outpath); } } SuperCollider-Source/SCClassLibrary/Common/Core/AbstractFunction.sc000644 000765 000024 00000032760 12756534416 026442 0ustar00crucialstaff000000 000000 AbstractFunction { // function compositions // override these in subclasses to perform different kinds of function compositions composeUnaryOp { arg aSelector; ^UnaryOpFunction.new(aSelector, this) } composeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunction.new(aSelector, this, something, adverb); } reverseComposeBinaryOp { arg aSelector, something, adverb; ^BinaryOpFunction.new(aSelector, something, this, adverb); } composeNAryOp { arg aSelector, anArgList; ^NAryOpFunction.new(aSelector, this, anArgList) } // double dispatch for mixed operations performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; ^this.reverseComposeBinaryOp(aSelector, aNumber, adverb) } performBinaryOpOnSignal { arg aSelector, aSignal, adverb; ^this.reverseComposeBinaryOp(aSelector, aSignal, adverb) } performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^this.reverseComposeBinaryOp(aSelector, aComplex, adverb) } performBinaryOpOnSeqColl { arg aSelector, aSeqColl, adverb; ^this.reverseComposeBinaryOp(aSelector, aSeqColl, adverb) } // respond to math operators neg { ^this.composeUnaryOp('neg') } reciprocal { ^this.composeUnaryOp('reciprocal') } bitNot { ^this.composeUnaryOp('bitNot') } abs { ^this.composeUnaryOp('abs') } asFloat { ^this.composeUnaryOp('asFloat') } asInteger { ^this.composeUnaryOp('asInteger') } ceil { ^this.composeUnaryOp('ceil') } floor { ^this.composeUnaryOp('floor') } frac { ^this.composeUnaryOp('frac') } sign { ^this.composeUnaryOp('sign') } squared { ^this.composeUnaryOp('squared') } cubed { ^this.composeUnaryOp('cubed') } sqrt { ^this.composeUnaryOp('sqrt') } exp { ^this.composeUnaryOp('exp') } midicps { ^this.composeUnaryOp('midicps') } cpsmidi { ^this.composeUnaryOp('cpsmidi') } midiratio { ^this.composeUnaryOp('midiratio') } ratiomidi { ^this.composeUnaryOp('ratiomidi') } ampdb { ^this.composeUnaryOp('ampdb') } dbamp { ^this.composeUnaryOp('dbamp') } octcps { ^this.composeUnaryOp('octcps') } cpsoct { ^this.composeUnaryOp('cpsoct') } log { ^this.composeUnaryOp('log') } log2 { ^this.composeUnaryOp('log2') } log10 { ^this.composeUnaryOp('log10') } sin { ^this.composeUnaryOp('sin') } cos { ^this.composeUnaryOp('cos') } tan { ^this.composeUnaryOp('tan') } asin { ^this.composeUnaryOp('asin') } acos { ^this.composeUnaryOp('acos') } atan { ^this.composeUnaryOp('atan') } sinh { ^this.composeUnaryOp('sinh') } cosh { ^this.composeUnaryOp('cosh') } tanh { ^this.composeUnaryOp('tanh') } rand { ^this.composeUnaryOp('rand') } rand2 { ^this.composeUnaryOp('rand2') } linrand { ^this.composeUnaryOp('linrand') } bilinrand { ^this.composeUnaryOp('bilinrand') } sum3rand { ^this.composeUnaryOp('sum3rand') } distort { ^this.composeUnaryOp('distort') } softclip { ^this.composeUnaryOp('softclip') } coin { ^this.composeUnaryOp('coin') } even { ^this.composeUnaryOp('even') } odd { ^this.composeUnaryOp('odd') } rectWindow { ^this.composeUnaryOp('rectWindow') } hanWindow { ^this.composeUnaryOp('hanWindow') } welWindow { ^this.composeUnaryOp('welWindow') } triWindow { ^this.composeUnaryOp('triWindow') } scurve { ^this.composeUnaryOp('scurve') } ramp { ^this.composeUnaryOp('ramp') } isPositive { ^this.composeUnaryOp('isPositive') } isNegative { ^this.composeUnaryOp('isNegative') } isStrictlyPositive { ^this.composeUnaryOp('isStrictlyPositive') } rho { ^this.composeUnaryOp('rho') } theta { ^this.composeUnaryOp('theta') } rotate { arg function; ^this.composeBinaryOp('rotate', function) } dist { arg function; ^this.composeBinaryOp('dist', function) } + { arg function, adverb; ^this.composeBinaryOp('+', function, adverb) } - { arg function, adverb; ^this.composeBinaryOp('-', function, adverb) } * { arg function, adverb; ^this.composeBinaryOp('*', function, adverb) } / { arg function, adverb; ^this.composeBinaryOp('/', function, adverb) } div { arg function, adverb; ^this.composeBinaryOp('div', function, adverb) } mod { arg function, adverb; ^this.composeBinaryOp('mod', function, adverb) } pow { arg function, adverb; ^this.composeBinaryOp('pow', function, adverb) } min { arg function, adverb; ^this.composeBinaryOp('min', function, adverb) } max { arg function=0, adverb; ^this.composeBinaryOp('max', function, adverb) } < { arg function, adverb; ^this.composeBinaryOp('<', function, adverb) } <= { arg function, adverb; ^this.composeBinaryOp('<=', function, adverb) } > { arg function, adverb; ^this.composeBinaryOp('>', function, adverb) } >= { arg function, adverb; ^this.composeBinaryOp('>=', function, adverb) } bitAnd { arg function, adverb; ^this.composeBinaryOp('bitAnd', function, adverb) } bitOr { arg function, adverb; ^this.composeBinaryOp('bitOr', function, adverb) } bitXor { arg function, adverb; ^this.composeBinaryOp('bitXor', function, adverb) } bitHammingDistance { arg function, adverb; ^this.composeBinaryOp('hammingDistance', function, adverb) } lcm { arg function, adverb; ^this.composeBinaryOp('lcm', function, adverb) } gcd { arg function, adverb; ^this.composeBinaryOp('gcd', function, adverb) } round { arg function=1, adverb; ^this.composeBinaryOp('round', function, adverb) } roundUp { arg function=1, adverb; ^this.composeBinaryOp('roundUp', function, adverb) } trunc { arg function=1, adverb; ^this.composeBinaryOp('trunc', function, adverb) } atan2 { arg function, adverb; ^this.composeBinaryOp('atan2', function, adverb) } hypot { arg function, adverb; ^this.composeBinaryOp('hypot', function, adverb) } hypotApx { arg function, adverb; ^this.composeBinaryOp('hypotApx', function, adverb) } leftShift { arg function, adverb; ^this.composeBinaryOp('leftShift', function, adverb) } rightShift { arg function, adverb; ^this.composeBinaryOp('rightShift', function, adverb) } unsignedRightShift { arg function, adverb; ^this.composeBinaryOp('unsignedRightShift', function, adverb) } ring1 { arg function, adverb; ^this.composeBinaryOp('ring1', function, adverb) } ring2 { arg function, adverb; ^this.composeBinaryOp('ring2', function, adverb) } ring3 { arg function, adverb; ^this.composeBinaryOp('ring3', function, adverb) } ring4 { arg function, adverb; ^this.composeBinaryOp('ring4', function, adverb) } difsqr { arg function, adverb; ^this.composeBinaryOp('difsqr', function, adverb) } sumsqr { arg function, adverb; ^this.composeBinaryOp('sumsqr', function, adverb) } sqrsum { arg function, adverb; ^this.composeBinaryOp('sqrsum', function, adverb) } sqrdif { arg function, adverb; ^this.composeBinaryOp('sqrdif', function, adverb) } absdif { arg function, adverb; ^this.composeBinaryOp('absdif', function, adverb) } thresh { arg function, adverb; ^this.composeBinaryOp('thresh', function, adverb) } amclip { arg function, adverb; ^this.composeBinaryOp('amclip', function, adverb) } scaleneg { arg function, adverb; ^this.composeBinaryOp('scaleneg', function, adverb) } clip2 { arg function=1, adverb; ^this.composeBinaryOp('clip2', function, adverb) } fold2 { arg function=1, adverb; ^this.composeBinaryOp('fold2', function, adverb) } wrap2 { arg function=1, adverb; ^this.composeBinaryOp('wrap2', function, adverb) } excess { arg function=1, adverb; ^this.composeBinaryOp('excess', function, adverb) } firstArg { arg function, adverb; ^this.composeBinaryOp('firstArg', function, adverb) } rrand { arg function, adverb; ^this.composeBinaryOp('rrand', function, adverb) } exprand { arg function, adverb; ^this.composeBinaryOp('exprand', function, adverb) } @ { arg function, adverb; ^this.composeBinaryOp('@', function, adverb) } // complex support real { ^this } imag { ^0.0 } || { arg function, adverb; ^this.composeBinaryOp('||', function, adverb) } && { arg function, adverb; ^this.composeBinaryOp('&&', function, adverb) } xor { arg function, adverb; ^this.composeBinaryOp('xor', function, adverb) } nand { arg function, adverb; ^this.composeBinaryOp('nand', function, adverb) } not { ^this.composeUnaryOp('not') } ref { ^this.composeUnaryOp('asRef') } // nary operators clip { arg lo, hi; ^this.composeNAryOp('clip', [lo,hi]) } wrap { arg lo, hi; ^this.composeNAryOp('wrap', [lo,hi]) } fold { arg lo, hi; ^this.composeNAryOp('fold', [lo,hi]) } blend { arg that, blendFrac = 0.5; ^this.composeNAryOp('blend', [that, blendFrac]) } linlin { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('linlin', [inMin, inMax, outMin, outMax, clip]) } linexp { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('linexp', [inMin, inMax, outMin, outMax, clip]) } explin { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('explin', [inMin, inMax, outMin, outMax, clip]) } expexp { arg inMin, inMax, outMin, outMax, clip=\minmax; ^this.composeNAryOp('expexp', [inMin, inMax, outMin, outMax, clip]) } lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; ^this.composeNAryOp('lincurve', [inMin, inMax, outMin, outMax, curve, clip]) } curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; ^this.composeNAryOp('curvelin', [inMin, inMax, outMin, outMax, curve, clip]) } bilin { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; ^this.composeNAryOp('bilin', [inCenter, inMin, inMax, outCenter, outMin, outMax, clip]) } biexp { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; ^this.composeNAryOp('biexp', [inCenter, inMin, inMax, outCenter, outMin, outMax, clip]) } moddif { arg function = 0.0, mod = 1.0; ^this.composeNAryOp('moddif', [function, mod]) } degreeToKey { arg scale, stepsPerOctave=12; ^this.composeNAryOp('degreeToKey', [scale, stepsPerOctave]) } degrad { ^this.composeUnaryOp('degrad') } raddeg { ^this.composeUnaryOp('raddeg') } applyTo { arg ... args; ^this.valueArray(args) } <> { arg that; // function composition ^{|...args| this.value(that.value(*args)) } } sampled{ |n=80,from=0.0,to=1.0| var valueArray; valueArray = (from,(to-from)/(n-1) .. to).collect{|x| this.value(x) }; ^{ |x| valueArray.blendAt( ((x.clip(from,to)-from)/(to-from))*(n-1) ) } } // embed in ugen graph asUGenInput { arg for; ^this.value(for) } asAudioRateInput { |for| var result = this.value(for); ^if(result.rate != \audio) { K2A.ar(result) } { result } } // convert to control input asControlInput { ^this.value } isValidUGenInput { ^true } } UnaryOpFunction : AbstractFunction { var selector, a; *new { arg selector, a; ^super.newCopyArgs(selector, a) } value { arg ... args; ^a.valueArray(args).perform(selector) } valueArray { arg args; ^a.valueArray(args).perform(selector) } valueEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector) } valueArrayEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector) } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } storeOn { arg stream; stream <<< a << "." << selector; } } BinaryOpFunction : AbstractFunction { var selector, a, b, adverb; *new { arg selector, a, b, adverb; ^super.newCopyArgs(selector, a, b, adverb) } value { arg ... args; ^a.valueArray(args).perform(selector, b.valueArray(args), adverb) } valueArray { arg args; ^a.valueArray(args).perform(selector, b.valueArray(args), adverb) } valueEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector, b.valueArrayEnvir(args), adverb) } valueArrayEnvir { arg ... args; ^a.valueArrayEnvir(args).perform(selector, b.valueArrayEnvir(args), adverb) } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } storeOn { arg stream; stream << "(" <<< a << " " << selector.asBinOpString; if(adverb.notNil) { stream << "." << adverb }; stream << " " <<< b << ")" } } NAryOpFunction : AbstractFunction { var selector, a, arglist; *new { arg selector, a, arglist; ^super.newCopyArgs(selector, a, arglist) } value { arg ... args; ^a.valueArray(args).performList(selector, arglist.collect(_.valueArray(args))) } valueArray { arg args; ^a.valueArray(args).performList(selector, arglist.collect(_.valueArray(args))) } valueEnvir { arg ... args; ^a.valueArrayEnvir(args).performList(selector, arglist.collect(_.valueArrayEnvir(args))) } valueArrayEnvir { arg ... args; ^a.valueArrayEnvir(args).performList(selector, arglist.collect(_.valueArrayEnvir(args))) } functionPerformList { arg selector, arglist; ^this.performList(selector, arglist) } storeOn { arg stream; stream <<< a << "." << selector << "(" <<<* arglist << ")" } } FunctionList : AbstractFunction { var <>array, 1) { forBy(1, queue.size-1, 3) {|i| queue[i+1].removedFromScheduler }; }; this.prClear; } *sched { arg delta, item; _SystemClock_Sched ^this.primitiveFailed } *schedAbs { arg time, item; _SystemClock_SchedAbs ^this.primitiveFailed } *prClear { _SystemClock_Clear ^this.primitiveFailed } } AppClock : Clock { classvar scheduler; *initClass { scheduler = Scheduler.new(this, drift:true, recursive:false); } *clear { scheduler.clear; } *sched { arg delta, item; scheduler.sched(delta, item); this.prSchedNotify; } *tick { var saveClock = thisThread.clock; thisThread.clock = this; scheduler.seconds = Main.elapsedTime; thisThread.clock = saveClock; ^scheduler.queue.topPriority; } *prSchedNotify { // notify clients that something has been scheduled _AppClock_SchedNotify } } Scheduler { var clock, drift, <>recursive, beats = 0.0, default; var permanent=false; /* You should only change the tempo 'now'. You can't set the tempo at some beat in the future or past, even though you might think so from the methods. There are several ideas of now: elapsed time, i.e. "real time" logical time in the current time base. logical time in another time base. logical time is time that is incremented by exact amounts from the time you started. It is not affected by the actual time your task gets scheduled, which may shift around somewhat due to system load. By calculating using logical time instead of actual time, your process will not drift out of sync over long periods. every thread stores a clock and its current logical time in seconds and beats relative to that clock. elapsed time is whatever the system clock says it is right now. elapsed time is always advancing. logical time only advances when your task yields or returns. */ *new { arg tempo, beats, seconds, queueSize=256; ^super.new.init(tempo, beats, seconds, queueSize) } *initClass { default = this.new(queueSize: 2048).permanent_(true); CmdPeriod.add(this); } *cmdPeriod { all.do({ arg item; item.clear(false) }); // copy is important: You must never iterate over the same // collection from which you're removing items all.copy.do({ arg item; if (item.permanent.not, { item.stop }) }) } init { arg tempo, beats, seconds, queueSize; queue = Array.new(queueSize); this.prStart(tempo, beats, seconds); all = all.add(this); } stop { this.changed(\stop); this.releaseDependants; all.take(this); this.prStop; } play { arg task, quant = 1; this.schedAbs(quant.nextTimeOnGrid(this), task) } playNextBar { arg task; this.schedAbs(this.nextBar, task) } tempo { _TempoClock_Tempo ^this.primitiveFailed } beatDur { _TempoClock_BeatDur ^this.primitiveFailed } elapsedBeats { _TempoClock_ElapsedBeats ^this.primitiveFailed /* primitive does this: ^this.secs2beats(Main.elapsedTime). */ } beats { // returns the appropriate beats for this clock from any thread _TempoClock_Beats ^this.primitiveFailed /* primitive does this: if (thisThread.clock == this) { ^thisThread.beats } ^this.secs2beats(thisThread.seconds) */ } beats_ { arg beats; _TempoClock_SetBeats ^this.primitiveFailed } seconds { ^thisThread.seconds } sched { arg delta, item; _TempoClock_Sched ^this.primitiveFailed } schedAbs { arg beat, item; _TempoClock_SchedAbs ^this.primitiveFailed } clear { | releaseNodes = true | // flag tells EventStreamPlayers that CmdPeriod is removing them, so // nodes are already freed // NOTE: queue is an Array, not a PriorityQueue, but it's used as such internally. That's why each item uses 3 slots. if (queue.size > 1) { forBy(1, queue.size-1, 3) {|i| queue[i+1].removedFromScheduler(releaseNodes) }; }; ^this.prClear; } // for setting the tempo at the current logical time // (even another TempoClock's logical time). tempo_ { arg newTempo; this.setTempoAtBeat(newTempo, this.beats); this.changed(\tempo); // this line is added } beatsPerBar_ { arg newBeatsPerBar; if (thisThread.clock != this) { "should only change beatsPerBar within the scheduling thread.".error; ^this }; this.setMeterAtBeat(newBeatsPerBar, thisThread.beats); } // for setting the tempo at the current elapsed time . etempo_ { arg newTempo; this.setTempoAtSec(newTempo, Main.elapsedTime); } beats2secs { arg beats; _TempoClock_BeatsToSecs ^this.primitiveFailed } secs2beats { arg secs; _TempoClock_SecsToBeats ^this.primitiveFailed } prDump { _TempoClock_Dump ^this.primitiveFailed } nextTimeOnGrid { arg quant = 1, phase = 0; if (quant == 0) { ^this.beats + phase }; if (quant < 0) { quant = beatsPerBar * quant.neg }; if (phase < 0) { phase = phase % quant }; ^roundUp(this.beats - baseBarBeat - (phase % quant), quant) + baseBarBeat + phase } timeToNextBeat { arg quant=1.0; // logical time to next beat ^quant.nextTimeOnGrid(this) - this.beats } beats2bars { arg beats; ^(beats - baseBarBeat) * barsPerBeat + baseBar; } bars2beats { arg bars; ^(bars - baseBar) * beatsPerBar + baseBarBeat; } bar { // return the current bar. ^this.beats2bars(this.beats).floor; } nextBar { arg beat; // given a number of beats, determine number beats at the next bar line. if (beat.isNil) { beat = this.beats }; ^this.bars2beats(this.beats2bars(beat).ceil); } beatInBar { // return the beat of the bar, range is 0 to < t.beatsPerBar ^this.beats - this.bars2beats(this.bar) } // PRIVATE prStart { arg tempo, beats, seconds; _TempoClock_New ^this.primitiveFailed } prStop { _TempoClock_Free ^this.primitiveFailed } prClear { _TempoClock_Clear ^this.primitiveFailed } setTempoAtBeat { arg newTempo, beats; _TempoClock_SetTempoAtBeat ^this.primitiveFailed } setTempoAtSec { arg newTempo, secs; _TempoClock_SetTempoAtTime ^this.primitiveFailed } // meter should only be changed in the TempoClock's thread. setMeterAtBeat { arg newBeatsPerBar, beats; // bar must be integer valued when meter changes or confusion results later. baseBar = round((beats - baseBarBeat) * barsPerBeat + baseBar, 1); baseBarBeat = beats; beatsPerBar = newBeatsPerBar; barsPerBeat = beatsPerBar.reciprocal; this.changed(\meter); } // these methods allow TempoClock to act as TempoClock.default *stop { TempoClock.default.stop } *play { | task, quant | TempoClock.default.play(task, quant) } *sched { | delta, item | TempoClock.default.sched(delta, item) } *schedAbs { | beat, item | TempoClock.default.schedAbs(beat, item) } *clear { | releaseNodes | TempoClock.default.clear(releaseNodes) } *tempo_ { | newTempo | TempoClock.default.tempo_(newTempo) } *etempo_ { | newTempo | TempoClock.default.etempo_(newTempo) } *tempo { ^TempoClock.default.tempo } *beats { ^TempoClock.default.beats } *beats2secs { | beats | ^TempoClock.default.beats2secs(beats) } *secs2beats { | secs | ^TempoClock.default.secs2beats(secs) } *nextTimeOnGrid { | quant = 1, phase = 0 | ^TempoClock.default.nextTimeOnGrid(quant, phase) } *timeToNextBeat { | quant = 1 | ^TempoClock.default.timeToNextBeat(quant) } *setTempoAtBeat { | newTempo, beats | TempoClock.default.setTempoAtBeat(newTempo, beats) } *setTempoAtSec { | newTempo, secs | TempoClock.default.setTempoAtSec(newTempo, secs) } *setMeterAtBeat { | newBeatsPerBar, beats | TempoClock.default.setMeterAtBeat(newBeatsPerBar, beats) } *beatsPerBar { ^TempoClock.default.beatsPerBar } *baseBarBeat { ^TempoClock.default.baseBarBeat } *baseBar { ^TempoClock.default.baseBar } *playNextBar { | task | ^TempoClock.default.playNextBar(task) } *beatDur { ^TempoClock.default.beatDur } *elapsedBeats { ^TempoClock.default.elapsedBeats } *beatsPerBar_ { | newBeatsPerBar | TempoClock.default.beatsPerBar_(newBeatsPerBar) } *beats2bars { | beats | ^TempoClock.default.beats2bars(beats) } *bars2beats { | bars | ^TempoClock.default.bars2beats(bars) } *bar { ^TempoClock.default.bar } *nextBar { | beat | ^TempoClock.default.nextBar(beat) } *beatInBar { ^TempoClock.default.beatInBar } archiveAsCompileString { ^true } } SuperCollider-Source/SCClassLibrary/Common/Core/Color.sc000644 000765 000024 00000104622 12766171707 024245 0ustar00crucialstaff000000 000000 Color { var <>red, <>green, <>blue, <>alpha; *new { arg red=0.0, green=0.0, blue=0.0, alpha=1.0; ^super.newCopyArgs(red, green, blue, alpha); } *new255 { arg red=0, green=0, blue=0, alpha=255; ^super.newCopyArgs(red/255, green/255, blue/255, alpha/255); } *fromArray { arg array; ^this.new(*array) } *black { ^Color.new(0.0, 0.0, 0.0) } *white { ^Color.new(1.0, 1.0, 1.0) } *red { arg val = 1.0, alpha = 1.0; ^Color.new(min(1,val), max(val-1,0), max(val-1,0), alpha) } *green { arg val = 1.0, alpha = 1.0; ^Color.new(max(val-1,0), min(1,val), max(val-1,0), alpha) } *blue { arg val = 1.0, alpha = 1.0; ^Color.new(max(val-1,0), max(val-1,0), min(1,val), alpha) } *cyan { arg val = 1.0, alpha = 1.0; ^Color.new(max(val-1,0), min(1,val), min(1,val), alpha) } *magenta { arg val = 1.0, alpha = 1.0; ^Color.new(min(1,val), max(val-1,0), min(1,val), alpha) } *yellow { arg val = 1.0, alpha = 1.0; ^Color.new(min(1,val), min(1,val), max(val-1,0), alpha) } *clear { ^Color.new(0.0, 0.0, 0.0, 0.0) } *grey { arg grey = 0.5, alpha = 1.0; ^Color.new(grey, grey, grey, alpha); } *gray { arg gray = 0.5, alpha = 1.0; // synonym ^Color.grey(gray, alpha); } *rand { arg lo=0.3,hi=0.9; ^Color.new(rrand(lo,hi),rrand(lo,hi),rrand(lo,hi)) } == { arg that; ^this.compareObject(that, #[\red, \green, \blue, \alpha]) } hash { ^this.instVarHash(#[\red, \green, \blue, \alpha]) } scaleByAlpha { ^Color.new(red * alpha, green * alpha, blue * alpha, 1.0) } blend { arg that, blend = 0.5; ^Color.fromArray(blend(this.asArray, that.asArray, blend)); } vary { arg val=0.1, lo=0.3, hi=0.9, alphaVal=0; ^Color.new( (red + val.rand2).clip(lo,hi), (green + val.rand2).clip(lo,hi), (blue + val.rand2).clip(lo,hi), (alpha + alphaVal.rand2).clip(0,1) ) } round { arg val=0.01; ^Color.fromArray([red, green, blue].round(val) ++ alpha) } complementary { ^Color.new(1.0 - red, 1.0 - green, 1.0 - blue, alpha) } multiply { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, vals * this.asArray, opacity) ++ alpha) } divide { arg aColor, opacity=1.0; var vals = aColor.asArray, d=0.0001 ! 3; ^Color.fromArray(blend(vals, ((this.asArray + d) / vals).min(1.0), opacity) ++ alpha) } subtract { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, (this.asArray - vals).max(0.0), opacity) ++ alpha) } add { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, (vals + this.asArray).min(1.0), opacity) ++ alpha) } symmetricDifference { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, abs(vals - this.asArray), opacity) ++ alpha) } screen { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, (1-vals) * (1-this.asArray), opacity) ++ alpha) } lighten { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, max(vals, this.asArray), opacity) ++ alpha) } darken { arg aColor, opacity=1.0; var vals = aColor.asArray; ^Color.fromArray(blend(vals, min(vals, this.asArray), opacity) ++ alpha) } hueBlend { arg aColor, blend=0.0; var f, b; f = this.asHSV; b = aColor.asHSV; ^Color.hsv(blend(f[0], b[0], blend), b[1], b[2], alpha) } saturationBlend { arg aColor, blend=0.0; var f, b; f = this.asHSV; b = aColor.asHSV; ^Color.hsv(b[0], blend(f[1], b[1], blend), b[2], alpha) } valueBlend { arg aColor, blend=0.0; var f, b; f = this.asHSV; b = aColor.asHSV; ^Color.hsv(b[0], b[1], blend(f[2], b[2], blend), alpha) } *hsv { arg hue, sat, val, alpha=1; var r, g, b, segment, fraction, t1, t2, t3; hue = hue.linlin(0, 1, 0, 360); if( sat == 0 ) { r = g = b = val } { segment = floor( hue/60 )%6; fraction = ( hue/60 - segment ); t1 = val * (1 - sat); t2 = val * (1 - (sat * fraction)); t3 = val * (1 - (sat * (1 - fraction))); if( segment == 0, { r=val; g=t3; b=t1 }); if( segment == 1, { r=t2; g = val; b=t1 }); if( segment == 2, { r=t1; g=val; b=t3 }); if( segment == 3, { r=t1; g=t2; b=val }); if( segment == 4, { r=t3; g=t1; b=val }); if( segment == 5, { r=val; g=t1; b=t2 }); }; //[r, g, b].postln; ^this.new(r, g, b, alpha); } asHSV { var max, min, delta, hue, sat, val; max = [red,green,blue].maxItem; min = [red,green,blue].minItem; delta = max - min; if (red == max, {hue = (green - blue) / delta}); if (green == max, {hue = (blue - red) / delta + 2}); if (blue == max, {hue = (red - green) / delta + 4}); hue = hue/6; if (hue < 0, {hue = hue + 1}); sat = delta / max; val = max; ^[hue, sat, val, alpha] } asArray { ^[red, green, blue, alpha] } printOn { arg stream; var title; stream << this.class.name; this.storeParamsOn(stream); } storeArgs { ^[red,green,blue,alpha] } // FIXME The following GUI redirections are rather ugly. // Shall we make GUI.color instead, and then SwingColor, QColor etc. ? setStroke { Pen.strokeColor = this; } setFill { Pen.fillColor = this; } set { this.setStroke.setFill; } hexString { // ignores alpha var hexRed, hexGreen, hexBlue; #hexRed, hexGreen, hexBlue = [red, green, blue] * 255; ^$# ++ hexRed.round.asInteger.asStringToBase(16, 2) ++ hexGreen.round.asInteger.asStringToBase(16, 2) ++ hexBlue.round.asInteger.asStringToBase(16, 2) } *fromHexString {|string| var red, green, blue; if(string[0] == $#, {string = string.copyToEnd(1)}); if(string.size == 3, {string = string[0] ++ string[0] ++ string[1] ++ string[1] ++ string[2] ++ string[2]}); red = ("0x" ++ string.copyRange(0, 1)).interpret; green = ("0x" ++ string.copyRange(2, 3)).interpret; blue = ("0x" ++ string.copyRange(4, 5)).interpret; ^this.new255(red, green, blue, 255); } } /* X-windows colors : ( alice blue: Color.new255(240, 248, 255), AliceBlue: Color.new255(240, 248, 255), antique white: Color.new255(250, 235, 215), AntiqueWhite: Color.new255(250, 235, 215), AntiqueWhite1: Color.new255(255, 239, 219), AntiqueWhite2: Color.new255(238, 223, 204), AntiqueWhite3: Color.new255(205, 192, 176), AntiqueWhite4: Color.new255(139, 131, 120), aquamarine: Color.new255(127, 255, 212), aquamarine1: Color.new255(127, 255, 212), aquamarine2: Color.new255(118, 238, 198), aquamarine3: Color.new255(102, 205, 170), aquamarine4: Color.new255(69, 139, 116), azure: Color.new255(240, 255, 255), azure1: Color.new255(240, 255, 255), azure2: Color.new255(224, 238, 238), azure3: Color.new255(193, 205, 205), azure4: Color.new255(131, 139, 139), beige: Color.new255(245, 245, 220), bisque: Color.new255(255, 228, 196), bisque1: Color.new255(255, 228, 196), bisque2: Color.new255(238, 213, 183), bisque3: Color.new255(205, 183, 158), bisque4: Color.new255(139, 125, 107), black: Color.new255(0, 0, 0), blanched almond: Color.new255(255, 235, 205), BlanchedAlmond: Color.new255(255, 235, 205), blue: Color.new255(0, 0, 255), blue violet: Color.new255(138, 43, 226), blue1: Color.new255(0, 0, 255), blue2: Color.new255(0, 0, 238), blue3: Color.new255(0, 0, 205), blue4: Color.new255(0, 0, 139), BlueViolet: Color.new255(138, 43, 226), brown: Color.new255(165, 42, 42), brown1: Color.new255(255, 64, 64), brown2: Color.new255(238, 59, 59), brown3: Color.new255(205, 51, 51), brown4: Color.new255(139, 35, 35), burlywood: Color.new255(222, 184, 135), burlywood1: Color.new255(255, 211, 155), burlywood2: Color.new255(238, 197, 145), burlywood3: Color.new255(205, 170, 125), burlywood4: Color.new255(139, 115, 85), cadet blue: Color.new255(95, 158, 160), CadetBlue: Color.new255(95, 158, 160), CadetBlue1: Color.new255(152, 245, 255), CadetBlue2: Color.new255(142, 229, 238), CadetBlue3: Color.new255(122, 197, 205), CadetBlue4: Color.new255(83, 134, 139), chartreuse: Color.new255(127, 255, 0), chartreuse1: Color.new255(127, 255, 0), chartreuse2: Color.new255(118, 238, 0), chartreuse3: Color.new255(102, 205, 0), chartreuse4: Color.new255(69, 139, 0), chocolate: Color.new255(210, 105, 30), chocolate1: Color.new255(255, 127, 36), chocolate2: Color.new255(238, 118, 33), chocolate3: Color.new255(205, 102, 29), chocolate4: Color.new255(139, 69, 19), coral: Color.new255(255, 127, 80), coral1: Color.new255(255, 114, 86), coral2: Color.new255(238, 106, 80), coral3: Color.new255(205, 91, 69), coral4: Color.new255(139, 62, 47), cornflower blue: Color.new255(100, 149, 237), CornflowerBlue: Color.new255(100, 149, 237), cornsilk: Color.new255(255, 248, 220), cornsilk1: Color.new255(255, 248, 220), cornsilk2: Color.new255(238, 232, 205), cornsilk3: Color.new255(205, 200, 177), cornsilk4: Color.new255(139, 136, 120), cyan: Color.new255(0, 255, 255), cyan1: Color.new255(0, 255, 255), cyan2: Color.new255(0, 238, 238), cyan3: Color.new255(0, 205, 205), cyan4: Color.new255(0, 139, 139), dark goldenrod: Color.new255(184, 134, 11), dark green: Color.new255(0, 100, 0), dark khaki: Color.new255(189, 183, 107), dark olive green: Color.new255(85, 107, 47), dark orange: Color.new255(255, 140, 0), dark orchid: Color.new255(153, 50, 204), dark salmon: Color.new255(233, 150, 122), dark sea green: Color.new255(143, 188, 143), dark slate blue: Color.new255(72, 61, 139), dark slate gray: Color.new255(47, 79, 79), dark slate grey: Color.new255(47, 79, 79), dark turquoise: Color.new255(0, 206, 209), dark violet: Color.new255(148, 0, 211), DarkGoldenrod: Color.new255(184, 134, 11), DarkGoldenrod1: Color.new255(255, 185, 15), DarkGoldenrod2: Color.new255(238, 173, 14), DarkGoldenrod3: Color.new255(205, 149, 12), DarkGoldenrod4: Color.new255(139, 101, 8), DarkGreen: Color.new255(0, 100, 0), DarkKhaki: Color.new255(189, 183, 107), DarkOliveGreen: Color.new255(85, 107, 47), DarkOliveGreen1: Color.new255(202, 255, 112), DarkOliveGreen2: Color.new255(188, 238, 104), DarkOliveGreen3: Color.new255(162, 205, 90), DarkOliveGreen4: Color.new255(110, 139, 61), DarkOrange: Color.new255(255, 140, 0), DarkOrange1: Color.new255(255, 127, 0), DarkOrange2: Color.new255(238, 118, 0), DarkOrange3: Color.new255(205, 102, 0), DarkOrange4: Color.new255(139, 69, 0), DarkOrchid: Color.new255(153, 50, 204), DarkOrchid1: Color.new255(191, 62, 255), DarkOrchid2: Color.new255(178, 58, 238), DarkOrchid3: Color.new255(154, 50, 205), DarkOrchid4: Color.new255(104, 34, 139), DarkSalmon: Color.new255(233, 150, 122), DarkSeaGreen: Color.new255(143, 188, 143), DarkSeaGreen1: Color.new255(193, 255, 193), DarkSeaGreen2: Color.new255(180, 238, 180), DarkSeaGreen3: Color.new255(155, 205, 155), DarkSeaGreen4: Color.new255(105, 139, 105), DarkSlateBlue: Color.new255(72, 61, 139), DarkSlateGray: Color.new255(47, 79, 79), DarkSlateGray1: Color.new255(151, 255, 255), DarkSlateGray2: Color.new255(141, 238, 238), DarkSlateGray3: Color.new255(121, 205, 205), DarkSlateGray4: Color.new255(82, 139, 139), DarkSlateGrey: Color.new255(47, 79, 79), DarkTurquoise: Color.new255(0, 206, 209), DarkViolet: Color.new255(148, 0, 211), deep pink: Color.new255(255, 20, 147), deep sky blue: Color.new255(0, 191, 255), DeepPink: Color.new255(255, 20, 147), DeepPink1: Color.new255(255, 20, 147), DeepPink2: Color.new255(238, 18, 137), DeepPink3: Color.new255(205, 16, 118), DeepPink4: Color.new255(139, 10, 80), DeepSkyBlue: Color.new255(0, 191, 255), DeepSkyBlue1: Color.new255(0, 191, 255), DeepSkyBlue2: Color.new255(0, 178, 238), DeepSkyBlue3: Color.new255(0, 154, 205), DeepSkyBlue4: Color.new255(0, 104, 139), dim gray: Color.new255(105, 105, 105), dim grey: Color.new255(105, 105, 105), DimGray: Color.new255(105, 105, 105), DimGrey: Color.new255(105, 105, 105), dodger blue: Color.new255(30, 144, 255), DodgerBlue: Color.new255(30, 144, 255), DodgerBlue1: Color.new255(30, 144, 255), DodgerBlue2: Color.new255(28, 134, 238), DodgerBlue3: Color.new255(24, 116, 205), DodgerBlue4: Color.new255(16, 78, 139), firebrick: Color.new255(178, 34, 34), firebrick1: Color.new255(255, 48, 48), firebrick2: Color.new255(238, 44, 44), firebrick3: Color.new255(205, 38, 38), firebrick4: Color.new255(139, 26, 26), floral white: Color.new255(255, 250, 240), FloralWhite: Color.new255(255, 250, 240), forest green: Color.new255(34, 139, 34), ForestGreen: Color.new255(34, 139, 34), gainsboro: Color.new255(220, 220, 220), ghost white: Color.new255(248, 248, 255), GhostWhite: Color.new255(248, 248, 255), gold: Color.new255(255, 215, 0), gold1: Color.new255(255, 215, 0), gold2: Color.new255(238, 201, 0), gold3: Color.new255(205, 173, 0), gold4: Color.new255(139, 117, 0), goldenrod: Color.new255(218, 165, 32), goldenrod1: Color.new255(255, 193, 37), goldenrod2: Color.new255(238, 180, 34), goldenrod3: Color.new255(205, 155, 29), goldenrod4: Color.new255(139, 105, 20), gray: Color.new255(190, 190, 190), gray0: Color.new255(0, 0, 0), gray1: Color.new255(3, 3, 3), gray10: Color.new255(26, 26, 26), gray100: Color.new255(255, 255, 255), gray11: Color.new255(28, 28, 28), gray12: Color.new255(31, 31, 31), gray13: Color.new255(33, 33, 33), gray14: Color.new255(36, 36, 36), gray15: Color.new255(38, 38, 38), gray16: Color.new255(41, 41, 41), gray17: Color.new255(43, 43, 43), gray18: Color.new255(46, 46, 46), gray19: Color.new255(48, 48, 48), gray2: Color.new255(5, 5, 5), gray20: Color.new255(51, 51, 51), gray21: Color.new255(54, 54, 54), gray22: Color.new255(56, 56, 56), gray23: Color.new255(59, 59, 59), gray24: Color.new255(61, 61, 61), gray25: Color.new255(64, 64, 64), gray26: Color.new255(66, 66, 66), gray27: Color.new255(69, 69, 69), gray28: Color.new255(71, 71, 71), gray29: Color.new255(74, 74, 74), gray3: Color.new255(8, 8, 8), gray30: Color.new255(77, 77, 77), gray31: Color.new255(79, 79, 79), gray32: Color.new255(82, 82, 82), gray33: Color.new255(84, 84, 84), gray34: Color.new255(87, 87, 87), gray35: Color.new255(89, 89, 89), gray36: Color.new255(92, 92, 92), gray37: Color.new255(94, 94, 94), gray38: Color.new255(97, 97, 97), gray39: Color.new255(99, 99, 99), gray4: Color.new255(10, 10, 10), gray40: Color.new255(102, 102, 102), gray41: Color.new255(105, 105, 105), gray42: Color.new255(107, 107, 107), gray43: Color.new255(110, 110, 110), gray44: Color.new255(112, 112, 112), gray45: Color.new255(115, 115, 115), gray46: Color.new255(117, 117, 117), gray47: Color.new255(120, 120, 120), gray48: Color.new255(122, 122, 122), gray49: Color.new255(125, 125, 125), gray5: Color.new255(13, 13, 13), gray50: Color.new255(127, 127, 127), gray51: Color.new255(130, 130, 130), gray52: Color.new255(133, 133, 133), gray53: Color.new255(135, 135, 135), gray54: Color.new255(138, 138, 138), gray55: Color.new255(140, 140, 140), gray56: Color.new255(143, 143, 143), gray57: Color.new255(145, 145, 145), gray58: Color.new255(148, 148, 148), gray59: Color.new255(150, 150, 150), gray6: Color.new255(15, 15, 15), gray60: Color.new255(153, 153, 153), gray61: Color.new255(156, 156, 156), gray62: Color.new255(158, 158, 158), gray63: Color.new255(161, 161, 161), gray64: Color.new255(163, 163, 163), gray65: Color.new255(166, 166, 166), gray66: Color.new255(168, 168, 168), gray67: Color.new255(171, 171, 171), gray68: Color.new255(173, 173, 173), gray69: Color.new255(176, 176, 176), gray7: Color.new255(18, 18, 18), gray70: Color.new255(179, 179, 179), gray71: Color.new255(181, 181, 181), gray72: Color.new255(184, 184, 184), gray73: Color.new255(186, 186, 186), gray74: Color.new255(189, 189, 189), gray75: Color.new255(191, 191, 191), gray76: Color.new255(194, 194, 194), gray77: Color.new255(196, 196, 196), gray78: Color.new255(199, 199, 199), gray79: Color.new255(201, 201, 201), gray8: Color.new255(20, 20, 20), gray80: Color.new255(204, 204, 204), gray81: Color.new255(207, 207, 207), gray82: Color.new255(209, 209, 209), gray83: Color.new255(212, 212, 212), gray84: Color.new255(214, 214, 214), gray85: Color.new255(217, 217, 217), gray86: Color.new255(219, 219, 219), gray87: Color.new255(222, 222, 222), gray88: Color.new255(224, 224, 224), gray89: Color.new255(227, 227, 227), gray9: Color.new255(23, 23, 23), gray90: Color.new255(229, 229, 229), gray91: Color.new255(232, 232, 232), gray92: Color.new255(235, 235, 235), gray93: Color.new255(237, 237, 237), gray94: Color.new255(240, 240, 240), gray95: Color.new255(242, 242, 242), gray96: Color.new255(245, 245, 245), gray97: Color.new255(247, 247, 247), gray98: Color.new255(250, 250, 250), gray99: Color.new255(252, 252, 252), green: Color.new255(0, 255, 0), green yellow: Color.new255(173, 255, 47), green1: Color.new255(0, 255, 0), green2: Color.new255(0, 238, 0), green3: Color.new255(0, 205, 0), green4: Color.new255(0, 139, 0), GreenYellow: Color.new255(173, 255, 47), grey: Color.new255(190, 190, 190), grey0: Color.new255(0, 0, 0), grey1: Color.new255(3, 3, 3), grey10: Color.new255(26, 26, 26), grey100: Color.new255(255, 255, 255), grey11: Color.new255(28, 28, 28), grey12: Color.new255(31, 31, 31), grey13: Color.new255(33, 33, 33), grey14: Color.new255(36, 36, 36), grey15: Color.new255(38, 38, 38), grey16: Color.new255(41, 41, 41), grey17: Color.new255(43, 43, 43), grey18: Color.new255(46, 46, 46), grey19: Color.new255(48, 48, 48), grey2: Color.new255(5, 5, 5), grey20: Color.new255(51, 51, 51), grey21: Color.new255(54, 54, 54), grey22: Color.new255(56, 56, 56), grey23: Color.new255(59, 59, 59), grey24: Color.new255(61, 61, 61), grey25: Color.new255(64, 64, 64), grey26: Color.new255(66, 66, 66), grey27: Color.new255(69, 69, 69), grey28: Color.new255(71, 71, 71), grey29: Color.new255(74, 74, 74), grey3: Color.new255(8, 8, 8), grey30: Color.new255(77, 77, 77), grey31: Color.new255(79, 79, 79), grey32: Color.new255(82, 82, 82), grey33: Color.new255(84, 84, 84), grey34: Color.new255(87, 87, 87), grey35: Color.new255(89, 89, 89), grey36: Color.new255(92, 92, 92), grey37: Color.new255(94, 94, 94), grey38: Color.new255(97, 97, 97), grey39: Color.new255(99, 99, 99), grey4: Color.new255(10, 10, 10), grey40: Color.new255(102, 102, 102), grey41: Color.new255(105, 105, 105), grey42: Color.new255(107, 107, 107), grey43: Color.new255(110, 110, 110), grey44: Color.new255(112, 112, 112), grey45: Color.new255(115, 115, 115), grey46: Color.new255(117, 117, 117), grey47: Color.new255(120, 120, 120), grey48: Color.new255(122, 122, 122), grey49: Color.new255(125, 125, 125), grey5: Color.new255(13, 13, 13), grey50: Color.new255(127, 127, 127), grey51: Color.new255(130, 130, 130), grey52: Color.new255(133, 133, 133), grey53: Color.new255(135, 135, 135), grey54: Color.new255(138, 138, 138), grey55: Color.new255(140, 140, 140), grey56: Color.new255(143, 143, 143), grey57: Color.new255(145, 145, 145), grey58: Color.new255(148, 148, 148), grey59: Color.new255(150, 150, 150), grey6: Color.new255(15, 15, 15), grey60: Color.new255(153, 153, 153), grey61: Color.new255(156, 156, 156), grey62: Color.new255(158, 158, 158), grey63: Color.new255(161, 161, 161), grey64: Color.new255(163, 163, 163), grey65: Color.new255(166, 166, 166), grey66: Color.new255(168, 168, 168), grey67: Color.new255(171, 171, 171), grey68: Color.new255(173, 173, 173), grey69: Color.new255(176, 176, 176), grey7: Color.new255(18, 18, 18), grey70: Color.new255(179, 179, 179), grey71: Color.new255(181, 181, 181), grey72: Color.new255(184, 184, 184), grey73: Color.new255(186, 186, 186), grey74: Color.new255(189, 189, 189), grey75: Color.new255(191, 191, 191), grey76: Color.new255(194, 194, 194), grey77: Color.new255(196, 196, 196), grey78: Color.new255(199, 199, 199), grey79: Color.new255(201, 201, 201), grey8: Color.new255(20, 20, 20), grey80: Color.new255(204, 204, 204), grey81: Color.new255(207, 207, 207), grey82: Color.new255(209, 209, 209), grey83: Color.new255(212, 212, 212), grey84: Color.new255(214, 214, 214), grey85: Color.new255(217, 217, 217), grey86: Color.new255(219, 219, 219), grey87: Color.new255(222, 222, 222), grey88: Color.new255(224, 224, 224), grey89: Color.new255(227, 227, 227), grey9: Color.new255(23, 23, 23), grey90: Color.new255(229, 229, 229), grey91: Color.new255(232, 232, 232), grey92: Color.new255(235, 235, 235), grey93: Color.new255(237, 237, 237), grey94: Color.new255(240, 240, 240), grey95: Color.new255(242, 242, 242), grey96: Color.new255(245, 245, 245), grey97: Color.new255(247, 247, 247), grey98: Color.new255(250, 250, 250), grey99: Color.new255(252, 252, 252), honeydew: Color.new255(240, 255, 240), honeydew1: Color.new255(240, 255, 240), honeydew2: Color.new255(224, 238, 224), honeydew3: Color.new255(193, 205, 193), honeydew4: Color.new255(131, 139, 131), hot pink: Color.new255(255, 105, 180), HotPink: Color.new255(255, 105, 180), HotPink1: Color.new255(255, 110, 180), HotPink2: Color.new255(238, 106, 167), HotPink3: Color.new255(205, 96, 144), HotPink4: Color.new255(139, 58, 98), indian red: Color.new255(205, 92, 92), IndianRed: Color.new255(205, 92, 92), IndianRed1: Color.new255(255, 106, 106), IndianRed2: Color.new255(238, 99, 99), IndianRed3: Color.new255(205, 85, 85), IndianRed4: Color.new255(139, 58, 58), ivory: Color.new255(255, 255, 240), ivory1: Color.new255(255, 255, 240), ivory2: Color.new255(238, 238, 224), ivory3: Color.new255(205, 205, 193), ivory4: Color.new255(139, 139, 131), khaki: Color.new255(240, 230, 140), khaki1: Color.new255(255, 246, 143), khaki2: Color.new255(238, 230, 133), khaki3: Color.new255(205, 198, 115), khaki4: Color.new255(139, 134, 78), lavender: Color.new255(230, 230, 250), lavender blush: Color.new255(255, 240, 245), LavenderBlush: Color.new255(255, 240, 245), LavenderBlush1: Color.new255(255, 240, 245), LavenderBlush2: Color.new255(238, 224, 229), LavenderBlush3: Color.new255(205, 193, 197), LavenderBlush4: Color.new255(139, 131, 134), lawn green: Color.new255(124, 252, 0), LawnGreen: Color.new255(124, 252, 0), lemon chiffon: Color.new255(255, 250, 205), LemonChiffon: Color.new255(255, 250, 205), LemonChiffon1: Color.new255(255, 250, 205), LemonChiffon2: Color.new255(238, 233, 191), LemonChiffon3: Color.new255(205, 201, 165), LemonChiffon4: Color.new255(139, 137, 112), light blue: Color.new255(173, 216, 230), light coral: Color.new255(240, 128, 128), light cyan: Color.new255(224, 255, 255), light goldenrod: Color.new255(238, 221, 130), light goldenrod yellow: Color.new255(250, 250, 210), light gray: Color.new255(211, 211, 211), light grey: Color.new255(211, 211, 211), light pink: Color.new255(255, 182, 193), light salmon: Color.new255(255, 160, 122), light sea green: Color.new255(32, 178, 170), light sky blue: Color.new255(135, 206, 250), light slate blue: Color.new255(132, 112, 255), light slate gray: Color.new255(119, 136, 153), light slate grey: Color.new255(119, 136, 153), light steel blue: Color.new255(176, 196, 222), light yellow: Color.new255(255, 255, 224), LightBlue: Color.new255(173, 216, 230), LightBlue1: Color.new255(191, 239, 255), LightBlue2: Color.new255(178, 223, 238), LightBlue3: Color.new255(154, 192, 205), LightBlue4: Color.new255(104, 131, 139), LightCoral: Color.new255(240, 128, 128), LightCyan: Color.new255(224, 255, 255), LightCyan1: Color.new255(224, 255, 255), LightCyan2: Color.new255(209, 238, 238), LightCyan3: Color.new255(180, 205, 205), LightCyan4: Color.new255(122, 139, 139), LightGoldenrod: Color.new255(238, 221, 130), LightGoldenrod1: Color.new255(255, 236, 139), LightGoldenrod2: Color.new255(238, 220, 130), LightGoldenrod3: Color.new255(205, 190, 112), LightGoldenrod4: Color.new255(139, 129, 76), LightGoldenrodYellow: Color.new255(250, 250, 210), LightGray: Color.new255(211, 211, 211), LightGrey: Color.new255(211, 211, 211), LightPink: Color.new255(255, 182, 193), LightPink1: Color.new255(255, 174, 185), LightPink2: Color.new255(238, 162, 173), LightPink3: Color.new255(205, 140, 149), LightPink4: Color.new255(139, 95, 101), LightSalmon: Color.new255(255, 160, 122), LightSalmon1: Color.new255(255, 160, 122), LightSalmon2: Color.new255(238, 149, 114), LightSalmon3: Color.new255(205, 129, 98), LightSalmon4: Color.new255(139, 87, 66), LightSeaGreen: Color.new255(32, 178, 170), LightSkyBlue: Color.new255(135, 206, 250), LightSkyBlue1: Color.new255(176, 226, 255), LightSkyBlue2: Color.new255(164, 211, 238), LightSkyBlue3: Color.new255(141, 182, 205), LightSkyBlue4: Color.new255(96, 123, 139), LightSlateBlue: Color.new255(132, 112, 255), LightSlateGray: Color.new255(119, 136, 153), LightSlateGrey: Color.new255(119, 136, 153), LightSteelBlue: Color.new255(176, 196, 222), LightSteelBlue1: Color.new255(202, 225, 255), LightSteelBlue2: Color.new255(188, 210, 238), LightSteelBlue3: Color.new255(162, 181, 205), LightSteelBlue4: Color.new255(110, 123, 139), LightYellow: Color.new255(255, 255, 224), LightYellow1: Color.new255(255, 255, 224), LightYellow2: Color.new255(238, 238, 209), LightYellow3: Color.new255(205, 205, 180), LightYellow4: Color.new255(139, 139, 122), lime green: Color.new255(50, 205, 50), LimeGreen: Color.new255(50, 205, 50), linen: Color.new255(250, 240, 230), magenta: Color.new255(255, 0, 255), magenta1: Color.new255(255, 0, 255), magenta2: Color.new255(238, 0, 238), magenta3: Color.new255(205, 0, 205), magenta4: Color.new255(139, 0, 139), maroon: Color.new255(176, 48, 96), maroon1: Color.new255(255, 52, 179), maroon2: Color.new255(238, 48, 167), maroon3: Color.new255(205, 41, 144), maroon4: Color.new255(139, 28, 98), medium aquamarine: Color.new255(102, 205, 170), medium blue: Color.new255(0, 0, 205), medium orchid: Color.new255(186, 85, 211), medium purple: Color.new255(147, 112, 219), medium sea green: Color.new255(60, 179, 113), medium slate blue: Color.new255(123, 104, 238), medium spring green: Color.new255(0, 250, 154), medium turquoise: Color.new255(72, 209, 204), medium violet red: Color.new255(199, 21, 133), MediumAquamarine: Color.new255(102, 205, 170), MediumBlue: Color.new255(0, 0, 205), MediumOrchid: Color.new255(186, 85, 211), MediumOrchid1: Color.new255(224, 102, 255), MediumOrchid2: Color.new255(209, 95, 238), MediumOrchid3: Color.new255(180, 82, 205), MediumOrchid4: Color.new255(122, 55, 139), MediumPurple: Color.new255(147, 112, 219), MediumPurple1: Color.new255(171, 130, 255), MediumPurple2: Color.new255(159, 121, 238), MediumPurple3: Color.new255(137, 104, 205), MediumPurple4: Color.new255(93, 71, 139), MediumSeaGreen: Color.new255(60, 179, 113), MediumSlateBlue: Color.new255(123, 104, 238), MediumSpringGreen: Color.new255(0, 250, 154), MediumTurquoise: Color.new255(72, 209, 204), MediumVioletRed: Color.new255(199, 21, 133), midnight blue: Color.new255(25, 25, 112), MidnightBlue: Color.new255(25, 25, 112), mint cream: Color.new255(245, 255, 250), MintCream: Color.new255(245, 255, 250), misty rose: Color.new255(255, 228, 225), MistyRose: Color.new255(255, 228, 225), MistyRose1: Color.new255(255, 228, 225), MistyRose2: Color.new255(238, 213, 210), MistyRose3: Color.new255(205, 183, 181), MistyRose4: Color.new255(139, 125, 123), moccasin: Color.new255(255, 228, 181), navajo white: Color.new255(255, 222, 173), NavajoWhite: Color.new255(255, 222, 173), NavajoWhite1: Color.new255(255, 222, 173), NavajoWhite2: Color.new255(238, 207, 161), NavajoWhite3: Color.new255(205, 179, 139), NavajoWhite4: Color.new255(139, 121, 94), navy: Color.new255(0, 0, 128), navy blue: Color.new255(0, 0, 128), NavyBlue: Color.new255(0, 0, 128), old lace: Color.new255(253, 245, 230), OldLace: Color.new255(253, 245, 230), olive drab: Color.new255(107, 142, 35), OliveDrab: Color.new255(107, 142, 35), OliveDrab1: Color.new255(192, 255, 62), OliveDrab2: Color.new255(179, 238, 58), OliveDrab3: Color.new255(154, 205, 50), OliveDrab4: Color.new255(105, 139, 34), orange: Color.new255(255, 165, 0), orange red: Color.new255(255, 69, 0), orange1: Color.new255(255, 165, 0), orange2: Color.new255(238, 154, 0), orange3: Color.new255(205, 133, 0), orange4: Color.new255(139, 90, 0), OrangeRed: Color.new255(255, 69, 0), OrangeRed1: Color.new255(255, 69, 0), OrangeRed2: Color.new255(238, 64, 0), OrangeRed3: Color.new255(205, 55, 0), OrangeRed4: Color.new255(139, 37, 0), orchid: Color.new255(218, 112, 214), orchid1: Color.new255(255, 131, 250), orchid2: Color.new255(238, 122, 233), orchid3: Color.new255(205, 105, 201), orchid4: Color.new255(139, 71, 137), pale goldenrod: Color.new255(238, 232, 170), pale green: Color.new255(152, 251, 152), pale turquoise: Color.new255(175, 238, 238), pale violet red: Color.new255(219, 112, 147), PaleGoldenrod: Color.new255(238, 232, 170), PaleGreen: Color.new255(152, 251, 152), PaleGreen1: Color.new255(154, 255, 154), PaleGreen2: Color.new255(144, 238, 144), PaleGreen3: Color.new255(124, 205, 124), PaleGreen4: Color.new255(84, 139, 84), PaleTurquoise: Color.new255(175, 238, 238), PaleTurquoise1: Color.new255(187, 255, 255), PaleTurquoise2: Color.new255(174, 238, 238), PaleTurquoise3: Color.new255(150, 205, 205), PaleTurquoise4: Color.new255(102, 139, 139), PaleVioletRed: Color.new255(219, 112, 147), PaleVioletRed1: Color.new255(255, 130, 171), PaleVioletRed2: Color.new255(238, 121, 159), PaleVioletRed3: Color.new255(205, 104, 137), PaleVioletRed4: Color.new255(139, 71, 93), papaya whip: Color.new255(255, 239, 213), PapayaWhip: Color.new255(255, 239, 213), peach puff: Color.new255(255, 218, 185), PeachPuff: Color.new255(255, 218, 185), PeachPuff1: Color.new255(255, 218, 185), PeachPuff2: Color.new255(238, 203, 173), PeachPuff3: Color.new255(205, 175, 149), PeachPuff4: Color.new255(139, 119, 101), peru: Color.new255(205, 133, 63), pink: Color.new255(255, 192, 203), pink1: Color.new255(255, 181, 197), pink2: Color.new255(238, 169, 184), pink3: Color.new255(205, 145, 158), pink4: Color.new255(139, 99, 108), plum: Color.new255(221, 160, 221), plum1: Color.new255(255, 187, 255), plum2: Color.new255(238, 174, 238), plum3: Color.new255(205, 150, 205), plum4: Color.new255(139, 102, 139), powder blue: Color.new255(176, 224, 230), PowderBlue: Color.new255(176, 224, 230), purple: Color.new255(160, 32, 240), purple1: Color.new255(155, 48, 255), purple2: Color.new255(145, 44, 238), purple3: Color.new255(125, 38, 205), purple4: Color.new255(85, 26, 139), red: Color.new255(255, 0, 0), red1: Color.new255(255, 0, 0), red2: Color.new255(238, 0, 0), red3: Color.new255(205, 0, 0), red4: Color.new255(139, 0, 0), rosy brown: Color.new255(188, 143, 143), RosyBrown: Color.new255(188, 143, 143), RosyBrown1: Color.new255(255, 193, 193), RosyBrown2: Color.new255(238, 180, 180), RosyBrown3: Color.new255(205, 155, 155), RosyBrown4: Color.new255(139, 105, 105), royal blue: Color.new255(65, 105, 225), RoyalBlue: Color.new255(65, 105, 225), RoyalBlue1: Color.new255(72, 118, 255), RoyalBlue2: Color.new255(67, 110, 238), RoyalBlue3: Color.new255(58, 95, 205), RoyalBlue4: Color.new255(39, 64, 139), saddle brown: Color.new255(139, 69, 19), SaddleBrown: Color.new255(139, 69, 19), salmon: Color.new255(250, 128, 114), salmon1: Color.new255(255, 140, 105), salmon2: Color.new255(238, 130, 98), salmon3: Color.new255(205, 112, 84), salmon4: Color.new255(139, 76, 57), sandy brown: Color.new255(244, 164, 96), SandyBrown: Color.new255(244, 164, 96), sea green: Color.new255(46, 139, 87), SeaGreen: Color.new255(46, 139, 87), SeaGreen1: Color.new255(84, 255, 159), SeaGreen2: Color.new255(78, 238, 148), SeaGreen3: Color.new255(67, 205, 128), SeaGreen4: Color.new255(46, 139, 87), seashell: Color.new255(255, 245, 238), seashell1: Color.new255(255, 245, 238), seashell2: Color.new255(238, 229, 222), seashell3: Color.new255(205, 197, 191), seashell4: Color.new255(139, 134, 130), sienna: Color.new255(160, 82, 45), sienna1: Color.new255(255, 130, 71), sienna2: Color.new255(238, 121, 66), sienna3: Color.new255(205, 104, 57), sienna4: Color.new255(139, 71, 38), sky blue: Color.new255(135, 206, 235), SkyBlue: Color.new255(135, 206, 235), SkyBlue1: Color.new255(135, 206, 255), SkyBlue2: Color.new255(126, 192, 238), SkyBlue3: Color.new255(108, 166, 205), SkyBlue4: Color.new255(74, 112, 139), slate blue: Color.new255(106, 90, 205), slate gray: Color.new255(112, 128, 144), slate grey: Color.new255(112, 128, 144), SlateBlue: Color.new255(106, 90, 205), SlateBlue1: Color.new255(131, 111, 255), SlateBlue2: Color.new255(122, 103, 238), SlateBlue3: Color.new255(105, 89, 205), SlateBlue4: Color.new255(71, 60, 139), SlateGray: Color.new255(112, 128, 144), SlateGray1: Color.new255(198, 226, 255), SlateGray2: Color.new255(185, 211, 238), SlateGray3: Color.new255(159, 182, 205), SlateGray4: Color.new255(108, 123, 139), SlateGrey: Color.new255(112, 128, 144), snow: Color.new255(255, 250, 250), snow1: Color.new255(255, 250, 250), snow2: Color.new255(238, 233, 233), snow3: Color.new255(205, 201, 201), snow4: Color.new255(139, 137, 137), spring green: Color.new255(0, 255, 127), SpringGreen: Color.new255(0, 255, 127), SpringGreen1: Color.new255(0, 255, 127), SpringGreen2: Color.new255(0, 238, 118), SpringGreen3: Color.new255(0, 205, 102), SpringGreen4: Color.new255(0, 139, 69), steel blue: Color.new255(70, 130, 180), SteelBlue: Color.new255(70, 130, 180), SteelBlue1: Color.new255(99, 184, 255), SteelBlue2: Color.new255(92, 172, 238), SteelBlue3: Color.new255(79, 148, 205), SteelBlue4: Color.new255(54, 100, 139), tan: Color.new255(210, 180, 140), tan1: Color.new255(255, 165, 79), tan2: Color.new255(238, 154, 73), tan3: Color.new255(205, 133, 63), tan4: Color.new255(139, 90, 43), thistle: Color.new255(216, 191, 216), thistle1: Color.new255(255, 225, 255), thistle2: Color.new255(238, 210, 238), thistle3: Color.new255(205, 181, 205), thistle4: Color.new255(139, 123, 139), tomato: Color.new255(255, 99, 71), tomato1: Color.new255(255, 99, 71), tomato2: Color.new255(238, 92, 66), tomato3: Color.new255(205, 79, 57), tomato4: Color.new255(139, 54, 38), turquoise: Color.new255(64, 224, 208), turquoise1: Color.new255(0, 245, 255), turquoise2: Color.new255(0, 229, 238), turquoise3: Color.new255(0, 197, 205), turquoise4: Color.new255(0, 134, 139), violet: Color.new255(238, 130, 238), violet red: Color.new255(208, 32, 144), VioletRed: Color.new255(208, 32, 144), VioletRed1: Color.new255(255, 62, 150), VioletRed2: Color.new255(238, 58, 140), VioletRed3: Color.new255(205, 50, 120), VioletRed4: Color.new255(139, 34, 82), wheat: Color.new255(245, 222, 179), wheat1: Color.new255(255, 231, 186), wheat2: Color.new255(238, 216, 174), wheat3: Color.new255(205, 186, 150), wheat4: Color.new255(139, 126, 102), white: Color.new255(255, 255, 255), white smoke: Color.new255(245, 245, 245), WhiteSmoke: Color.new255(245, 245, 245), yellow: Color.new255(255, 255, 0), yellow green: Color.new255(154, 205, 50), yellow1: Color.new255(255, 255, 0), yellow2: Color.new255(238, 238, 0), yellow3: Color.new255(205, 205, 0), yellow4: Color.new255(139, 139, 0), YellowGreen: Color.new255(154, 205, 50) ); */ SuperCollider-Source/SCClassLibrary/Common/Core/Condition.sc000644 000765 000024 00000002352 12756534416 025111 0ustar00crucialstaff000000 000000 Condition { var <>test, waitingThreads; *new { arg test=false; ^super.newCopyArgs(test, Array(8)) } wait { if (test.value.not, { waitingThreads = waitingThreads.add(thisThread.threadPlayer); \hang.yield; }); } hang { arg value = \hang; // ignore the test, just wait waitingThreads = waitingThreads.add(thisThread.threadPlayer); value.yield; } signal { var tempWaitingThreads, time; if (test.value, { time = thisThread.seconds; tempWaitingThreads = waitingThreads; waitingThreads = nil; tempWaitingThreads.do({ arg thread; thread.clock.sched(0, thread); }); }); } unhang { var tempWaitingThreads, time; // ignore the test, just resume all waiting threads time = thisThread.seconds; tempWaitingThreads = waitingThreads; waitingThreads = nil; tempWaitingThreads.do({ arg thread; thread.clock.sched(0, thread); }); } } FlowVar { var value = \unbound; var condition; *new { arg inVal = \unbound; ^super.new.init(inVal) } init { arg inVal; value = inVal; condition = Condition { value != \unbound }; } value_ { arg inVal; if (value != \unbound) { Error("cannot rebind a FlowVar").throw }; value = inVal; condition.signal; } value { condition.wait ^value } } SuperCollider-Source/SCClassLibrary/Common/Core/debug.sc000644 000765 000024 00000001044 12756534416 024246 0ustar00crucialstaff000000 000000 + Object { debug { arg caller; if(caller.notNil,{ Post << caller << ": " << this << Char.nl; },{ Post << this << Char.nl; }); } } + RawArray { // string, signal debug { arg caller; if(caller.notNil,{ Post << caller << ": " << this << Char.nl; },{ Post << this << Char.nl; }); } } + Collection { debug { arg caller; if(caller.notNil,{ if(this.size < 10,{ Post << caller << ": " << this << Char.nl; },{ Post << caller << ": " <<* this << Char.nl; }); },{ Post <<* this << Char.nl; }); } } SuperCollider-Source/SCClassLibrary/Common/Core/Error.sc000644 000765 000024 00000016253 12756534416 024261 0ustar00crucialstaff000000 000000 Exception { classvar <>handling = false; classvar <>debug = false; classvar <>inProtectedFunction = false; var <>what, <>protectedBacktrace, <>path; *new { arg what; var protectedBacktrace, instance; if (debug || inProtectedFunction, { protectedBacktrace = this.getBackTrace.caller; inProtectedFunction = false; }); ^super.newCopyArgs(what ? this.name, protectedBacktrace, thisProcess.nowExecutingPath); } errorString { ^"EXCEPTION: " ++ what } reportError { this.errorString.postln; if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; // this.adviceLink.postln; "^^ The preceding error dump is for %\n".postf(this.errorString); } adviceLink { ^("For advice: [http://supercollider.sf.net/wiki/index.php/%]" .format(this.adviceLinkPage)); } adviceLinkPage { ^this.errorString.tr($ , $_).tr($\n, $_); } postProtectedBacktrace { var out, currentFrame, def, ownerClass, methodName, pos, tempStr; out = CollStream.new; "\nPROTECTED CALL STACK:".postln; currentFrame = protectedBacktrace; while({currentFrame.notNil}, { def = currentFrame.functionDef; if(def.isKindOf(Method), { ownerClass = def.ownerClass; methodName = def.name; if(ownerClass == Function && { #['protect', 'try'].includes(methodName) }, { pos = out.pos; }); out << "\t%:%\t%\n".format(ownerClass, methodName, currentFrame.address); }, { out << "\ta FunctionDef\t%\n".format(currentFrame.address); // sourceCode may be ridiculously huge, // so steal the technique from Object:asString to reduce the printed size tempStr = String.streamContentsLimit({ |stream| stream << "\t\tsourceCode = " <<< (def.sourceCode ? ""); }, 512); out << tempStr; if(tempStr.size >= 512) { out << "...etc..." << $" }; out << Char.nl; }); def.argNames.do({|name, i| out << "\t\targ % = %\n".format(name, currentFrame.args[i]); }); def.varNames.do({|name, i| out << "\t\tvar % = %\n".format(name, currentFrame.vars[i]); }); currentFrame = currentFrame.caller; }); // lose everything after the last Function:protect // it just duplicates the normal stack with less info // but, an Error in a routine in a Scheduler // may not have a try/protect in the protectedBacktrace // then, pos is nil and we should print everything postln( if(pos.notNil) { out.collection.copyFromStart(pos) } { out.collection } ); } isException { ^true } } Error : Exception { errorString { ^"ERROR: " ++ what } errorPathString { ^if(path.isNil) { "" } { "PATH:" + path ++ "\n" } } } MethodError : Error { var <>receiver; *new { arg what, receiver; ^super.new(what).receiver_(receiver) } reportError { this.errorString.postln; "RECEIVER:\n".post; receiver.dump; this.errorPathString.post; if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; // this.adviceLink.postln; "^^ The preceding error dump is for %\nRECEIVER: %\n\n\n".postf(this.errorString, receiver); } adviceLinkPage { ^this.class.name } } PrimitiveFailedError : MethodError { var <>failedPrimitiveName; *new { arg receiver; ^super.new(Thread.primitiveErrorString, receiver) .failedPrimitiveName_(thisThread.failedPrimitiveName) } errorString { ^"ERROR: Primitive '%' failed.\n%".format(failedPrimitiveName, what ? "") } } SubclassResponsibilityError : MethodError { var <>method, <>class; *new { arg receiver, method, class; ^super.new(nil, receiver).method_(method).class_(class) } errorString { ^"ERROR: '" ++ method.name ++ "' should have been implemented by " ++ class.name ++ "." } } ShouldNotImplementError : MethodError { var <>method, <>class; *new { arg receiver, method, class; ^super.new(nil, receiver).method_(method).class_(class) } errorString { ^"ERROR: '" ++ method.ownerClass.name ++ "-" ++ method.name ++ "' Message not valid for this subclass: " ++ class.name ++ "." } } DoesNotUnderstandError : MethodError { var <>selector, <>args; *new { arg receiver, selector, args; ^super.new(nil, receiver).selector_(selector).args_(args) } errorString { ^"ERROR: Message '" ++ selector ++ "' not understood." } reportError { this.errorString.postln; "RECEIVER:\n".post; receiver.dump; "ARGS:\n".post; args.dumpAll; this.errorPathString.post; if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; // this.adviceLink.postln; "^^ The preceding error dump is for %\nRECEIVER: %\n\n\n".postf(this.errorString, receiver); } adviceLinkPage { ^"%#%".format(this.class.name, selector) } } MustBeBooleanError : MethodError { errorString { ^"ERROR: Non Boolean in test." } } NotYetImplementedError : MethodError { } OutOfContextReturnError : MethodError { var <>method, <>result; *new { arg receiver, method, result; ^super.new(nil, receiver).method_(method).result_(result) } errorString { ^"ERROR: '" ++ method.ownerClass.name ++ "-" ++ method.name ++ "' Out of context return of value: " ++ result } } ImmutableError : MethodError { var <>value; *new { arg receiver, value; ^super.new(nil, receiver).value_(value) } errorString { ^"ERROR: Object is immutable: " ++ receiver } } BinaryOpFailureError : DoesNotUnderstandError { errorString { ^"ERROR: binary operator '" ++ selector ++ "' failed." } } DeprecatedError : MethodError { var <>method, <>class, <>alternateMethod; *new { arg receiver, method, alternateMethod, class; ^super.new(nil).receiver_(receiver).method_(method).class_(class).alternateMethod_(alternateMethod) } errorString { var methodSignature = { arg m; m.ownerClass.name.asString ++ ":" ++ m.name; }; var searchForCaller = { arg backtrace, m; while { backtrace.notNil and: { backtrace.functionDef !== m } } { backtrace = backtrace.caller; }; // backtrace.caller may now be a FunctionDef, // useless for troubleshooting // so roll back to the last real method while { backtrace.notNil and: { backtrace = backtrace.caller; backtrace.functionDef.isKindOf(Method).not } }; if(backtrace.notNil) { backtrace.tryPerform(\functionDef) }; }; var caller, string; if(protectedBacktrace.notNil) { caller = searchForCaller.value(protectedBacktrace, method); }; if(caller.isNil) { caller = searchForCaller.value(this.getBackTrace, method); }; if(caller.isNil) { caller = "{unknown}" } { if(caller.isKindOf(Method)) { caller = methodSignature.value(caller); } { caller = caller.asString; }; }; string = "WARNING: Called from %, method % is deprecated and will be removed.".format( caller, methodSignature.value(method) ); if(alternateMethod.notNil, { string = string + "Use" + methodSignature.value(alternateMethod) + "instead."; }); ^string; } reportError { this.errorString.postln; this.errorPathString.post; // this.adviceLink.postln; "\n\n".post; } throw { Error.handling = true; this.reportError; if (Error.debug) { if(protectedBacktrace.notNil, { this.postProtectedBacktrace }); this.dumpBackTrace; Error.handling = false; this.halt; } { Error.handling = false; }; } adviceLinkPage { ^"DeprecatedError" } } SuperCollider-Source/SCClassLibrary/Common/Core/Finalize.sc000644 000765 000024 00000001661 12756534416 024726 0ustar00crucialstaff000000 000000 /* Finalization is a way for the C primitives to release resources back to the system. Rather than having a very complex system where any object can be finalized, I have decided to centralize finalization in one class. This makes handling it in the garbage collector very efficient. Any class that needs finalizable data should create and point to an instance of this class and put the data into it. This should be done from a primitive. When the garbage collector collects this object it will call the C function you stored in cFunction with this object as the parameter. You can also call the finalize method to finalize on demand. You should put your C function pointer into cFunction, and the finalizable object into 'object'. */ Finalizer { var cFunction, object; // no getters or setters! // no *new method! Create in a primitive. //finalize { _Finalize } notFinalized { ^cFunction.notNil } isFinalized { ^cFunction.isNil } } SuperCollider-Source/SCClassLibrary/Common/Core/Function.sc000644 000765 000024 00000015121 12756534416 024746 0ustar00crucialstaff000000 000000 Function : AbstractFunction { var classesInited; // Every class has a metaclass which has 'Meta_' prepended to the name. // Though there is a class Meta_Class which is the class of Class, the // class of Meta_Class is Class. It is a loop, but a different one // than the structure in Smalltalk. superclass { // superclass is stored as a symbol to allow forward reference during compilation ^superclass.asClass } asClass { ^this } isMetaClass { ^this.class === Class } initClass { } // call Class.initClassTree(SomeClass) to force a class to init if you depend on its resources *initClassTree { arg aClass; var implementsInitClass; // sometimes you need a class to be inited before another class // start the process: Class.initClassTree(Object) if(classesInited.isNil, { classesInited = IdentitySet.new }); if(classesInited.includes(aClass).not, { if(aClass.isMetaClass.not and: { aClass.class.findMethod(\initClass).notNil }, { aClass.initClass; }); classesInited.add(aClass); if(aClass.subclasses.notNil,{ aClass.subclasses.do({ arg class; this.initClassTree(class); }); }); }); } *allClasses { _AllClasses } findMethod { arg methodName; if ( methods.notNil, { ^methods.detect({ arg method; method.name == methodName }); },{ ^nil }); } findRespondingMethodFor { arg methodName; this.superclassesDo { arg class; var method = class.findMethod(methodName); method !? { ^method }; }; ^nil } findOverriddenMethod { arg methodName; if(this.findMethod(methodName).isNil) { ^nil }; this.superclass.superclassesDo { arg class; var method = class.findMethod(methodName); if(method.notNil) { ^method } }; ^nil } superclassesDo { arg function; var class = this; while { class.notNil } { function.value(class); class = class.superclass; } } dumpByteCodes { arg methodName; var meth; meth = this.findMethod(methodName); if (meth.notNil, { meth.dumpByteCodes },{ Post << methodName << " not found.\n"; }); } dumpClassSubtree { _DumpClassSubtree } dumpInterface { // show all methods and their arguments defined for this class // does not include methods defined in superclasses this.methods.do({ arg meth; var numargs; numargs = meth.argNames.size - 1; " ".post; meth.name.post; " ( ".post; meth.argNames.do({ arg name, i; if (i > 0, { // skip 'this' name.post; if (i < numargs, { ", ".post; }); }); }); " )\n".post; }); } asString { ^name.asString } printOn { arg stream; stream << "class " << name; } storeOn { arg stream; stream << name; } archiveAsCompileString { ^true } hasHelpFile { //should cache this in Library or classvar //can't add instance variables to Class ^this.name.asString.findHelpFile.notNil } helpFilePath { ^this.name.asString.findHelpFile } help { this.openHelpFile } openHelpFile { // NOTE: because wslib provided the shortcut "Object:*help --> Object:*openHelpFile", we do the same // rather than moving the implementation to the future-compatible :help method. // This prevents infinite recursions for people with wslib installed. // In future (3.7) this method content should be moved to :help, but no sooner. this.name.asString.help } shallowCopy { ^this } //listInstances { _ListInstancesOf } //traceAnyPathToAllInstancesOf { _TraceAnyPathToAllInstancesOf } openCodeFile { this.filenameSymbol.asString.openTextFile(this.charPos, -1); } classVars { var start, end; start = this.classVarIndex; end = start + this.classVarNames.size; ^thisProcess.instVarAt(0).copyRange(start, end) } inspectorClass { ^ClassInspector } findReferences { arg aSymbol, references; methods.do({ arg meth; references = meth.findReferences(aSymbol, references) }); ^references } *findAllReferences { arg aSymbol; // this will not find method calls that are compiled with special byte codes such as 'value'. var references; Class.allClasses.do({ arg class; references = class.findReferences(aSymbol, references); }); ^references; } allSubclasses { var list; list = subclasses.copy; subclasses.do({ arg class; list = list ++ class.allSubclasses; }); ^list } superclasses { var list; this.superclass.superclassesDo { arg class; list = list.add(class) } ^list } } Process { // A Process is a runtime environment. var classVars, nowExecutingPath; startup { var time; Class.initClassTree(AppClock); // AppClock first in case of error time = this.class.elapsedTime; Class.initClassTree(Object); ("Class tree inited in" + (this.class.elapsedTime - time).round(0.01) + "seconds").inform; Class.classesInited = nil; topEnvironment = Environment.new; currentEnvironment = topEnvironment; Archive.read; // This method is called automatically right after compiling. // Override in class 'Main' to do initialization stuff, // but make sure to call this superclass method. // the AppClock is not started until after this method is complete } run { // This method is called when 'Run Main' is chosen from the menu. // Override in class 'Main' to do whatever you want. } stop { // This method is called when 'Stop Main' is chosen from the menu. // Override in class 'Main' to do whatever you want. } shutdown { // This method is called before recompiling or quitting. // Override in class 'Main' to do whatever you want. ShutDown.run; NetAddr.disconnectAll; File.closeAll; Archive.write; } tick { // called repeatedly by SCVirtualMachine::doPeriodicTask ^AppClock.tick; } *tailCallOptimize { _GetTailCallOptimize } *tailCallOptimize_ { arg bool; _SetTailCallOptimize ^this.primitiveFailed } getCurrentSelection { var qt = \QtGUI.asClass; ^if(qt.notNil and: {qt.focusView.notNil}) { qt.selectedText; } { interpreter.cmdLine; } } openCodeFile { var string, class, method, words; string = this.getCurrentSelection; if (string.includes($:), { string.removeAllSuchThat(_.isSpace); words = string.delimit({ arg c; c == $: }); class = words.at(0).asSymbol.asClass; if (class.notNil, { method = class.findMethod(words.at(1).asSymbol); if (method.notNil, { method.filenameSymbol.asString.openTextFile(method.charPos, -1); }); }); },{ class = string.asSymbol.asClass; if (class.notNil, { class = class.classRedirect; class.filenameSymbol.asString.openTextFile(class.charPos, -1); }); }); } openWinCodeFile { var string, class, method, words; string = this.getCurrentSelection; if (string.includes($:), { string.removeAllSuchThat(_.isSpace); words = string.delimit({ arg c; c == $: }); class = words.at(0).asSymbol.asClass; if (class.notNil, { method = class.findMethod(words.at(1).asSymbol); if (method.notNil, { method.filenameSymbol.asString.openWinTextFile(method.charPos, -1); }); }); },{ class = string.asSymbol.asClass; if (class.notNil, { class = class.classRedirect; class.filenameSymbol.asString.openWinTextFile(class.charPos, -1); }); }); } methodReferences { // this will not find method calls that are compiled with special byte codes such as 'value'. var name, out, references, nameString; out = CollStream.new; name = this.getCurrentSelection.asSymbol; references = Class.findAllReferences(name); if (references.notNil, { out << "References to '" << name << "' :\n"; references.do({ arg ref; nameString = ref.ownerClass.name ++ ":" ++ ref.name; out << " [" << nameString << "]\n"; }); out.collection.newTextWindow(name.asString); },{ Post << "\nNo references to '" << name << "'.\n"; }); } methodTemplates { // this constructs the method templates when cmd-Y is pressed in the Lang menu. var name, out, found = 0, namestring, text; out = CollStream.new; text = this.getCurrentSelection; if (text.isEmpty){ Post << "\nNo implementations of ''.\n"; ^this }; if (text[0].toLower != text[0]) { // user pressed the wrong key. DWIM. ^this.openCodeFile; }; name = text.asSymbol; out << "Implementations of '" << name << "' :\n"; Class.allClasses.do({ arg class; class.methods.do({ arg method; if (method.name == name, { found = found + 1; namestring = class.name ++ ":" ++ name; out << " [" << namestring << "] : "; if (method.argNames.isNil or: { method.argNames.size == 1 }, { out << "this." << name; if (name.isSetter, { out << "(val)"; }); },{ out << method.argNames.at(0); if (name.asString.at(0).isAlpha, { out << "." << name << "("; method.argNames.do({ arg argName, i; if (i > 0, { if (i != 1, { out << ", " }); out << argName; }); }); out << ")"; },{ out << " " << name << " "; out << method.argNames.at(1); }); }); out.nl; }); }); }); case { found == 0 } { Post << "\nNo implementations of '" << name << "'.\n"; } { found == 1 } { interpreter.cmdLine = namestring; this.openCodeFile; } { out.collection.newTextWindow(name.asString); }; } interpretCmdLine { // interpret some text from the command line interpreter.interpretCmdLine; } interpretPrintCmdLine { // interpret some text from the command line and print result interpreter.interpretPrintCmdLine; } interpretPrintSelectedText { interpreter.cmdLine = this.getCurrentSelection; interpreter.interpretPrintCmdLine; } showHelp { this.getCurrentSelection.help } argv { ^[] } shallowCopy { ^this } *elapsedTime { _ElapsedTime } *monotonicClockTime { _monotonicClockTime } storeOn { arg stream; stream << "thisProcess"; } archiveAsCompileString { ^true } prSchedulerQueue { ^schedulerQueue } } FunctionDef { var raw1, raw2, cmdLine; // place holder for text executed from a worksheet var context; // faked interpreter context frame. Don't mess with it. // a-z are predefined variables for use by the interactive context. // They are read+write so that programmatic methods can // get and alter the values that the interpreter has access to. var <>a, <>b, <>c, <>d, <>e, <>f, <>g, <>h, <>i, <>j; var <>k, <>l, <>m, <>n, <>o, <>p, <>q, <>r, <>s, <>t; var <>u, <>v, <>w, <>x, <>y, <>z; var <>codeDump, <>preProcessor; *new { ^this.shouldNotImplement(thisMethod) } interpretCmdLine { ^this.compile(cmdLine).value; } interpretPrintCmdLine { var res, func, code = cmdLine, doc, ideClass = \ScIDE.asClass; preProcessor !? { cmdLine = preProcessor.value(cmdLine, this) }; func = this.compile(cmdLine); if (ideClass.notNil) { thisProcess.nowExecutingPath = ideClass.currentPath } { if(\Document.asClass.notNil and: {(doc = Document.current).tryPerform(\dataptr).notNil}) { thisProcess.nowExecutingPath = doc.tryPerform(\path); } }; res = func.value; thisProcess.nowExecutingPath = nil; codeDump.value(code, res, func, this); ("-> " ++ res).postln; } interpret { arg string ... args; // compile, evaluate cmdLine = string; ^this.compile(string).valueArray(args); } interpretPrint { arg string ... args; // compile, evaluate, print cmdLine = string; ^this.compile(string).valueArray(args).postln; } compile { arg string; _CompileExpression // compiles string and returns a Function. // the string must be a valid expression. // You cannot compile a class definition this way. // This method is not implemented in SCPlay. ^nil } clearAll { a = b = c = d = e = f = g = h = i = j = k = l = m = n = o = p = q = r = s = t = u = v = w = x = y = z = nil; } executeFile { arg pathName ... args; var result, saveExecutingPath = thisProcess.nowExecutingPath; if (File.exists(pathName).not) { "file \"%\" does not exist.\n".postf(pathName); ^nil }; thisProcess.nowExecutingPath = pathName; protect { result = this.compileFile(pathName).valueArray(args) } { |exception| exception !? { exception.path = pathName }; thisProcess.nowExecutingPath = saveExecutingPath }; ^result } compileFile { arg pathName; var file, text; file = File.new(pathName, "r"); if (file.isNil, { error("file open failed\n"); ^nil }); text = file.readAllString; file.close; preProcessor !? { text = preProcessor.value(text, this) }; if (text.beginsWith("#!"), { // comment out shebang to preserve line count text.overWrite("//"); }); ^this.compile(text) } // PRIVATE functionCompileContext { // compiler uses this method as a fake context in which to compile // the user's function. // Do not edit this method! {} // this forces the compiler to generate a heap allocated frame rather than // a frame on the stack } shallowCopy { ^this } } SuperCollider-Source/SCClassLibrary/Common/Core/LanguageConfig.sc000644 000765 000024 00000001425 12756534416 026034 0ustar00crucialstaff000000 000000 LanguageConfig { *store {|file| _LanguageConfig_writeConfigFile ^this.primitiveFailed } *currentPath { _LanguageConfig_getCurrentConfigPath } *includePaths { _LanguageConfig_getIncludePaths } *addIncludePath {|aPath| _LanguageConfig_addIncludePath ^this.primitiveFailed } *removeIncludePath {|aPath| _LanguageConfig_removeIncludePath ^this.primitiveFailed } *excludePaths { _LanguageConfig_getExcludePaths } *addExcludePath {|aPath| _LanguageConfig_addExcludePath ^this.primitiveFailed } *removeExcludePath {|aPath| _LanguageConfig_removeExcludePath ^this.primitiveFailed } *postInlineWarnings { _LanguageConfig_getPostInlineWarnings } *postInlineWarnings_ {|aBoolean| _LanguageConfig_setPostInlineWarnings ^this.primitiveFailed } } SuperCollider-Source/SCClassLibrary/Common/Core/Message.sc000644 000765 000024 00000000714 12756534416 024547 0ustar00crucialstaff000000 000000 Message { var <>receiver, <>selector, <>args; *new { arg receiver, selector, args; ^super.newCopyArgs(receiver, selector, args); } value { arg ... moreArgs; ^receiver.performList(selector, args ++ moreArgs); } storeArgs { ^[receiver, selector, args] } } MethodQuote { var <>selector; *new { arg selector; ^super.newCopyArgs(selector); } value { arg receiver ... args; ^receiver.performList(selector, args); } storeArgs { ^[selector] } } SuperCollider-Source/SCClassLibrary/Common/Core/Model.sc000644 000765 000024 00000004261 12756534416 024224 0ustar00crucialstaff000000 000000 SimpleController { var model, actions; // responds to updates of a model *new { arg model; ^super.newCopyArgs(model).init } init { model.addDependant(this); } put { arg what, action; if (actions.isNil, { actions = IdentityDictionary.new(4); }); actions.put(what, action); } update { arg theChanger, what ... moreArgs; var action; if(actions.notNil) { action = actions.at(what); if (action.notNil, { action.valueArray(theChanger, what, moreArgs); }); }; } remove { model.removeDependant(this); } removeAt{ |what| if (actions.notNil) { actions.removeAt(what) } } } TestDependant { update { arg thing; (thing.asString ++ " was changed.\n").post; } } NotificationCenter { classvar registrations; // who \didSomething *notify { arg object, message, args; registrations.at(object,message).copy.do({ arg function; function.valueArray(args) }) } // who \didSomething *register { arg object,message,listener,action; var nr; nr = NotificationRegistration(object,message,listener); registrations.put(object,message,listener,action); ^nr; } *unregister { arg object,message,listener; var lastKey,lastDict; lastDict = registrations.at(object,message); if(lastDict.notNil,{ lastDict.removeAt(listener); (lastDict.size == 0).if({ registrations.removeAt(object,message); (registrations.at(object).size == 0).if({ registrations.removeAt(object); }); }); }); } *registerOneShot { arg object,message,listener,action; var nr; nr = NotificationRegistration(object,message,listener); registrations.put(object,message,listener, { |args| action.value(args); this.unregister(object,message,listener) }); ^nr } *clear { registrations = MultiLevelIdentityDictionary.new; } *registrationExists { |object,message,listener| ^registrations.at(object,message,listener).notNil } *initClass { this.clear } *removeForListener { |listener| registrations.removeAt(listener) } } NotificationRegistration { var <>object,<>message,<>listener; *new { arg o,m,l; ^super.new.object_(o).message_(m).listener_(l) } remove { NotificationCenter.unregister(object,message,listener) } } SuperCollider-Source/SCClassLibrary/Common/Core/Nil.sc000644 000765 000024 00000004352 12756534416 023707 0ustar00crucialstaff000000 000000 Nil { *new { ^this.shouldNotImplement(thisMethod) } isNil { ^true } notNil { ^false } ? { arg obj; ^obj } ?? { arg obj; ^obj.value } !? {} asBoolean { ^false } booleanValue { ^false } // TODO in the long-run, deprecate for asBoolean // support a nil Environment push { arg function; ^function.value } appendStream { arg stream; ^stream } pop {} // support a nil Plug source {} source_ {} // rate access support rate { ^nil } numChannels { ^nil } isPlaying { ^false } do {} reverseDo {} pairsDo {} collect {} select {} reject {} detect {} collectAs {} selectAs {} rejectAs {} collectInPlace {} collectCopy {} // dependancy operators are no-ops dependants { ^IdentitySet.new } changed {} addDependant {} removeDependant {} release {} update {} // nil Event support transformEvent { arg event; ^event } awake { arg inBeats, inSeconds, inClock; var temp; temp = inBeats; // prevent optimization ^nil } play {} nextTimeOnGrid { arg clock; ^clock !? { clock.nextTimeOnGrid } } asQuant { ^Quant.default } // { ^Quant.new } swapThisGroup {} performMsg {} printOn { arg stream; stream.putAll("nil"); } storeOn { arg stream; stream.putAll("nil"); } matchItem { ^true } // nil matches anything // Array support add { arg value; // This makes it unecessary to check for array.isNil when doing: // array = array.add(thing); Instead, it just works. ^[value] } addAll { arg array; ^array.asArray } ++ { arg array; ^array } asCollection { ^[] } remove {} // ControlView support set {} get { arg prevVal; ^prevVal } // FunctionList support addFunc { arg ... functions; ^if(functions.size <= 1) {functions[0] } { FunctionList(functions) } } removeFunc { ^this } replaceFunc { } // if Main-startup fails then AppClock scheduler may be nil. If that happens an // endless cascade of doesNotUnderstand messages gets printed in response to each clock tick // unless we do this. seconds_ {} // throwing Nil throw {} handleError { arg error; Error.handling = true; if (Error.debug) { { error.inspect }.defer; } { error.reportError }; Error.handling = false; this.halt; } archiveAsCompileString { ^true } asSpec { ^ControlSpec.new; } superclassesDo {} } SuperCollider-Source/SCClassLibrary/Common/Core/Object.sc000644 000765 000024 00000053407 12766171707 024401 0ustar00crucialstaff000000 000000 Object { classvar { arg obj; ^Association.new(this, obj) } // stream next { ^this } reset { ^this } first { arg inval; this.reset; ^this.next(inval) } iter { ^OneShotStream(this) } stop { ^this } free { ^this } clear { ^this } removedFromScheduler { ^this } isPlaying { ^false } embedInStream { ^this.yield; } cyc { arg n = inf; ^r {|inval| n.do { inval = this.embedInStream(inval); this.reset; } } } fin { arg n = 1; ^r {|inval| var item; n.do { item = this.next(inval); if (item.isNil) { nil.alwaysYield }; inval = item.yield } } } repeat { arg repeats = inf; ^Pn(this, repeats).asStream } loop { ^this.repeat(inf) } nextN { arg n, inval; ^Array.fill(n, { this.next(inval) }); } asStream { ^this } streamArg { arg embed = false; ^if(embed) { Routine { arg inval; this.embedInStream(inval) } } { Routine { arg inval; loop { inval = this.next(inval).yield } } } } eventAt { ^nil } composeEvents { arg event; ^event.copy } finishEvent {} atLimit { ^false } isRest { ^false } threadPlayer {} threadPlayer_ {} // testing ? { arg obj; ^this } ?? { arg obj; ^this } !? { arg obj; ^obj.value(this) } isNil { ^false } notNil { ^true } isNumber { ^false } isInteger { ^false } isFloat { ^false } isSequenceableCollection { ^false } isCollection { ^false } isArray { ^false } isString { ^false } containsSeqColl { ^false } isValidUGenInput { ^false } isException { ^false } isFunction { ^false } matchItem {|item| ^this === item } trueAt { ^false } falseAt { arg key; ^this.trueAt(key).not } pointsTo { arg obj; _ObjectPointsTo; ^this.primitiveFailed } mutable { _ObjectIsMutable; ^this.primitiveFailed } frozen { _ObjectIsPermanent; ^this.primitiveFailed } // errors halt { thisProcess.nowExecutingPath = nil; OnError.run; this.prHalt } prHalt { _Halt } primitiveFailed { PrimitiveFailedError(this).throw; } reportError { error(this.asString); this.dumpBackTrace; } subclassResponsibility { arg method; SubclassResponsibilityError(this, method, this.class).throw; } doesNotUnderstand { arg selector ... args; DoesNotUnderstandError(this, selector, args).throw; } shouldNotImplement { arg method; ShouldNotImplementError(this, method, this.class).throw; } outOfContextReturn { arg method, result; OutOfContextReturnError(this, method, result).throw; } immutableError { arg value; ImmutableError(this, value).throw; } deprecated { arg method, alternateMethod; DeprecatedError(this, method, alternateMethod, this.class).throw; } mustBeBoolean { MustBeBooleanError(nil, this).throw; } notYetImplemented { NotYetImplementedError(nil, this).throw; } dumpBackTrace { _DumpBackTrace } getBackTrace { _GetBackTrace } throw { if (Error.handling) { error("throw during error handling!\n"); this.dump; ^this }; thisThread.handleError(this); } // conversion species { ^this.class } asCollection { ^[this] } asSymbol { ^this.asString.asSymbol } asString { arg limit = 512; var string; _ObjectString string = String.streamContentsLimit({ arg stream; this.printOn(stream); }, limit); if (string.size >= limit, { ^(string ++ "...etc..."); }); ^string } asCompileString { _ObjectCompileString ^String.streamContents({ arg stream; this.storeOn(stream); }); } cs { ^this.asCompileString } printClassNameOn { arg stream; var title; title = this.class.name.asString; stream << if((title @ 0).isVowel, { "an " }, { "a " }) << title; } printOn { arg stream; this.printClassNameOn(stream); } storeOn { arg stream; stream << this.class.name; this.storeParamsOn(stream); this.storeModifiersOn(stream); } storeParamsOn { arg stream; var args = this.storeArgs; if(args.notEmpty) { stream << "(" <<<* this.simplifyStoreArgs(args) << ")"; } { stream << ".new" } } simplifyStoreArgs { arg args; var res = Array.new, newMethod, methodArgs; newMethod = this.class.class.findRespondingMethodFor(\new); methodArgs = newMethod.prototypeFrame.drop(1); args.size.reverseDo { |i| if(methodArgs[i] != args[i]) { ^args.keep(i + 1) } } ^[] } storeArgs { ^#[] } storeModifiersOn { arg stream;} as { arg aSimilarClass; ^aSimilarClass.newFrom(this) } dereference { ^this } // see Ref::dereference reference { ^Ref.new(this) } asRef { ^Ref.new(this) } // asArray { ^Array.with(this) } asArray { ^this.asCollection.asArray } asSequenceableCollection { ^this.asArray } // arrays rank { ^0 } deepCollect { arg depth, function, index = 0, rank = 0; ^function.value(this, index, rank) } deepDo { arg depth, function, index = 0, rank = 0; function.value(this, index, rank) } slice { ^this } shape { ^nil } unbubble { ^this } bubble { arg depth=0, levels=1; if (levels <= 1) { ^[this] }; ^[this.bubble(depth,levels-1)] } // compatibility with sequenceable collection obtain { arg index, default; ^if(index == 0) { this } { default } } instill { arg index, item, default; ^if(index == 0) { item } { this.asArray.instill(index, item, default) } } // FunctionList support addFunc { arg ... functions; ^FunctionList([this] ++ functions) } removeFunc { arg function; if(this === function) { ^nil } } replaceFunc { arg find, replace; if(this === find) { ^replace } } addFuncTo { arg variableName ... functions; this.perform(variableName.asSetter, this.perform(variableName).addFunc(*functions)) } removeFuncFrom { arg variableName, function; this.perform(variableName).removeFunc(function) } // looping while { arg body; // compiler magic: the compiler inlines the following loop // thus an uninlinable while can be implemented using while itself while({ this.value }, { body.value }); } switch { arg ... cases; cases.pairsDo { | test, trueFunc | if (this == test.value) { ^trueFunc.value }; }; if (cases.size.odd) { ^cases.last.value }; ^nil } // coroutine support yield { _RoutineYield ^this.primitiveFailed } alwaysYield { _RoutineAlwaysYield ^this.primitiveFailed } yieldAndReset { arg reset = true; _RoutineYieldAndReset ^this.primitiveFailed } idle { arg val; var time = thisThread.beats; while { thisThread.beats - time < val } { this.value.yield } } // dependancy support *initClass { dependantsDictionary = IdentityDictionary.new(4); } dependants { ^dependantsDictionary.at(this) ?? { IdentitySet.new }; } changed { arg what ... moreArgs; dependantsDictionary.at(this).copy.do({ arg item; item.update(this, what, *moreArgs); }); } addDependant { arg dependant; var theDependants; theDependants = dependantsDictionary.at(this); if(theDependants.isNil,{ theDependants = IdentitySet.new.add(dependant); dependantsDictionary.put(this, theDependants); },{ theDependants.add(dependant); }); } removeDependant { arg dependant; var theDependants; theDependants = dependantsDictionary.at(this); if (theDependants.notNil, { theDependants.remove(dependant); if (theDependants.size == 0, { dependantsDictionary.removeAt(this); }); }); } release { this.releaseDependants; } releaseDependants { dependantsDictionary.removeAt(this); } update { arg theChanged, theChanger; // respond to a change in a model } // instance specific method support addUniqueMethod { arg selector, function; var methodDict; if(function.isKindOf(Function).not) { Error("A method must be defined using a function").throw }; if(uniqueMethods.isNil, { uniqueMethods = IdentityDictionary.new }); methodDict = uniqueMethods.at(this); if (methodDict.isNil, { methodDict = IdentityDictionary.new; uniqueMethods.put(this, methodDict); }); methodDict.put(selector, function); } removeUniqueMethods { if (uniqueMethods.notNil, { uniqueMethods.removeAt(this); }); } removeUniqueMethod { arg selector; var methodDict; if (uniqueMethods.notNil, { methodDict = uniqueMethods.at(this); if (methodDict.notNil, { methodDict.removeAt(selector); if (methodDict.size < 1, { uniqueMethods.removeAt(this); }); }); }); } inspect { ^this.inspectorClass.new(this) } inspectorClass { ^ObjectInspector } inspector { // finds the inspector for this object, if any. ^Inspector.inspectorFor(this) } // virtual machine debugging... crash { _HostDebugger } // for serious problems.. stackDepth { _StackDepth } dumpStack { _DumpStack } dumpDetailedBackTrace { _DumpDetailedBackTrace } freeze { _ObjectDeepFreeze ^this.primitiveFailed } // Math protocol support // translate these operators to names the code generator can safely generate in C++ & { arg that; ^bitAnd(this, that) } | { arg that; ^bitOr(this, that) } % { arg that; ^mod(this, that) } ** { arg that; ^pow(this, that) } << { arg that; ^leftShift(this, that) } >> { arg that; ^rightShift(this, that) } +>> { arg that; ^unsignedRightShift(this, that) } 0) { stream << "(" << size << ")" }; }; }; stream << "\n];\np = ["; // put in slots firsttime = true; list.do {|obj, i| var slots; if (obj.archiveAsCompileString.not) { slots = obj.getSlots; if (slots.size > 0) { if (firsttime.not) { stream << ", "; }; firsttime = false; stream << "\n\t// " << obj.class.name; stream << "\n\t"; stream << i << ", [ "; if (obj.isKindOf(ArrayedCollection)) { slots.do {|slot, j| var index; if (j != 0) { stream << ", "; }; if ((j != 0) && ((j & 3) == 0)) { stream << "\n\t\t" }; index = objects[slot]; if (index.isNil) { stream << slot.asCompileString; }{ stream << "o[" << index << "]"; }; }; }{ slots.pairsDo {|key, slot, j| var index; if (j != 0) { stream << ", "; }; if ((j != 0) && ((j & 3) == 0)) { stream << "\n\t\t" }; stream << key << ": "; index = objects[slot]; if (index.isNil) { stream << slot.asCompileString; }{ stream << "o[" << index << "]"; }; }; }; stream << " ]"; }; }; }; stream << "\n];\n"; stream << "prUnarchive(o,p);\n"; ^stream.contents } getContainedObjects { arg objects; if (objects[this].notNil) {^this}; objects[this] = objects.size; if (this.archiveAsCompileString.not) { this.slotsDo {|key, slot| if (slot.archiveAsObject) { slot.getContainedObjects(objects); }; }; }; } // old binary archiving // this will break if the instance vars change ! // not recommended writeBinaryArchive { arg pathname; _WriteArchive ^this.primitiveFailed; } *readBinaryArchive { arg pathname; _ReadArchive ^this.primitiveFailed; } asBinaryArchive { _AsArchive ^this.primitiveFailed; } // support for Gen genNext { ^nil } genCurrent { ^this } // support for ViewRedirect *classRedirect { ^this } help { this.class.asString.help } } SuperCollider-Source/SCClassLibrary/Common/Core/Ref.sc000644 000765 000024 00000003230 12756534416 023673 0ustar00crucialstaff000000 000000 // a Ref is a handle to a value. you can use it to return results by reference // example: // x = Ref.new(nil); // z = obj.method(x); // method puts something in reference // x.value.doSomething; // retrieve value // // it is also used as a quoting device to insulate from multiChannelPerform in UGens // // A special syntax shortcut for Ref.new( expr ) is to use a backquote: `expr Ref : AbstractFunction { var <>value; *new { arg thing; ^super.new.value_(thing) } set { arg thing; value = thing } get { ^value } dereference { ^value } asRef { ^this } valueArray { ^value } valueEnvir { ^value } valueArrayEnvir { ^value } // behave like a stream next { ^value } // embedInStream { arg inval; // ^this.value.embedInStream(inval) // } // prevent multichannel expansion in ugens asUGenInput { ^this } printOn { arg stream; stream << "`(" << value << ")"; } storeOn { arg stream; stream << "`(" <<< value << ")"; } at { | key | ^value.at(key) } put { | key, val | value.put(key, val) } seq { | pat | value = pat.embedInStream(this) } asControlInput { ^value.asControlInput } // Some UGens take Buffer data which // the user might want to specify simply as `[0.9, 0.1, 0.3] asBufWithValues { ^LocalBuf.newFrom(value); } // Allow to multichannel expand ugen specs, like those of Klank, // in the case of which two is the rank, but could be otherwise. multichannelExpandRef { |rank| var array, refarray; array = this.value.asArray; if(array.maxSizeAtDepth(rank) <= 1) { ^this }; // no need to expand refarray = array.flopDeep(rank).collect { |item| this.class.new(item) }; ^refarray.unbubble } } RefCopy : Ref { next { ^value.copy } } SuperCollider-Source/SCClassLibrary/Common/Core/Semaphore.sc000644 000765 000024 00000000650 12756534416 025105 0ustar00crucialstaff000000 000000 Semaphore { var 0 } } isMap { _Symbol_IsMap // returns true if symbol starts with 'a' or 'c' followed by a number } isRest { ^this.isMap.not } // Environment support // The compiler translates use of an Environment variable like ~myvar // to a call to one of these methods, for example: // ~myvar = 5; translates to: 'myvar'.envirPut(5); // the implementations have been replaced by primitives envirGet { _Symbol_envirGet ^currentEnvironment.at(this) } envirPut { arg aValue; _Symbol_envirPut currentEnvironment.put(this, aValue); ^aValue } blend { // Envelopes may call this on the curves inst var. ^this } ++ { arg aString; ^this.asString ++ aString } asBinOpString { var res; res = this.asString; ^if(res[0].isAlphaNum) { res ++ ":" } { res } } applyTo { arg firstArg ... args; ^firstArg.performList(this, args) } // support for math on symbols performBinaryOpOnSomething { ^this } // unary ops neg { ^this } bitNot { ^this } abs { ^this } ceil { ^this } floor { ^this } frac { ^this } sign { ^this } sqrt { ^this } exp { ^this } midicps { ^this } cpsmidi { ^this } midiratio { ^this } ratiomidi { ^this } ampdb { ^this } dbamp { ^this } octcps { ^this } cpsoct { ^this } log { ^this } log2 { ^this } log10 { ^this } sin { ^this } cos { ^this } tan { ^this } asin { ^this } acos { ^this } atan { ^this } sinh { ^this } cosh { ^this } tanh { ^this } rand { ^this } rand2 { ^this } linrand { ^this } bilinrand { ^this } sum3rand { ^this } distort { ^this } softclip { ^this } coin { ^this } even { ^this } odd { ^this } rectWindow { ^this } hanWindow { ^this } welWindow { ^this } triWindow { ^this } scurve { ^this } ramp { ^this } // binary ops + { ^this } - { ^this } * { ^this } / { ^this } mod { ^this } min { ^this } max { ^this } bitAnd { ^this } bitOr { ^this } bitXor { ^this } bitHammingDistance { ^this } hammingDistance { |that| ^this.asString.hammingDistance(that.asString) } lcm { ^this } gcd { ^this } round { ^this } roundUp { ^this } trunc { ^this } atan2 { ^this } hypot { ^this } hypotApx { ^this } pow { ^this } leftShift { ^this } rightShift { ^this } unsignedRightShift { ^this } rrand { ^this } exprand { ^this } < { arg aNumber; _LT; ^this } > { arg aNumber; _GT; ^this } <= { arg aNumber; _LE; ^this } >= { arg aNumber; _GE; ^this } degreeToKey { ^this } degrad { ^this } raddeg { ^this } doNumberOp { ^this } doComplexOp { ^this } doSignalOp { ^this } doListOp { arg aSelector, aList; aList.collect({ arg item; item.perform(aSelector, this) }) } primitiveIndex { _Symbol_PrimitiveIndex ^this.primitiveFailed } specialIndex { // used by BasicOpUGens to get an ID number for the operator _Symbol_SpecialIndex ^this.primitiveFailed } printOn { arg stream; stream.putAll(this.asString); } storeOn { arg stream; stream.putAll(this.asCompileString); } // code gen codegen_UGenCtorArg { arg stream; this.asString.codegen_UGenCtorArg(stream); } archiveAsCompileString { ^true } kr { | val, lag, fixedLag = false | ^NamedControl.kr(this, val, lag, fixedLag) } ir { | val | ^NamedControl.ir(this, val) } tr { | val | ^NamedControl.tr(this, val) } ar { | val, lag | ^NamedControl.ar(this, val, lag) } matchOSCAddressPattern { arg addressPattern; _Symbol_matchOSCPattern ^this.primitiveFailed } help { this.asString.help } } SuperCollider-Source/SCClassLibrary/Common/Core/Thread.sc000644 000765 000024 00000007201 12756534416 024370 0ustar00crucialstaff000000 000000 // you must not make any change at all to the order or number of // instance variables in these classes! // You should also not muck with the contents of the instance // variables unless you are sure you know what you are doing. // You may add methods. // Thread inherits from Stream for the benefit of its subclass Routine which can // behave like a Stream. Thread itself is not used like a Stream. Thread : Stream { var endBeat, <>endValue; var environment; var <>exceptionHandler, >threadPlayer; var numFrames, <>numChannels, <>sampleRate; var <>path, <>startFrame, >doOnInfo; classvar serverCaches; *initClass { serverCaches = IdentityDictionary.new } // doesn't send *new { arg server, numFrames, numChannels, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum, numFrames, numChannels).sampleRate_(server.sampleRate).cache } *alloc { arg server, numFrames, numChannels = 1, completionMessage, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum, numFrames, numChannels) .alloc(completionMessage).sampleRate_(server.sampleRate).cache } *allocConsecutive { arg numBufs = 1, server, numFrames, numChannels = 1, completionMessage, bufnum; var bufBase, newBuf; bufBase = bufnum ?? { server.bufferAllocator.alloc(numBufs) }; if(bufBase.isNil) { Error("No block of % consecutive buffer numbers is available.".format(numBufs)).throw }; ^Array.fill(numBufs, { |i| newBuf = Buffer.new(server, numFrames, numChannels, i + bufBase); server.sendMsg(\b_alloc, i + bufBase, numFrames, numChannels, completionMessage.value(newBuf, i)); newBuf.cache }) } alloc { arg completionMessage; server.listSendMsg( this.allocMsg(completionMessage) ) } allocRead { arg argpath, startFrame = 0, numFrames = -1, completionMessage; path = argpath; this.startFrame = startFrame; server.listSendMsg(this.allocReadMsg( argpath, startFrame, numFrames, completionMessage)) } allocReadChannel { arg argpath, startFrame, numFrames = 0, channels = -1, completionMessage; path = argpath; this.startFrame = startFrame; server.listSendMsg(this.allocReadChannelMsg( argpath, startFrame, numFrames, channels, completionMessage)) } allocMsg { arg completionMessage; this.cache; ^["/b_alloc", bufnum, numFrames.asInt, numChannels, completionMessage.value(this)] } allocReadMsg { arg argpath, startFrame = 0, numFrames = -1, completionMessage; this.cache; path = argpath; this.startFrame = startFrame; ^["/b_allocRead", bufnum, path, startFrame, (numFrames ? -1).asInt, completionMessage.value(this)] } allocReadChannelMsg { arg argpath, startFrame = 0, numFrames = -1, channels, completionMessage; this.cache; path = argpath; this.startFrame = startFrame; ^["/b_allocReadChannel", bufnum, path, startFrame, (numFrames ? -1).asInt] ++ channels ++ [completionMessage.value(this)] } // read whole file into memory for PlayBuf etc. // adds a query as a completion message *read { arg server, path, startFrame = 0, numFrames = -1, action, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum) .doOnInfo_(action).cache .allocRead(path, startFrame, numFrames, {|buf|["/b_query", buf.bufnum] }) } read { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, action; this.cache; doOnInfo = action; server.listSendMsg( this.readMsg(argpath, fileStartFrame, numFrames, bufStartFrame, leaveOpen, {|buf| ["/b_query", buf.bufnum] }) ); } *readChannel { arg server, path, startFrame = 0, numFrames = -1, channels, action, bufnum; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum) .doOnInfo_(action).cache .allocReadChannel(path, startFrame, numFrames, channels, {|buf|["/b_query", buf.bufnum]}) } readChannel { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, channels, action; this.cache; doOnInfo = action; server.listSendMsg( this.readChannelMsg(argpath, fileStartFrame, numFrames, bufStartFrame, leaveOpen, channels, {|buf| ["/b_query", buf.bufnum] }) ) } *readNoUpdate { arg server, path, startFrame = 0, numFrames = -1, bufnum, completionMessage; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; ^super.newCopyArgs(server, bufnum).allocRead(path, startFrame, numFrames, completionMessage) } readNoUpdate { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, completionMessage; server.listSendMsg( this.readMsg( argpath, fileStartFrame, numFrames, bufStartFrame, leaveOpen, completionMessage ) ) } readMsg { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, completionMessage; path = argpath; ^["/b_read", bufnum, path, fileStartFrame, (numFrames ? -1).asInt, bufStartFrame, leaveOpen.binaryValue, completionMessage.value(this)] // doesn't set my numChannels etc. } readChannelMsg { arg argpath, fileStartFrame = 0, numFrames = -1, bufStartFrame = 0, leaveOpen = false, channels, completionMessage; path = argpath; ^["/b_readChannel", bufnum, path, fileStartFrame, (numFrames ? -1).asInt, bufStartFrame, leaveOpen.binaryValue] ++ channels ++ [completionMessage.value(this)] // doesn't set my numChannels etc. } // preload a buffer for use with DiskIn *cueSoundFile { arg server, path, startFrame = 0, numChannels= 2, bufferSize=32768, completionMessage; ^this.alloc(server, bufferSize, numChannels, { arg buffer; buffer.readMsg(path, startFrame, bufferSize, 0, true, completionMessage) }).cache } cueSoundFile { arg path, startFrame, completionMessage; this.path_(path); server.listSendMsg( this.cueSoundFileMsg(path, startFrame, completionMessage) ) } cueSoundFileMsg { arg path, startFrame = 0, completionMessage; ^["/b_read", bufnum, path, startFrame, numFrames.asInt, 0, 1, completionMessage.value(this)] } // transfer a collection of numbers to a buffer through a file *loadCollection { arg server, collection, numChannels = 1, action; var data, sndfile, path, bufnum, buffer; server = server ? Server.default; bufnum = server.bufferAllocator.alloc(1); if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; if(server.isLocal, { if(collection.isKindOf(RawArray).not) { collection = collection.as(FloatArray) }; sndfile = SoundFile.new; sndfile.sampleRate = server.sampleRate; sndfile.numChannels = numChannels; path = PathName.tmp ++ sndfile.hash.asString; if(sndfile.openWrite(path), { sndfile.writeData(collection); sndfile.close; ^super.newCopyArgs(server, bufnum) .cache.doOnInfo_({ |buf| if(File.delete(path), { buf.path = nil}, {("Could not delete data file:" + path).warn;}); action.value(buf); }).allocRead(path, 0, -1, {|buf| ["/b_query", buf.bufnum] }) }, { "Failed to write data".warn; ^nil } ) }, { "cannot use loadCollection with a non-local Server".warn; ^nil }) } loadCollection { arg collection, startFrame = 0, action; var data, sndfile, path; if(server.isLocal, { if(collection.isKindOf(RawArray).not, {data = collection.collectAs({|item| item}, FloatArray)}, {data = collection;} ); if ( collection.size > ((numFrames - startFrame) * numChannels), { "Collection larger than available number of Frames".warn }); sndfile = SoundFile.new; sndfile.sampleRate = server.sampleRate; sndfile.numChannels = numChannels; path = PathName.tmp ++ sndfile.hash.asString; if(sndfile.openWrite(path), { sndfile.writeData(data); sndfile.close; this.read(path, bufStartFrame: startFrame, action: { |buf| if(File.delete(path), { buf.path = nil }, {("Could not delete data file:" + path).warn }); action.value(buf) }) }, { "Failed to write data".warn }); }, {"cannot do fromCollection with a non-local Server".warn }) } // send a Collection to a buffer one UDP sized packet at a time *sendCollection { arg server, collection, numChannels = 1, wait = -1, action; var buffer = this.new(server, ceil(collection.size / numChannels), numChannels); forkIfNeeded { buffer.alloc; server.sync; buffer.sendCollection(collection, 0, wait, action); } ^buffer } sendCollection { arg collection, startFrame = 0, wait = -1, action; var collstream, collsize, bundsize; if(collection.isSequenceableCollection and: { startFrame.isNumber and: { wait.isNumber } }) { collstream = CollStream.new; collstream.collection = collection; collsize = collection.size; if ( collsize > ((numFrames - startFrame) * numChannels), { "Collection larger than available number of Frames".warn }); this.streamCollection(collstream, collsize, startFrame * numChannels, wait, action) } { MethodError("Invalid arguments to Buffer:sendCollection", this).throw } } // called internally streamCollection { arg collstream, collsize, startFrame = 0, wait = -1, action; var bundsize, pos; { // wait = -1 allows an OSC roundtrip between packets // wait = 0 might not be safe in a high traffic situation // maybe okay with tcp pos = collstream.pos; while { pos < collsize } { // 1626 max size for setn under udp bundsize = min(1626, collsize - pos); server.listSendMsg(['/b_setn', bufnum, pos + startFrame, bundsize] ++ Array.fill(bundsize, { collstream.next })); pos = collstream.pos; if(wait >= 0) { wait.wait } { server.sync }; }; action.value(this); }.forkIfNeeded } // these next two get the data and put it in a float array which is passed to action loadToFloatArray { arg index = 0, count = -1, action; var msg, cond, path, file, array; { path = PathName.tmp ++ this.hash.asString; msg = this.write(path, "aiff", "float", count, index); server.sync; file = SoundFile.new; protect { file.openRead(path); array = FloatArray.newClear(file.numFrames * file.numChannels); file.readData(array); } { file.close; if(File.delete(path).not) { ("Could not delete data file:" + path).warn }; }; action.value(array, this); }.forkIfNeeded } // risky without wait getToFloatArray { arg index = 0, count, wait = 0.01, timeout = 3, action; var refcount, array, pos, getsize, resp, done = false; pos = index = index.asInteger; count = (count ? (numFrames * numChannels)).asInteger; array = FloatArray.newClear(count); refcount = (count / 1633).roundUp; count = count + pos; //("refcount" + refcount).postln; resp = OSCFunc({ arg msg; if(msg[1] == bufnum, { //("received" + msg).postln; array = array.overWrite(FloatArray.newFrom(msg.copyToEnd(4)), msg[2] - index); refcount = refcount - 1; //("countDown" + refcount).postln; if(refcount <= 0, {done = true; resp.clear; action.value(array, this); }); }); }, '/b_setn', server.addr); { while({ pos < count }, { // 1633 max size for getn under udp getsize = min(1633, count - pos); //("sending from" + pos).postln; server.listSendMsg(this.getnMsg(pos, getsize)); pos = pos + getsize; if(wait >= 0) { wait.wait } { server.sync }; }); }.forkIfNeeded; // lose the responder if the network choked SystemClock.sched(timeout, { if(done.not, { resp.free; "Buffer-streamToFloatArray failed!".warn; "Try increasing wait time".postln }) }) } write { arg path, headerFormat = "aiff", sampleFormat = "int24", numFrames = -1, startFrame = 0, leaveOpen = false, completionMessage; path = path ?? { thisProcess.platform.recordingsDir +/+ "SC_" ++ Date.localtime.stamp ++ "." ++ headerFormat }; server.listSendMsg( this.writeMsg(path, headerFormat, sampleFormat, numFrames, startFrame, leaveOpen, completionMessage) ) } writeMsg { arg path, headerFormat = "aiff", sampleFormat = "int24", numFrames = -1, startFrame = 0, leaveOpen = false, completionMessage; // doesn't change my path ^["/b_write", bufnum, path, headerFormat, sampleFormat, numFrames, startFrame, leaveOpen.binaryValue, completionMessage.value(this)]; } free { arg completionMessage; server.listSendMsg( this.freeMsg(completionMessage) ) } freeMsg { arg completionMessage; var msg; this.uncache; server.bufferAllocator.free(bufnum); msg = ["/b_free", bufnum, completionMessage.value(this)]; bufnum = numFrames = numChannels = sampleRate = path = startFrame = nil; ^msg } *freeAll { arg server; var b; server = server ? Server.default; server.bufferAllocator.blocks.do({ arg block; (block.address .. block.address + block.size - 1).do({ |i| b = b.add( ["/b_free", i] ); }); server.bufferAllocator.free(block.address); }); server.sendBundle(nil, *b); this.clearServerCaches(server); } zero { arg completionMessage; server.listSendMsg(this.zeroMsg(completionMessage)) } zeroMsg { arg completionMessage; ^["/b_zero", bufnum , completionMessage.value(this) ] } set { arg index, float ... morePairs; server.listSendMsg(["/b_set", bufnum, index, float] ++ morePairs) } setMsg { arg index, float ... morePairs; ^["/b_set", bufnum, index, float] ++ morePairs } setn { arg ... args; server.sendMsg(*this.setnMsg(*args)); } setnMsgArgs{arg ... args; var nargs; nargs = List.new; args.pairsDo{ arg control, moreVals; if(moreVals.isArray, { nargs.addAll([control, moreVals.size]++ moreVals) }, { nargs.addAll([control, 1, moreVals]); }); }; ^nargs } setnMsg { arg ... args; ^["/b_setn", bufnum] ++ this.setnMsgArgs(*args) } get { arg index, action; OSCpathResponder(server.addr, ['/b_set', bufnum, index], { arg time, r, msg; action.value(msg.at(3)); r.remove }).add; server.listSendMsg(["/b_get", bufnum, index]) } getMsg { arg index; ^["/b_get", bufnum, index] } getn { arg index, count, action; OSCpathResponder(server.addr, ['/b_setn', bufnum, index], {arg time, r, msg; action.value(msg.copyToEnd(4)); r.remove } ).add; server.listSendMsg(["/b_getn", bufnum, index, count]); } getnMsg { arg index, count; ^["/b_getn", bufnum, index, count] } fill { arg startAt, numFrames, value ... more; server.listSendMsg(["/b_fill", bufnum, startAt, numFrames.asInt, value] ++ more) } fillMsg { arg startAt, numFrames, value ... more; ^["/b_fill", bufnum, startAt, numFrames.asInt, value] ++ more } normalize { arg newmax=1, asWavetable=false; server.listSendMsg(["/b_gen", bufnum, if(asWavetable, "wnormalize", "normalize"), newmax]) } normalizeMsg { arg newmax=1, asWavetable=false; ^["/b_gen", bufnum, if(asWavetable, "wnormalize", "normalize"), newmax] } gen { arg genCommand, genArgs, normalize=true, asWavetable=true, clearFirst=true; server.listSendMsg(["/b_gen", bufnum, genCommand, normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ genArgs) } genMsg { arg genCommand, genArgs, normalize=true, asWavetable=true, clearFirst=true; ^["/b_gen", bufnum, genCommand, normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ genArgs } sine1 { arg amps, normalize=true, asWavetable=true, clearFirst=true; server.listSendMsg(["/b_gen", bufnum, "sine1", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amps) } sine2 { arg freqs, amps, normalize=true, asWavetable=true, clearFirst=true; server.listSendMsg(["/b_gen", bufnum, "sine2", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps].lace(freqs.size * 2)) } sine3 { arg freqs, amps, phases, normalize=true, asWavetable=true, clearFirst=true; server.listSendMsg(["/b_gen", bufnum, "sine3", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps, phases].lace(freqs.size * 3)) } cheby { arg amplitudes, normalize=true, asWavetable=true, clearFirst=true; server.listSendMsg(["/b_gen", bufnum, "cheby", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amplitudes) } sine1Msg { arg amps, normalize=true, asWavetable=true, clearFirst=true; ^["/b_gen", bufnum, "sine1", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amps } sine2Msg { arg freqs, amps, normalize=true, asWavetable=true, clearFirst=true; ^["/b_gen", bufnum, "sine2", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps].lace(freqs.size * 2) } sine3Msg { arg freqs, amps, phases, normalize=true, asWavetable=true, clearFirst=true; ^["/b_gen", bufnum, "sine3", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ [freqs, amps, phases].lace(freqs.size * 3) } chebyMsg { arg amplitudes, normalize=true, asWavetable=true, clearFirst=true; ^["/b_gen", bufnum, "cheby", normalize.binaryValue + (asWavetable.binaryValue * 2) + (clearFirst.binaryValue * 4)] ++ amplitudes } copyData { arg buf, dstStartAt = 0, srcStartAt = 0, numSamples = -1; server.listSendMsg( this.copyMsg(buf, dstStartAt, srcStartAt, numSamples) ) } copyMsg { arg buf, dstStartAt = 0, srcStartAt = 0, numSamples = -1; ^["/b_gen", buf.bufnum, "copy", dstStartAt, bufnum, srcStartAt, numSamples] } // close a file, write header, after DiskOut usage close { arg completionMessage; server.listSendMsg( this.closeMsg(completionMessage) ) } closeMsg { arg completionMessage; ^["/b_close", bufnum, completionMessage.value(this) ] } query { OSCFunc({ arg msg; Post << "bufnum : " << msg[1] << Char.nl << "numFrames : " << msg[2] << Char.nl << "numChannels : " << msg[3] << Char.nl << "sampleRate : " << msg[4] << Char.nl << Char.nl; }, '/b_info', server.addr).oneShot; server.sendMsg("/b_query", bufnum) } updateInfo { arg action; // add to the array here. That way, update will be accurate even if this buf // has been freed this.cache; doOnInfo = action; server.sendMsg("/b_query", bufnum); } // cache Buffers for easy info updating cache { Buffer.initServerCache(server); serverCaches[server][bufnum] = this; } uncache { if(serverCaches[server].notNil, { serverCaches[server].removeAt(bufnum); }); if(serverCaches[server].size == 1) { // the 1 item would be the responder // if there is more than 1 item then the rest are cached buffers // else we can remove. // cx: tho i don't see why its important. it will just have to be added // back when the next buffer is added and the responder is removed when // the server reboots Buffer.clearServerCaches(server); } } *initServerCache { arg server; serverCaches[server] ?? { serverCaches[server] = IdentityDictionary.new; serverCaches[server][\responder] = OSCFunc({ |m| var buffer = serverCaches[server][m[1]]; if(buffer.notNil) { buffer.numFrames = m[2]; buffer.numChannels = m[3]; buffer.sampleRate = m[4]; buffer.queryDone; }; }, '/b_info', server.addr).fix; NotificationCenter.register(server, \newAllocators, this, { this.clearServerCaches(server); }); } } *clearServerCaches { arg server; if(serverCaches[server].notNil) { serverCaches[server][\responder].free; serverCaches.removeAt(server); } } *cachedBuffersDo { arg server, func; var i = 0; serverCaches[server] !? { serverCaches[server].keysValuesDo({ |key, value| if(key.isNumber) { func.value(value, i); i = i + 1 }; }) } } *cachedBufferAt { arg server, bufnum; ^serverCaches[server].tryPerform(\at, bufnum) } // called from Server when b_info is received queryDone { doOnInfo.value(this); doOnInfo = nil; } printOn { arg stream; stream << this.class.name << "(" <<* [bufnum, numFrames, numChannels, sampleRate, path] <<")" } *loadDialog { arg server, startFrame = 0, numFrames, action, bufnum; var buffer; server = server ? Server.default; bufnum ?? { bufnum = server.bufferAllocator.alloc(1) }; if(bufnum.isNil) { Error("No more buffer numbers -- free some buffers before allocating more.").throw }; buffer = super.newCopyArgs(server, bufnum).cache; File.openDialog("Select a file...", { arg path; buffer.doOnInfo_(action) .allocRead(path, startFrame, numFrames, { ["/b_query", buffer.bufnum] }) }); ^buffer } play { arg loop = false, mul = 1; ^{ var player; player = PlayBuf.ar(numChannels, bufnum, BufRateScale.kr(bufnum), loop: loop.binaryValue); if(loop.not, FreeSelfWhenDone.kr(player)); player * mul; }.play(server) } duration { ^numFrames / sampleRate } asUGenInput { ^this.bufnum } asControlInput { ^this.bufnum } asBufWithValues { ^this } } SuperCollider-Source/SCClassLibrary/Common/Control/Bus.sc000644 000765 000024 00000015432 12756534416 024447 0ustar00crucialstaff000000 000000 Bus { var bus.numChannels or: { numChannels + offset > bus.numChannels }) { Error("Bus:newFrom tried to reach outside the channel range of %".format( bus )).throw }; ^this.new(bus.rate, bus.index + offset, numChannels) } isSettable { ^rate != \audio } set { arg ... values; // shouldn't be larger than this.numChannels if(this.isSettable, { server.sendBundle(nil, (["/c_set"] ++ values.collect({ arg v, i; [index + i , v] }).flat)); }, { error("Cannot set an audio rate bus") }); } setMsg { arg ... values; if(this.isSettable, { ^["/c_set"] ++ values.collect({ arg v, i; [index + i , v] }).flat }, { error("Cannot set an audio rate bus"); ^nil }); } setn { arg values; // could throw an error if values.size > numChannels if(this.isSettable, { server.sendBundle(nil, ["/c_setn", index, values.size] ++ values); }, { error("Cannot set an audio rate bus") }); } setnMsg { arg values; if(this.isSettable, { ^["/c_setn", index, values.size] ++ values; }, { error("Cannot set an audio rate bus"); ^nil }); } setAt { |offset ... values| // shouldn't be larger than this.numChannels - offset if(this.isSettable, { server.sendBundle(nil, (["/c_set"] ++ values.collect({ arg v, i; [index + offset + i , v] }).flat)); }, { error("Cannot set an audio rate bus") }); } setnAt { |offset, values| // could throw an error if values.size > numChannels if(this.isSettable, { server.sendBundle(nil, ["/c_setn", index + offset, values.size] ++ values); }, { error("Cannot set an audio rate bus")}); } setPairs { | ... pairs| if(this.isSettable, { server.sendBundle(nil, (["/c_set"] ++ pairs.clump(2).collect({ arg pair; [pair[0] + index, pair[1]] }).flat)); }, { error("Cannot set an audio rate bus") }); } get { arg action; if(numChannels == 1) { action = action ? { |vals| "Bus % index: % value: %.\n".postf(rate, index, vals); }; OSCpathResponder(server.addr, ['/c_set', index], { arg time, r, msg; action.value(msg.at(2)); r.remove }).add; server.listSendMsg(["/c_get", index]); } { this.getn(numChannels, action) }; } getn { arg count, action; action = action ? { |vals| "Bus % index: % values: %.\n".postf(rate, index, vals) }; OSCpathResponder(server.addr, ['/c_setn', index], { arg time, r, msg; action.value(msg.copyToEnd(3)); r.remove }).add; server.listSendMsg(this.getnMsg(count)); } getMsg { ^["/c_get", index]; } getnMsg { arg count; ^["/c_getn", index, count ? numChannels]; } getSynchronous { if (not(this.isSettable)) { Error("Bus-getSynchronous only works for control-rate busses").throw; } { ^server.getControlBusValue(index); } } getnSynchronous { |count| if (not(this.isSettable)) { Error("Bus-getnSynchronous only works for control-rate busses").throw; } { ^server.getControlBusValues(index, count ? numChannels); } } setSynchronous { |... values| if (not(this.isSettable)) { Error("Bus-setSynchronous only works for control-rate busses").throw; } { if (values.size == 1) { server.setControlBusValue(index, values[0]) } { server.setControlBusValues(index, values) } } } setnSynchronous { |values| if (not(this.isSettable)) { Error("Bus-setnSynchronous only works for control-rate busses").throw; } { server.setControlBusValues(index, values) } } fill { arg value, numChans; // could throw an error if numChans > numChannels server.sendBundle(nil, ["/c_fill", index, numChans, value]); } fillMsg { arg value; ^["/c_fill", index, numChannels, value] } free { arg clear = false; if(index.isNil, { (this.asString + " has already been freed").warn; ^this }); if(rate == \audio, { server.audioBusAllocator.free(index); }, { server.controlBusAllocator.free(index); if(clear) { this.setAll(0) }; }); index = nil; numChannels = nil; mapSymbol = nil; } // allow reallocation alloc { if(rate === 'audio', { index = server.audioBusAllocator.alloc(numChannels); }, { index = server.controlBusAllocator.alloc(numChannels); }); mapSymbol = nil; } realloc { var r, n; if(index.notNil, { r = rate; n = numChannels; this.free; rate = r; numChannels = n; this.alloc; }) } // alternate syntaxes setAll { arg value; this.fill(value, numChannels); } value_ { arg value; this.fill(value, numChannels); } printOn { arg stream; stream << this.class.name << "(" <<* [rate, index, numChannels, server] <<")" } storeOn { arg stream; stream << this.class.name << "(" <<* [rate.asCompileString, index, numChannels, server.asCompileString] <<")" } == { arg aBus; ^this.compareObject(aBus, #[\index, \numChannels, \rate, \server]) } hash { ^this.instVarHash(#[\index, \numChannels, \rate, \server]) } isAudioOut { // audio interface ^(rate === \audio and: { index < server.options.firstPrivateBus}) } ar { arg numChannels=(this.numChannels), offset=0; if(rate == \audio, { ^In.ar(index + offset, numChannels) }, { //"Bus converting control to audio rate".inform; ^K2A.ar( In.kr(index + offset, numChannels) ) }) } kr { arg numChannels=(this.numChannels), offset=0; if(rate == \audio, { ^A2K.kr( In.ar(index + offset, numChannels) ) }, { ^In.kr(index + offset, numChannels) }) } play { arg target=0, outbus, fadeTime, addAction=\addToTail; if(this.isAudioOut.not, { // returns a Synth ^{ this.ar }.play(target, outbus, fadeTime, addAction) }) } asUGenInput { ^this.index } asControlInput { ^this.index } asMap { ^mapSymbol ?? { if(index.isNil) { MethodError("bus not allocated.", this).throw }; mapSymbol = if(rate == \control) { "c" } { "a" }; mapSymbol = (mapSymbol ++ index).asSymbol; } } subBus { arg offset, numChannels=1; ^this.class.newFrom(this, offset, numChannels); } } SuperCollider-Source/SCClassLibrary/Common/Control/Engine.sc000644 000765 000024 00000017443 12756534416 025127 0ustar00crucialstaff000000 000000 NodeIDAllocator { var 31) { "NodeIDAllocator user id > 31".error; ^nil }; ^super.newCopyArgs(user, initTemp).reset } reset { mask = user << 26; temp = initTemp; perm = 2; permFreed = IdentitySet.new; } alloc { var x; x = temp; temp = (x + 1).wrap(initTemp, 0x03FFFFFF); ^x | mask } allocPerm { var x; if(permFreed.size > 0) { x = permFreed.minItem; permFreed.remove(x); } { x = perm; perm = (x + 1).min(initTemp - 1); } ^x | mask } freePerm { |id| // should not add a temp node id to the freed-permanent collection id = id bitAnd: 0x03FFFFFF; if(id < initTemp) { permFreed.add(id) } } } PowerOfTwoBlock { var next; *new { arg address, size; ^super.newCopyArgs(address, size) } } PowerOfTwoAllocator { // THIS IS THE RECOMMENDED ALLOCATOR FOR BUSES AND BUFFERS var size, array, freeLists, pos=0; *new { arg size, pos=0; ^super.newCopyArgs(size, Array.newClear(size), Array.newClear(32), pos) } alloc { arg n; var sizeClass, node, address; n = n.nextPowerOfTwo; sizeClass = n.log2Ceil; node = freeLists.at(sizeClass); if (node.notNil, { freeLists.put(sizeClass, node.next); ^node.address }); if (pos + n <= size, { array.put(pos, PowerOfTwoBlock(pos, n)); address = pos; pos = pos + n; ^address }); ^nil } free { arg address; var node, sizeClass,next; if((node = array.at(address)).notNil,{ sizeClass = node.size.log2Ceil; node.next = freeLists.at(sizeClass); freeLists.put(sizeClass, node); array.put(address, nil); }); } blocks { ^array.select({ arg b; b.notNil }) } } LRUNumberAllocator { // implements a least recently used ID allocator. var lo, hi; var array, size, head=0, tail=0; *new { arg lo, hi; ^super.newCopyArgs(lo, hi).init } init { size = hi-lo+1; array = Array.newClear(size); for(lo, hi-1, { arg i, j; array.put(j, i) }); head = size-1; tail=0; } free { arg id; var nextIndex; nextIndex = (head+1) % size; if ( nextIndex == tail, { ^nil }); // full array.put(head, id); head = nextIndex; } alloc { var id; if (head == tail, { ^nil }); // empty id = array.at(tail); tail = (tail+1) % size; ^id } } StackNumberAllocator { var lo, hi, freeList, next; *new { arg lo, hi; ^super.newCopyArgs(lo, hi).init } init { next = lo - 1; } alloc { if (freeList.size > 0, { ^freeList.pop }); if (next < hi, { ^next = next + 1; }); ^nil } free { arg inIndex; freeList = freeList.add(inIndex); } } RingNumberAllocator { var lo, hi, next; *new { arg lo, hi; ^super.newCopyArgs(lo, hi).init } init { next = hi; } alloc { ^next = (next + 1).wrap(lo,hi) } } // by hjh: for better handling of dynamic allocation ContiguousBlock { var used = false; // assume free; owner must say otherwise *new { |start, size| ^super.newCopyArgs(start, size) } address { ^start } adjoins { |block| ^(start < block.start and: { start + size >= block.start }) or: { start > block.start and: { block.start + block.size >= start } } } join { |block| var newstart; this.adjoins(block).if({ ^this.class.new(newstart = min(start, block.start), max(start + size, block.start + block.size) - newstart) }, { ^nil }); } split { |span| (span < size).if({ ^[this.class.new(start, span), this.class.new(start + span, size - span)] }, { (span == size).if({ ^[this, nil] }, { ^nil }); }); } storeArgs { ^[start, size, used] } printOn { |stream| this.storeOn(stream) } } ContiguousBlockAllocator { var size, array, freed, pos, top; *new { |size, pos = 0| ^super.newCopyArgs(size, Array.newClear(size).put(pos, ContiguousBlock(pos, size-pos)), IdentityDictionary.new, pos, pos); } alloc { |n = 1| var block; (block = this.findAvailable(n)).notNil.if({ ^this.prReserve(block.start, n, block).start }, { ^nil }); } reserve { |address, size = 1, warn = true| var block, new; ((block = array[address] ?? { this.findNext(address) }).notNil and: { block.used and: { address + size > block.start } }).if({ warn.if({ "The block at (%, %) is already in use and cannot be reserved." .format(address, size).warn; }); }, { (block.start == address).if({ new = this.prReserve(address, size, block); ^new; }, { ((block = this.findPrevious(address)).notNil and: { block.used and: { block.start + block.size > address } }).if({ warn.if({ "The block at (%, %) is already in use and cannot be reserved." .format(address, size).warn; }); }, { new = this.prReserve(address, size, nil, block); ^new; }); }); }); ^nil } free { |address| var block, prev, next, temp; // this 'if' prevents an error if a Buffer object is freed twice if(address.isNil) { ^this }; ((block = array[address]).notNil and: { block.used }).if({ block.used = false; this.addToFreed(block); ((prev = this.findPrevious(address)).notNil and: { prev.used.not }).if({ (temp = prev.join(block)).notNil.if({ // if block is the last one, reduce the top (block.start == top).if({ top = temp.start }); array[temp.start] = temp; array[block.start] = nil; this.removeFromFreed(prev).removeFromFreed(block); (top > temp.start).if({ this.addToFreed(temp); }); block = temp; }); }); ((next = this.findNext(block.start)).notNil and: { next.used.not }).if({ (temp = next.join(block)).notNil.if({ // if next is the last one, reduce the top (next.start == top).if({ top = temp.start }); array[temp.start] = temp; array[next.start] = nil; this.removeFromFreed(next).removeFromFreed(block); (top > temp.start).if({ this.addToFreed(temp); }); }); }); }); } blocks { ^array.select({ arg b; b.notNil and: { b.used } }) } findAvailable { |n| (freed[n].size > 0).if({ ^freed[n].choose }); freed.keysValuesDo({ |size, set| (size >= n and: { set.size > 0 }).if({ ^set.choose }); }); (top + n > size or: { array[top].used }).if({ ^nil }); ^array[top] } addToFreed { |block| freed[block.size].isNil.if({ freed[block.size] = IdentitySet.new }); freed[block.size].add(block); } removeFromFreed { |block| freed[block.size].tryPerform(\remove, block); // I tested without gc; performance is about half as efficient without it (freed[block.size].size == 0).if({ freed.removeAt(block.size) }); } findPrevious { |address| forBy(address-1, pos, -1, { |i| array[i].notNil.if({ ^array[i] }); }); ^nil } findNext { |address| var temp; (temp = array[address]).notNil.if({ ^array[temp.start + temp.size] }, { for(address+1, top, { |i| array[i].notNil.if({ ^array[i] }); }); }); ^nil } prReserve { |address, size, availBlock, prevBlock| var new, leftover; (availBlock.isNil and: { prevBlock.isNil }).if({ prevBlock = this.findPrevious(address); }); availBlock = availBlock ? prevBlock; (availBlock.start < address).if({ #leftover, availBlock = this.prSplit(availBlock, address - availBlock.start, false); }); ^this.prSplit(availBlock, size, true)[0]; } prSplit { |availBlock, n, used = true| var new, leftover; #new, leftover = availBlock.split(n); new.used = used; this.removeFromFreed(availBlock); used.not.if({ this.addToFreed(new) }); array[new.start] = new; leftover.notNil.if({ array[leftover.start] = leftover; top = max(top, leftover.start); (top > leftover.start).if({ this.addToFreed(leftover); }); }); ^[new, leftover] } debug { |text| Post << text << ":\n\nArray:\n"; array.do({ |item, i| item.notNil.if({ Post << i << ": " << item << "\n"; }); }); Post << "\nFree sets:\n"; freed.keysValuesDo({ |size, set| Post << size << ": " <<< set << "\n"; }); } } SuperCollider-Source/SCClassLibrary/Common/Control/extConvertToOSC.sc000644 000765 000024 00000003454 12766171707 026731 0ustar00crucialstaff000000 000000 // The following interface in an optimized version of asControlInput that // flattens arrayed values and marks the outermost array of a value with $[ and $] // These Chars are turning into typetags ([ and ]) in the OSC message to mark that array // Inner arrays are flattened (they are not meaningful in the server context) // This makes it possible to write Synth("test", [0, [[100,200,300], [0.1,0.2,0.3], [10,20,30]] ]) // and have all the arguments be assigned to consecutive controls in the synth. +SequenceableCollection { asOSCArgBundle { var array = Array(100); // allocate a bunch of space this.do { | msg | array = array.add(msg.asOSCArgArray) }; ^array } asOSCArgArray { var array = Array(100); // allocate a bunch of space this.do { | e | array = e.asOSCArgEmbeddedArray(array) }; ^array } asOSCArgEmbeddedArray { | array| array = array.add($[); this.do{ | e | array = e.asOSCArgEmbeddedArray(array) }; ^array.add($]) } } +String { asOSCArgEmbeddedArray { | array| ^array.add(this) } asOSCArgArray { ^this } } +Env { asControlInput { ^this.asArray } asOSCArgEmbeddedArray { | array| ^this.asArray.asOSCArgEmbeddedArray(array) } } +Object { asOSCArgEmbeddedArray { | array| ^array.add(this.asControlInput) } asOSCArgArray { ^this.asControlInput } asOSCArgBundle { ^this.asControlInput } asStringff { | size = 8 | var str = this.asString; str = str[0..size-1]; str = str ++ String.fill(size - str.size, Char.space); ^str; } postff { | size = 8 | this.asStringff(size).post } } +Nil { asOSCArgArray {} } +Ref { asOSCArgEmbeddedArray { | array| ^value.asOSCArgEmbeddedArray(array) } } +AbstractFunction { eq { arg function, adverb; ^this.composeBinaryOp('==', function, adverb) } // ne { arg function, adverb; ^this.composeBinaryOp('!=', function, adverb) } } SuperCollider-Source/SCClassLibrary/Common/Control/extSystemActions.sc000644 000765 000024 00000001147 12756534416 027242 0ustar00crucialstaff000000 000000 + Server { onBootAdd { arg object; ServerBoot.add(object, this); } onBootRemove { arg object; ServerBoot.remove(object, this); } onQuitAdd { arg object; ServerQuit.add(object, this); } onQuitRemove { arg object; ServerQuit.remove(object, this); } } + Function { doOnStartUp { this.value } doOnCmdPeriod { this.value } doOnShutDown { this.value } doOnError { this.value } doOnServerBoot { arg server; this.value(server) } doOnServerQuit { arg server; this.value(server) } doOnServerTree { arg server; this.value(server) } } + Object { doOnCmdPeriod { ^this.cmdPeriod } // compatibility } SuperCollider-Source/SCClassLibrary/Common/Control/GraphBuilder.sc000644 000765 000024 00000010024 12766171707 026257 0ustar00crucialstaff000000 000000 GraphBuilder { //used to create an out ugen automatically and a fade envelope *wrapOut { arg name, func, rates, prependArgs, outClass=\Out, fadeTime; ^SynthDef.new(name, { arg i_out=0; var result, rate, env; result = SynthDef.wrap(func, rates, prependArgs).asUGenInput; rate = result.rate; if(rate.isNil or: { rate === \scalar }) { // Out, SendTrig, [ ] etc. probably a 0.0 result } { if(fadeTime.notNil) { result = this.makeFadeEnv(fadeTime) * result; }; outClass = outClass.asClass; outClass.replaceZeroesWithSilence(result.asArray); outClass.multiNewList([rate, i_out]++result) } }) } *makeFadeEnv { arg fadeTime = (0.02); var dt = NamedControl.kr(\fadeTime, fadeTime); var gate = NamedControl.kr(\gate, 1.0); var startVal = (dt <= 0); ^EnvGen.kr(Env.new([startVal, 1, 0], #[1, 1], \lin, 1), gate, 1.0, 0.0, dt, 2) } } EnvGate { *new { arg i_level=1, gate, fadeTime, doneAction=2, curve='sin'; var synthGate = gate ?? { NamedControl.kr(\gate, 1.0) }; var synthFadeTime = fadeTime ?? { NamedControl.kr(\fadeTime, 0.02) }; var startVal = (synthFadeTime <= 0); ^EnvGen.kr( Env.new([ startVal, 1.0, 0.0], #[1.0, 1.0], curve, 1), synthGate, i_level, 0.0, synthFadeTime, doneAction ) } } NamedControl { classvar currentControls, buildSynthDef; var debug = false, action, <>deviceAction, <>closeAction; var <>debug = false, info; var action; var <>deviceAction; var <>closeAction; var <>debug = false; */ *new { arg ...args; ^HID.open( *args ); } *basicNew { |id| ^super.new.init( id ); } init { |i| isOpen = true; id = i; elements = IdentityDictionary.new; collections = IdentityDictionary.new; usages = IdentityDictionary.new; // elementDictionary = MultiLevelIdentityDictionary.new; } valueDeviceAction { arg ...args; if ( debug ) { ( [ "device", id ] ++ args).postln; }; deviceAction.value( *args ); this.changed( \elementdata ); } valueAction { arg ...args; // mappedvalue, value, usage, page, elid if ( debug ) { ([ "element", id ] ++ args).postln; }; if ( elements.at( args[6] ).notNil ) { elements.at( args[6] ).setValueFromInput( args[0], args[1], args[2], args[3] ); }; action.value( *args ); } getCollections { var numberOfCollections = HID.prGetNumberOfCollections( id ); numberOfCollections.do { |i| var colInfo = this.getCollectionInfo( i ); collections.put( i, HIDCollection.new( *colInfo ).device_( this ) ); }; info.setUsageAndPage( collections.at(0).usagePage, collections.at(0).usage ); } getCollectionInfo { |colid| ^HID.prGetCollectionInfo( id, colid ); } getElements { var numberOfElements = HID.prGetNumberOfElements( id ); numberOfElements.do { |i| var elInfo = this.getElementInfo( i ); elements.put( i, HIDElement.new( *elInfo ).device_( this ) ); } } getUsages { elements.do { |it| it.getUsages( usages ); } } getElementWithID { |elid| ^elements.at( elid ); } findElementWithUsage { |elUsage, elUsagePage| ^elements.select { |el| ( el.usage == elUsage ) and: ( el.usagePage == elUsagePage ) }.asArray; } getElementInfo { |elid| ^HID.prGetElementInfo( id, elid ); } getInfo { var result = HID.prGetDeviceInfo( id ); if ( result.isKindOf( Array ) ) { info = HIDInfo.new( *result ); // this.prettyPrint; } { "could not get info on hid device; maybe it is not open?".postln; } } usagePage { |collectionID=0| ^collections.at( collectionID ).usagePage; } usage { |collectionID=0| ^collections.at( collectionID ).usage; } pageName { |collectionID=0| ^collections.at( collectionID ).pageName; } usageName { |collectionID=0| ^collections.at( collectionID ).usageName; } vendor { ^info.vendorID; } product { ^info.productID; } // prettyPrint { // "Device [%] : [%] has the following properties:\n".postf(id, name); // [ ["number of axes", numAxes], ["number of buttons", numButtons ], [ "number of hats", numHats ], [ "number of balls", numBalls ], [ "unique identifier", guid ] ].do { |it| // "\t % : % \n".postf( it[0], it[1] ); // }; // } close { "HID: closing device %\n".postf( id ); isOpen = false; HID.prCloseDevice( id ); } prDeviceClosed { HID.removeUsageDict( this ); closeAction.value; if ( isOpen ) { this.close; }; isOpen = false; } postCollections { this.collections.sortedKeysValuesDo { |k, v| v.postCollection; }; } postUsages { this.usages.sortedKeysValuesDo { |k, v| "Usage: %\n".postf(k); v.do { |it| it.postElement("\t"); }; }; } postElements { this.elements.sortedKeysValuesDo { |k, v| v.postElement; "".postln; }; } postInputElements { this.elements.sortedKeysValuesDo { |k, v| if( v.ioType == 1 ) { v.postElement; "".postln; } }; } postOutputElements { this.elements.sortedKeysValuesDo { |k, v| if( v.ioType == 2 ) { v.postElement; "".postln; } }; } postFeatureElements { this.elements.sortedKeysValuesDo { |k, v| if( v.ioType == 3 ) { v.postElement; "".postln; } }; } *postAvailable { this.available.sortedKeysValuesDo { |k, v| "%: ".postf( k ); v.postInfo; }; } *postAvailableUsages { this.availableUsages.sortedKeysValuesDo { |k, v| "Usage: %\n".postf(k); v.sortedKeysValuesDo { |k2, v2| "\tDevice id: %".postf( k2 ); v2.do { |it| it.postElement("\t"); }; }; }; } postInfo { info.postInfo; } } HIDInfo { //------- do not change the order of these variables, they correspond to the primitive data order: <------- var do not change the order of these variables, they correspond to the primitive data order ------------ var pageName, usageName; *new { |...args| ^super.newCopyArgs( *args ); } setUsageAndPage { |page, us| usage = us; usagePage = page; } postInfo { "\tUsage name and page: \t%, \t%\n".postf( this.usageName, this.pageName ); "\tVendor name: \t%\n".postf( vendorName ); "\tProduct name: \t%\n".postf( productName ); "\tVendor and product ID: \t%, %\n".postf( vendorID, productID ); "\tPath: \t%\n".postf( path ); "\tSerial Number: \t%\n".postf( serialNumber ); "\tReleasenumber and interfaceNumber: \t%, %\n".postf( releaseNumber, interfaceNumber ); } pageName { if ( pageName.isNil ) { #pageName, usageName = HIDUsage.getUsageDescription( usagePage, usage ); }; ^pageName; } usageName { if ( usageName.isNil ) { #pageName, usageName = HIDUsage.getUsageDescription( usagePage, usage ); }; ^usageName; } printOn { | stream | super.printOn(stream); stream << $( << vendorName << ", " << productName << ", IDs:"; [ vendorID, productID ]//.collect( { | x | "0x" ++ x.asHexString(4) }) .printItemsOn(stream); stream << ", " << path << ", " << serialNumber << ", " << releaseNumber << ", " << interfaceNumber; // stream << this.usageName << "(" << this.usage << "), " << this.pageName << "(" << this.usagePage << ")"; stream.put($)); } open { ^HID.open( vendorID, productID, path ); // ^HID.open( vendorID, productID, serialNumber ); } } HIDCollection { var device; var pageName, usageName; *new { arg ...args; ^super.newCopyArgs( *args ); } pageName { if ( pageName.isNil ) { #pageName, usageName = HIDUsage.getUsageDescription( usagePage, usage ); }; ^pageName; } usageName { if ( usageName.isNil ) { #pageName, usageName = HIDUsage.getUsageDescription( usagePage, usage ); }; ^usageName; } postCollection { "HID Collection: %, type: %, usage page: %, usage index: %\n\tDescription: %, %\n\tParent collection: %, number of collections contained: %, first collection: %\n\tnumber of elements contained: %, first element %\n" .postf( id, type, usagePage, usage, this.pageName, this.usageName, parent, numCollections, firstCollection, numElements, firstElement ); } printOn { | stream | super.printOn(stream); stream << $( << id << ": " ; stream << "type: " << type << "usage: " << usagePage << ", " << usage; // [ type, usagePage, usage ].printItemsOn(stream); // stream << ": description: "; // [ this.pageName, this.usageName ].printItemsOn(stream); // stream << ": parent, : " << parent; // stream << ": collections, : "; // [ numCollections, firstCollection ].printItemsOn( stream ); // stream << ": elements, : "; // [ numElements, firstElement ].printItemsOn( stream ); stream.put($)); } } HIDElement { //------- do not change the order of these variables, they correspond to the primitive data order: <------- var do not change the order of these variables ------- var action; var hutDirectory; classvar defaultDispatchers, traceFunc, traceRunning = false; var id; var <>vendorID, <>productID; var <>path; var <>serialNumber; var <>vendorName, <>productName; var <>releaseNumber; var <>interfaceNumber; var <>usagePage, <>usage; var <>pageName, <>usageName; var = this.usageMin ) }, \usageMax, { matches = matches and: ( ele.usage <= this.usageMax ) }, { // default matches = matches and: ( this.perform( key ).matchItem( ele.perform( key ) ) ) } ); }; }; ^matches; } } SuperCollider-Source/SCClassLibrary/Common/Control/MIDIOut.sc000644 000765 000024 00000030231 12756534416 025122 0ustar00crucialstaff000000 000000 MIDIEndPoint { var <>device, <>name, <>uid; *new{ arg device, name, uid; ^super.newCopyArgs(device, name, uid) } printOn { arg stream; stream << this.class.name << "(" <<<* [device, name] <<")" } } MIDIClient { classvar status, <>port, <>chan, <>b, <>c, <>thread; *new { arg status, port, chan, b, c, thread; ^super.newCopyArgs(status, port, chan, b, c, thread) } set { arg inStatus, inPort, inChan, inB, inC, inThread; status = inStatus; port = inPort; chan = inChan; b = inB; c = inC; inThread !? { thread = inThread }; } match { arg inPort, inChan, inB, inC; ^port.matchItem(inPort) and: { chan.matchItem(inChan) and: { b.matchItem(inB) and: { c.matchItem(inC) }}} } // convenience accessors note { ^b } veloc { ^c } ctlnum { ^b } ctlval { ^c } } MIDIIn { var port; classvar <>action, <> noteOn, <> noteOff, <> polytouch, <> control, <> program, <> touch, <> bend, <> sysex, sysexPacket, <> sysrt, <> smpte, <> invalid; classvar <> noteOnList, <> noteOffList, <> polyList, <> controlList, <> programList, <> touchList, <> bendList; classvar <> noteOnZeroAsNoteOff = true; // safer than global setters *addFuncTo { |what, func| this.perform(what.asSetter, this.perform(what).addFunc(func)) } *removeFuncFrom { |what, func| this.perform(what.asSetter, this.perform(what).removeFunc(func)) } *replaceFuncTo { |what, func, newFunc| this.perform(what.asSetter, this.perform(what).replaceFunc(func, newFunc)) } *waitNoteOn { arg port, chan, note, veloc; var event; event = MIDIEvent(\noteOn, port, chan, note, veloc, thisThread); noteOnList = noteOnList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitNoteOff { arg port, chan, note, veloc; var event; event = MIDIEvent(\noteOff, port, chan, note, veloc, thisThread); noteOffList = noteOffList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitPoly { arg port, chan, note, veloc; var event; event = MIDIEvent(\poly, port, chan, note, veloc, thisThread); polyList = polyList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitTouch { arg port, chan, val; var event; event = MIDIEvent(\touch, port, chan, val, nil, thisThread); touchList = touchList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitControl { arg port, chan, num, val; var event; event = MIDIEvent(\control, port, chan, num, val, thisThread); controlList = controlList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitBend { arg port, chan, val; var event; event = MIDIEvent(\bend, port, chan, val, nil, thisThread); bendList = bendList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *waitProgram { arg port, chan, num; var event; event = MIDIEvent(\program, port, chan, num, nil, thisThread); programList = programList.add(event); // add to waiting list nil.yield; // pause the thread. ^event } *doAction { arg src, status, a, b, c; action.value(src, status, a, b, c); } *doNoteOnAction { arg src, chan, num, veloc; if ( noteOnZeroAsNoteOff and: ( veloc == 0 ) ){ noteOff.value(src, chan, num, veloc); this.prDispatchEvent(noteOffList, \noteOff, src, chan, num, veloc); }{ noteOn.value(src, chan, num, veloc); this.prDispatchEvent(noteOnList, \noteOn, src, chan, num, veloc); }; } *doNoteOffAction { arg src, chan, num, veloc; noteOff.value(src, chan, num, veloc); this.prDispatchEvent(noteOffList, \noteOff, src, chan, num, veloc); } *doPolyTouchAction { arg src, chan, num, val; polytouch.value(src, chan, num, val); this.prDispatchEvent(polyList, \poly, src, chan, num, val); } *doControlAction { arg src, chan, num, val; control.value(src, chan, num, val); this.prDispatchEvent(controlList, \control, src, chan, num, val); } *doProgramAction { arg src, chan, val; program.value(src, chan, val); this.prDispatchEvent(programList, \program, src, chan, val); } *doTouchAction { arg src, chan, val; touch.value(src, chan, val); this.prDispatchEvent(touchList, \touch, src, chan, val); } *doBendAction { arg src, chan, val; bend.value(src, chan, val); this.prDispatchEvent(bendList, \bend, src, chan, val); } *doSysexAction { arg src, packet; sysexPacket = sysexPacket ++ packet; if (packet.last == -9, { sysex.value(src, sysexPacket); sysexPacket = nil }); } *doInvalidSysexAction { arg src, packet; invalid.value(src, packet); } *doSysrtAction { arg src, index, val; sysrt.value(src, index, val); } *doSMPTEaction { arg src, frameRate, timecode; smpte.value(src, frameRate, timecode); } *findPort { arg deviceName,portName; ^MIDIClient.sources.detect({ |endPoint| endPoint.device == deviceName and: {endPoint.name == portName}}); } *disconnectAll { if(MIDIClient.initialized,{ MIDIClient.externalSources.do({ |src,i| MIDIIn.disconnect(i,src); }); }); } *connectAll { |verbose=true| if(MIDIClient.initialized.not, { MIDIClient.init(verbose: verbose) }, { MIDIIn.disconnectAll; MIDIClient.list; } ); MIDIClient.externalSources.do({ |src,i| MIDIIn.connect(i,src); }); } *connect { arg inport=0, device=0; var uid,source; if(MIDIClient.initialized.not,{ MIDIClient.init }); if(device.isNumber, { if(device >= 0, { if ( device > MIDIClient.sources.size,{ // on linux the uid's are very large numbers source = MIDIClient.sources.detect{ |it| it.uid == device }; if(source.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = source.uid; }) },{ source = MIDIClient.sources.at(device); if(source.isNil,{ "MIDIClient failed to init".warn; },{ uid = MIDIClient.sources.at(device).uid; }); }); },{ // elsewhere they tend to be negative uid = device; }); },{ if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); // else error }); this.connectByUID(inport,uid); } *disconnect { arg inport=0, device=0; var uid, source; if(device.isKindOf(MIDIEndPoint), {uid = device.uid}); if(device.isNumber, { if(device.isPositive, { if ( device > MIDIClient.sources.size, { source = MIDIClient.sources.select{ |it| it.uid == device }.first; if(source.isNil,{ ("MIDI device with uid"+device+ "not found").warn; },{ uid = source.uid; }) }, { source = MIDIClient.sources.at(device); if(source.isNil,{ "MIDIClient failed to init".warn; },{ uid = MIDIClient.sources.at(device).uid; }); }); },{ uid = device; }); }); this.disconnectByUID(inport,uid); } *connectByUID {arg inport, uid; _ConnectMIDIIn ^this.primitiveFailed; } *disconnectByUID {arg inport, uid; _DisconnectMIDIIn ^this.primitiveFailed; } *prDispatchEvent { arg eventList, status, port, chan, b, c; var selectedEvents; eventList ?? {^this}; eventList.takeThese {| event | if (event.match(port, chan, b, c)) { selectedEvents = selectedEvents.add(event); true } { false }; }; selectedEvents.do{ |event| event.set(status, port, chan, b, c); event.thread.next; } } } MIDIOut { var <>port, <>uid, <>latency=0.2; *new { arg port, uid; if(thisProcess.platform.name != \linux) { ^super.newCopyArgs(port, uid ?? { MIDIClient.destinations[port].uid }); } { ^super.newCopyArgs(port, uid ?? 0 ); } } *newByName { arg deviceName,portName,dieIfNotFound=true; var endPoint,index; endPoint = MIDIClient.destinations.detect({ |ep,epi| index = epi; ep.device == deviceName and: {ep.name == portName} }); if(endPoint.isNil,{ if(dieIfNotFound,{ Error("Failed to find MIDIOut port " + deviceName + portName).throw; },{ ("Failed to find MIDIOut port " + deviceName + portName).warn; }); }); if(thisProcess.platform.name != \linux) { ^this.new(index,endPoint.uid) } { if (index < MIDIClient.myoutports){ ^this.new(index,endPoint.uid) } { ^this.new(0,endPoint.uid) } } } *findPort { arg deviceName,portName; ^MIDIClient.destinations.detect({ |endPoint| endPoint.device == deviceName and: {endPoint.name == portName}}); } write { arg len, hiStatus, loStatus, a=0, b=0; this.send(port, uid, len, hiStatus, loStatus, a, b, latency); } noteOn { arg chan, note=60, veloc=64; this.write(3, 16r90, chan.asInteger, note.asInteger, veloc.asInteger); } noteOff { arg chan, note=60, veloc=64; this.write(3, 16r80, chan.asInteger, note.asInteger, veloc.asInteger); } polyTouch { arg chan, note=60, val=64; this.write(3, 16rA0, chan.asInteger, note.asInteger, val.asInteger); } control { arg chan, ctlNum=7, val=64; this.write(3, 16rB0, chan.asInteger, ctlNum.asInteger, val.asInteger); } program { arg chan, num=1; this.write(2, 16rC0, chan.asInteger, num.asInteger); } touch { arg chan, val=64; this.write(2, 16rD0, chan.asInteger, val.asInteger); } bend { arg chan, val=8192; val = val.asInteger; this.write(3, 16rE0, chan, val bitAnd: 127, val >> 7); } allNotesOff { arg chan; this.control(chan, 123, 0); } smpte { arg frames=0, seconds=0, minutes=0, hours=0, frameRate = 3; var packet; packet = [frames, seconds, minutes, hours] .asInteger .collect({ arg v, i; [(i * 2 << 4) | (v & 16rF), (i * 2 + 1 << 4) | (v >> 4) ] }); packet = packet.flat; packet.put(7, packet.at(7) | ( frameRate << 1 ) ); packet.do({ arg v; this.write(2, 16rF0, 16r01, v); }); } songPtr { arg songPtr; songPtr = songPtr.asInteger; this.write(4, 16rF0, 16r02, songPtr & 16r7f, songPtr >> 7 & 16r7f); } songSelect { arg song; this.write(3, 16rF0, 16r03, song.asInteger); } midiClock { this.write(1, 16rF0, 16r08); } start { this.write(1, 16rF0, 16r0A); } continue { this.write(1, 16rF0, 16r0B); } stop { this.write(1, 16rF0, 16r0C); } reset { this.write(1, 16rF0, 16r0F); } sysex { arg packet; ^this.prSysex( uid, packet ); } send { arg outport, uid, len, hiStatus, loStatus, a=0, b=0, late; _SendMIDIOut ^this.primitiveFailed; } prSysex { arg uid, packet; _SendSysex ^this.primitiveFailed; } } SuperCollider-Source/SCClassLibrary/Common/Control/MIDIResponder.sc000644 000765 000024 00000014444 12756534416 026324 0ustar00crucialstaff000000 000000 // see MIDIResponder help for all classes on this page MIDIResponder { var <>function,<>swallowEvent=false, <>matchEvent; // for matching ports, channels, and parameters init { arg install; if(this.class.initialized.not,{ this.class.init }); matchEvent.port = matchEvent.port.asMIDIInPortUID; if(install,{this.class.add(this);}); } respond { arg src,chan,num,value; if(this.match(src,chan,num,value),{ this.value(src,chan,num,value) ^swallowEvent }); ^false; } match { arg src,chan,num,value; ^matchEvent.match(src,chan,num,value); } value { arg src,chan,a,b; function.value(src, chan, a, b) } remove { this.class.remove(this) } *removeAll { if(this == MIDIResponder,{ this.allSubclasses.do({ |responderClass| responderClass.removeAll }) },{ this.init }) } } NoteOnResponder : MIDIResponder { classvar presets.size, { presets = presets.add(values); }); presets.put(presetIndex, values); } recall { if (presetIndex < presets.size, { values = presets.at(presetIndex).copy; // set gui elems and synth controls }); } save { presets.writeArchive("server/presets/" ++ name ++ ".scpreset"); } load { var filename; filename = "server/presets/" ++ name ++ ".scpreset"; if (File.exists(filename), { presets = Object.readArchive(filename); }); } start { var msg; isOn = true; msg = ["/s_new", name, id, 0]; values.keysValuesDo({ arg key, value; msg = msg.addAll([key, value]); }); server.addr.sendBundle(nil, msg); } stop { isOn = false; server.sendMsg("/n_set", id, \gate, 0); } } SuperCollider-Source/SCClassLibrary/Common/Control/NetAddr.sc000644 000765 000024 00000013243 12756534416 025235 0ustar00crucialstaff000000 000000 NetAddr { var port, 65535) {// udp max size. args.clumpBundles.do { |item| if(time.notNil) { time = time + 1e-9 }; // make it a nanosecond later this.sendBundle(time, *item) }; } { this.sendBundle(time, *args) } } sync { arg condition, bundles, latency; // array of bundles that cause async action var resp, id; if (condition.isNil) { condition = Condition.new }; if(bundles.isNil) { id = this.makeSyncResponder(condition); this.sendBundle(latency, ["/sync", id]); condition.wait; } { // not sure what the exact size is, but its about 20000 // this relates to what _NetAddr_SendBundle can send if(bundles.bundleSize > 20000/*65515*/) { // 65515 = 65535 - 16 - 4 (sync msg size) bundles.clumpBundles.do { |item| id = this.makeSyncResponder(condition); this.sendBundle(latency, *(item ++ [["/sync", id]])); if(latency.notNil) { latency = latency + 1e-9 }; condition.wait; } } { id = this.makeSyncResponder(condition); this.sendBundle(latency, *(bundles ++ [["/sync", id]])); condition.wait; } }; // maybe needed: a timeout } makeSyncResponder { arg condition; var id = UniqueID.next; var resp; resp = OSCFunc({|msg| if (msg[1] == id) { resp.free; condition.test = true; condition.signal; }; }, '/synced', this); condition.test = false; ^id } isConnected { ^socket.notNil } connect { | disconnectHandler | if (this.isConnected.not) { this.prConnect; connections.put(this, disconnectHandler); }; } disconnect { if (this.isConnected) { this.prDisconnect; this.prConnectionClosed; }; } == { arg that; ^this.compareObject(that, #[\port, \addr]) } hash { ^this.instVarHash(#[\port, \addr]) } // Asymmetric: "that" may be nil or have nil port (wildcards) matches { arg that; ^that.isNil or: { this.isLocal and: { that.isLocal } and: { that.port.isNil or: { this.port == that.port } } } or: { this == that } or: { that.port.isNil and: { this.addr == that.addr } } } isLocal { ^this.class.matchLangIP(this.ip) } ip { ^addr.asIPString } hasBundle { ^false } printOn { | stream | super.printOn(stream); stream << $( << this.ip << ", " << port << $) } storeOn { | stream | super.storeOn(stream); stream << $( << "\"" << this.ip << "\", " << port << $) } // PRIVATE prConnect { _NetAddr_Connect ^this.primitiveFailed; } prDisconnect { _NetAddr_Disconnect ^this.primitiveFailed; } prConnectionClosed { // called when connection is closed either by sclang or by peer socket = nil; connections.removeAt(this).value(this); } recover { ^this } } BundleNetAddr : NetAddr { var bundle; var nodeID, <>server, <>group; var <>isPlaying = false, <>isRunning = false; classvar 0, { result = result.add(["/n_mapn", nodeID] ++ krVals) }); if(arVals.size > 0, { result = result.add(["/n_mapan", nodeID] ++ arVals) }); if(result.size < 2, { result = result.flatten; }); ^result; } mapn { arg ... args; server.sendMsg(48, nodeID, *(args.asControlInput)); //"/n_mapn" } mapnMsg { arg ... args; ^[48, nodeID] ++ args.asControlInput; //"/n_mapn" } set { arg ... args; server.sendMsg(15, nodeID, *(args.asOSCArgArray)); //"/n_set" } setMsg { arg ... args; ^[15, nodeID] ++ args.asOSCArgArray; //"/n_set" } setn { arg ... args; server.sendMsg(*this.setnMsg(*args)); } *setnMsgArgs{ arg ... args; var nargs=List.new; args = args.asControlInput; args.pairsDo { arg control, moreVals; if(moreVals.isArray, { nargs.addAll([control, moreVals.size]++ moreVals); }, { nargs.addAll([control, 1, moreVals]); }); }; ^nargs; } setnMsg { arg ... args; ^[16, nodeID] ++ Node.setnMsgArgs(*args); // "n_setn" } fill { arg controlName, numControls, value ... args; server.sendMsg(17, nodeID, controlName, numControls, value, *(args.asControlInput));//"n_fill" } fillMsg { arg controlName, numControls, value ... args; ^[17, nodeID, controlName, numControls, value] ++ args.asControlInput; //"n_fill" } release { arg releaseTime; server.sendMsg(*this.releaseMsg(releaseTime)) } releaseMsg { arg releaseTime; //assumes a control called 'gate' in the synth if(releaseTime.isNil, { releaseTime = 0.0; }, { releaseTime = -1.0 - releaseTime; }); ^[15, nodeID, \gate, releaseTime] } trace { server.sendMsg(10, nodeID);//"/n_trace" } query { OSCFunc({ arg msg; var cmd, argnodeID, parent, prev, next, isGroup, head, tail; # cmd, argnodeID, parent, prev, next, isGroup, head, tail = msg; // assuming its me ... if(nodeID == argnodeID) Post << if(isGroup == 1, "Group:" , "Synth:") << nodeID << Char.nl << "parent : " << parent << Char.nl << "prev : " << prev << Char.nl << "next :" << next << Char.nl; if(isGroup==1, { Post << "head :" << head << Char.nl << "tail :" << tail << Char.nl << Char.nl; }); }, '/n_info', server.addr).oneShot; server.sendMsg(46, nodeID) //"/n_query" } register { arg assumePlaying=false; NodeWatcher.register(this, assumePlaying) } onFree { arg func; var f = {|n, m| if(m == \n_end) { func.value(this, m); this.removeDependant(f); } }; this.register; this.addDependant(f); } waitForFree { var c = Condition.new; this.onFree({c.unhang}); c.hang; } moveBefore { arg aNode; group = aNode.group; server.sendMsg(18, nodeID, aNode.nodeID); //"/n_before" } moveAfter { arg aNode; group = aNode.group; server.sendMsg(19, nodeID, aNode.nodeID); //"/n_after" } moveToHead { arg aGroup; (aGroup ? server.defaultGroup).moveNodeToHead(this); } moveToTail { arg aGroup; (aGroup ? server.defaultGroup).moveNodeToTail(this); } // message creating methods moveBeforeMsg { arg aNode; group = aNode.group; ^[18, nodeID, aNode.nodeID];//"/n_before" } moveAfterMsg { arg aNode; group = aNode.group; ^[19, nodeID, aNode.nodeID]; //"/n_after" } moveToHeadMsg { arg aGroup; ^(aGroup ? server.defaultGroup).moveNodeToHeadMsg(this); } moveToTailMsg { arg aGroup; ^(aGroup ? server.defaultGroup).moveNodeToTailMsg(this); } *orderNodesMsg { arg nodes; var msg = [18]; // "/n_after" nodes.doAdjacentPairs { |first, toMoveAfter| msg = msg.add(toMoveAfter.nodeID); msg = msg.add(first.nodeID); }; ^msg } == { arg that; ^this.compareObject(that, #[\nodeID, \server]) } hash { ^this.instVarHash(#[\nodeID, \server]) } printOn { arg stream; stream << this.class.name << "(" << nodeID <<")" } asUGenInput { Error("should not use a % inside a SynthDef".format(this.class.name)).throw } asControlInput { ^this.nodeID } } // common base for Group and ParGroup classes AbstractGroup : Node { /** immediately sends **/ *new { arg target, addAction=\addToHead; var group, server, addNum, inTarget; inTarget = target.asTarget; server = inTarget.server; group = this.basicNew(server); addNum = addActions[addAction]; if((addNum < 2), { group.group = inTarget; }, { group.group = inTarget.group; }); server.sendMsg(this.creationCmd, group.nodeID, addNum, inTarget.nodeID); ^group } newMsg { arg target, addAction = \addToHead; var addNum, inTarget; // if target is nil set to default group of server specified when basicNew was called inTarget = (target ? server.defaultGroup).asTarget; addNum = addActions[addAction]; (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; }); ^[this.class.creationCmd, nodeID, addNum, inTarget.nodeID] } // for bundling addToHeadMsg { arg aGroup; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[this.class.creationCmd, nodeID, 0, group.nodeID] } addToTailMsg { arg aGroup; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[this.class.creationCmd, nodeID, 1, group.nodeID] } addAfterMsg { arg aNode; group = aNode.group; ^[this.class.creationCmd, nodeID, 3, aNode.nodeID] } addBeforeMsg { arg aNode; group = aNode.group; ^[this.class.creationCmd, nodeID, 2, aNode.nodeID] } addReplaceMsg { arg nodeToReplace; group = nodeToReplace.group; ^[this.class.creationCmd, nodeID, 4, nodeToReplace.nodeID] } *after { arg aNode; ^this.new(aNode, \addAfter) } *before { arg aNode; ^this.new(aNode, \addBefore) } *head { arg aGroup; ^this.new(aGroup, \addToHead) } *tail { arg aGroup; ^this.new(aGroup, \addToTail) } *replace { arg nodeToReplace; ^this.new(nodeToReplace, \addReplace) } // move Nodes to this group moveNodeToHead { arg aNode; aNode.group = this; server.sendMsg(22, nodeID, aNode.nodeID) //"/g_head" } moveNodeToTail { arg aNode; aNode.group = this; server.sendMsg(23, nodeID, aNode.nodeID) //"/g_tail" } moveNodeToHeadMsg { arg aNode; aNode.group = this; ^[22, nodeID, aNode.nodeID] //"/g_head" } moveNodeToTailMsg { arg aNode; aNode.group = this; ^[23, nodeID, aNode.nodeID] //g_tail } freeAll { // free my children, but this node is still playing server.sendMsg(24, nodeID) //"/g_freeAll" } freeAllMsg { // free my children, but this node is still playing ^[24, nodeID] //"/g_freeAll" } deepFree { server.sendMsg(50, nodeID) //"/g_deepFree" } deepFreeMsg { ^[50, nodeID] //"/g_deepFree" } // Introspection dumpTree { arg postControls = false; server.sendMsg("/g_dumpTree", nodeID, postControls.binaryValue) } queryTree { //|action| var resp, done = false; resp = OSCFunc({ arg msg; var i = 2, tabs = 0, printControls = false, dumpFunc; if(msg[1] != 0, { printControls = true }); ("NODE TREE Group" + msg[2]).postln; if(msg[3] > 0, { dumpFunc = {|numChildren| var j; tabs = tabs + 1; numChildren.do({ if(msg[i + 1] >=0, {i = i + 2}, { i = i + 3 + if(printControls, { msg[i + 3] * 2 + 1 }, { 0 }); }); tabs.do({ " ".post }); msg[i].post; // nodeID if(msg[i + 1] >= 0, { " group".postln; if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) }); }, { (" " ++ msg[i + 2]).postln; // defname if(printControls, { if(msg[i + 3] > 0, { " ".post; tabs.do({ " ".post }); }); j = 0; msg[i + 3].do({ " ".post; if(msg[i + 4 + j].isMemberOf(Symbol), { (msg[i + 4 + j] ++ ": ").post; }); msg[i + 5 + j].post; j = j + 2; }); "\n".post; }); }); }); tabs = tabs - 1; }; dumpFunc.value(msg[3]); }); // action.value(msg); done = true; }, '/g_queryTree.reply', server.addr).oneShot; server.sendMsg("/g_queryTree", nodeID); SystemClock.sched(3, { if(done.not, { resp.free; "Server failed to respond to Group:queryTree!".warn; }) }) } *creationCmd { ^this.subclassMustImplementThisMethod } } Group : AbstractGroup { *creationCmd { ^21 } //"/g_new" } Synth : Node { var <>defName; /** immediately sends **/ *new { arg defName, args, target, addAction=\addToHead; var synth, server, addNum, inTarget; inTarget = target.asTarget; server = inTarget.server; addNum = addActions[addAction]; synth = this.basicNew(defName, server); if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; }); server.sendMsg(9, //"s_new" defName, synth.nodeID, addNum, inTarget.nodeID, *(args.asOSCArgArray) ); ^synth } *newPaused { arg defName, args, target, addAction=\addToHead; var synth, server, addNum, inTarget; inTarget = target.asTarget; server = inTarget.server; addNum = addActions[addAction]; synth = this.basicNew(defName, server); if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; }); server.sendBundle(nil, [9, defName, synth.nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray, [12, synth.nodeID, 0]); // "s_new" + "/n_run" ^synth } *replace { arg nodeToReplace, defName, args, sameID=false; var synth, server, addNum, inTarget, newNodeID; if (sameID) { newNodeID = nodeToReplace.nodeID }; server = nodeToReplace.server; synth = this.basicNew(defName, server, newNodeID); server.sendMsg(9, //"s_new" defName, synth.nodeID, 4, // addReplace nodeToReplace.nodeID, *(args.asOSCArgArray) ); ^synth } // does not send (used for bundling) *basicNew { arg defName, server, nodeID; ^super.basicNew(server, nodeID).defName_(defName.asDefName) } newMsg { arg target, args, addAction = \addToHead; var addNum, inTarget; addNum = addActions[addAction]; // if target is nil set to default group of server specified when basicNew was called inTarget = (target ? server.defaultGroup).asTarget; (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; }); ^[9, defName, nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray //"/s_new" } *after { arg aNode, defName, args; ^this.new(defName, args, aNode, \addAfter) } *before { arg aNode, defName, args; ^this.new(defName, args, aNode, \addBefore) } *head { arg aGroup, defName, args; ^this.new(defName, args, aGroup, \addToHead) } *tail { arg aGroup, defName, args; ^this.new(defName, args, aGroup, \addToTail) } replace { arg defName, args, sameID; ^this.class.replace(this, defName, args, sameID) } // for bundling addToHeadMsg { arg aGroup, args; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[9, defName, nodeID, 0, group.nodeID] ++ args.asOSCArgArray // "/s_new" } addToTailMsg { arg aGroup, args; // if aGroup is nil set to default group of server specified when basicNew was called group = (aGroup ? server.defaultGroup); ^[9, defName, nodeID, 1, group.nodeID] ++ args.asOSCArgArray // "/s_new" } addAfterMsg { arg aNode, args; group = aNode.group; ^[9, defName, nodeID, 3, aNode.nodeID] ++ args.asOSCArgArray // "/s_new" } addBeforeMsg { arg aNode, args; group = aNode.group; ^[9, defName, nodeID, 2, aNode.nodeID] ++ args.asOSCArgArray // "/s_new" } addReplaceMsg { arg nodeToReplace, args; group = nodeToReplace.group; ^[9, defName, nodeID, 4, nodeToReplace.nodeID] ++ args.asOSCArgArray // "/s_new" } // nodeID -1 *grain { arg defName, args, target, addAction=\addToHead; var server; target = target.asTarget; server = target.server; server.sendMsg(9, defName.asDefName, -1, addActions[addAction], target.nodeID, *(args.asOSCArgArray)); //"/s_new" ^nil } get { arg index, action; OSCpathResponder(server.addr, ['/n_set', nodeID, index], { arg time, r, msg; action.value(msg.at(3)); r.remove }).add; server.sendMsg(44, nodeID, index) //"/s_get" } getMsg { arg index; ^[44, nodeID, index] //"/s_get" } getn { arg index, count, action; OSCpathResponder(server.addr, ['/n_setn', nodeID, index], {arg time, r, msg; action.value(msg.copyToEnd(4)); r.remove } ).add; server.sendMsg(45, nodeID, index, count) //"/s_getn" } getnMsg { arg index, count; ^[45, nodeID, index, count] //"/s_getn" } seti { arg ... args; // args are [key, index, value, key, index, value ...] var msg = Array.new(args.size div: 3 * 2); var synthDesc = SynthDescLib.at(defName.asSymbol); if(synthDesc.isNil) { "message seti failed, because SynthDef % was not added.".format(defName).warn; ^this }; forBy(0, args.size-1, 3, { |i| var key = args[i], offset = args[i+1], value = args[i+2]; var controlName = synthDesc.controlDict[key]; if(controlName.notNil and: { offset < controlName.numChannels }) { msg.add(controlName.index+offset); if(value.isArray) { msg.add(value.keep(controlName.numChannels - offset)) } { msg.add(value) } } }); server.sendMsg("/n_set", nodeID, *msg.asOSCArgArray) } printOn { arg stream; stream << this.class.name << "(" <<< defName << " : " << nodeID <<")" } } RootNode : Group { classvar name; *new { arg node,index; ^super.newCopyArgs(node,index) } value_ { arg aval; node.set(index,aval) } readFromBus { arg bus; node.map(index,bus) } stopReadFromBus { node.map(index,-1) } setMsg { arg value; ^[15, node.nodeID,index, value] } server { ^node.server } group { ^node.group } } SuperCollider-Source/SCClassLibrary/Common/Control/NodeWatcher.sc000644 000765 000024 00000010706 12756534416 026120 0ustar00crucialstaff000000 000000 //watches a server address for node-related messages AbstractNodeWatcher { var all; *initClass { all = IdentityDictionary.new; CmdPeriod.add(this); ServerBoot.add(this); ServerQuit.add(this); } *cmdPeriod { all.do { arg item; item.clear } } *doOnServerQuit {|aServer| this.doOnServerBoot(aServer) } *doOnServerBoot {|aServer| var serverName = aServer.name; var serverNodeWatchers = all.removeAt(serverName); if (serverNodeWatchers.notNil) { serverNodeWatchers.clear } } *newFrom { arg server; var res; res = all.at(server.name); if(res.isNil, { res = this.new(server); res.start; all.put(server.name, res) }); ^res } *register { arg node, assumePlaying=false; var watcher; watcher = this.newFrom(node.server); watcher.register(node, assumePlaying); } *unregister { arg node; var watcher; watcher = this.newFrom(node.server); watcher.unregister(node); } cmds { ^#["/n_go", "/n_end", "/n_off", "/n_on"] } respond { arg method, msg; var node, group; node = nodes.at(msg.at(1)); if(node.notNil, { group = nodes.at(msg.at(2)); this.performList(method, node, group) }) } clear { // we must copy 'nodes' // b/c a /n_end dependant might add or remove nodes // from the collection // NEVER iterate over a collection that might change nodes.copy.do({ arg node; node.isPlaying = false; node.isRunning = false; node.changed(\n_end); }); nodes = IdentityDictionary.new } register { arg node, assumePlaying=false; if(server.serverRunning.not) { nodes.removeAll; ^this }; if(isWatching) { if(assumePlaying and: { nodes.at(node.nodeID).isNil }) { node.isPlaying = true }; nodes.put(node.nodeID, node); }; } unregister { arg node; nodes.removeAt(node.nodeID); } //////////////private implementation////////////// n_go { arg node; node.isPlaying = true; node.isRunning = true; node.changed(\n_go); // notify all the node's dependents of the change } n_end { arg node; this.unregister(node); node.isPlaying = false; node.isRunning = false; node.changed(\n_end); } n_off { arg node; node.isRunning = false; node.changed(\n_off); } n_on { arg node; node.isRunning = true; node.changed(\n_on); } } DebugNodeWatcher : BasicNodeWatcher { cmds { ^#["/n_go", "/n_end", "/n_off", "/n_on"] } //////////////private implementation////////////// doPost { arg action, nodeID, groupID, prevID, nextID; Post << ("[ server: " + server.name + "]" + action + nodeID + "in group" + groupID + "between nodes" + prevID + "and" + nextID ) << Char.nl } n_go { arg nodeID, groupID, prevID, nextID; this.doPost("started", nodeID, groupID, prevID, nextID); nodes.add(nodeID); } n_end { arg nodeID, groupID, prevID, nextID; nodes.remove(nodeID); this.doPost("ended", nodeID, groupID, prevID, nextID); } n_off { arg nodeID, groupID, prevID, nextID; this.doPost("turned off", nodeID, groupID, prevID, nextID); } n_on { arg nodeID, groupID, prevID, nextID; this.doPost("turned on", nodeID, prevID, nextID); } } SuperCollider-Source/SCClassLibrary/Common/Control/OSC.sc000644 000765 000024 00000013100 12756534416 024330 0ustar00crucialstaff000000 000000 // this is probably not working anymore. see NetAddr.sc instead for the newer way. /* // Open Sound Control support OSCNode { classvar <>sc; // this contains the "/sc" default behaviour for all input ports. // a not-very-secure password for access to the compiler // setting password to a Symbol opens SC to potential hacking classvar <>password; var children, <>function, <>value, oscNode; *closeAll { if (openPorts.notNil, { openPorts.copy.do({ arg port; port.close; }); }); } close { openPorts.remove(this); this.prClose; } // PRIVATE prClose { _OSCPort_Close ^this.primitiveFailed; } addOpenPort { if (openPorts.isNil, { openPorts = Array.new(4); }); openPorts = openPorts.add(this); } } OSCInPort : OSCPort { // UDP port for incoming OSC messages *new { arg portID, oscNode; ^super.new.init(portID, oscNode) } reply { arg oscAddress ... args; _OSCInPort_Reply ^this.primitiveFailed; } // PRIVATE init { arg argPortID, argOSCNode; portID = argPortID; oscNode = argOSCNode; this.addOpenPort; this.prInit } prInit { _OSCInPort_Init ^this.primitiveFailed; } } OSCOutPort : OSCPort { // UDP port for outgoing OSC messages var cmdPathIndices; var <>pathResponders; var <>maxPathSize = 0; *new { arg addr, cmdName, action, pathSize; ^super.new(addr, cmdName, action).initPathSize(pathSize); } initPathSize { arg pathSize; maxPathSize = pathSize; pathResponders = Set.new; } value { arg time, msg; var cmdPath, match, responder; super.value(time, msg); if (maxPathSize.notNil, { cmdPath = [cmdName] ++ msg[1..maxPathSize]; responder = OSCpathResponder(addr, cmdPath); match = pathResponders.findMatch(responder); if (match.notNil, { match.value(time, msg); }); (maxPathSize - 1).do({ arg i; responder.path.removeAt(responder.path.size - 1); match = pathResponders.findMatch(responder); if (match.notNil, { match.value(time, msg); }); }); }); } addChild { arg responder; var old; old = pathResponders.findMatch(responder); if(old.notNil,{ pathResponders.remove(old) }); pathResponders.add(responder); if(responder.path.size > maxPathSize) { maxPathSize = responder.path.size }; } removeChild { arg responder; pathResponders.remove(responder); if(responder.path.size == maxPathSize) { maxPathSize = pathResponders.maxValue({ |resp| resp.path.size }) ? 0; }; if(this.isEmpty) { this.remove }; } isEmpty { ^(nodes.size + pathResponders.size) == 0 } } OSCpathResponder : OSCresponder { var <>path; var <>dispatcher; *new { arg addr, cmdPath, action; var cmdName, path; #cmdName ...path = cmdPath; ^super.new(addr, cmdName, action).path_(path); } findDispatcher { var responder, match, pathIndices; responder = OSCpathDispatcher(addr, cmdName, nil, path.size); match = OSCresponder.all.findMatch(responder); if(match.isNil, { ^responder.add }); if (match.class === OSCresponder, { match.remove; responder.nodes_([match]); ^responder.add }); if (match.class === OSCMultiResponder, { match.remove; responder.nodes_(match.nodes); ^responder.add; }); ^match; } add { dispatcher = this.findDispatcher; dispatcher.addChild(this); } remove { dispatcher.removeChild(this); } == { arg that; ^that respondsTo: \path and: { path == that.path } } hash { ^path.hash } } /* ( var s, commandpath, response, aSynth, nodeID, triggerID; s = Server.local; s.boot; triggerID = 1; aSynth = {arg freq = 1, triggerID = 1; SendTrig.kr(SinOsc.kr(freq), triggerID, 666); }.play; nodeID = aSynth.nodeID; commandpath = ['/tr', nodeID, triggerID]; response = { arg time, responder, message; message.postln }; o = OSCpathResponder(s.addr, commandpath, response); o.add; ) o.remove ( var s, commandpath, response, aSynth, nodeID, triggerID; s = Server.local; commandpath = ['/tr', nil, triggerID]; response = { arg time, responder, message; message.postln }; o = OSCpathResponder(s.addr, commandpath, response); o.add; ) */ SuperCollider-Source/SCClassLibrary/Common/Control/OSCresponder.sc000644 000765 000024 00000005304 12756534416 026261 0ustar00crucialstaff000000 000000 OSCresponder { classvar <>all; var <>addr, action; var nodes; value { arg time, msg, addr; var iterlist; iterlist = nodes.copy; iterlist.do({ arg node; node.value(time, msg, addr) }); } isEmpty { ^nodes.size == 0 } } OSCresponderNode : OSCresponder { var func; value { this.subclassResponsibility(thisMethod) } valueArray {arg args; ^this.value(*args) } // needed to work in FunctionLists } ///////////////////// OSC OSCMessageDispatcher : AbstractWrappingDispatcher { wrapFunc {|funcProxy| var func, srcID, recvPort, argTemplate; func = funcProxy.func; srcID = funcProxy.srcID; recvPort = funcProxy.recvPort; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = OSCArgsMatcher(argTemplate, func)}); ^case( { srcID.notNil && recvPort.notNil }, { OSCFuncBothMessageMatcher(srcID, recvPort, func) }, { srcID.notNil }, { OSCFuncAddrMessageMatcher(srcID, func) }, { recvPort.notNil }, { OSCFuncRecvPortMessageMatcher(recvPort, func) }, { func } ); } getKeysForFuncProxy {|funcProxy| ^[funcProxy.path];} value {|msg, time, addr, recvPort| active[msg[0]].value(msg, time, addr, recvPort);} register { thisProcess.addOSCRecvFunc(this); registered = true; } unregister { thisProcess.removeOSCRecvFunc(this); registered = false; } typeKey { ^('OSC unmatched').asSymbol } } OSCMessagePatternDispatcher : OSCMessageDispatcher { value {|msg, time, addr, recvPort| var pattern; pattern = msg[0]; active.keysValuesDo({|key, func| if(key.matchOSCAddressPattern(pattern), {func.value(msg, time, addr, recvPort);}); }) } typeKey { ^('OSC matched').asSymbol } } OSCFunc : AbstractResponderFunc { classvar <>defaultDispatcher, <>defaultMatchingDispatcher, traceFunc, traceRunning = false; var messageType; *new {|messageType| ^super.new.messageType_(messageType) } getKeysForFuncProxy {|funcProxy| ^(funcProxy.msgNum ? (0..127)).asArray;} // noteNum, etc. value {|src, chan, num, val| active[num].value(val, num, chan, src);} register { MIDIIn.perform(messageType.asSetter, MIDIIn.perform(messageType.asGetter).addFunc(this)); registered = true; } unregister { MIDIIn.perform(messageType.asSetter, MIDIIn.perform(messageType.asGetter).removeFunc(this)); registered = false; } // wrapper objects based on arg type and testing requirements wrapFunc {|funcProxy| var func, chan, srcID, argTemplate; func = funcProxy.func; chan = funcProxy.chan; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^case( { srcID.notNil && chan.isArray }, {MIDIFuncBothCAMessageMatcher(chan, srcID, func)}, { srcID.notNil && chan.notNil }, {MIDIFuncBothMessageMatcher(chan, srcID, func)}, { srcID.notNil }, {MIDIFuncSrcMessageMatcher(srcID, func)}, { chan.isArray }, {MIDIFuncChanArrayMessageMatcher(chan, func)}, { chan.notNil }, {MIDIFuncChanMessageMatcher(chan, func)}, { func } ); } typeKey { ^('MIDI ' ++ messageType).asSymbol } } // for \touch, \program, \bend MIDIMessageDispatcherNV : MIDIMessageDispatcher { getKeysForFuncProxy {|funcProxy| ^(funcProxy.chan ? (0..15)).asArray;} // chan value {|src, chan, val| active[chan].value(val, chan, src);} // wrapper objects based on arg type and testing requirements wrapFunc {|funcProxy| var func, chan, srcID, argTemplate; func = funcProxy.func; chan = funcProxy.chan; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^case( { srcID.notNil }, {MIDIFuncSrcMessageMatcherNV(srcID, func)}, { func } ); } } // for \sysex MIDISysexDispatcher : MIDIMessageDispatcher { getKeysForFuncProxy {|funcProxy| ^(funcProxy.srcID ? \all)} value {|srcID, data| active[srcID].value(data, srcID); active[\all].value(data, srcID); } wrapFunc {|funcProxy| var func, srcID, argTemplate; func = funcProxy.func; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^func; } } // sysrt with data MIDISysDataDispatcher : MIDIMessageDispatcher { register { var hook; // select the correct low-level hook. hook = switch(messageType, \sysex, {\sysex}, \mtcQF, {\smpte}, {\sysrt} ); MIDIIn.perform(hook.asSetter, MIDIIn.perform(hook.asGetter).addFunc(this)); registered = true; } unregister { var hook; // select the correct low-level hook. hook = switch(messageType, \sysex, {\sysex}, \mtcQF, {\smpte}, {\sysrt} ); MIDIIn.perform(hook.asSetter, MIDIIn.perform(hook.asGetter).removeFunc(this)); registered = false; } getKeysForFuncProxy {|funcProxy| ^(funcProxy.msgNum ? (0..15)).asArray;} // noteNum, etc. value {|srcID, index, data| active[index].value(data, srcID, index); } wrapFunc {|funcProxy| var func, srcID, argTemplate; func = funcProxy.func; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); ^case( { srcID.notNil }, {MIDIFuncSrcSysMessageMatcherND(srcID, func)}, { func } ); } } MIDISysDataDropIndDispatcher : MIDISysDataDispatcher { value {|srcID, index, data| active[index].value(data, srcID); } } MIDISysNoDataDispatcher : MIDISysDataDispatcher { value {|srcID, index| active[index].value(srcID); } wrapFunc {|funcProxy| var func, srcID; func = funcProxy.func; srcID = funcProxy.srcID; ^case( { srcID.notNil }, {MIDIFuncSrcSysMessageMatcher(srcID, func)}, { func } ); } } MIDIMTCtoSMPTEDispatcher : MIDISysexDispatcher { value {|srcID, index, data| active[srcID].value(srcID, index, data); active[\all].value(srcID, index, data); } wrapFunc {|funcProxy| var func, srcID, argTemplate; func = funcProxy.func; srcID = funcProxy.srcID; argTemplate = funcProxy.argTemplate; if(argTemplate.notNil, { func = MIDIValueMatcher(argTemplate, func)}); func = MIDISMPTEAssembler(func); ^func; } } // thanks to nescivi for code from MTC class!! MIDISMPTEAssembler : AbstractMessageMatcher { var defaultDispatchers, traceFuncs, traceRunning = false, sysIndices; var 1, \songPosition->2, \songSelect->3, \tuneRequest->6, \midiClock->8, \tick->9, \start->10, \continue->11, \stop->12, \activeSense->14, \reset->15]; [\noteOn, \noteOff, \control, \polytouch].do({|type| defaultDispatchers[type] = MIDIMessageDispatcher(type); traceFuncs[type] = {|src, chan, num, val| "MIDI Message Received:\n\ttype: %\n\tsrc: %\n\tchan: %\n\tnum: %\n\tval: %\n\n".postf(type, src, chan, num, val); }; }); [\sysex].do({|type| defaultDispatchers[type] = MIDISysexDispatcher(type); traceFuncs[type] = {|src, data| "MIDI Message Received:\n\ttype: %\n\tsrc: %\n\tdata: %\n\n".postf(type, src, data); }; }); [\mtcQF].do({|type| defaultDispatchers[type] = MIDISysDataDispatcher(type); traceFuncs[type] = {|src, ind, data| "MIDI Message Received:\n\ttype: %\n\tindex: %\n\tsrc: %\n\tdata: %\n\n".postf(type, ind, src, data); }; }); [\smpte].do({|type| defaultDispatchers[type] = MIDIMTCtoSMPTEDispatcher(type); /* traceFuncs[type] = {|src, ind, data| "MIDI Message Received:\n\ttype: %\n\tsrc: %\n\tdata: %\n\n".postf(type, src, data); };*/ // unneeded? Just trace raw MTC }); [\songPosition, \songSelect].do({|type| defaultDispatchers[type] = MIDISysDataDropIndDispatcher(type); traceFuncs[type] = {|src, ind, data| if(ind == sysIndices[type], { "MIDI Message Received:\n\ttype: %\n\tsrc: %\n\tdata: %\n\n".postf(type, src, data); }); }; }); [\sysrt].do({|type| defaultDispatchers[type] = MIDISysDataDispatcher(type); traceFuncs[type] = {|src, ind, data| "MIDI Message Received:\n\ttype: %\n\tindex: %\n\tsrc: %\n\tdata: %\n\n".postf(type, ind, src, data); };// maybe unneeded }); [\tuneRequest, \midiClock, \tick, \start, \continue, \stop, \activeSense, \reset].do({|type| defaultDispatchers[type] = MIDISysNoDataDispatcher(type); traceFuncs[type] = {|src, ind| if(ind == sysIndices[type], { "MIDI Message Received:\n\ttype: %\n\tsrc: %\n\n".postf(type, src); }); }; }); [\touch, \program, \bend].do({|type| defaultDispatchers[type] = MIDIMessageDispatcherNV(type); traceFuncs[type] = {|src, chan, num| "MIDI Message Received:\n\ttype: %\n\tsrc: %\n\tchan: %\n\tnum: %\n\n".postf(type, src, chan, num); }; }); } *trace {|bool = true| if(bool, { if(traceRunning.not, { [\noteOn, \noteOff, \control, \polytouch, \touch, \program, \bend, \sysex].do({|type| MIDIIn.addFuncTo(type, traceFuncs[type]); }); [\tuneRequest, \midiClock, \tick, \start, \continue, \stop, \activeSense, \reset, \songPosition, \songSelect].do({|type| MIDIIn.addFuncTo(\sysrt, traceFuncs[type]); }); [\mtcQF].do({|type| MIDIIn.addFuncTo(\smpte, traceFuncs[type]); }); CmdPeriod.add(this); traceRunning = true; }); }, { [\noteOn, \noteOff, \control, \polytouch, \touch, \program, \bend, \sysex].do({|type| MIDIIn.removeFuncFrom(type, traceFuncs[type]); }); [\tuneRequest, \midiClock, \tick, \start, \continue, \stop, \activeSense, \reset, \songPosition, \songSelect].do({|type| MIDIIn.removeFuncFrom(\sysrt, traceFuncs[type]); }); [\mtcQF].do({|type| MIDIIn.removeFuncFrom(\smpte, traceFuncs[type]); }); CmdPeriod.remove(this); traceRunning = false; }); } *cmdPeriod { this.trace(false) } *new { arg func, msgNum, chan, msgType, srcID, argTemplate, dispatcher; ^super.new.init(func, msgNum, chan, msgType, srcID, argTemplate, dispatcher ? defaultDispatchers[msgType]); } *cc { arg func, ccNum, chan, srcID, argTemplate, dispatcher; ^this.new(func, ccNum, chan, \control, srcID, argTemplate, dispatcher); } *noteOn { arg func, noteNum, chan, srcID, argTemplate, dispatcher; ^this.new(func, noteNum, chan, \noteOn, srcID, argTemplate, dispatcher); } *noteOff { arg func, noteNum, chan, srcID, argTemplate, dispatcher; ^this.new(func, noteNum, chan, \noteOff, srcID, argTemplate, dispatcher); } *polytouch { arg func, noteNum, chan, srcID, argTemplate, dispatcher; ^this.new(func, noteNum, chan, \polytouch, srcID, argTemplate, dispatcher); } *touch { arg func, chan, srcID, argTemplate, dispatcher; ^this.new(func, nil, chan, \touch, srcID, argTemplate, dispatcher); } *bend { arg func, chan, srcID, argTemplate, dispatcher; ^this.new(func, nil, chan, \bend, srcID, argTemplate, dispatcher); } *program { arg func, chan, srcID, argTemplate, dispatcher; ^this.new(func, nil, chan, \program, srcID, argTemplate, dispatcher); } ///// system messages *sysex { arg func, srcID, argTemplate, dispatcher; ^this.new(func, nil, nil, \sysex, srcID, argTemplate, dispatcher); } // system common // does this need to be registered on the SMPTE hook? Yes! *mtcQuarterFrame {arg func, srcID, argTemplate, dispatcher; ^this.new(func, nil, nil, \mtcQF, srcID, argTemplate, dispatcher); // actually index 1 sysrt, but on smpte hook } *smpte {arg func, srcID, argTemplate, dispatcher; ^this.new(func, nil, nil, \smpte, srcID, argTemplate, dispatcher); // actually index 1 sysrt, but on smpte hook } *songPosition {arg func, srcID, argTemplate, dispatcher; ^this.new(func, 2, nil, \songPosition, srcID, argTemplate, dispatcher); } *songSelect {arg func, srcID, argTemplate, dispatcher; ^this.new(func, 3, nil, \songSelect, srcID, argTemplate, dispatcher); } *tuneRequest {arg func, srcID, dispatcher; ^this.new(func, 6, nil, \tuneRequest, srcID, nil, dispatcher); } *midiClock {arg func, srcID, dispatcher; ^this.new(func, 8, nil, \midiClock, srcID, nil, dispatcher); } // system realtime // generic *sysrt { arg func, index, srcID, argTemplate, dispatcher; ^this.new(func, index, nil, \sysrt, srcID, argTemplate, dispatcher); } *tick {arg func, srcID, dispatcher; ^this.new(func, 9, nil, \tick, srcID, nil, dispatcher); } *start {arg func, srcID, dispatcher; ^this.new(func, 10, nil, \start, srcID, nil, dispatcher); } *continue {arg func, srcID, dispatcher; ^this.new(func, 11, nil, \continue, srcID, nil, dispatcher); } *stop {arg func, srcID, dispatcher; ^this.new(func, 12, nil, \stop, srcID, nil, dispatcher); } *activeSense {arg func, srcID, dispatcher; ^this.new(func, 14, nil, \activeSense, srcID, nil, dispatcher); } *reset {arg func, srcID, dispatcher; ^this.new(func, 15, nil, \reset, srcID, nil, dispatcher); } init {|argfunc, argmsgNum, argchan, argType, argsrcID, argtempl, argdisp| msgNum = argmsgNum ? msgNum; msgNum = msgNum.isNumber.if({ msgNum.asInteger }, msgNum); msgNum = msgNum.isCollection.if({ msgNum.collect(_.asInteger) }, msgNum); chan = argchan ? chan; srcID = argsrcID ? srcID; func = argfunc ? func; msgType = argType ? msgType; dispatcher = argdisp ? dispatcher; argTemplate = argtempl ? argTemplate; this.enable; allFuncProxies.add(this); } // swap out func and wait learn {|learnVal = false| // check for cc or noteon? var learnFunc; /*this.remove(func);*/ learnFunc = this.learnFunc(learnVal); this.disable; this.init(learnFunc); // keep old args if specified, so we can learn from particular channels, srcs, etc. } learnFunc {|learnVal| var oldFunc, learnFunc; oldFunc = func; // old funk is ultimately better than new funk if([\control, \noteOn, \noteOff, \polytouch].includes(msgType), { ^{|val, num, chan, srcID| "MIDIFunc learned: type: %\tnum: %\tval: %\tchan: %\tsrcID: %\t\n".postf(msgType, num, val, chan, srcID); this.disable; this.remove(learnFunc); oldFunc.value(val, num, chan, srcID);// do first action this.init(oldFunc, num, chan, msgType, srcID, if(learnVal, val, nil)); } }); // noNum if([\touch, \program, \bend].includes(msgType), { ^{|val, chan, srcID| "MIDIFunc learned: type: %\tval: %\tchan: %\tsrcID: %\t\n".postf(msgType, val, chan, srcID); this.disable; this.remove(learnFunc); oldFunc.value(val, chan, srcID);// do first action this.init(oldFunc, nil, chan, msgType, srcID, if(learnVal, val, nil)); } }); // sys with Data if([\mtcQF, \smpte, \songPosition, \songSelect, \sysrt].includes(msgType), { ^{|val, srcID, index| "MIDIFunc learned: type: %\tnum: %\tval: %\tsrcID: %\t\n".postf(msgType, index, val, srcID); this.disable; this.remove(learnFunc); oldFunc.value(val, srcID, index);// do first action this.init(oldFunc, index, nil, msgType, srcID, if(learnVal, val, nil)); } }); // sys no Data if([\tuneRequest, \midiClock, \tick, \start, \continue, \stop, \activeSense, \reset].includes(msgType), { ^{|srcID, index| "MIDIFunc learned: type: %\tnum: %\tsrcID: %\t\n".postf(msgType, index, srcID); this.disable; this.remove(learnFunc); oldFunc.value(srcID, index);// do first action this.init(oldFunc, index, nil, msgType, srcID, nil); } }); // sysex if(msgType == \sysex, { ^{|val, srcID| "MIDIFunc learned: type: %\tdata: %\tsrcID: %\t\n".postf(msgType, val, srcID); this.disable; this.remove(learnFunc); oldFunc.value(val, srcID);// do first action this.init(oldFunc, nil, nil, msgType, srcID, if(learnVal, val, nil)); } }); "msgType: % not standard, cannot learn".format(msgType).warn; } // post pretty printOn { arg stream; stream << this.class.name << "(" <<* [msgType, msgNum, chan, argTemplate] << ")" } } MIDIdef : MIDIFunc { classvar <>all; // same as other def classes, do we need a setter really? var = 0.0,{ // should we prepare this a few seconds ahead of time ? bundle.send(server,delta,timeOfRequest); }); } } SuperCollider-Source/SCClassLibrary/Common/Control/ScopeBuffer.sc000644 000765 000024 00000002152 12756534416 026114 0ustar00crucialstaff000000 000000 ScopeBuffer { var score, routine, isPlaying = false; classvar <>program, <>options; *initClass { options = ServerOptions.new; } *new { arg list; ^super.new.init(list); } *newFromFile { arg path; var list; list = thisProcess.interpreter.executeFile(path); ^super.new.init(list); } init { arg list; score = [[0.0, ["/g_new", 1, 0, 0]]] ++ list; this.sort; } add { arg bundle; score = score.add(bundle) } *playFromFile { arg path, server; var list; list = thisProcess.interpreter.executeFile(path); ^this.new(list).play(server); } *play { arg list, server; ^this.new(list).play(server); } sort { score = score.sort({ arg a, b; b[0] >= a[0] }); } play { arg server, clock, quant=0.0; var size, osccmd, timekeep, inserver, rout; isPlaying.not.if({ inserver = server ? Server.default; size = score.size; timekeep = 0; routine = Routine({ size.do { |i| var deltatime, msg; osccmd = score[i]; deltatime = osccmd[0]; msg = osccmd.copyToEnd(1); (deltatime-timekeep).wait; inserver.listSendBundle(inserver.latency, msg); timekeep = deltatime; }; isPlaying = false; }); isPlaying = true; routine.play(clock, quant); }, {"Score already playing".warn;} ); } endTime { ^score.last[0] } startTime { ^score.first[0] } section { arg start = 0, end, configevents; var sectionlist; if(end.isNil) { end = this.endTime }; sectionlist = Array.new; score.do { arg item; if(item[0].inclusivelyBetween(start, end)) { item = item.copy; item[0] = item[0] - start; sectionlist = sectionlist.add(item); } }; sectionlist = sectionlist.add([end - start, [0]]); // add dummy command (cmd_none) if(configevents.notNil, {if(configevents.isArray, {if(configevents[0] == 0.0, {sectionlist = sectionlist.addFirst(configevents)}, {"Configuration events should have a timestamp of 0.0".warn; ^nil})}, {"Configuration events need to be a bundle array: [time, [events]]".warn; ^nil})}); ^this.class.new(sectionlist); } writeOSCFile { arg path, from, to, clock; if(to.notNil or: {from.notNil}) { from = from ? 0.0; to = to ? this.endTime; this.section(from, to).write(path, clock) } { this.write(path, clock) }; } recordNRT { arg oscFilePath, outputFilePath, inputFilePath, sampleRate = 44100, headerFormat = "AIFF", sampleFormat = "int16", options, completionString="", duration = nil, action = nil; if(oscFilePath.isNil) { oscFilePath = PathName.tmp +/+ "temp_oscscore" ++ UniqueID.next; }; this.writeOSCFile(oscFilePath, 0, duration); unixCmd(program + " -N" + oscFilePath.quote + if(inputFilePath.notNil, { inputFilePath.quote }, { "_" }) + outputFilePath.quote + sampleRate + headerFormat + sampleFormat + (options ? Score.options).asOptionsString + completionString, action); } *recordNRT { arg list, oscFilePath, outputFilePath, inputFilePath, sampleRate = 44100, headerFormat = "AIFF", sampleFormat = "int16", options, completionString="", duration = nil, action = nil; this.new(list).recordNRT(oscFilePath, outputFilePath, inputFilePath, sampleRate, headerFormat, sampleFormat, options, completionString, duration, action); } stop { isPlaying.if({routine.stop; isPlaying = false; routine = nil;}, {"Score not playing".warn;} ); } *writeFromFile { arg path, oscFilePath, clock; var list; list = thisProcess.interpreter.executeFile(path); this.write(list, oscFilePath, clock); } *write { arg list, oscFilePath, clock; var osccmd, f, tempoFactor; f = File(oscFilePath, "w"); if(f.isOpen.not) { Error("Failed to write OSC score file: Could not open % for writing".format(oscFilePath)).throw; }; tempoFactor = (clock ? TempoClock.default).tempo.reciprocal; protect { list.size.do { |i| var msg = list[i].copy; msg[0] = msg[0]* tempoFactor; osccmd = msg.asRawOSC; f.write(osccmd.size).write(osccmd); }; }{ f.close; }; //"done".postln; } write { arg oscFilePath, clock; this.class.write(score, oscFilePath, clock); } saveToFile { arg path; var f; f = File.new(path, "w"); if(f.isOpen.not) { Error("Failed to write Score to text: Could not open % for writing".format(path)).throw; }; f.putString("[ // SuperCollider Score output " ++ Date.getDate ++ "\n"); score.do{ arg me; f.putString((me).asCompileString ++ ",\n"); }; f.putString("]"); f.close; } storeArgs { ^score } asScore {} } SuperCollider-Source/SCClassLibrary/Common/Control/SerialPort.sc000644 000765 000024 00000005016 12766171707 026000 0ustar00crucialstaff000000 000000 SerialPort { classvar <>devicePattern, allPorts; var dataptr, semaphore; var <>doneAction; *initClass { allPorts = Array[]; ShutDown.add { this.cleanupAll; }; } // device listing *devices { ^(devicePattern ?? { thisProcess.platform.name.switch( \linux, "/dev/tty[A,S,U]*", \osx, "/dev/tty.*", \windows, "COM" ) }).pathMatch } *listDevices { this.devices.do(_.postln); } *new { | port, baudrate(9600), databits(8), stopbit(true), parity(nil), crtscts(false), xonxoff(false) exclusive(false) | if (port.isNumber) { port = this.devices[port] ?? { Error("invalid port index").throw; }; } ^super.new.initSerialPort( port, exclusive, baudrate, databits, stopbit, ( even: 1, odd: 2 ).at(parity) ? 0, crtscts, xonxoff ) } initSerialPort { | ... args | semaphore = Semaphore(0); if ( dataptr.isNil ){ this.prOpen(*args); allPorts = allPorts.add(this); doneAction = { ("SerialPort"+args[0]+"was closed").postln; }; } } isOpen { ^dataptr.notNil } close { if (this.isOpen) { this.prClose; allPorts.remove(this); } } *closeAll { var ports = allPorts; allPorts = Array[]; ports.do(_.close); } *cleanupAll { var ports = allPorts; allPorts = Array[]; ports.do(_.primCleanup); } // non-blocking read next { _SerialPort_Next ^this.primitiveFailed } // blocking read read { var byte; while { (byte = this.next).isNil } { semaphore.wait; }; ^byte } // rx errors since last query rxErrors { _SerialPort_RXErrors ^this.primitiveFailed; } // always blocks put { | byte, timeout=0.005 | if ( dataptr.notNil ){ while { this.prPut(byte).not } { timeout.wait; timeout = timeout * 2; } }{ "SerialPort not open".warn; } } putAll { | bytes, timeout=0.005 | bytes.do { |byte| this.put(byte, timeout); } } // PRIMITIVE prOpen { | ... args | // was: | port, baudRate | but that misses out on all the other args? _SerialPort_Open ^this.primitiveFailed } prClose { _SerialPort_Close ^this.primitiveFailed } primCleanup { // _SerialPort_Cleanup must be called from the AppClock thread. _SerialPort_Cleanup ^this.primitiveFailed } prCleanup{ if (this.isOpen) { allPorts.remove(this); defer({ this.primCleanup }, 0); } } prPut { | byte | _SerialPort_Put ^this.primitiveFailed } prDataAvailable { // callback semaphore.signal; } prDoneAction { // callback this.doneAction.value; // cleanup the port this.prCleanup } } SuperCollider-Source/SCClassLibrary/Common/Control/Server.sc000644 000765 000024 00000061346 13007176140 025153 0ustar00crucialstaff000000 000000 ServerOptions { // order of variables is important here. Only add new instance variables to the end. var numControlBusChannels=16384; var maxNodes=1024; var <>maxSynthDefs=1024; var <>protocol = \udp; var <>blockSize = 64; var <>hardwareBufferSize = nil; var <>memSize = 8192; var <>numRGens = 64; var <>numWireBufs = 64; var <>sampleRate = nil; var <>loadDefs = true; var <>inputStreamsEnabled; var <>outputStreamsEnabled; var <>inDevice = nil; var <>outDevice = nil; var <>verbosity = 0; var <>zeroConf = false; // Whether server publishes port to Bonjour, etc. var <>restrictedPath = nil; var <>ugenPluginsPath = nil; var <>initialNodeID = 1000; var <>remoteControlVolume = false; var <>memoryLocking = false; var <>threads = nil; // for supernova var <>useSystemClock = false; // for supernova var pingsBeforeConsideredDead = 5; var <>maxLogins = 1; device { ^if(inDevice == outDevice) { inDevice } { [inDevice, outDevice] } } device_ { |dev| inDevice = outDevice = dev; } // max logins // session-password // prevent buffer conflicts in Server-prepareForRecord and Server-scope by // ensuring reserved buffers numBuffers { ^numBuffers - 2 } numBuffers_ { | argNumBuffers | numBuffers = argNumBuffers + 2 } asOptionsString { | port = 57110 | var o; o = if (protocol == \tcp, " -t ", " -u "); o = o ++ port; o = o ++ " -a " ++ (numPrivateAudioBusChannels + numInputBusChannels + numOutputBusChannels) ; if (numControlBusChannels != 16384, { o = o ++ " -c " ++ numControlBusChannels; }); if (numInputBusChannels != 8, { o = o ++ " -i " ++ numInputBusChannels; }); if (numOutputBusChannels != 8, { o = o ++ " -o " ++ numOutputBusChannels; }); if (numBuffers != 1024, { o = o ++ " -b " ++ numBuffers; }); if (maxNodes != 1024, { o = o ++ " -n " ++ maxNodes; }); if (maxSynthDefs != 1024, { o = o ++ " -d " ++ maxSynthDefs; }); if (blockSize != 64, { o = o ++ " -z " ++ blockSize; }); if (hardwareBufferSize.notNil, { o = o ++ " -Z " ++ hardwareBufferSize; }); if (memSize != 8192, { o = o ++ " -m " ++ memSize; }); if (numRGens != 64, { o = o ++ " -r " ++ numRGens; }); if (numWireBufs != 64, { o = o ++ " -w " ++ numWireBufs; }); if (sampleRate.notNil, { o = o ++ " -S " ++ sampleRate; }); if (loadDefs.not, { o = o ++ " -D 0"; }); if (inputStreamsEnabled.notNil, { o = o ++ " -I " ++ inputStreamsEnabled ; }); if (outputStreamsEnabled.notNil, { o = o ++ " -O " ++ outputStreamsEnabled ; }); if ((thisProcess.platform.name!=\osx) or: {inDevice == outDevice}) { if (inDevice.notNil, { o = o ++ " -H %".format(inDevice.quote); }); } { o = o ++ " -H % %".format(inDevice.asString.quote, outDevice.asString.quote); }; if (verbosity != 0, { o = o ++ " -V " ++ verbosity; }); if (zeroConf.not, { o = o ++ " -R 0"; }); if (restrictedPath.notNil, { o = o ++ " -P " ++ restrictedPath; }); if (ugenPluginsPath.notNil, { o = o ++ " -U " ++ if(ugenPluginsPath.isString) { ugenPluginsPath } { ugenPluginsPath.join("; "); }; }); if (memoryLocking, { o = o ++ " -L"; }); if (threads.notNil, { if (Server.program.asString.endsWith("supernova")) { o = o ++ " -T " ++ threads; } }); if (useSystemClock.notNil, { o = o ++ " -C " ++ useSystemClock.asInteger }); if (maxLogins.notNil, { o = o ++ " -l " ++ maxLogins; }); ^o } firstPrivateBus { // after the outs and ins ^numOutputBusChannels + numInputBusChannels } bootInProcess { _BootInProcessServer ^this.primitiveFailed } numPrivateAudioBusChannels_ {arg numChannels = 112; numPrivateAudioBusChannels = numChannels; this.recalcChannels; } numAudioBusChannels_ {arg numChannels=1024; numAudioBusChannels = numChannels; numPrivateAudioBusChannels = numAudioBusChannels - numInputBusChannels - numOutputBusChannels; } numInputBusChannels_ {arg numChannels=8; numInputBusChannels = numChannels; this.recalcChannels; } numOutputBusChannels_ {arg numChannels=8; numOutputBusChannels = numChannels; this.recalcChannels; } recalcChannels { numAudioBusChannels = numPrivateAudioBusChannels + numInputBusChannels + numOutputBusChannels; } *prListDevices { arg in, out; _ListAudioDevices ^this.primitiveFailed } *devices { ^this.prListDevices(1, 1); } *inDevices { ^this.prListDevices(1, 0); } *outDevices { ^this.prListDevices(0, 1); } } ServerShmInterface { // order matters! var ptr, finalizer; *new {|port| ^super.new.connect(port) } copy { // never ever copy! will cause duplicate calls to the finalizer! ^this } connect { _ServerShmInterface_connectSharedMem ^this.primitiveFailed } disconnect { _ServerShmInterface_disconnectSharedMem ^this.primitiveFailed } getControlBusValue { _ServerShmInterface_getControlBusValue ^this.primitiveFailed } getControlBusValues { _ServerShmInterface_getControlBusValues ^this.primitiveFailed } setControlBusValue { _ServerShmInterface_setControlBusValue ^this.primitiveFailed } setControlBusValues { _ServerShmInterface_setControlBusValues ^this.primitiveFailed } } Server { classvar <>local, <>internal, named, <>set, <>program, <>sync_s = true; var addr, sendQuit, <>remoteControlled; var <>options, <>latency = 0.2, tree; var scopeWindow; var recHeaderFormat="aiff", <>recSampleFormat="float"; var <>recChannels=2, <>recBufSize; var (options.maxLogins - 1)) { "Client ID exceeds maxLogins. Some buses and buffers may overlap for remote server: %".format(this).warn; }; ^clientID % options.maxLogins; } newScopeBufferAllocators { if (isLocal) { scopeBufferAllocator = StackNumberAllocator.new(0, 127); } } nextNodeID { ^nodeAllocator.alloc } nextPermNodeID { ^nodeAllocator.allocPerm } freePermNodeID { |id| ^nodeAllocator.freePerm(id) } *initClass { Class.initClassTree(ServerOptions); Class.initClassTree(NotificationCenter); named = IdentityDictionary.new; set = Set.new; default = local = Server.new(\localhost, NetAddr("127.0.0.1", 57110)); internal = Server.new(\internal, NetAddr.new); } *fromName { arg name; ^Server.named[name] ?? { Server(name, NetAddr.new("127.0.0.1", 57110), ServerOptions.new) } } // bundling support added sendMsg { arg ... msg; addr.sendMsg(*msg); } sendBundle { arg time ... msgs; addr.sendBundle(time, *msgs) } sendRaw { arg rawArray; addr.sendRaw(rawArray); } sendMsgSync { arg condition ... args; var cmdName, resp; if (condition.isNil) { condition = Condition.new }; cmdName = args[0].asString; if (cmdName[0] != $/) { cmdName = cmdName.insert(0, $/) }; resp = OSCFunc({|msg| if (msg[1].asString == cmdName) { resp.free; condition.test = true; condition.signal; }; }, '/done', addr); condition.test = false; addr.sendBundle(nil, args); condition.wait; } sync { arg condition, bundles, latency; // array of bundles that cause async action addr.sync(condition, bundles, latency) } schedSync { arg func; syncTasks = syncTasks.add(func); if(syncThread.isNil) { syncThread = Routine.run { var c; c = Condition.new; while { syncTasks.notEmpty } { syncTasks.removeAt(0).value(c) }; syncThread = nil; }; }; } // bundling support added listSendMsg { arg msg; addr.sendMsg(*msg); } listSendBundle { arg time, msgs; addr.sendBundle(time, *(msgs.asArray)); } // load from disk locally, send remote sendSynthDef { arg name, dir; var file, buffer; dir = dir ? SynthDef.synthDefDir; file = File(dir ++ name ++ ".scsyndef","r"); if (file.isNil, { ^nil }); protect { buffer = Int8Array.newClear(file.length); file.read(buffer); }{ file.close; }; this.sendMsg("/d_recv", buffer); } // tell server to load from disk loadSynthDef { arg name, completionMsg, dir; dir = dir ? SynthDef.synthDefDir; this.listSendMsg( ["/d_load", dir ++ name ++ ".scsyndef", completionMsg ] ) } //loadDir loadDirectory { arg dir, completionMsg; this.listSendMsg(["/d_loadDir", dir, completionMsg]); } wait { arg responseName; var routine; routine = thisThread; OSCFunc({ routine.resume(true); }, responseName, addr).oneShot; } waitForBoot { arg onComplete, limit=100, onFailure; // onFailure.true: why is this necessary? // this.boot also calls doWhenBooted. // doWhenBooted prints the normal boot failure message. // if the server fails to boot, the failure error gets posted TWICE. // So, we suppress one of them. if(this.serverRunning.not) { this.boot(onFailure: true) }; this.doWhenBooted(onComplete, limit, onFailure); } doWhenBooted { arg onComplete, limit=100, onFailure; statusWatcher.doWhenBooted(onComplete, limit, onFailure) } bootSync { arg condition; condition ?? { condition = Condition.new }; condition.test = false; this.waitForBoot({ // Setting func to true indicates that our condition has become true and we can go when signaled. condition.test = true; condition.signal }); condition.wait; } ping { arg n=1, wait=0.1, func; var result=0, pingFunc; if(statusWatcher.serverRunning.not) { "server not running".postln; ^this }; pingFunc = { Routine.run { var t, dt; t = Main.elapsedTime; this.sync; dt = Main.elapsedTime - t; ("measured latency:" + dt + "s").postln; result = max(result, dt); n = n - 1; if(n > 0) { SystemClock.sched(wait, {pingFunc.value; nil }) } { ("maximum determined latency of" + name + ":" + result + "s").postln; func.value(result) } }; }; pingFunc.value; } cachedBuffersDo { |func| Buffer.cachedBuffersDo(this, func) } cachedBufferAt { |bufnum| ^Buffer.cachedBufferAt(this, bufnum) } inputBus { ^Bus(\audio, this.options.numOutputBusChannels, this.options.numInputBusChannels, this); } outputBus { ^Bus(\audio, 0, this.options.numOutputBusChannels, this); } /* server status */ numUGens { ^statusWatcher.numUGens } numSynths { ^statusWatcher.numSynths } numGroups { ^statusWatcher.numGroups } numSynthDefs { ^statusWatcher.numSynthDefs } avgCPU { ^statusWatcher.avgCPU } peakCPU { ^statusWatcher.peakCPU } sampleRate { ^statusWatcher.sampleRate } actualSampleRate { ^statusWatcher.actualSampleRate } serverRunning { ^statusWatcher.serverRunning } serverBooting { ^statusWatcher.serverBooting } unresponsive { ^statusWatcher.unresponsive } startAliveThread { | delay=0.0 | statusWatcher.startAliveThread(delay) } stopAliveThread { statusWatcher.stopAliveThread } aliveThreadIsRunning { ^statusWatcher.aliveThread.isPlaying } aliveThreadPeriod_ { |val| statusWatcher.aliveThreadPeriod_(val) } aliveThreadPeriod { |val| ^statusWatcher.aliveThreadPeriod } disconnectSharedMemory { if (serverInterface.notNil) { "server '%' disconnected shared memory interface\n".postf(name); serverInterface.disconnect; serverInterface = nil; } } *resumeThreads { set.do { |server| server.statusWatcher.resumeThread } } boot { | startAliveThread=true, recover=false, onFailure | if (statusWatcher.serverRunning) { "server already running".inform; ^this }; if (statusWatcher.serverBooting) { "server already booting".inform; ^this }; statusWatcher.serverBooting = true; if(startAliveThread) { statusWatcher.startAliveThread }; if(recover) { this.newNodeAllocators } { this.newAllocators }; statusWatcher.bootNotifyFirst = true; // unclear what this means. statusWatcher.doWhenBooted({ statusWatcher.serverBooting = false; if (recChannels.notNil and: (recChannels != options.numOutputBusChannels)) { "Resetting recChannels to %".format(options.numOutputBusChannels).inform }; recChannels = options.numOutputBusChannels; if(sendQuit.isNil) { sendQuit = this.inProcess or: {this.isLocal}; }; if(this.inProcess) { serverInterface = ServerShmInterface(thisProcess.pid); } { if(isLocal) { serverInterface = ServerShmInterface(addr.port); } }; if(dumpMode != 0) { this.sendMsg(\dumpOSC, dumpMode) }; this.initTree; }, onFailure: onFailure ? false); if(remoteControlled.not) { "You will have to manually boot remote server.".inform; } { this.bootServerApp; } } bootServerApp { var f; if (inProcess) { "booting internal".inform; this.bootInProcess; pid = thisProcess.pid; } { this.disconnectSharedMemory; pid = (program ++ options.asOptionsString(addr.port)).unixCmd; if( options.protocol == \tcp ){ f = { |attempts| attempts = attempts - 1; try { addr.connect } { |err| if (err.isKindOf(PrimitiveFailedError) and: { err.failedPrimitiveName == '_NetAddr_Connect'}) { if(attempts > 0){ 0.2.wait; f.value(attempts) }{ "Couldn't connect to server % via TCP\n".postf(this.name); } } { err.throw; } } }; fork{ f.(10) } }; ("booting " ++ addr.port.asString).inform; }; } reboot { arg func; // func is evaluated when server is off if (isLocal.not) { "can't reboot a remote server".inform; ^this }; if(statusWatcher.serverRunning) { Routine.run { this.quit; this.wait(\done); 0.1.wait; func.value; defer { this.boot } } } { func.value; this.boot } } status { addr.sendStatusMsg } notify { ^statusWatcher.notify } notify_ { |flag| statusWatcher.notify_(flag) } notified { ^statusWatcher.notified } dumpOSC { arg code=1; /* 0 - turn dumping OFF. 1 - print the parsed contents of the message. 2 - print the contents in hexadecimal. 3 - print both the parsed and hexadecimal representations of the contents. */ dumpMode = code; this.sendMsg(\dumpOSC, code); this.changed(\dumpOSC, code); } quit { |watchShutDown = true| addr.sendMsg("/quit"); statusWatcher.quit(watchShutDown); if( options.protocol == \tcp ){ fork{ 0.1.wait; addr.disconnect } }; // sure? can we receive the above reply? if (inProcess, { this.quitInProcess; "quit done\n".inform; },{ "/quit sent\n".inform; }); pid = nil; sendQuit = nil; if(scopeWindow.notNil) { scopeWindow.quit }; if(volume.isPlaying) { volume.free }; RootNode(this).freeAll; this.newAllocators; } *quitAll { |watchShutDown = true| set.do({ arg server; if (server.sendQuit === true) { server.quit(watchShutDown) }; }) } *killAll { // if you see Exception in World_OpenUDP: unable to bind udp socket // its because you have multiple servers running, left // over from crashes, unexpected quits etc. // you can't cause them to quit via OSC (the boot button) // this brutally kills them all off thisProcess.platform.killAll(this.program.basename); this.quitAll(false); } freeAll { this.sendMsg("/g_freeAll", 0); this.sendMsg("/clearSched"); this.initTree; } *freeAll { arg evenRemote = false; if (evenRemote) { set.do { arg server; if ( server.serverRunning ) { server.freeAll } } } { set.do { arg server; if (server.isLocal and:{ server.serverRunning }) { server.freeAll } } } } *hardFreeAll { arg evenRemote = false; if (evenRemote) { set.do { arg server; server.freeAll } } { set.do { arg server; if (server.isLocal) { server.freeAll } } } } *allRunningServers { ^this.all.select(_.serverRunning) } // bundling support openBundle { arg bundle; // pass in a bundle that you want to // continue adding to, or nil for a new bundle. if(addr.hasBundle) { bundle = addr.bundle.addAll(bundle); addr.bundle = []; // debatable }; addr = BundleNetAddr.copyFrom(addr, bundle); } closeBundle { arg time; // set time to false if you don't want to send. var bundle; if(addr.hasBundle) { bundle = addr.closeBundle(time); addr = addr.saveAddr; } { "there is no open bundle.".warn }; ^bundle; } makeBundle { arg time, func, bundle; this.openBundle(bundle); try { func.value(this); bundle = this.closeBundle(time); }{|error| addr = addr.saveAddr; // on error restore the normal NetAddr error.throw } ^bundle } bind { arg func; ^this.makeBundle(this.latency, func) } // internal server commands bootInProcess { ^options.bootInProcess; } quitInProcess { _QuitInProcessServer ^this.primitiveFailed } allocSharedControls { arg numControls=1024; _AllocSharedControls ^this.primitiveFailed } setSharedControl { arg num, value; _SetSharedControl ^this.primitiveFailed } getSharedControl { arg num; _GetSharedControl ^this.primitiveFailed } // recording output record { |path| if(recordBuf.isNil) { this.prepareForRecord(path); Routine({ this.sync; this.record; }).play; } { if(this.isRecording.not) { recordNode = Synth.tail(RootNode(this), "server-record", [\bufnum, recordBuf.bufnum]); CmdPeriod.doOnce { recordNode = nil; if (recordBuf.notNil) { recordBuf.close {|buf| buf.freeMsg }; recordBuf = nil; }; } } { recordNode.run(true) }; "Recording: %\n".postf(recordBuf.path); }; } isRecording { ^recordNode.isPlaying } pauseRecording { recordNode.notNil.if({ recordNode.run(false); "Paused".postln }, { "Not Recording".warn }); } stopRecording { var recordPath; if(recordNode.notNil) { recordNode.free; recordNode = nil; recordPath = recordBuf.path; recordBuf.close({ |buf| buf.freeMsg }); "Recording Stopped: %\n".postf(recordPath); recordBuf = nil; } { "Not Recording".warn }; } prepareForRecord { arg path; if (path.isNil) { if(File.exists(thisProcess.platform.recordingsDir).not) { thisProcess.platform.recordingsDir.mkdir }; // temporary kludge to fix Date's brokenness on windows if(thisProcess.platform.name == \windows) { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Main.elapsedTime.round(0.01) ++ "." ++ recHeaderFormat; } { path = thisProcess.platform.recordingsDir +/+ "SC_" ++ Date.localtime.stamp ++ "." ++ recHeaderFormat; }; }; recordBuf = Buffer.alloc(this, recBufSize ?? { this.sampleRate.nextPowerOfTwo }, recChannels, {arg buf; buf.writeMsg(path, recHeaderFormat, recSampleFormat, 0, 0, true);}, this.options.numBuffers + 1); // prevent buffer conflicts by using reserved bufnum recordBuf.path = path; SynthDef("server-record", { arg bufnum; DiskOut.ar(bufnum, In.ar(0, recChannels)) }).send(this); } // CmdPeriod support for Server-scope and Server-record and Server-volume cmdPeriod { addr = addr.recover; this.changed(\cmdPeriod); } doOnServerTree { if(scopeWindow.notNil) { scopeWindow.run } } defaultGroup { ^Group.basicNew(this, 1) } queryAllNodes { arg queryControls = false; var resp, done = false; if(isLocal, {this.sendMsg("/g_dumpTree", 0, queryControls.binaryValue);}, { resp = OSCFunc({ arg msg; var i = 2, tabs = 0, printControls = false, dumpFunc; if(msg[1] != 0, {printControls = true}); ("NODE TREE Group" + msg[2]).postln; if(msg[3] > 0, { dumpFunc = {|numChildren| var j; tabs = tabs + 1; numChildren.do({ if(msg[i + 1] >=0, {i = i + 2}, { i = i + 3 + if(printControls, {msg[i + 3] * 2 + 1}, {0}); }); tabs.do({ " ".post }); msg[i].post; // nodeID if(msg[i + 1] >=0, { " group".postln; if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) }); }, { (" " ++ msg[i + 2]).postln; // defname if(printControls, { if(msg[i + 3] > 0, { " ".post; tabs.do({ " ".post }); }); j = 0; msg[i + 3].do({ " ".post; if(msg[i + 4 + j].isMemberOf(Symbol), { (msg[i + 4 + j] ++ ": ").post; }); msg[i + 5 + j].post; j = j + 2; }); "\n".post; }); }); }); tabs = tabs - 1; }; dumpFunc.value(msg[3]); }); done = true; }, '/g_queryTree.reply', addr).oneShot; this.sendMsg("/g_queryTree", 0, queryControls.binaryValue); SystemClock.sched(3, { done.not.if({ resp.free; "Remote server failed to respond to queryAllNodes!".warn; }); }); }) } printOn { |stream| stream << name; } storeOn { arg stream; var codeStr = this.switch ( Server.default, { if (sync_s) { "s" } { "Server.default" } }, Server.local, { "Server.local" }, Server.internal, { "Server.internal" }, { "Server.fromName(" + name.asCompileString + ")" } ); stream << codeStr; } archiveAsCompileString { ^true } archiveAsObject { ^true } volume_ {arg newVolume; volume.volume_(newVolume); } mute { volume.mute; } unmute { volume.unmute; } hasShmInterface { ^serverInterface.notNil } reorder { arg nodeList, target, addAction=\addToHead; target = target.asTarget; this.sendMsg(62, Node.actionNumberFor(addAction), target.nodeID, *(nodeList.collect(_.nodeID))); //"/n_order" } getControlBusValue {|busIndex| if (serverInterface.isNil) { Error("Server-getControlBusValue only supports local servers").throw; } { ^serverInterface.getControlBusValue(busIndex) } } getControlBusValues {|busIndex, busChannels| if (serverInterface.isNil) { Error("Server-getControlBusValues only supports local servers").throw; } { ^serverInterface.getControlBusValues(busIndex, busChannels) } } setControlBusValue {|busIndex, value| if (serverInterface.isNil) { Error("Server-getControlBusValue only supports local servers").throw; } { ^serverInterface.setControlBusValue(busIndex, value) } } setControlBusValues {|busIndex, valueArray| if (serverInterface.isNil) { Error("Server-getControlBusValues only supports local servers").throw; } { ^serverInterface.setControlBusValues(busIndex, valueArray) } } *scsynth { this.program = this.program.replace("supernova", "scsynth") } *supernova { this.program = this.program.replace("scsynth", "supernova") } } SuperCollider-Source/SCClassLibrary/Common/Control/ServerStatus.sc000644 000765 000024 00000012165 13007174002 026345 0ustar00crucialstaff000000 000000 ServerStatusWatcher { var server; var <>notified = false, aliveThreadPeriod = 0.7, statusWatcher; var serverBooting = false, bootNotifyFirst; *new { |server| ^super.newCopyArgs(server) } quit { |watchShutDown = true| if(watchShutDown) { this.watchQuit } { this.stopStatusWatcher }; this.stopAliveThread; notified = false; serverBooting = false; this.serverRunning = false; } notify_ { |flag = true| notify = flag; if(flag){ if(serverRunning){ this.sendNotifyRequest(true); notified = true; "Receiving notification messages from server %\n".postf(server.name); } }{ this.sendNotifyRequest(false); notified = false; "Switched off notification messages from server %\n".postf(server.name); } } sendNotifyRequest { | flag=true | var doneOSCFunc, failOSCFunc; notified = flag; if(server.userSpecifiedClientID.not) { doneOSCFunc = OSCFunc({|msg| if(flag) { server.clientID = msg[2] }; failOSCFunc.free; }, '/done', server.addr, argTemplate:['/notify', nil]).oneShot; failOSCFunc = OSCFunc({|msg| doneOSCFunc.free; Error( "Failed to register with server '%' for notifications: %\n" "To recover, please reboot the server.".format(server.name, msg)).throw; }, '/fail', server.addr, argTemplate:['/notify', nil, nil]).oneShot; }; server.sendMsg("/notify", flag.binaryValue); } doWhenBooted { arg onComplete, limit=100, onFailure; var mBootNotifyFirst = bootNotifyFirst, postError = true; bootNotifyFirst = false; ^Routine { while { ((serverRunning.not or: (serverBooting and: mBootNotifyFirst.not)) and: { (limit = limit - 1) > 0 }) and: { server.pid.tryPerform(\pidRunning) == true } } { 0.2.wait; }; if(serverRunning.not, { if(onFailure.notNil) { postError = (onFailure.value == false); }; if(postError) { "server failed to start".error; "For advice: [http://supercollider.github.io/tutorials/server-failed-to-start]".postln; }; serverBooting = false; server.changed(\serverRunning); }, onComplete); }.play(AppClock); } watchQuit { var serverReallyQuitWatcher, serverReallyQuit = false; statusWatcher !? { statusWatcher.disable; if(notified) { serverReallyQuitWatcher = OSCFunc({ |msg| if(msg[1] == '/quit') { if (statusWatcher.notNil) { statusWatcher.enable; }; serverReallyQuit = true; serverReallyQuitWatcher.free; }; }, '/done', server.addr); AppClock.sched(3.0, { if(serverReallyQuit.not) { "Server % failed to quit after 3.0 seconds.".format(server.name).warn; // don't accumulate quit-watchers if /done doesn't come back serverReallyQuitWatcher.free; statusWatcher.disable; }; }); }; }; } addStatusWatcher { if(statusWatcher.isNil) { statusWatcher = OSCFunc({ arg msg; var cmd, one; if(notify){ if(notified.not){ this.sendNotifyRequest; "Receiving notification messages from server %\n".postf(server.name); } }; alive = true; #cmd, one, numUGens, numSynths, numGroups, numSynthDefs, avgCPU, peakCPU, sampleRate, actualSampleRate = msg; { this.updateRunningState(true); server.changed(\counts); nil // no resched }.defer; }, '/status.reply', server.addr).fix; } { statusWatcher.enable; } } stopStatusWatcher { statusWatcher.disable; } startAliveThread { | delay=0.0 | this.addStatusWatcher; ^aliveThread ?? { aliveThread = Routine { // this thread polls the server to see if it is alive delay.wait; loop { server.status; aliveThreadPeriod.wait; this.updateRunningState(alive); alive = false; }; }.play(AppClock); aliveThread } } stopAliveThread { statusWatcher.free; statusWatcher = nil; aliveThread.stop; alive = false; aliveThread = nil; } resumeThread { aliveThread !? { this.stopAliveThread; this.startAliveThread; } } serverRunning_ { | val | if(val != serverRunning) { serverRunning = val; unresponsive = false; if (server.serverRunning) { ServerBoot.run(server); } { ServerQuit.run(server); server.disconnectSharedMemory; if(server.isRecording) { server.stopRecording }; NotificationCenter.notify(server, \didQuit); if(server.isLocal.not) { notified = false; }; }; { server.changed(\serverRunning) }.defer; } } updateRunningState { | val | if(server.addr.hasBundle) { { server.changed(\bundling) }.defer; } { if(val) { this.serverRunning = true; this.unresponsive = false; reallyDeadCount = server.options.pingsBeforeConsideredDead; } { reallyDeadCount = reallyDeadCount - 1; this.unresponsive = (reallyDeadCount <= 0); } } } unresponsive_ { arg val; if (val != unresponsive) { unresponsive = val; { server.changed(\serverRunning) }.defer; } } } SuperCollider-Source/SCClassLibrary/Common/Control/SkipJack.sc000644 000765 000024 00000002753 12756534416 025417 0ustar00crucialstaff000000 000000 SkipJack { classvar <>verbose = false, dt, <>stopTest, specs; *initClass { specs = IdentityDictionary.new; } *add { arg name, args; var spec = args.asSpec; specs.put(name, spec); ^spec } asSpec { ^this } defaultControl { ^this.subclassResponsibility(thisMethod) } == { arg that; ^this.compareObject(that) } hash { ^this.instVarHash } findKey { ^Spec.specs.findKeyForValue(this) } printOn { arg stream; var args; this.printClassNameOn(stream); args = this.storeArgs; if(args.notEmpty) { stream << "(" <<<* args << ")"; } } } ControlSpec : Spec { var default, <>units, >grid; var ControlSpec(0, 1), \bipolar -> ControlSpec(-1, 1, default: 0), \freq -> ControlSpec(20, 20000, \exp, 0, 440, units: " Hz"), \lofreq -> ControlSpec(0.1, 100, \exp, 0, 6, units: " Hz"), \midfreq -> ControlSpec(25, 4200, \exp, 0, 440, units: " Hz"), \widefreq -> ControlSpec(0.1, 20000, \exp, 0, 440, units: " Hz"), \phase -> ControlSpec(0, 2pi), \rq -> ControlSpec(0.001, 2, \exp, 0, 0.707), \audiobus -> ControlSpec(0, Server.default.options.numAudioBusChannels-1, step: 1), \controlbus -> ControlSpec(0, Server.default.options.numControlBusChannels-1, step: 1), \midi -> ControlSpec(0, 127, default: 64), \midinote -> ControlSpec(0, 127, default: 60), \midivelocity -> ControlSpec(1, 127, default: 64), \db -> ControlSpec(0.ampdb, 1.ampdb, \db, units: " dB"), \amp -> ControlSpec(0, 1, \amp, 0, 0), \boostcut -> ControlSpec(-20, 20, units: " dB",default: 0), \pan -> ControlSpec(-1, 1, default: 0), \detune -> ControlSpec(-20, 20, default: 0, units: " Hz"), \rate -> ControlSpec(0.125, 8, \exp, 0, 1), \beats -> ControlSpec(0, 20, units: " Hz"), \delay -> ControlSpec(0.0001, 1, \exp, 0, 0.3, units: " secs") ]); } copy { ^this.class.newFrom(this) } } // Warps specify the mapping from 0..1 and the control range Warp { classvar <>warps; var <>spec; *new { arg spec; ^super.newCopyArgs(spec.asSpec); } map { arg value; ^value } unmap { arg value; ^value } *asWarp { arg spec; ^this.new(spec) } asWarp { ^this } *initClass { // support Symbol-asWarp warps = IdentityDictionary[ \lin -> LinearWarp, \exp -> ExponentialWarp, \sin -> SineWarp, \cos -> CosineWarp, \amp -> FaderWarp, \db -> DbFaderWarp, \linear -> LinearWarp, \exponential -> ExponentialWarp ]; // CurveWarp is specified by a number, not a Symbol } asSpecifier { ^warps.findKeyForValue(this.class) } == { arg that; if(this === that,{ ^true; }); if(that.class !== this.class,{ ^false }); //^spec == that.spec ^true } hash { ^this.class.hash } } LinearWarp : Warp { map { arg value; // maps a value from [0..1] to spec range ^value * spec.range + spec.minval } unmap { arg value; // maps a value from spec range to [0..1] ^(value - spec.minval) / spec.range } } ExponentialWarp : Warp { // minval and maxval must both be non zero and have the same sign. map { arg value; // maps a value from [0..1] to spec range ^(spec.ratio ** value) * spec.minval } unmap { arg value; // maps a value from spec range to [0..1] ^log(value/spec.minval) / log(spec.ratio) } } CurveWarp : Warp { var a, b, grow, objects; classvar clearClocks = true; classvar <>freeServers = true; classvar <>freeRemote = false; *doOnce { arg object; var f = { this.remove(f); object.doOnCmdPeriod }; this.add(f); } *run { if(clearClocks, { SystemClock.clear; AppClock.clear; // TempoClock.default.clear; }); objects.copy.do({ arg item; item.doOnCmdPeriod; }); if(freeServers, { Server.freeAll(freeRemote); // stop all sounds on local, or remote servers Server.resumeThreads; }); era = era + 1; } *hardRun { SystemClock.clear; AppClock.clear; TempoClock.default.clear; objects.copy.do({ arg item; item.doOnCmdPeriod; }); Server.hardFreeAll; // stop all sounds on local servers Server.resumeThreads; era = era + 1; } } // things to do after startup file executed StartUp : AbstractSystemAction { classvar <>objects, objects; *run { objects.copy.do({ arg item; item.doOnShutDown; }); // "ShutDown done.".postln; } } // things to do on a system reset OnError : AbstractSystemAction { classvar <>objects; *run { objects.copy.do({ arg item; item.doOnError; }); } } AbstractServerAction : AbstractSystemAction { *init { this.objects = IdentityDictionary.new; } *performFunction { arg server, function; if (this.objects.notNil) { this.objects.at(server).copy.do(function); if(server === Server.default) { this.objects.at(\default).copy.do(function) }; this.objects.at(\all).copy.do(function); } } *run { arg server; var selector = this.functionSelector; // selector.postln; this.performFunction(server, { arg obj; obj.perform(selector, server) }); } *functionSelector { ^this.subclassResponsibility(thisMethod) } *add { arg object, server; var list; if (server.isNil) { server = \all }; if (this.objects.isNil) { this.init }; list = this.objects.at(server); if (list.isNil) { list = List.new; this.objects.put(server, list) }; if (list.includes(object).not) { list.add(object) }; } *addToAll { arg object; this.add(object, \all); } *remove { arg object, server; if(server.isNil) { server = \default }; this.objects !? { this.objects.at(server).remove(object) }; } *removeServer { arg server; this.objects.removeAt(server) } } // things to do after server has booted ServerBoot : AbstractServerAction { classvar <>objects; *functionSelector { ^\doOnServerBoot } } // things to do after server has quit ServerQuit : AbstractServerAction { classvar <>objects; *functionSelector { ^\doOnServerQuit } } // things to do after server has booted and initialised ServerTree : AbstractServerAction { classvar <>objects; *functionSelector { ^\doOnServerTree } } SuperCollider-Source/SCClassLibrary/Common/Control/Volume.sc000644 000765 000024 00000007711 12756534416 025166 0ustar00crucialstaff000000 000000 Volume { var startBus, numChans, window, model; var window, spec, slider, box, simpleController; *new{|model, win, bounds| ^super.new.model_(model).init(win, bounds) } init{|win, bounds| spec = [model.min, model.max, \db].asSpec; bounds = bounds ?? {Rect(100, 100, 80, 330)}; window = win ?? {GUI.window.new("Volume", bounds).front}; box = GUI.numberBox.new(window, Rect(10, 10, 60, 30)) .value_(model.volume) ; slider = GUI.slider.new(window, Rect(10, 40, 60, 280)) .value_(spec.unmap(model.volume)) ; slider.action_({ arg item ; model.volume_(spec.map(item.value)); }) ; box.action_({ arg item ; model.volume_(item.value) ; }) ; window.onClose_({ simpleController.remove; }); simpleController = SimpleController(model) .put(\amp, {|changer, what, volume| this.debug(volume); box.value_(volume.round(0.01)) ; slider.value_(spec.unmap(volume)) ; }) .put(\ampRange, {|changer, what, min, max| spec = [min, max, \db].asSpec.debug; slider.value_(spec.unmap(model.volume)) ; }) } } SuperCollider-Source/SCClassLibrary/Common/Control/WII.sc000644 000765 000024 00000030574 12756534416 024352 0ustar00crucialstaff000000 000000 /// NOTE: this code is still in an experimental state and only works on Linux, if compiled with Wii support. /// Therefor, it also has no helpfile yet /// This code may change without notice; do not use this code, unless you really want to and don't mind /// having to change your code in the future. /// Expect this code to be fully functional by version 3.2 /// - october 2007 - nescivi WiiCalibrationInfo { var id, <>valid, <>posx, <>posy, <>size; var <>action; } WiiMote { var dataPtr, id; var closeAction, <>connectAction, <>disconnectAction; var remote_buttons, <>remote_motion, <>remote_ir; var <>nunchuk_buttons, <>nunchuk_motion, <>nunchuk_stick; var <>classic_buttons, <>classic_stick1, <>classic_stick2, <>classic_analog; var <>dumpEvents = false; classvar all; classvar < eventLoopIsRunning = false; // classvar < updateDataTask, maxTime, <>score, beats, <>tempo; var <>bundleList, <>maxTime; *new { ^super.new("record").initScoreStreamPlayer } initScoreStreamPlayer { this.latency_(0); Server.set.remove(this); // we do not want to be part of the server list ^this } beats2secs { | beats | ^beats } secs2beats { | beats | ^beats } add { | beats, args| bundleList = bundleList.add([beats min: maxTime] ++ args) } prepareEvent { | event | event = event.copy; event.use({ ~schedBundle = { | lag, offset, server ...bundle | this.add(offset * tempo + lag + beats, bundle) }; ~schedBundleArray = { | lag, offset, server, bundle | this.add(offset * tempo + lag + beats, bundle) }; }); ^event; } makeScore { | stream, duration = 1, event, timeOffset = 0| var ev, startTime, proto; proto = ( server: this, schedBundle: { | lag, offset, server ...bundle | this.add(offset * tempo + lag + beats, bundle) }, schedBundleArray: { | lag, offset, server, bundle | this.add(offset * tempo + lag + beats, bundle) } ); event = event ? Event.default; event = event.copy.putAll(proto); beats = timeOffset; tempo = 1; bundleList = []; maxTime = timeOffset + duration; Routine { thisThread.clock = this; while ({ thisThread.beats = beats; ev = stream.next(event.copy); (maxTime >= beats) && ev.notNil },{ ev.putAll(proto); ev.play; beats = ev.delta * tempo + beats }) }.next; bundleList = bundleList.sort({ | a, b | b[0] >= a[0] }); if ((startTime = bundleList[0][0]) < 0 ) { timeOffset = timeOffset - startTime; }; // bundleList.do { | b | b[0] = b[0] + timeOffset } ^Score(bundleList.add([duration+timeOffset, [\c_set, 0, 0]]) ); } } SuperCollider-Source/SCClassLibrary/Common/Collections/Array.sc000644 000765 000024 00000015533 12756534416 025634 0ustar00crucialstaff000000 000000 Array[slot] : ArrayedCollection { *with { arg ... args; // return an array of the arguments given // cool! the interpreter does it for me.. ^args } reverse { _ArrayReverse ^this.primitiveFailed } scramble { _ArrayScramble ^this.primitiveFailed } mirror { _ArrayMirror ^this.primitiveFailed } mirror1 { _ArrayMirror1 ^this.primitiveFailed } mirror2 { _ArrayMirror2 ^this.primitiveFailed } stutter { arg n=2; _ArrayStutter ^this.primitiveFailed } rotate { arg n=1; _ArrayRotate ^this.primitiveFailed } pyramid { arg patternType=1; // an integer from 1-10 _ArrayPyramid ^this.primitiveFailed } pyramidg { arg patternType=1; var list = []; var lastIndex = this.lastIndex; if (patternType == 1) { for (0,lastIndex) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 2) { for (0,lastIndex) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; ^list }; if (patternType == 3) { for (lastIndex,0) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 4) { for (0,lastIndex) {|i| list = list.add(this[i..lastIndex]) }; ^list }; if (patternType == 5) { for (0,lastIndex) {|i| list = list.add(this[0..i]) }; for (lastIndex-1,0) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 6) { for (0,lastIndex) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; for (lastIndex-1,0) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; ^list }; if (patternType == 7) { for (lastIndex,0) {|i| list = list.add(this[0..i]) }; for (1,lastIndex) {|i| list = list.add(this[0..i]) }; ^list }; if (patternType == 8) { for (0,lastIndex) {|i| list = list.add(this[i..lastIndex]) }; for (lastIndex-1,0) {|i| list = list.add(this[i..lastIndex]) }; ^list }; if (patternType == 9) { for (0,lastIndex) {|i| list = list.add(this[0..i]) }; for (1,lastIndex) {|i| list = list.add(this[i..lastIndex]) }; ^list }; if (patternType == 10) { for (0,lastIndex) {|i| list = list.add(this[lastIndex-i..lastIndex]) }; for (lastIndex-1,0) {|i| list = list.add(this[0..i]) }; ^list }; } sputter { arg probability=0.25, maxlen = 100; var i=0; var list = Array.new; var size = this.size; probability = 1.0 - probability; while { (i < size) and: { list.size < maxlen }}{ list = list.add(this[i]); if (probability.coin) { i = i + 1; } }; ^list } lace { arg length; _ArrayLace ^this.primitiveFailed } permute { arg nthPermutation; _ArrayPermute ^this.primitiveFailed } allTuples { arg maxTuples = 16384; _ArrayAllTuples ^this.primitiveFailed } wrapExtend { arg length; _ArrayExtendWrap ^this.primitiveFailed } foldExtend { arg length; _ArrayExtendFold ^this.primitiveFailed } clipExtend { arg length; _ArrayExtendLast ^this.primitiveFailed } slide { arg windowLength=3, stepSize=1; _ArraySlide ^this.primitiveFailed } containsSeqColl { _ArrayContainsSeqColl ^this.primitiveFailed } //************** inconsistent argnames, see SequenceableColllection unlace! unlace { arg clumpSize=2, numChan=1, clip=false; ^if(clip) { super.unlace(clumpSize, numChan, true) } { this.prUnlace(clumpSize, numChan) // clip not yet implemented in primitive } } prUnlace { arg clumpSize=2, numChan=1; _ArrayUnlace ^this.primitiveFailed; } interlace { arg clumpSize=1; //_ArrayInterlace //^this.primitiveFailed; Error("interlace was replaced by lace\n").throw } deinterlace { arg clumpSize=2, numChan=1; //_ArrayUnlace //^this.primitiveFailed; Error("deinterlace was replaced by unlace\n").throw } // multiChannelExpand and flop do the same thing. flop { _ArrayMultiChannelExpand ^super.flop } multiChannelExpand { _ArrayMultiChannelExpand ^super.flop } envirPairs { // given an array of symbols, this returns an array of pairs of symbol, value // from the current environment var result; this.do {|name| var value = name.envirGet; value !? { result = result.add(name).add(value); }; }; ^result } shift { arg n, filler = 0.0; var fill = Array.fill(n.abs, filler); var remain = this.drop(n.neg); ^if (n<0) { remain ++ fill } { fill ++ remain } } powerset { var arrSize = this.size; var powersize = (2 ** arrSize).asInteger; var powersOf2 = ({ |i| 2 ** i }).dup(arrSize); ^Array.fill(powersize, { |i| var elemArr = Array.new; powersOf2.do { |mod, j| if (i div: mod % 2 != 0) { elemArr = elemArr.add(this[j]) }; }; elemArr; }); } // UGen support: source { // returns the source UGen from an Array of OutputProxy(s) var elem = this.at(0); if (elem.isKindOf(OutputProxy), { ^elem.source },{ Error("source: Not an Array of OutputProxy(s)\n").throw; }); } asUGenInput { arg for; ^this.collect(_.asUGenInput(for)) } asAudioRateInput { arg for; ^this.collect(_.asAudioRateInput(for)) } asControlInput { ^this.collect(_.asControlInput) } isValidUGenInput { ^true } numChannels { ^this.size } // multichannel UGen-poll poll { arg trig = 10, label, trigid = -1; if(label.isNil){ label = this.size.collect{|index| "UGen Array [%]".format(index) } }; ^Poll(trig, this, label, trigid) } dpoll { arg label, run = 1, trigid = -1; if(label.isNil){ label = this.size.collect{|index| "UGen Array [%]".format(index) } }; ^Dpoll(this, label, run, trigid) } envAt { arg time; _ArrayEnvAt ^this.primitiveFailed } // // 2D array support // *newClear2D { arg rows=1, cols=1; // ^super.fill(rows, { Array.newClear(cols) }); // } // *new2D { arg rows=1, cols=1; // ^this.newClear2D(rows, cols); // } // at2D { arg row, col; ^this.at(row).at(col) } // put2D { arg row, col, val; ^this.at(row).put(col, val) } // fill2D { arg val; // this.do({ arg row; // row.size.do({ arg i; // row.put(i, val) // }) // }) // } // IdentitySet support atIdentityHash { arg argKey; _Array_AtIdentityHash ^this.primitiveFailed } // IdentityDictionary support atIdentityHashInPairs { arg argKey; _Array_AtIdentityHashInPairs ^this.primitiveFailed } asSpec { ^ControlSpec( *this ) } // threads fork { arg join (this.size), clock, quant=0.0, stackSize=64; var count = 0; var cond = Condition({ count >= join }); this.do({ arg func; Routine({ arg time; func.value(time); count = count + 1; cond.signal; }).play(clock, quant); }); cond.wait; } // UGen support madd { arg mul = 1.0, add = 0.0; ^MulAdd(this, mul, add); } // OSC asRawOSC { _Array_OSCBytes ^this.primitiveFailed; } printOn { arg stream; if (stream.atLimit, { ^this }); stream << "[ " ; this.printItemsOn(stream); stream << " ]" ; } storeOn { arg stream; if (stream.atLimit, { ^this }); stream << "[ " ; this.storeItemsOn(stream); stream << " ]" ; } prUnarchive { arg slotArray; slotArray.pairsDo {|index, slots| this[index].setSlots(slots) }; this.do {|obj| obj.initFromArchive }; ^this.first } } SuperCollider-Source/SCClassLibrary/Common/Collections/Array2D.sc000644 000765 000024 00000002351 12756534416 026014 0ustar00crucialstaff000000 000000 Array2D : Collection { var 0, { array = this ++ this.class.newClear(grow); },{ array = this }); //aCollection.do({ arg item, i; array.put(pos + i, item); }); //^array } grow { arg sizeIncrease; // returns an array of sufficient capacity. // may return same object if it still has enough space or if sizeIncrease <= 0. _ArrayGrow ^this.primitiveFailed } growClear { arg sizeIncrease; // returns an array of sufficient capacity. // may return same object if it still has enough space or if sizeIncrease <= 0. // clears new space _ArrayGrowClear ^this.primitiveFailed } seriesFill { arg start, step; this.size.do({ arg i; this.put(i, start); start = start + step; }); } fill { arg value; _ArrayFill ^this.primitiveFailed /* replaced by primitive var i = 0, size; size = this.size; while ({ i < size }, { this.put(i, val); i = i + 1; }); */ } do { arg function; // special byte codes inserted by compiler for this method var i=0; while ({ i < this.size }, { function.value(this.at(i), i); i = i + 1; }) } reverseDo { arg function; // special byte codes inserted by compiler for this method var i=0, j=0; i = this.size - 1; while ({ i >= 0 },{ function.value(this.at(i), j); i = i - 1; j = j + 1; }) } reverse { var i = 0; var res = this.copy; var size1 = res.size - 1; var halfsize = res.size div: 2; halfsize.do({ arg i; res.swap(i, size1 - i); }); ^res } windex { _ArrayWIndex ^this.primitiveFailed // var r, sum = 0.0, index; // r = 1.0.rand; // this.detect({ arg weight, i; // sum = sum + weight; // if (sum >= r, { // index = i; // true; // },{ false }); // }); // ^index; } normalizeSum { _ArrayNormalizeSum ^(this * this.sum.reciprocal) } normalize { arg min=0.0, max=1.0; var minItem = this.minItem; var maxItem = this.maxItem; ^this.collect { |el| el.linlin(minItem, maxItem, min, max) }; } asciiPlot { // draw the waveform down the page as asterisks var lo = this.minItem; var hi = this.maxItem; var scale = 80 / (hi - lo); this.size.do { |i| var pt = ((this[i] - lo) * scale).asInteger; pt.do({ " ".post; }); "*\n".post; }; } perfectShuffle { if(this.size < 2) { ^this.copy }; ^this[(0 .. this.size div: 2 - 1).stutter + [0, this.size + 1 div: 2]] } performInPlace { arg selector, from, to, argList; ^this.overWrite(this.copyRange(from, to).performList(selector, argList), from) } clipExtend { arg length; ^this.extend(length, this.last) } // concepts borrowed from J programming language rank { // rank is the number of dimensions in a multidimensional array. // see also Object-rank // this assumes every element has the same rank ^1 + this.first.rank } shape { // this assumes every element has the same shape ^[this.size] ++ this[0].shape } reshape { arg ... shape; var size = shape.product; var result = this.flat.wrapExtend(size); shape[1..].reverseDo {|n| result = result.clump(n) }; ^result } reshapeLike { arg another, indexing=\wrapAt; var index = 0; var flat = this.flat; ^another.deepCollect(0x7FFFFFFF) { var item = flat.perform(indexing, index); index = index + 1; item; }; } deepCollect { arg depth = 1, function, index = 0, rank = 0; if(depth.isNil) { rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } }; if (depth <= 0) { ^function.value(this, index, rank) }; depth = depth - 1; rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } } deepDo { arg depth = 1, function, index = 0, rank = 0; if(depth.isNil) { rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } }; if (depth <= 0) { function.value(this, index, rank); ^this }; depth = depth - 1; rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } } unbubble { arg depth=0, levels=1; if (depth <= 0) { // converts a size 1 array to the item. if (this.size > 1) { ^this }; if (levels <= 1) { ^this[0] } ^this[0].unbubble(depth, levels-1) }; ^this.collect {|item| item.unbubble(depth-1) } } bubble { arg depth=0, levels=1; if (depth <= 0) { if (levels <= 1) { ^[this] } ^[this.bubble(depth,levels-1)] }; ^this.collect {|item| item.bubble(depth-1, levels) } } slice { arg ... cuts; var firstCut, index, list; if (cuts.size == 0) { ^this.copy }; firstCut = cuts[0]; if (firstCut.isNil) { list = this.copy } { list = this[firstCut.asArray] }; if (cuts.size == 1) { ^list.unbubble }{ cuts = cuts[1..]; ^list.collect {|item| item.slice(*cuts) }.unbubble } } *iota { arg ... sizes; ^(0..sizes.product-1).reshape(*sizes) } // random distribution table asRandomTable { arg size; var a=this, b; if(size.isNil) { size = this.size } { a = a.resamp1(size) }; a = a.integrate; // incrementally integrate a = a.normalize(0, size-1); // normalize and scale by max index b = Array.fill(size, { arg i; a.indexInBetween(i) }); // flip array b = b / size // rescale to 0..1 ^b } tableRand { ^this.blendAt((this.size - 1).asFloat.rand) } // osc bundle support msgSize { _NetAddr_MsgSize; ^this.primitiveFailed } bundleSize { // array of messages ^([nil] ++ this).prBundleSize; } clumpBundles { var size=0, res, clumps, count=0, bundleSizes; bundleSizes = this.collect {|item| [item].bundleSize }; bundleSizes.do { |a, i| size = size + a; if(size >= 8192) { clumps = clumps.add(count); count = 0; size = a }; count = count + 1; }; ^this.clumps(clumps); } prBundleSize { _NetAddr_BundleSize; ^this.primitiveFailed } includes { |item| ^this.indexOf(item).notNil } } RawArray : ArrayedCollection { // species { ^this.class } archiveAsCompileString { ^true } archiveAsObject { ^true } rate { ^\scalar } readFromStream { |stream, method| if(method.notNil) { this.size.do({ |i| this.put(i, stream.perform(method)); }) } { this.shouldNotImplement(thisMethod); } } powerset { ^this.as(Array).powerset } } Int8Array[int8] : RawArray { unarchive { _Unarchive ^this.primitiveFailed } readFromStream { |stream| super.readFromStream(stream, \getInt8); } } Int16Array[int16] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getInt16); } } Int32Array[int32] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getInt32); } } FloatArray[float] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getFloat); } } DoubleArray[double] : RawArray { readFromStream { |stream| super.readFromStream(stream, \getDouble); } } // readFromStream not implemented yet SymbolArray[symbol] : RawArray { } SuperCollider-Source/SCClassLibrary/Common/Collections/Association.sc000644 000765 000024 00000001073 12756534416 027024 0ustar00crucialstaff000000 000000 Association : Magnitude { var <>key, <>value; *new { arg key, value; ^super.newCopyArgs(key, value) } == { arg anAssociation; ^anAssociation respondsTo: \key and: { key == anAssociation.key } } hash { ^key.hash } < { arg anAssociation; ^key < anAssociation.key } printOn { arg stream; stream << "(" << key << " -> " << value << ")"; } storeOn { arg stream; stream << "(" <<< key << " -> " <<< value << ")"; } // Pattern support embedInStream { arg inval; ^inval.add(this).yield; } transformEvent { arg event; ^event.add(this); } } SuperCollider-Source/SCClassLibrary/Common/Collections/Bag.sc000644 000765 000024 00000003651 12766171707 025246 0ustar00crucialstaff000000 000000 Bag : Collection { var > 1).rand << 1; // generate an even index. array.at(index).isNil; // key is at even index. }); // return the first non-nil key ^array.at(index); } wchoose { var items = Array(contents.size), counts = Array(contents.size); contents.keysValuesDo({ |item, count| items.add(item); counts.add(count); }); ^items[counts.normalizeSum.windex] } take { var result = this.choose; this.remove(result); ^result } // enumerating do { arg function; var j = 0; contents.associationsDo({ arg assn; assn.value.do({ function.value(assn.key, j); j = j + 1; }) }); } countsDo { arg function; var j = 0; contents.associationsDo({ arg assn; function.value(assn.key,assn.value,j); j = j + 1; }); } itemCount { arg item; ^(contents.at(item) ? 0) } // PRIVATE IMPLEMENTATION setDictionary { arg n; contents = Dictionary.new(n) } asBag { ^this } } IdentityBag : Bag { // PRIVATE IMPLEMENTATION setDictionary { arg n; contents = IdentityDictionary.new(n) } } SuperCollider-Source/SCClassLibrary/Common/Collections/Collection.sc000644 000765 000024 00000040314 12756534416 026644 0ustar00crucialstaff000000 000000 Collection { *newFrom { | aCollection | var newCollection = this.new(aCollection.size); aCollection.do {| item | newCollection.add(item) }; ^newCollection } *with { | ... args | var newColl; // answer a collection of my class of the given arguments // the class Array has a simpler implementation newColl = this.new(args.size); newColl.addAll(args); ^newColl } *fill { | size, function | var obj; if(size.isSequenceableCollection) { ^this.fillND(size, function) }; obj = this.new(size); size.do { | i | obj.add(function.value(i)); }; ^obj } *fill2D { | rows, cols, function | var obj = this.new(rows); rows.do { |row| var obj2 = this.new(cols); cols.do { |col| obj2 = obj2.add(function.value(row, col)) }; obj = obj.add(obj2); }; ^obj } *fill3D { | planes, rows, cols, function | var obj = this.new(planes); planes.do { |plane| var obj2 = this.new(rows); rows.do { |row| var obj3 = this.new(cols); cols.do { |col| obj3 = obj3.add(function.value(plane, row, col)) }; obj2 = obj2.add(obj3); }; obj = obj.add(obj2); }; ^obj } *fillND { | dimensions, function, args = #[] | // args are private var n = dimensions.first; var obj = this.new(n); var argIndex = args.size; args = args ++ 0; if(dimensions.size <= 1) { n.do { |i| obj.add(function.valueArray(args.put(argIndex, i))) } } { dimensions = dimensions.drop(1); n.do { |i| obj = obj.add(this.fillND(dimensions, function, args.put(argIndex, i))) } }; ^obj } ++ { | collection| ^this.copy.addAll(collection) } @ { | index | ^this[index] } == { | aCollection | if (aCollection.class != this.class) { ^false }; if (this.size != aCollection.size) { ^false }; this.do { | item, i | // this is enough since both collections are finite if ((aCollection.includes(item)).not) { ^false }; }; ^true } hash { var hash = this.class.hash; this.do { | item | hash = hash bitXor: item.hash; }; ^hash } species { ^Array } do { ^this.subclassResponsibility(thisMethod) } iter { ^r { this.do {|item| item.yield } } } size { // this is the slow way. Most collections have a faster way. var tally = 0; this.do { tally = tally + 1 }; ^tally } flatSize { ^this.sum(_.flatSize) } isEmpty { ^this.size == 0 } notEmpty { ^this.size > 0 } asCollection { ^this } isCollection { ^true } isAssociationArray { ^this.subclassResponsibility(thisMethod) } add { ^this.subclassResponsibility(thisMethod) } addAll { | aCollection | aCollection.asCollection.do { | item | this.add(item) } } remove { ^this.subclassResponsibility(thisMethod) } removeAll { | list | list.do { | item | this.remove(item) } } removeEvery { | list | this.removeAllSuchThat(list.includes(_)) } removeAllSuchThat { | function | var removedItems = this.class.new; var copy = this.copy; copy.do { | item, i | if ( function.value(item, i) ) { this.remove(item); removedItems = removedItems.add(item); } }; ^removedItems } atAll { arg keys; ^keys.collect {|index| this[index] } } putEach { arg keys, values; // works for ArrayedCollections and Dictionaries keys = keys.asArray; values = values.asArray; keys.do { |key, i| this[key] = values.wrapAt(i) } ; } includes { | item1 | this.do {|item2| if (item1 === item2) {^true} }; ^false } includesEqual { | item1 | this.do {|item2| if (item1 == item2) {^true} }; ^false } includesAny { | aCollection | aCollection.do { | item | if (this.includes(item)) {^true} }; ^false } includesAll { | aCollection | aCollection.do { | item | if (this.includes(item).not) {^false} }; ^true } matchItem { | item | ^this.includes(item) } collect { | function | ^this.collectAs(function, this.species); } select { | function | ^this.selectAs(function, this.species); } reject { | function | ^this.rejectAs(function, this.species); } collectAs { | function, class | var res = class.new(this.size); this.do {|elem, i| res.add(function.value(elem, i)) } ^res; } selectAs { | function, class | var res = class.new(this.size); this.do {|elem, i| if (function.value(elem, i)) { res = res.add(elem) } } ^res; } rejectAs { | function, class | var res = class.new(this.size); this.do {|elem, i| if (function.value(elem, i).not) {res.add(elem)} } ^res; } collectInPlace { |function | this.do { |item, i| this.put(i, function.value(item, i)) } } collectCopy { |func| ^this.copy.collectInPlace(func) } detect { | function | this.do {|elem, i| if (function.value(elem, i)) { ^elem } } ^nil; } detectIndex { | function | this.do {|elem, i| if (function.value(elem, i)) { ^i } } ^nil; } doMsg { | selector ... args | this.do {| item | item.performList(selector, args) } } collectMsg { | selector ... args | ^this.collect {| item | item.performList(selector, args) } } selectMsg { | selector ... args | ^this.select {| item | item.performList(selector, args) } } rejectMsg { | selector ... args | ^this.reject {| item | item.performList(selector, args) } } detectMsg { | selector ... args | ^this.detect {| item | item.performList(selector, args) } } detectIndexMsg { | selector ... args | ^this.detectIndex {| item | item.performList(selector, args) } } lastForWhich { | function | var prev; this.do {|elem, i| if (function.value(elem, i)) { prev = elem; }{ ^prev } }; ^prev } lastIndexForWhich { | function | var prev; this.do {|elem, i| if (function.value(elem, i)) { prev = i; }{ ^prev } }; ^prev } inject { | thisValue, function | var nextValue = thisValue; this.do { | item, i | nextValue = function.value(nextValue, item, i); }; ^nextValue } injectr { | thisValue, function | var size = this.size; var nextValue = thisValue; this.do { | item, i | nextValue = function.value(nextValue, this.at(size-1-i), i); }; ^nextValue } count { | function | var sum = 0; this.do {|elem, i| if (function.value(elem, i)) { sum=sum+1 } } ^sum; } occurrencesOf { | obj | var sum = 0; this.do { | elem | if (elem == obj) { sum=sum+1 } } ^sum; } any { | function | this.do {|elem, i| if (function.value(elem, i)) { ^true } } ^false; } every { | function | this.do {|elem, i| if (function.value(elem, i).not) { ^false } } ^true; } sum { | function | var sum = 0; if (function.isNil) { // optimized version if no function this.do { | elem | sum = sum + elem; } }{ this.do {|elem, i| sum = sum + function.value(elem, i); } } ^sum; } mean { | function | ^this.sum(function) / this.size; } product { | function | var product = 1; if (function.isNil) { // optimized version if no function this.do { | elem | product = product * elem; } }{ this.do {|elem, i| product = product * function.value(elem, i); } } ^product; } sumabs { // sum of the absolute values - used to convert Mikael Laursen's rhythm lists. var sum = 0; this.do { | elem | if (elem.isSequenceableCollection) { elem = elem[0] }; sum = sum + elem.abs; } ^sum; } maxItem { | function | var maxValue, maxElement; if (function.isNil) { // optimized version if no function this.do { | elem | if (maxElement.isNil) { maxElement = elem; }{ if (elem > maxElement) { maxElement = elem; } } } ^maxElement; }{ this.do {|elem, i| var val; if (maxValue.isNil) { maxValue = function.value(elem, i); maxElement = elem; }{ val = function.value(elem, i); if (val > maxValue) { maxValue = val; maxElement = elem; } } } ^maxElement; } } minItem { | function | var minValue, minElement; if (function.isNil) { // optimized version if no function this.do {|elem, i| if (minElement.isNil) { minElement = elem; }{ if (elem < minElement) { minElement = elem; } } }; ^minElement; }{ this.do {|elem, i| var val; if (minValue.isNil) { minValue = function.value(elem, i); minElement = elem; }{ val = function.value(elem, i); if (val < minValue) { minValue = val; minElement = elem; } } } ^minElement; } } maxIndex { | function | var maxValue, maxIndex; if (function.isNil) { // optimized version if no function this.do { | elem, index | if (maxValue.isNil) { maxValue = elem; maxIndex = index; }{ if (elem > maxValue) { maxValue = elem; maxIndex = index; } } } ^maxIndex; }{ this.do {|elem, i| var val; if (maxValue.isNil) { maxValue = function.value(elem, i); maxIndex = i; }{ val = function.value(elem, i); if (val > maxValue) { maxValue = val; maxIndex = i; } } } ^maxIndex; } } minIndex { | function | var minValue, minIndex; if (function.isNil) { // optimized version if no function this.do {|elem, i| if (minValue.isNil) { minValue = elem; minIndex = i; }{ if (elem < minValue) { minValue = elem; minIndex = i; } } }; ^minIndex; }{ this.do {|elem, i| var val; if (minValue.isNil) { minValue = function.value(elem, i); minIndex = i; }{ val = function.value(elem, i); if (val < minValue) { minValue = val; minIndex = i; } } } ^minIndex; } } maxValue { | function | // must supply a function var maxValue, maxElement; this.do {|elem, i| var val; if (maxValue.isNil) { maxValue = function.value(elem, i); maxElement = elem; }{ val = function.value(elem, i); if (val > maxValue) { maxValue = val; maxElement = elem; } } }; ^maxValue; } minValue { | function | var minValue, minElement; this.do {|elem, i| var val; if (minValue.isNil) { minValue = function.value(elem, i); minElement = elem; }{ val = function.value(elem, i); if (val < minValue) { minValue = val; minElement = elem; } } }; ^minValue; } maxSizeAtDepth { arg rank; var maxsize = 0; if(rank == 0) { ^this.size }; this.do { |sublist| var sz = if(sublist.isCollection) { sublist.maxSizeAtDepth(rank - 1) } { 1 }; if (sz > maxsize) { maxsize = sz }; }; ^maxsize } maxDepth { arg max = 1; var res = max; this.do { |elem| if(elem.isCollection) { res = max(res, elem.maxDepth(max + 1)) } }; ^res } deepCollect { | depth = 1, function, index = 0, rank = 0 | if(depth.isNil) { rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } }; if (depth <= 0) { ^function.value(this, index, rank) }; depth = depth - 1; rank = rank + 1; ^this.collect { |item, i| item.deepCollect(depth, function, i, rank) } } deepDo { | depth = 1, function, index = 0, rank = 0 | if(depth.isNil) { rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } }; if (depth <= 0) { function.value(this, index, rank); ^this }; depth = depth - 1; rank = rank + 1; ^this.do { |item, i| item.deepDo(depth, function, i, rank) } } invert { | axis | var index; // can be used to invert a pitch list about a given axis // [3, 2, 9, 7].invert(11) becomes [ 19, 20, 13, 15 ] // if axis is nil, invert uses the registral center // [3, 2, 9, 7].invert becomes [ 8, 9, 2, 4 ] if(this.isEmpty) { ^this.species.new }; if(axis.notNil) { index = axis * 2 } { index = this.minItem + this.maxItem }; ^index - this; } sect { | that | var result = this.species.new; this.do { | item | if (that.includes(item)) { result = result.add(item); } }; ^result } union { | that | var result = this.copy; that.do { | item | if (result.includes(item).not) { result = result.add(item); } }; ^result } difference { | that | ^this.copy.removeAll(that); } symmetricDifference { | that | var result = this.species.new; this.do { | item | if (that.includes(item).not) { result = result.add(item); } }; that.do { | item | if (this.includes(item).not) { result = result.add(item); } }; ^result; } isSubsetOf { | that | ^that.includesAll(this) } asArray { ^Array.new(this.size).addAll(this) } asBag { ^Bag.new(this.size).addAll(this) } asList { ^List.new(this.size).addAll(this) } asSet { ^Set.new(this.size).addAll(this) } asSortedList { | function | ^SortedList.new(this.size, function).addAll(this) } asAssociations { var res; if(this.isAssociationArray) { ^this }; res = Array.new(this.size div: 2); this.pairsDo { |key, val| res.add(key -> val) } ^res } asPairs { var res; if(this.isAssociationArray.not) { ^this }; res = Array.new(this.size div: 2); this.do { |assoc| res.add(assoc.key).add(assoc.value) } ^res } asDict { |mergeFunc| var res = IdentityDictionary.new; // another dispute: Dictionary would default to a very inefficient lookup. if(mergeFunc.notNil) { ^this.asDictWith(mergeFunc) }; if(this.isAssociationArray) { this.do { |assoc| res.put(assoc.key, assoc.value) } } { this.pairsDo { |key, val| res.put(key, val) } }; ^res } asDictWith { |mergeFunc| var res = IdentityDictionary.new; if(this.isAssociationArray) { this.do { |assoc| res.mergeItem(assoc.key, assoc.value, mergeFunc) } } { this.pairsDo { |key, val| res.mergeItem(key, val, mergeFunc) } }; ^res } powerset { var species = this.species; var result = this.asArray.powerset; ^if(species == Array) { result } { result.collectAs({ | item | item.as(species) }, species) } } flopDict { | unbubble=true | var res, first = true; this.do { | dict | if(first) { res = dict.class.new; first = false }; dict.keysValuesDo { | key, val | res[key] = res[key].add(val) } }; if(unbubble) { res = res.collect(_.unbubble) }; ^res } histo { arg steps = 100, min, max; var freqs, freqIndex, lastIndex, stepSize, outliers = 0; if(this.isEmpty) { ^this.species.new }; min = min ?? { this.minItem }; max = max ?? { this.maxItem }; freqs = Array.fill(steps, 0); lastIndex = steps - 1; stepSize = steps / (max - min); this.do { arg el; freqIndex = ((el - min) * stepSize).asInteger; if (freqIndex.inclusivelyBetween(0, lastIndex)) { freqs[freqIndex] = freqs[freqIndex] + 1; } { // if max is derived from maxItem, count it in: if (el == max) { freqs[steps-1] = freqs[steps-1] + 1; } { // else it is an outlier. outliers = outliers + 1; }; }; }; if (outliers > 0) { ("histogram :" + outliers + "out of (histogram) range values in collection.").inform; }; ^freqs; } // printAll { this.do { | item | item.postln; }; } // convenience method printAll { |before, after| if (before.isNil and: after.isNil) { this.do { | item | item.postln; }; } { before = before ? ""; after = after ? ""; this.do { | item | before.post; item.post; after.postln; }; }; } printcsAll { this.do { | item | item.postcs; }; } // convenience method dumpAll { this.do { | item | item.dump; }; } // convenience method printOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << "[ " ; this.printItemsOn(stream); stream << " ]" ; } storeOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << "[ " ; this.storeItemsOn(stream); stream << " ]" ; } storeItemsOn { | stream | var addComma = false; this.do { | item | if (stream.atLimit) { ^this }; if (addComma) { stream.comma.space; } { addComma = true }; item.storeOn(stream); }; } printItemsOn { | stream | var addComma = false; this.do { | item | if (stream.atLimit) { ^this }; if (addComma) { stream.comma.space; } { addComma = true }; item.printOn(stream); }; } // Synth support writeDef { | file | file.putString("SCgf"); file.putInt32(2); // file version file.putInt16(this.size); // number of defs in file. this.do { | item | item.writeDef(file); } } writeInputSpec { | file, synthDef | this.do { | item | item.writeInputSpec(file, synthDef) }; } // Flow control case { | default | var out = this.detect {|it| it.key.value;}; if (out.notNil) { ^out.value.value }{ ^default.value; } } // Event support makeEnvirValPairs { var res = Array.new(this.size * 2); this.do { |item| res.add(item); res.add(currentEnvironment[item]); }; ^res } } SuperCollider-Source/SCClassLibrary/Common/Collections/Dictionary.sc000644 000765 000024 00000027430 12766171707 026663 0ustar00crucialstaff000000 000000 Dictionary : Set { *new { arg n=8; ^super.new(n*2) } *newFrom { arg aCollection; var newCollection = this.new(aCollection.size); aCollection.keysValuesDo({ arg k,v, i; newCollection.put(k,v) }); ^newCollection } // accessing at { arg key; ^array.at(this.scanFor(key) + 1) } atFail { arg key, function; var val; val = this.at(key); if ( val.isNil, { ^function.value }, { ^val }); } matchAt { |key| this.keysValuesDo({ |k, v| if(k.matchItem(key)) { ^v } }); ^nil } trueAt { arg key; ^this.at(key) ? false } add { arg anAssociation; this.put(anAssociation.key, anAssociation.value); } put { arg key, value; var atKey; var index; value ?? { this.removeAt(key); ^this }; index = this.scanFor(key); array.put(index+1, value); if ( array.at(index).isNil, { array.put(index, key); size = size + 1; if (array.size < (size * 4), { this.grow }); }); } putAll { arg ... dictionaries; dictionaries.do {|dict| dict.keysValuesDo { arg key, value; this.put(key, value) } } } putPairs { arg args; args.pairsDo { |key, val| this.put(key, val) } } getPairs { arg args; var result; args = args ?? { this.keys }; args.do { |key| var val = this.at(key); val !? { result = result.add(key).add(val) } }; ^result } ++ { arg dict; ^this.copy.putAll(dict) } associationAt { arg key; var index = this.scanFor(key); if (index >= 0, { ^Association.new(array.at(index), array.at(index+1)); },{ ^nil }); } associationAtFail { arg argKey, function; var index = this.scanFor(argKey); var key = array.at(index); if ( key.isNil, { ^function.value }, { ^Association.new(key, array.at(index+1)) }); } keys { arg species(Set); var set = species.new(size); this.keysDo({ arg key; set.add(key) }); ^set } values { var list = List.new(size); this.do({ arg value; list.add(value) }); ^list } // testing includes { arg item1; this.do({ arg item2; if (item1 == item2, {^true}) }); ^false } includesKey { arg key; ^this.at( key ).notNil; } // removing removeAt { arg key; var val; var index = this.scanFor(key); var atKeyIndex = array.at(index); if ( atKeyIndex.isNil, { ^nil }); val = array.at(index+1); array.put(index, nil); array.put(index+1, nil); size = size - 1; this.fixCollisionsFrom(index); ^val } removeAtFail { arg key, function; var val; var index = this.scanFor(key); var atKeyIndex = array.at(index); if ( atKeyIndex.isNil, { ^function.value }); val = array.at(index+1); array.put(index, nil); array.put(index+1, nil); size = size - 1; this.fixCollisionsFrom(index); ^val } remove { ^this.shouldNotImplement(thisMethod) } removeFail { ^this.shouldNotImplement(thisMethod) } // enumerating keysValuesDo { arg function; this.keysValuesArrayDo(array, function); } keysValuesChange { arg function; this.keysValuesDo({ arg key, value, i; this.put(key, function.value(key, value, i)); }) } do { arg function; this.keysValuesDo({ arg key, value, i; function.value(value, i); }) } keysDo { arg function; this.keysValuesDo({ arg key, val, i; function.value(key, i); }) } associationsDo { arg function; this.keysValuesDo({ arg key, val, i; function.value( Association.new(key, val), i); }) } pairsDo { arg function; this.keysValuesArrayDo(array, function); } collect { arg function; var res = this.class.new(this.size); this.keysValuesDo { arg key, elem; res.put(key, function.value(elem, key)) } ^res; } select { arg function; var res = this.class.new(this.size); this.keysValuesDo { arg key, elem; if(function.value(elem, key)) { res.put(key, elem) } } ^res; } reject { arg function; var res = this.class.new(this.size); this.keysValuesDo { arg key, elem; if(function.value(elem, key).not) { res.put(key, elem) } } ^res; } invert { var dict = this.class.new(this.size); this.keysValuesDo {|key, val| dict.put(val, key) }; ^dict } merge {|that, func, fill = true| var commonKeys, myKeys = this.keys, otherKeys = that.keys; var res = this.species.new; if (myKeys == otherKeys) { commonKeys = myKeys } { commonKeys = myKeys.sect(otherKeys); }; commonKeys.do { |key| res[key] = func.value(this[key], that[key], key) }; if (fill) { myKeys.difference(otherKeys).do { |key| res[key] = this[key] }; otherKeys.difference(myKeys).do { |key| res[key] = that[key] }; }; ^res } mergeItem { |key, val, func| var old; if(func.notNil) { old = this.at(key); if(old.notNil) { val = func.value(val, old) } }; this.put(key, val) } blend { |that, blend = 0.5, fill = true, specs| ^this.merge(that, { |a, b, key| var spec = if (specs.notNil) { specs[key].asSpec }; if (spec.notNil) { spec.map(blend(spec.unmap(a), spec.unmap(b), blend)) } { blend(a, b, blend) } }, fill) } findKeyForValue { arg argValue; this.keysValuesArrayDo(array, { arg key, val, i; if (argValue == val, { ^key }) }); ^nil } sortedKeysValuesDo { arg function, sortFunc; var keys = this.keys(Array); keys.sort(sortFunc); keys.do { arg key, i; function.value(key, this[key], i); }; } choose { var index, key, val; if( this.isEmpty, { ^nil }); // empty dictionary while({ index = (array.size >> 1).rand << 1; // generate an even index. array.at(index).isNil; // key is at even index. }); // return the value for the first non Nil key we find. // the value is at the odd index. ^array.at(index + 1); } order { arg func; var assoc; if( this.isEmpty, { ^nil }); this.keysValuesDo { arg key, val; assoc = assoc.add(key -> val); }; ^assoc.sort(func).collect(_.key) } powerset { var keys = this.keys.asArray.powerset; ^keys.collect { | list | var dict = this.class.new; list.do { |key| dict.put(key, this[key]) }; dict } } // Pattern support transformEvent { arg event; ^event.putAll(this); } embedInStream { arg event; var func = this.at(\embedInStream); if(func.notNil) { ^func.value(this, event) }; ^if(event.isNil) { this } { event.copy.putAll(this) }.yield } asSortedArray { var array; if ( this.notEmpty ){ this.keysValuesDo({ arg key, value; array = array.add([key,value]); }); array = array.sort({ arg a, b; a.at(0) < b.at(0) }); }{ array = []; }; ^array; } asKeyValuePairs { var array = Array.new(this.size * 2); this.keysValuesDo { |key, val| array.add(key); array.add(val) }; ^array } isAssociationArray { ^false } asPairs { ^this.getPairs } asDict { ^this } // PRIVATE IMPLEMENTATION keysValuesArrayDo { arg argArray, function; // special byte codes inserted by compiler for this method var i=0, j=0, key, val; var arraySize = argArray.size; while ({ i < arraySize },{ key = argArray.at(i); if (key.notNil, { val = argArray.at(i+1); function.value(key, val, j); j = j + 1; }); i = i + 2; }); } grow { var index; var oldElements = array; array = Array.newClear(array.size * 2); this.keysValuesArrayDo(oldElements, { arg key, val; index = this.scanFor(key); array.put(index, key); array.put(index+1, val); }); } fixCollisionsFrom { arg index; var newIndex, key; var oldIndex = index; var lastKeyIndex = array.size - 2; while ({ if (oldIndex == lastKeyIndex, { oldIndex = 0 }, { oldIndex = oldIndex + 2 }); (key = array.at(oldIndex)).notNil },{ newIndex = this.scanFor(key); if ( oldIndex != newIndex, { array.swap(oldIndex, newIndex); array.swap(oldIndex+1, newIndex+1) }) }) } scanFor { arg argKey; var maxHash = array.size div: 2; var start = (argKey.hash % maxHash) * 2; var end = array.size-1; var i = start; forBy( start, end, 2, { arg i; var key = array.at(i); if ( key.isNil or: { key == argKey }, { ^i }); }); end = start - 1; forBy( 0, start-2, 2, { arg i; var key = array.at(i); if ( key.isNil or: { key == argKey }, { ^i }); }); ^-2 } storeItemsOn { arg stream, itemsPerLine = 5; var itemsPerLinem1 = itemsPerLine - 1; var last = this.size - 1; this.associationsDo({ arg item, i; item.storeOn(stream); if (i < last, { stream.comma.space; if (i % itemsPerLine == itemsPerLinem1, { stream.nl.space.space }); }); }); } printItemsOn { arg stream, itemsPerLine = 5; var itemsPerLinem1 = itemsPerLine - 1; var last = this.size - 1; this.associationsDo({ arg item, i; item.printOn(stream); if (i < last, { stream.comma.space; if (i % itemsPerLine == itemsPerLinem1, { stream.nl.space.space }); }); }); } } IdentityDictionary : Dictionary { var <>proto; // inheritance of properties var <>parent; // inheritance of properties var <>know = false; // if know is set to true then not understood messages will look in the dictionary // for that selector and send the value message to them. *new { arg n=8, proto, parent, know=false; ^super.new(n).proto_(proto).parent_(parent).know_(know) } at { arg key; _IdentDict_At ^this.primitiveFailed /*^array.at(this.scanFor(key) + 1)*/ } put { arg key, value; _IdentDict_Put value ?? { this.removeAt(key); ^this }; ^this.primitiveFailed /* var index, atKey; index = this.scanFor(key); array.put(index+1, value); if ( array.at(index).isNil, { array.put(index, key); size = size + 1; if (array.size < (size * 4), { this.grow }); }); */ } putGet { arg key, value; _IdentDict_PutGet ^this.primitiveFailed /* var index, atKey, prev; index = this.scanFor(key); prev = array.at(index + 1); array.put(index+1, value); if ( array.at(index).isNil, { array.put(index, key); size = size + 1; if (array.size < (size * 4), { this.grow }); }); ^prev */ } includesKey { arg key; ^this.at( key ).notNil; } findKeyForValue { arg argValue; this.keysValuesArrayDo(array, { arg key, val, i; if (argValue === val, { ^key }) }); ^nil } scanFor { arg argKey; ^array.atIdentityHashInPairs(argKey) } freezeAsParent { var frozenParent = this.freeze; ^this.class.new(this.size, nil, frozenParent, know) } insertParent { arg newParent, insertionDepth = 0, reverseInsertionDepth = inf; if(parent.isNil) { parent = newParent; ^this }; if(insertionDepth > 0) { parent.insertParent(newParent, insertionDepth - 1, reverseInsertionDepth); ^this }; newParent.insertParent(parent, reverseInsertionDepth, inf); // insert current parent back into new parent parent = newParent; } storeItemsOn { arg stream, itemsPerLine = 5; super.storeItemsOn(stream, itemsPerLine); if(proto.notNil) { stream << "\n.proto_(" <<< proto << ")" }; if(parent.notNil) { stream << "\n.parent_(" <<< parent << ")" }; } doesNotUnderstand { arg selector ... args; var func; if (know) { func = this[selector]; if (func.notNil) { ^func.functionPerformList(\value, this, args); }; if (selector.isSetter) { selector = selector.asGetter; if(this.respondsTo(selector)) { warn(selector.asCompileString + "exists a method name, so you can't use it as pseudo-method.") }; ^this[selector] = args[0]; }; func = this[\forward]; if (func.notNil) { ^func.functionPerformList(\value, this, selector, args); }; ^nil }; ^this.superPerformList(\doesNotUnderstand, selector, args); } // Quant support. // The Quant class assumes the quant/phase/offset scheduling model. // If you want a different model, you can write a dictionary like so: // (nextTimeOnGrid: { |self, clock| ... calculate absolute beat number here ... }, // parameter: value, parameter: value, etc.) // If you leave out the nextTimeOnGrid function, fallback to quant/phase/offset. nextTimeOnGrid { |clock| if(this[\nextTimeOnGrid].notNil) { ^this[\nextTimeOnGrid].value(this, clock) } { ^clock.nextTimeOnGrid(this[\quant] ? 1, (this[\phase] ? 0) - (this[\offset] ? 0)) } } asQuant { ^this.copy } timingOffset { ^this[\timingOffset] } // for synchWithQuant() } SuperCollider-Source/SCClassLibrary/Common/Collections/Environment.sc000644 000765 000024 00000002474 12756534416 027062 0ustar00crucialstaff000000 000000 Environment : IdentityDictionary { classvar <>stack; *make { arg function; ^this.new.make(function) } *use { arg function; ^this.new.use(function) } make { arg function; // pushes the Envir, executes function, returns the Envir // usually used to create an environment by adding new variables to it. var result, saveEnvir; saveEnvir = currentEnvironment; currentEnvironment = this; protect { function.value(this); }{ currentEnvironment = saveEnvir; }; } use { arg function; // temporarily replaces the currentEnvironment with this, // executes function, returns the result of the function var result, saveEnvir; saveEnvir = currentEnvironment; currentEnvironment = this; protect { result = function.value(this); }{ currentEnvironment = saveEnvir; }; ^result } eventAt { arg key; ^this.at(key) } composeEvents { arg event; ^this.copy.putAll(event) } *pop { if(stack.notNil and: { stack.notEmpty }) { currentEnvironment = stack.pop }; } *push { arg envir; stack = stack.add(currentEnvironment); currentEnvironment = envir; } pop { ^this.class.pop } push { this.class.push(this) } linkDoc { arg doc; doc = doc ? Document.current; doc.envir_(this); } unlinkDoc { arg doc; doc = doc ? Document.current; if(doc.envir === this) { doc.envir_(nil) }; } } SuperCollider-Source/SCClassLibrary/Common/Collections/EnvironmentRedirect.sc000644 000765 000024 00000010554 12756534416 030542 0ustar00crucialstaff000000 000000 // abstract class that dispatches assignment / reference in environments. EnvironmentRedirect { var proxyClass=\Maybe; makeProxy { ^proxyClass.asClass.new } at { arg key; var proxy; proxy = super.at(key); if(proxy.isNil) { proxy = this.makeProxy(key); envir.put(key, proxy); }; ^proxy } put { arg key, obj; this.at(key).source_(obj); dispatch.value(key, obj); // forward to dispatch for networking } removeAt { arg key; var proxy; proxy = envir.removeAt(key); if(proxy.notNil) { proxy.clear }; } localPut { arg key, obj; this.at(key).source_(obj); } copy { var result = this.class.new; dispatch !? { result.dispatch = dispatch }; envir.keysValuesDo { |key, val| result.envir[key] = val.copy; }; ^result } storeOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << ".newFrom([" ; stream <<<* envir.getPairs.collect { |x, i| if(i.even) { x } { x.source } }; stream << "])" ; } } SuperCollider-Source/SCClassLibrary/Common/Collections/Event.sc000644 000765 000024 00000067446 12756534416 025651 0ustar00crucialstaff000000 000000 Event : Environment { classvar defaultParentEvent; classvar event does not specify note release defaultMsgFunc: #{|freq = 440, amp = 0.1, pan = 0, out = 0| [\freq, freq, \amp, amp, \pan, pan, \out, out] }, // for \type \set args: #[\freq, \amp, \pan, \trig], timingOffset: 0, // it is more efficient to directly use schedBundleArrayOnClock // we keep these for compatibility. schedBundle: #{ |lag, offset, server ... bundle | schedBundleArrayOnClock(offset, thisThread.clock, bundle, lag, server); }, schedBundleArray: #{ | lag, offset, server, bundleArray, latency | schedBundleArrayOnClock(offset, thisThread.clock, bundleArray, lag, server, latency); }, schedStrummedNote: {| lag, strumTime, sustain, server, msg, sendGate | var dur, schedBundle = ~schedBundle; schedBundle.value(lag, strumTime + ~timingOffset, server, msg); if(sendGate) { if (~strumEndsTogether) { dur = sustain ; } { dur = sustain + strumTime }; schedBundle.value(lag, dur + ~timingOffset, server, [15 /* \n_set */, msg[2], \gate, 0]) } } ), bufferEvent: ( bufnum: 0, filename: "", frame: 0, numframes: 0, numchannels: 1, gencmd: \sine1, genflags: 7, genarray: [1], bufpos: 0, leaveOpen: 0 ), midiEvent: ( midiEventFunctions: ( noteOn: #{ arg chan=0, midinote=60, amp=0.1; [chan, midinote, asInteger((amp * 127).clip(0, 127)) ] }, noteOff: #{ arg chan=0, midinote=60, amp=0.1; [ chan, midinote, asInteger((amp * 127).clip(0, 127)) ] }, polyTouch: #{ arg chan=0, midinote=60, polyTouch=125; [ chan, midinote, polyTouch ] }, control: #{ arg chan=0, ctlNum, control=125; [chan, ctlNum, control ] }, program: #{ arg chan=0, progNum=1; [ chan, progNum ] }, touch: #{ arg chan=0, val=125; [ chan, val ] }, bend: #{ arg chan=0, val=125; [ chan, val ] }, allNotesOff: #{ arg chan=0; [chan] }, smpte: #{ arg frames=0, seconds=0, minutes=0, hours=0, frameRate=25; [frames, seconds, minutes, hours, frameRate] }, songPtr: #{ arg songPtr; [songPtr] }, sysex: #{ arg uid, array; [array] } // Int8Array ), midicmd: \noteOn ), nodeEvent: ( delta: 0, addAction: 0, group: 1, latency: 0.2, instrument: \default, hasGate: true, stopServerNode: #{ if (~hasGate == true) {currentEnvironment.set(\gate, 0) } {currentEnvironment.sendOSC([11, ~id]) }; ~isPlaying = false; }, freeServerNode: #{ currentEnvironment.sendOSC([11, ~id]); ~isPlaying = false; }, releaseServerNode: #{ currentEnvironment.set(\gate, 0); ~isPlaying = false; }, pauseServerNode: #{ currentEnvironment.sendOSC([12, ~id, false]); }, resumeServerNode: #{ currentEnvironment.sendOSC([12, ~id, true]); }, // perhaps these should be changed into mapServerNode etc. map: #{ | ev, key, busIndex | ev.sendOSC([14, ev[\id], key, busIndex]) }, before: #{ | ev,target | ev.sendOSC([18, ev[\id], target]); ev[\group] = target; ev[\addAction] = 2; }, after: #{ | ev, target | ev.sendOSC([19, ev[\id], target]); ev[\group] = target; ev[\addAction] = 3; }, headOf: #{ | ev, group | ev.sendOSC([22, group, ev[\id]]); ev[\group] = group; ev[\addAction] = 0; }, tailOf: #{ |ev, group | ev.sendOSC([23, group, ev[\id]]); ev[\group] = group; ev[\addAction] = 1; }, isPlaying: #{ |ev| ^(ev[\isPlaying] == true) }, isPlaying_: #{ | ev, flag | ev[\isPlaying] = flag; }, nodeID: #{ |ev| ^ev[\id].asArray.last }, asEventStreamPlayer: #{|ev| ev } ), playerEvent: ( type: \note, play: #{ var tempo, server; ~finish.value; server = ~server ?? { Server.default }; tempo = ~tempo; if (tempo.notNil) { thisThread.clock.tempo = tempo; }; if(currentEnvironment.isRest.not) { ~eventTypes[~type].value(server) }; }, // synth / node interface // this may be better moved into the cleanup events, but for now // it avoids confusion. // this is a preliminary implementation and does not recalculate dependent // values like degree, octave etc. freeServerNode: #{ if(~id.notNil) { ~server.sendBundle(~server.latency, ["/n_free"] ++ ~id); ~isPlaying = false; }; }, // for some yet unknown reason, this function is uncommented, // it breaks the play method for gatelesss synths releaseServerNode: #{ |releaseTime| var sendGate, msg; if(~id.notNil) { releaseTime = if(releaseTime.isNil) { 0.0 } { -1.0 - releaseTime }; sendGate = ~sendGate ? ~hasGate; if(sendGate) { ~server.sendBundle(~server.latency, *["/n_set", ~id, "gate", releaseTime].flop); } { ~server.sendBundle(~server.latency, ["/n_free"] ++ ~id); }; ~isPlaying = false; }; }, // the event types eventTypes: ( rest: #{}, note: #{|server| var freqs, lag, strum, sustain; var bndl, addAction, sendGate, ids; var msgFunc, instrumentName, offset, strumOffset; // var schedBundleArray; freqs = ~detunedFreq.value; // msgFunc gets the synth's control values from the Event msgFunc = ~getMsgFunc.valueEnvir; instrumentName = ~synthDefName.valueEnvir; // determine how to send those commands // sendGate == false turns off releases sendGate = ~sendGate ? ~hasGate; // update values in the Event that may be determined by functions ~freq = freqs; ~amp = ~amp.value; ~sustain = sustain = ~sustain.value; lag = ~lag; offset = ~timingOffset; strum = ~strum; ~server = server; ~isPlaying = true; addAction = Node.actionNumberFor(~addAction); // compute the control values and generate OSC commands bndl = msgFunc.valueEnvir; bndl = [9 /* \s_new */, instrumentName, ids, addAction, ~group] ++ bndl; if(strum == 0 and: { (sendGate and: { sustain.isArray }) or: { offset.isArray } or: { lag.isArray } }) { bndl = flopTogether( bndl, [sustain, lag, offset] ); #sustain, lag, offset = bndl[1].flop; bndl = bndl[0]; } { bndl = bndl.flop }; // produce a node id for each synth ~id = ids = Array.fill(bndl.size, { server.nextNodeID }); bndl = bndl.collect { | msg, i | msg[2] = ids[i]; msg.asOSCArgArray }; // schedule when the bundles are sent if (strum == 0) { ~schedBundleArray.(lag, offset, server, bndl, ~latency); if (sendGate) { ~schedBundleArray.( lag, sustain + offset, server, [15 /* \n_set */, ids, \gate, 0].flop, ~latency ); } } { if (strum < 0) { bndl = bndl.reverse }; strumOffset = offset + Array.series(bndl.size, 0, strum.abs); ~schedBundleArray.( lag, strumOffset, server, bndl, ~latency ); if (sendGate) { if (~strumEndsTogether) { strumOffset = sustain + offset } { strumOffset = sustain + strumOffset }; ~schedBundleArray.( lag, strumOffset, server, [15 /* \n_set */, ids, \gate, 0].flop, ~latency ); } } }, // optimized version of type \note, about double as efficient. // Synth must have no gate and free itself after sustain. // Event supports no strum, no conversion of argument objects to controls grain: #{|server| var freqs, lag, instr; var bndl, addAction, sendGate, ids; var msgFunc, instrumentName, offset; freqs = ~detunedFreq.value; // msgFunc gets the synth's control values from the Event instr = ( ~synthLib ?? { SynthDescLib.global } ).at(~instrument); if(instr.isNil) { "Event: instrument % not found in SynthDescLib" .format(~instrument).warn; ^this }; msgFunc = instr.msgFunc; instrumentName = ~synthDefName.valueEnvir; // update values in the Event that may be determined by functions ~freq = freqs; ~amp = ~amp.value; ~sustain = ~sustain.value; addAction = Node.actionNumberFor(~addAction); // compute the control values and generate OSC commands bndl = msgFunc.valueEnvir; bndl = [9 /* \s_new */, instrumentName, -1, addAction, ~group] ++ bndl; ~schedBundleArray.( ~lag, ~timingOffset, server, bndl.flop, ~latency ); }, on: #{|server| var freqs; var bndl, sendGate, ids; var msgFunc, desc, synthLib, bundle, instrumentName; freqs = ~detunedFreq.value; ~freq = freqs; ~amp = ~amp.value; ~isPlaying = true; msgFunc = ~getMsgFunc.valueEnvir; instrumentName = ~synthDefName.valueEnvir; bndl = msgFunc.valueEnvir; bndl = [9 /* \s_new */, instrumentName, ~id, Node.actionNumberFor(~addAction), ~group] ++ bndl; bndl = bndl.flop; if ( (ids = ~id).isNil ) { ids = Array.fill(bndl.size, {server.nextNodeID }); bndl = bndl.collect { | msg, i | msg[2] = ids[i]; msg.asOSCArgArray }; } { bndl = bndl.asOSCArgBundle; }; ~schedBundleArray.value(~lag, ~timingOffset, server, bndl, ~latency); ~server = server; ~id = ids; ~callback.value(currentEnvironment) }, set: #{|server| var freqs, lag, dur, strum, bndl, msgFunc; freqs = ~freq = ~detunedFreq.value; ~server = server; ~amp = ~amp.value; if(~args.size == 0) { msgFunc = ~getMsgFunc.valueEnvir; bndl = msgFunc.valueEnvir; } { bndl = ~args.envirPairs; }; bndl = ([15 /* \n_set */, ~id] ++ bndl).flop.asOSCArgBundle; ~schedBundleArray.value(~lag, ~timingOffset, server, bndl, ~latency); }, off: #{|server| var gate; if (~hasGate) { gate = min(0.0, ~gate ? 0.0); // accept release times ~schedBundleArray.value(~lag, ~timingOffset, server, [15 /* \n_set */, ~id.asControlInput, \gate, gate].flop, ~latency ) } { ~schedBundleArray.value(~lag, ~timingOffset, server, [\n_free, ~id.asControlInput].flop, ~latency) }; ~isPlaying = false; }, kill: #{|server| ~schedBundleArray.value(~lag, ~timingOffset, server, [\n_free, ~id.asControlInput].flop, ~latency) }, group: #{|server| var bundle, cmd; if (~id.isNil) { ~id = server.nextNodeID }; bundle = [21 /* \g_new */, ~id.asArray, Node.actionNumberFor(~addAction), ~group.asControlInput].flop; ~schedBundleArray.value(~lag, ~timingOffset, server, bundle, ~latency); }, parGroup: #{|server| var bundle, cmd; if (~id.isNil) { ~id = server.nextNodeID }; bundle = [63 /* \p_new */, ~id.asArray, Node.actionNumberFor(~addAction), ~group.asControlInput].flop; ~schedBundleArray.value(~lag, ~timingOffset, server, bundle, ~latency); }, bus: #{|server| var array; array = ~array.asArray; ~schedBundle.value(~lag, ~timingOffset, server, [\c_setn, ~out.asControlInput, array.size] ++ array); }, fadeBus: #{ |server| var bundle, instrument, rate, bus; var array = ~array.as(Array); var numChannels = min(~numChannels.value ? 1, array.size); if(numChannels > SystemSynthDefs.numChannels) { Error( "Can't set more than % channels with current setup in SystemSynthDefs." .format(SystemSynthDefs.numChannels) ).throw; }; if (~id.isNil) { ~id = server.nextNodeID }; instrument = "system_setbus_%_%".format(~rate.value ? \control, numChannels); // addToTail, so that old bus value can be overridden: bundle = [9, instrument, ~id, 1, ~group.asControlInput, "values", array, "out", ~out.value, "fadeTime", ~fadeTime, "curve", ~curve ].asOSCArgArray; ~schedBundle.value(~lag, ~timingOffset, server, bundle); if(~rate == \audio) { // control rate synth frees by itself, because bus holds the value ~stopServerNode = { server.sendBundle(server.latency, [\n_set, ~id, \gate, 0]) } }; }, gen: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, ~bufnum.asControlInput, ~gencmd, ~genflags] ++ ~genarray); }, load: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_allocRead, ~bufnum.asControlInput, ~filename, ~frame, ~numframes]); }, read: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_read, ~bufnum.asControlInput, ~filename, ~frame, ~numframes, ~bufpos, ~leaveOpen]); }, alloc: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, ~bufnum.asControlInput, ~numframes, ~numchannels]); }, free: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_free, ~bufnum.asControlInput]); }, midi: #{|server| var freqs, lag, dur, sustain, strum; var bndl, midiout, hasGate, midicmd; freqs = ~freq = ~detunedFreq.value; ~amp = ~amp.value; ~midinote = (freqs.cpsmidi).round(1).asInteger; strum = ~strum; lag = ~lag; sustain = ~sustain = ~sustain.value; midiout = ~midiout.value; ~uid ?? { ~uid = midiout.uid }; // mainly for sysex cmd hasGate = ~hasGate ? true; midicmd = ~midicmd; bndl = ~midiEventFunctions[midicmd].valueEnvir.asCollection; bndl = bndl.asControlInput.flop; bndl.do {|msgArgs, i| var latency; latency = i * strum + lag; if(latency == 0.0) { midiout.performList(midicmd, msgArgs) } { thisThread.clock.sched(latency, { midiout.performList(midicmd, msgArgs); }) }; if(hasGate and: { midicmd === \noteOn }) { thisThread.clock.sched(sustain + latency, { midiout.noteOff(*msgArgs) }); }; }; }, setProperties: { var receiver = ~receiver, go = { ~args.do { |each| var selector, value = each.envirGet; if(value.notNil) { selector = each.asSetter; if(~doTrace == true) { postf("%.%_(%)\n",receiver,selector,value) }; receiver.perform(selector.asSetter, value) }; } }; if(~defer ? true) { // inEnvir is needed // because we'll no longer be in this Event // when defer wakes up go.inEnvir.defer } { go.value }; }, monoOff: #{|server| if(~hasGate == false) { ~schedBundle.value(~lag, ~timingOffset, server, [\n_free] ++ ~id.asControlInput); } { ~schedBundle.value(~lag, ~timingOffset, server, *([15 /* \n_set */, ~id.asControlInput, \gate, 0].flop) ); }; }, monoSet: #{|server| var freqs, lag, bndl; freqs = ~freq = ~detunedFreq.value; ~amp = ~amp.value; ~sustain = ~sustain.value; bndl = ([15 /* \n_set */, ~id.asControlInput] ++ ~msgFunc.valueEnvir).flop; bndl = bndl.collect(_.asOSCArgArray); ~schedBundle.value(~lag, ~timingOffset, server, *bndl); }, monoNote: #{ |server| var bndl, id, ids, addAction, f; addAction = Node.actionNumberFor(~addAction); ~freq = ~detunedFreq.value; f = ~freq; ~amp = ~amp.value; bndl = ( [9 /* \s_new */, ~instrument, ids, addAction, ~group.asControlInput] ++ ~msgFunc.valueEnvir).flop; bndl.do { | b | id = server.nextNodeID; ids = ids.add(id); b[2] = id; }; if ((addAction == 0) || (addAction == 3)) { bndl = bndl.reverse; }; bndl = bndl.collect(_.asOSCArgArray); ~schedBundle.value(~lag, ~timingOffset, server, *bndl); ~updatePmono.value(ids, server); }, Synth: #{ |server| var instrumentName, desc, msgFunc, sustain; var bndl, synthLib, addAction, group, latency, ids, id, groupControls; ~server = server; addAction = Node.actionNumberFor(~addAction); group = ~group.asControlInput; ~freq = ~detunedFreq.value; ~amp = ~amp.value; ~sustain = sustain = ~sustain.value; ids = ~id; msgFunc = ~getMsgFunc.valueEnvir; instrumentName = ~synthDefName.valueEnvir; bndl = [9 /* \s_new */, instrumentName, ids, addAction, group] ++ msgFunc.valueEnvir; if ((addAction == 0) || (addAction == 3)) { bndl = bndl.reverse; }; bndl = bndl.collect(_.asOSCArgArray); server.sendBundle(server.latency, *bndl); ~id = ids; ~isPlaying = true; NodeWatcher.register(currentEnvironment); }, Group: #{|server| var ids, group, addAction, bundle; ids = ~id = (~id ?? { server.nextNodeID }).asArray; addAction = Node.actionNumberFor(~addAction); group = ~group.asControlInput; ~server = server; if ((addAction == 0) || (addAction == 3) ) { ids = ids.reverse; }; bundle = ids.collect {|id, i| [21 /* \g_new */, id, addAction, group]; }; server.sendBundle(server.latency, *bundle); ~isPlaying = true; NodeWatcher.register(currentEnvironment); }, tree: #{ |server| var doTree = { |tree, currentNode, addAction=1| if(tree.isKindOf(Association)) { ~bundle = ~bundle.add([21 /* \g_new */, tree.key.asControlInput, Node.actionNumberFor(addAction), currentNode.asControlInput]); currentNode = tree.key; tree = tree.value; }; if(tree.isSequenceableCollection) { tree.do { |x, i| x ?? { tree[i] = x = server.nextNodeID }; doTree.(x, currentNode) }; } { ~bundle = ~bundle.add([21 /* \g_new */, tree.asControlInput, Node.actionNumberFor(addAction), currentNode.asControlInput]); }; }; ~bundle = nil; ~treeGroups = ~treeGroups ?? { ~tree.deepCopy }; ~treeGroups !? { doTree.(~treeGroups, ~group, ~addAction); CmdPeriod.doOnce { ~treeGroups = nil }; }; ~bundle !? { server.sendBundle(server.latency, *~bundle); }; ~bundle = nil; } ) ) ); parentEvents = ( default: ().putAll( partialEvents.pitchEvent, partialEvents.ampEvent, partialEvents.durEvent, partialEvents.bufferEvent, partialEvents.serverEvent, partialEvents.playerEvent, partialEvents.midiEvent ), groupEvent: ( lag: 0, play: #{ var server, group, addAction, ids, bundle; ~finish.value; group = ~group.asControlInput; addAction = Node.actionNumberFor(~addAction); ~server = server= ~server ?? {Server.default}; ids = Event.checkIDs(~id, server); if (ids.isNil) { ids = ~id = server.nextNodeID }; if ((addAction == 0) || (addAction == 3) ) { ids = ids.asArray.reverse; }; bundle = ids.collect {|id, i| [21 /* \g_new */, id, addAction, group]; }; server.sendBundle(server.latency, *bundle); ~isPlaying = true; ~isRunning = true; NodeWatcher.register(currentEnvironment); }).putAll(partialEvents.nodeEvent), synthEvent: ( lag: 0, play: #{ var server, latency, group, addAction; var instrumentName, synthLib, desc, msgFunc; var msgs, cvs; var bndl, ids; ~finish.value; ~server = server = ~server ?? { Server.default }; ~sustain = ~sustain.value; group = ~group.asControlInput; addAction = Node.actionNumberFor(~addAction); synthLib = ~synthLib ?? { SynthDescLib.global }; instrumentName = ~instrument.asDefName; desc = synthLib.synthDescs[instrumentName]; if (desc.notNil) { msgFunc = desc.msgFunc; ~hasGate = desc.hasGate; } { msgFunc = ~defaultMsgFunc; }; msgs = msgFunc.valueEnvir.flop; ids = Event.checkIDs(~id, server); if (ids.isNil) { ids = msgs.collect { server.nextNodeID } }; bndl = ids.collect { |id, i| [9 /* \s_new */, instrumentName, id, addAction, group] ++ msgs[i] }; if ((addAction == 0) || (addAction == 3)) { bndl = bndl.reverse; }; bndl = bndl.asOSCArgBundle; if (~lag !=0) { server.sendBundle(server.latency ? 0 + ~lag, *bndl); } { server.sendBundle(server.latency, *bndl); }; ~id = ids; ~isPlaying = true; ~isRunning = true; NodeWatcher.register(currentEnvironment); }, defaultMsgFunc: #{|freq = 440, amp = 0.1, pan = 0, out = 0| [\freq, freq, \amp, amp, \pan, pan, \out, out] } ).putAll(partialEvents.nodeEvent) ); defaultParentEvent = parentEvents.default; } } SuperCollider-Source/SCClassLibrary/Common/Collections/EventTypesWithCleanup.sc000644 000765 000024 00000016200 12766171707 031021 0ustar00crucialstaff000000 000000 EventTypesWithCleanup { classvar <>cleanupTypes, <>ugenInputTypes, <>notNodeType; *initClass { Class.initClassTree(Event); Event.default[\eventTypes].putAll( ( // ~bufnum has a default of 0, so we use ~bufNum instead.... table: #{ | server | var bufNum; if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_setn, bufNum.asUGenInput, 0, ~amps.size] ++ ~amps) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~amps.size; ~numChannels = 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_setn, bufNum.asUGenInput, 0, ~amps.size] ++ ~amps ]); } }, cheby: #{ | server | var bufNum; if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \cheby, ~genflags ? 7] ++ ~amps) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \cheby, ~genflags ? 7] ++ ~amps ]); } }, sine1: #{ | server | var bufNum; if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \sine1, ~genflags ? 7] ++ ~amps) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \sine1, ~genflags ? 7] ++ ~amps ]); } }, sine2: #{ | server | var bufNum, array = [~freqs, ~amps].lace(~freqs.size * 2); if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \sine2, ~genflags ? 7] ++ array) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \sine1, ~genflags ? 7] ++ array ]); } }, sine3: #{ | server | var bufNum, array = [~freqs, ~amps, ~phases].lace(~freqs.size * 3); if ( (bufNum = ~bufNum).notNil) { ~schedBundle.value(~lag, ~timingOffset, server, [\b_gen, bufNum.asUGenInput, \sine3, ~genflags ? 7] ++ array) } { ~type = \buffer; bufNum = ~bufNum = server.bufferAllocator.alloc; ~numFrames = ~numFrames ? 1024; ~numChannels = ~numChannels ? 1; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels, [\b_gen, bufNum, \sine1, ~genflags ? 7] ++ array ]); } }, buffer: #{ | server | ~bufNum = server.bufferAllocator.alloc(~numBufs ?? { ~numBufs = 1}); ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, ~bufNum, ~numFrames, ~numChannels]); }, freeBuffer: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_free, ~bufNum]); server.bufferAllocator.free(~bufNum); }, allocRead: #{|server| var bufNum; if ( (bufNum = ~bufNum).isNil ) { bufNum = ~bufNum = server.bufferAllocator.alloc; ~type = \allocReadID }; ~schedBundle.value(~lag, ~timingOffset, server, [\b_allocRead, bufNum, ~path, ~firstFileFrame, ~numFrames]); }, allocWrite: #{|server| var bufNum; if ( (bufNum = ~bufNum).isNil ) { bufNum = ~bufNum = server.bufferAllocator.alloc; ~type = \allocWriteID }; ~schedBundle.value(~lag, ~timingOffset, server, [\b_alloc, bufNum, ~numFrames, ~numChannels], [\b_write, bufNum, ~path, ~headerFormat, ~sampleFormat, 0, 0, 1]); }, cue: #{ | server | var bufNum, bndl, completion; if ( (bufNum = ~bufNum).isNil ) { bufNum = ~bufNum = server.bufferAllocator.alloc; ~type = \cueID }; completion = ["/b_read", bufNum, ~path, ~firstFileFrame, ~bufferSize, ~firstBufferFrame, ~leaveOpen]; bndl = ["/b_alloc", bufNum, ~bufferSize, ~numChannels, completion]; ~schedBundle.value(~lag, ~timingOffset, server, bndl); }, freeAllocRead: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_free, ~bufNum]); }, freeAllocWrite: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_close, ~bufNum], [\b_free, ~bufNum]); }, freeAllocWriteID: #{|server| ~schedBundle.value(~lag, ~timingOffset, server, [\b_close, ~bufNum], [\b_free, ~bufNum]); server.bufferAllocator.free(~bufNum); }, freeCue: #{ | server | var bufNum = ~bufNum; ~schedBundleArray.value(~lag, ~timingOffset, server, [['/b_close', bufNum],['/b_free', bufNum ]] ); }, freeCueID: #{ | server | var bufNum = ~bufNum; ~schedBundleArray.value(~lag, ~timingOffset, server, [['/b_close', bufNum], ['/b_free', bufNum ]] ); server.bufferAllocator.free(bufNum); }, audioBus: #{ | server | ~out = server.audioBusAllocator.alloc(~channels ? 1) }, controlBus: #{ | server | ~out = server.controlBusAllocator.alloc(~channels ? 1) }, freeAudioBus: #{ | server | server.audioBusAllocator.free(~out) }, freeControlBus: #{ | server | server.controlBusAllocator.free(~out) } //, // // group: #{|server| // var bundle; // if (~id.isNil) { ~id = server.nextNodeID }; // bundle = [\g_new, ~id.asArray, Node.actionNumberFor(~addAction), ~group.asUGenInput].flop; // ~schedBundleArray.value(~lag, ~timingOffset, server, bundle); // } ) ); notNodeType = ( note: false, on: false, group: false, fadeBus: false, tree: false ); cleanupTypes = ( table: \freeBuffer, // free buffer and deallocate bufNum buffer: \freeBuffer, // free buffer and deallocate bufNum allocRead: \freeAllocRead, // free buffer allocWrite: \freeAllocWrite, // close file and free buffer allocWriteID: \freeAllocWriteID, // close file, free buffer and deallocate bufNum cue: \freeCue, // free buffer, close file allocReadID: \freeBuffer, // free buffer and deallocate bufNum cueID: \freeCueID, // free buffer, close file, and deallocate bufNum audioBus: \freeAudioBus, // deallocate bus controlBus: \freeControlBus, // deallocate bus // load: \free, // bufNum was allocated elsewhere, let the source clean it up // gen: \free, // read: \free, alloc: \free, on: \off, group: \kill, tree: \kill ); ugenInputTypes = ( buffer: \bufNum, allocRead: \bufNum, allocReadID: \bufNum, allocWrite: \bufNum, allocWriteID: \bufNum, audioBus: \out, controlBus: \out, on: \id, group: \id, tree: \id ); } *cleanup { | ev, flag = true | var type, notNode; type = ev[\type]; notNode = notNodeType[type] ? true; if (flag || notNode) { if(cleanupTypes[type].notNil, { ( parent: ev, type: cleanupTypes[type] ).play; }, { "Cleanup type for event type '%' not found".format(type).warn; } ); } } } SuperCollider-Source/SCClassLibrary/Common/Collections/Harmonics.sc000644 000765 000024 00000003525 12756534416 026477 0ustar00crucialstaff000000 000000 Harmonics { var <>size; // Harmonics objects are convenient factories for creating Arrays that // are used to fill buffers using the b_gen sine fill commands on the server. *new { arg size = 32; ^super.newCopyArgs(size) } // decays with frequency decay { arg k = 1; ^Array.fill(size) {|i| 1.0 / ((i+1) ** k) } } geom { arg k = 1.2; ^Array.fill(size) {|i| 1.0 / (k ** i) } } // random values rand { arg lo=0.0, hi=1.0; ^Array.rand(size, lo, hi) } exprand { arg lo=0.01, hi=1.0; ^Array.exprand(size, lo, hi) } linrand { arg lo=0.0, hi=1.0; ^Array.linrand(size, lo, hi) } rand2 { arg val=1.0; ^Array.rand2(size, val) } coin { arg prob = 0.5; ^Array.fill(size) { if (prob.coin, 1.0, -1.0) } } // other useful shapes formant { arg center=12, width = 3; var start, end; start = center - (width/2); end = center + (width/2); ^Array.fill(size) {|i| if (i <= start) { 0.0 } { if (i >= end) { 0.0 } { hanWindow((i - start) / width); } } } } teeth { arg spacing = 2, start = 0; ^Array.fill(size) {|i| if (i < start) { 0.0 } { i = i - start; if ((i % spacing) == 0, 1.0, 0.0) } } } cutoff { arg n; ^Array.fill(size) {|i| if (i <= n, 1.0, 0.0) } } shelf { arg start, end, startLevel = 1.0, endLevel = 0.0; ^Array.fill(size) {|i| if (i <= start) { startLevel } { if (i >= end) { endLevel } { ((i - start) / (end - start)) * (endLevel - startLevel) + startLevel; } } } } sine { arg wavelength=4, iphase=0.5pi, mul=1.0, add=0.0; ^Array.fill(size) {|i| sin(2pi/wavelength * i + iphase) * mul + add } } pulse { arg wavelength=4, iphase=0, duty = 0.5, mul=1.0, add=0.0; ^Array.fill(size) {|i| if (((i - iphase) % wavelength) < duty, 1.0, 0.0) * mul + add } } ramp { arg start=1.0, step; step = step ? size.reciprocal; ^Array.series(size, start, step) } } SuperCollider-Source/SCClassLibrary/Common/Collections/Interval.sc000644 000765 000024 00000003013 12756534416 026330 0ustar00crucialstaff000000 000000 Interval : Collection { var <>start, <>end, <>step; *new { arg start, end, step=1; ^super.newCopyArgs(start, end, step) } size { ^end - start div: step + 1 } at { arg index; if (index < 0 or: { index >= this.size }, { ^nil }); ^step * index + start; } wrapAt { arg index; ^step * (index % this.size) + start } clipAt { arg index; if (index < 0) { ^start }; if (index >= this.size) { ^end }; ^step * index + start; } do { arg function; forBy(start, end, step, function); } add { ^this.shouldNotImplement(thisMethod) } put { ^this.shouldNotImplement(thisMethod) } storeArgs { ^[start, end, step] } storeOn { arg stream; stream << this.class.name; this.storeParamsOn(stream); } printOn { arg stream; this.storeOn(stream) } } Range : Collection { var <>start, <>size; *new { arg start, size; ^super.newCopyArgs(start, size); } end { ^start + size } do { arg function; for(start, start+size-1, function); } at { arg index; var val; if (index < 0 or: { index >= size }, { ^nil }); ^start + index; } includes { arg val; ^(val >= start) and: { (val < this.end) and: { val.frac == 0 }} } add { ^this.shouldNotImplement(thisMethod) } put { ^this.shouldNotImplement(thisMethod) } split { arg num; // assert: size > num var newRange = this.class.new(start, num); start = start + num; size = size - num; ^newRange } storeArgs { ^[start, size] } storeOn { arg stream; stream << this.class.name; this.storeParamsOn(stream); } printOn { arg stream; this.storeOn(stream) } } SuperCollider-Source/SCClassLibrary/Common/Collections/Library.sc000644 000765 000024 00000021646 12756534416 026164 0ustar00crucialstaff000000 000000 MultiLevelIdentityDictionary : Collection { var <>dictionary; *new { ^super.new.init } init { dictionary = this.newInternalNode; } newInternalNode { ^this.nodeType.new } nodeType { ^IdentityDictionary; } at { arg ... path; ^this.atPath(path) } atPathFail { arg path, function; var item; item = dictionary; path.do({ arg name; item = item.at(name); if (item.isNil, { ^function.value }); }); ^item } atPath { arg path; ^this.atPathFail(path) } put { arg ... path; var item; item = path.pop; ^this.putAtPath(path, item); } putAtPath { arg path, val; var item, lastName; path = path.copy; lastName = path.pop; item = dictionary; path.do({ arg name; item = item.atFail(name, { var newitem; newitem = this.newInternalNode; item.put(name, newitem); newitem }); }); item.put(lastName, val); } create { arg ... args; var item; item = dictionary; args.do({ arg name; item = item.atFail(name, { var newitem; newitem = this.newInternalNode; item.put(name, newitem); newitem }); }); } choose { arg ... start; var item; if(start.isEmpty,{ item = dictionary; },{ item = this.at(*start); if(item.isNil,{ Error("Library-choose start address not found: " ++ start).throw; }); }); ^this.prChooseFrom(item); } putTree { arg ... items; this.prPutTree([],items) } postTree { arg obj,tabs=0; if(obj.isNil,{ obj = dictionary }); if(obj.isKindOf(this.nodeType),{ "".postln; obj.keysValuesDo({ arg k,v; tabs.do({ Char.tab.post }); k.post; ": ".post; this.postTree(v,tabs + 1) }); },{ Char.tab.post; obj.asString.postln; }) } do { arg function; dictionary.do(function); } // remove only the leaf node indicated by path // parent nodes remain in the MLID even if they are empty removeAt { arg ... path; ^this.removeAtPath(path) } removeAtPath { arg path; var item, lastName; path = path.copy; lastName = path.pop; item = dictionary; path.do({ arg name; item = item.at(name); if (item.isNil, { ^nil }); }); ^item.removeAt(lastName); } // remove the leaf node // as well as parent nodes that become empty after removing the child // slower but leaves less cruft in the tree prRemoveAtPathRecursive { |path, i = 0, item| var name = path[i], result; if(item[name].isNil) { ^nil }; if(i < (path.size-1)) { result = this.prRemoveAtPathRecursive(path, i+1, item[name]); (item[name].isEmpty).if({ item.removeAt(name) }); ^result } { ^item.removeAt(name) }; } removeEmptyAtPath { arg path; ^this.prRemoveAtPathRecursive(path, 0, dictionary) } removeEmptyAt { arg ...path; ^this.prRemoveAtPathRecursive(path, 0, dictionary); } //private add { arg assn; this.put(assn.key, assn.value); } remove { ^this.shouldNotImplement(thisMethod) } removeFail { ^this.shouldNotImplement(thisMethod) } prChooseFrom { arg dict; var item; item = dict.choose; if(item.isKindOf(this.nodeType),{ ^this.prChooseFrom(item); },{ ^item }) } prPutTree { arg keys,items; forBy(0,items.size - 1,2,{ arg i; var key,item; key = items.at(i); item = items.at(i + 1); if(item.isArray.not,{ this.put(* keys ++ [key,item]); },{ //array this.prPutTree(keys ++ [key],item); }) }); } leaves { arg startAt; if(startAt.isNil,{ startAt = dictionary; },{ startAt = this.at(*startAt); }); ^this.prNestedValuesFromDict(startAt); } prNestedValuesFromDict { arg dict; ^dict.values.collect({ arg thing; if(thing.isKindOf(this.nodeType),{ this.prNestedValuesFromDict(thing) },{ thing }) }) } // Tree-like do methods leafDo { arg func; this.doLeafDo([], this.dictionary, func); } leafDoFrom { arg folderpath, func; var folder; folderpath = folderpath.asArray; folder = this.atPath(folderpath); if (folder.notNil && folder.isKindOf(this.nodeType), { this.doLeafDo(folderpath, folder, func); }); } doLeafDo { arg path, object, func; if (object.isKindOf(this.nodeType), { object.keysValuesDo({ arg name, subobject; this.doLeafDo(path ++ [name], subobject, func) }); }, { func.value(path, object); }) } treeDo { arg branchFunc, leafFunc, argument0, postBranchFunc; var result; result = this.doTreeDo([], this.dictionary, branchFunc, leafFunc, argument0, postBranchFunc); ^result; } treeDoFrom { arg folderpath, branchFunc, leafFunc, argument0, postBranchFunc; var folder, result; folderpath = folderpath.asArray; folder = this.atPath(folderpath); if (folder.isKindOf(this.nodeType), { result = this.doTreeDo(folderpath, folder, branchFunc, leafFunc, argument0, postBranchFunc); }, { result = nil; }); ^result; } doTreeDo { arg path, object, branchFunc, leafFunc, argument, postBranchFunc; var result; if (object.isKindOf(this.nodeType), { if (branchFunc.notNil, { result = branchFunc.value(path, object, argument); }, { result = argument; }); object.keysValuesDo({ arg name, subobject; this.doTreeDo(path ++ [name], subobject, branchFunc, leafFunc, result, postBranchFunc) }); if (postBranchFunc.notNil, { result = postBranchFunc.value(path, object, result); }); ^result }, { leafFunc.value(path, object, argument); }) } treeCollect { arg branchFunc, leafFunc, postBranchFunc; var result; result = this.doTreeCollect([], this.dictionary, branchFunc, leafFunc, postBranchFunc); ^result; } doTreeCollect { arg path, object, branchFunc, leafFunc, postBranchFunc; var confirm, collection, result; if (object.isKindOf(this.nodeType), { if (branchFunc.notNil, { #confirm, result = branchFunc.value(path, object); }, { #confirm, result = [true, nil] }); if (confirm, { collection = []; object.keysValuesDo({ arg name, subobject; collection = collection.add(this.doTreeCollect(path ++ [name], subobject, branchFunc, leafFunc, postBranchFunc)); }); collection.removeAllSuchThat({arg item; item.isNil}); if (postBranchFunc.notNil, { result = postBranchFunc.value(path, object, collection); }, { result = nil; }); ^result }, { ^nil }); }, { ^leafFunc.value(path, object) }); } sortedTreeDo { arg branchFunc, leafFunc, argument0, postBranchFunc, sortFunc; var result; result = this.doSortedTreeDo([], this.dictionary, branchFunc, leafFunc, argument0, postBranchFunc, sortFunc); ^result; } doSortedTreeDo { arg path, object, branchFunc, leafFunc, argument, postBranchFunc, sortFunc; var result; sortFunc = sortFunc ? {arg a, b; a < b}; if (object.isKindOf(this.nodeType), { if (branchFunc.notNil, { result = branchFunc.value(path, object, argument); }, { result = argument; }); object.sortedKeysValuesDo({ arg name, subobject; this.doSortedTreeDo(path ++ [name], subobject, branchFunc, leafFunc, result, postBranchFunc, sortFunc) }); if (postBranchFunc.notNil, { postBranchFunc.value(path, object, result); }); ^result }, { leafFunc.value(path, object, argument); }) } leafDoInBranch { arg folderpath, function; var path, folder; folderpath = folderpath.asArray; folder = this.atPath(folderpath); if (folder.notNil && folder.isKindOf(this.nodeType), { folder.keysValuesDo({ arg name, object; if (object.isKindOf(this.nodeType).not, { function.value(folderpath ++ [name], object); }); }); }); } storeOn { arg stream; stream << this.class.name << "[" <<<* dictionary << "]" } printOn { arg stream; stream << this.class.name << "[" <<* dictionary << "]" } } LibraryBase : MultiLevelIdentityDictionary { *global { ^this.subclassResponsibility(thisMethod); } *global_ { arg obj; ^this.subclassResponsibility(thisMethod); } *clear { this.global = this.new; } *at { arg ... args; ^this.global.at(*args); } *atList { arg args; ^this.global.at(*args) } *putList { arg args; ^this.global.put(*args) } *put { arg ... args; ^this.global.put(*args) } *create { arg ... args; ^this.global.create(*args) } *postTree { this.global.postTree } } Library : LibraryBase { classvar global; *global { ^global } *global_ { arg obj; global = obj; } *initClass { global = this.new; } } Archive : LibraryBase { classvar global; classvar <>archiveDir; *global { ^global } *global_ { arg obj; global = obj; } *initClass { global = this.new; archiveDir = Platform.userAppSupportDir; } *read { arg filename; var expandedFileName; expandedFileName = filename ?? (archiveDir ++ "/archive.sctxar"); if (File.exists(expandedFileName)) { if (expandedFileName.endsWith(".scar")) { global = this.readBinaryArchive(expandedFileName); }{ global = this.readArchive(expandedFileName); }; if (global.isNil) { global = this.new; }; } } *write { arg filename; var expandedFileName; expandedFileName = filename ?? (archiveDir ++ "/archive.sctxar"); global.writeArchive(expandedFileName); } } SuperCollider-Source/SCClassLibrary/Common/Collections/LinkedList.sc000644 000765 000024 00000005504 12756534416 026615 0ustar00crucialstaff000000 000000 LinkedListNode { var <>prev, <>next, <>obj; // this class supports the LinkedList class *new { arg item; ^super.new.obj_(item) } remove { if (prev.notNil, { prev.next_(next); }); if (next.notNil, { next.prev_(prev); }); next = prev = nil; } } LinkedList : SequenceableCollection { var head, tail, = 0 and: { index < size }, { if (index < (size - index), { node = head; while ({ i != index },{ node = node.next; i = i + 1; }); ^node },{ i = size - 1; node = tail; while ({ i != index },{ node = node.prev; i = i - 1; }); ^node }); },{ this.indexOutOfRange; ^nil }) } findNodeOfObj { arg obj; var node = head; while ({ node.notNil },{ if (node.obj == obj, { ^node }); node = node.next; }); ^nil } } SuperCollider-Source/SCClassLibrary/Common/Collections/linux/000755 000765 000024 00000000000 13007315613 025341 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/Collections/List.sc000644 000765 000024 00000006246 12756534416 025472 0ustar00crucialstaff000000 000000 List : SequenceableCollection { var <>array; *new { arg size = 8; ^super.new.setCollection(Array.new(size)); } *newClear { arg size = 0; if ( size == 0, { ^super.new.setCollection(Array.new(8)); },{ ^super.new.setCollection(Array.newClear(size)); }); } *copyInstance { arg aList; ^super.new.array_( aList.array.copy ) } *newUsing { arg anArray; // an array is supplied to use directly ^super.new.setCollection( anArray ) } asArray { ^array.copy } copy { ^this.class.copyInstance(this) } copyRange { arg start, end; ^this.class.newUsing(array.copyRange(start, end)) } copySeries { arg first, second, last; ^this.class.newUsing(array.copySeries(first, second, last)) } putSeries { arg first, second, last, value; array.putSeries(first, second, last, value); } grow { arg sizeIncrease; array = array.grow(sizeIncrease); } size { ^array.size } dump { "List's array:\n".post; array.dump } clear { this.setCollection(Array.new(8)); } // accessing at { arg i; ^array.at(i) } clipAt { arg i; i = i.asInteger.clip(0, this.size - 1); ^array.at(i) } wrapAt { arg i; i = i.asInteger.wrap(0, this.size - 1); ^array.at(i) } foldAt { arg i; i = i.asInteger.fold(0, this.size - 1); ^array.at(i) } put { arg i, item; array.put(i, item) } clipPut { arg i, item; i = i.asInteger.clip(0, this.size - 1); ^array.put(i, item) } wrapPut { arg i, item; i = i.asInteger.wrap(0, this.size - 1); ^array.put(i, item) } foldPut { arg i, item; i = i.asInteger.fold(0, this.size - 1); ^array.put(i, item) } add { arg item; array = array.add(item); } addFirst { arg item; array = array.addFirst(item); } insert { arg index, item; array = array.insert(index, item); } removeAt { arg index; ^array.removeAt(index); } pop { ^array.pop } first { if (this.size > 0, { ^array.at(0) }, { ^nil }) } last { if (this.size > 0, { ^array.at(this.size - 1) }, { ^nil }) } fill { arg item; array.fill(item) } // enumerating do { arg function; array.do(function); } reverseDo { arg function; array.reverseDo(function); } pairsDo { arg function; array.pairsDo(function); } doAdjacentPairs { arg function; array.doAdjacentPairs(function); } // ordering swap { arg i,j; array.swap(i, j) } reverse { ^this.class.newUsing(array.reverse); } rotate { arg n=1; ^this.class.newUsing(array.rotate(n)); } stutter { arg n=2; ^this.class.newUsing(array.stutter(n)); } mirror { ^this.class.newUsing(array.mirror); } mirror2 { ^this.class.newUsing(array.mirror2); } mirror1 { ^this.class.newUsing(array.mirror1); } scramble { ^this.class.newUsing(array.scramble); } permute { arg nthPermutation; ^this.class.newUsing(array.permute(nthPermutation)); } wrapExtend { arg length; ^this.class.newUsing(array.wrapExtend(length)); } foldExtend { arg length; ^this.class.newUsing(array.foldExtend(length)); } pyramid { arg patternType=1; // an integer from 1-10 ^this.class.newUsing(array.pyramid(patternType)); } lace { arg length; ^this.class.newUsing(array.lace(length)) } slide { arg windowLength=3, stepSize=1; ^this.class.newUsing(array.slide(windowLength, stepSize)); } // PRIVATE: setCollection { arg aColl; array = aColl.asArray; } asList { ^this } } SuperCollider-Source/SCClassLibrary/Common/Collections/ObjectTable.sc000644 000765 000024 00000002754 12756534416 026735 0ustar00crucialstaff000000 000000 TwoWayIdentityDictionary : Collection { var idToObj, objToID; *new { ^super.new.init; } add { arg anAssociation; this.put(anAssociation.key, anAssociation.value); } put { arg key, obj; idToObj.put(key, obj); objToID.put(obj, key); } remove { arg obj; var key; key = this.getID(obj); idToObj.removeAt(key); objToID.removeAt(obj); } removeAt { arg key; var obj = this.at(key); idToObj.removeAt(key); objToID.removeAt(obj); } do { arg function; ^idToObj.do(function); } at { arg id; ^idToObj.at(id); } getID { arg obj; ^objToID.at(obj); } storeItemsOn { arg stream, itemsPerLine = 5; ^idToObj.storeItemsOn(stream, itemsPerLine) } printItemsOn { arg stream, itemsPerLine = 5; ^idToObj.printItemsOn(stream, itemsPerLine) } // PRIVATE init { idToObj = IdentityDictionary.new; objToID = IdentityDictionary.new; } } UniqueID { classvar linkDown, <>linkAcross; *new { arg linkDown, linkAcross; ^super.newCopyArgs(linkDown, linkAcross) } // create from nested array *newFrom { arg collection; var linkDown = collection.at(0); var linkAcross = collection.at(1); if(linkDown.isKindOf(Collection)) { linkDown = this.newFrom(linkDown) }; if(linkAcross.isKindOf(Collection)) { linkAcross = this.newFrom(linkAcross) }; ^this.new(linkDown, linkAcross) } size { var i = 0, link; link = linkAcross; while ({ link.respondsTo('linkAcross') },{ i = i + 1; link = link.linkAcross; }); ^i } depth { var i = 0, link; link = linkDown; while ({ link.respondsTo('linkDown') },{ i = i + 1; link = link.linkDown; }); ^i } do { arg function; var i = 0, link, res; link = linkAcross; while ({ link.respondsTo('linkAcross') },{ i = i + 1; res = function.value(link, i); link = link.linkAcross; }); ^res } traverse { arg function; // the default traversal order ^this.depthFirstPreOrderTraversal(function) } depthFirstPreOrderTraversal { arg function; var link; function.value(this); if ( linkDown.respondsTo('depthFirstPreOrderTraversal'), { linkDown.depthFirstPreOrderTraversal(function); }); // iterate linkAcross to conserve stack depth link = linkAcross; while ({ link.notNil },{ function.value(link); if (link.respondsTo(\linkDown) and: { link.linkDown.respondsTo('depthFirstPreOrderTraversal') }, { link.linkDown.depthFirstPreOrderTraversal(function); }); if(link.respondsTo('linkAcross')) { link = link.linkAcross; } { link = nil }; }); } depthFirstPostOrderTraversal { arg function; var link; if ( linkDown.respondsTo('depthFirstPostOrderTraversal'), { linkDown.depthFirstPostOrderTraversal(function); }); function.value(this); // iterate linkAcross to conserve stack depth link = linkAcross; while ({ link.notNil },{ if (link.respondsTo(\linkDown) and: { link.linkDown.respondsTo('depthFirstPostOrderTraversal') }, { link.linkDown.depthFirstPostOrderTraversal(function); }); function.value(link); if(link.respondsTo('linkAcross')) { link = link.linkAcross; } { link = nil }; }); } storeArgs { arg stream; ^[linkDown, linkAcross] } printOn { arg stream; stream << this.class.name << "(" <<* this.storeArgs << ")" } storeOn { arg stream; stream << this.class.name << "(" <<<* this.storeArgs << ")" } } SuperCollider-Source/SCClassLibrary/Common/Collections/PriorityQueue.sc000644 000765 000024 00000001622 12756534416 027376 0ustar00crucialstaff000000 000000 PriorityQueue { var array; put { arg time, item; _PriorityQueueAdd ^this.primitiveFailed; } pop { _PriorityQueuePop ^this.primitiveFailed; } topPriority { _PriorityQueueTop ^this.primitiveFailed; } clear { _PriorityQueueClear ^this.primitiveFailed; } postpone { arg time; _PriorityQueuePostpone ^this.primitiveFailed; } isEmpty { _PriorityQueueEmpty ^this.primitiveFailed; } notEmpty { ^this.isEmpty.not } removeValue {|value| var newObject = PriorityQueue(), currentPriority, topObject; while {this.notEmpty} { currentPriority = this.topPriority; topObject = this.pop; if (topObject != value) { newObject.put(currentPriority, topObject) } }; array = newObject.prInternalArray; } do {|func| if (array.size > 1) { forBy(1, array.size-1, 3) {|i| func.value(array[i+1],array[i+0]) } } } // private prInternalArray { ^array } } SuperCollider-Source/SCClassLibrary/Common/Collections/RingBuffer.sc000644 000765 000024 00000002544 12756534416 026605 0ustar00crucialstaff000000 000000 // Fixed size ringbuffer RingBuffer : SequenceableCollection { var 0) { array.put(writePos, value); writePos = (writePos + 1) % array.size; } } // return next readable item and increase readPos. // return nil if no items can be read. pop { var result; if (this.readable > 0) { result = array.at(readPos); readPos = (readPos + 1) % array.size; }; ^result } // add value and increase writePos by overwriting oldest readable // item. overwrite { | value | var result; if (this.writable == 0) { result = this.pop; }; this.add(value); ^result } // iterate over the currently readable items. do { | function | var n = this.readable, i = 0; while { i < n } { function.value(array.wrapAt(readPos + i), i); i = i + 1; } } } SuperCollider-Source/SCClassLibrary/Common/Collections/Scale.sc000644 000765 000024 00000051132 12756534416 025600 0ustar00crucialstaff000000 000000 Scale { var name; classvar name; classvar descScale; *new { | degrees, pitchesPerOctave, descDegrees, tuning, name = "Unknown Scale" | ^super.new(degrees, pitchesPerOctave, tuning, name) .descScale_(Scale(descDegrees, pitchesPerOctave, tuning, name ++ "desc")) ; } asStream { ^ScaleStream(this, 0) } embedInStream { ScaleStream(this).yield } } ScaleStream { var <>scale, <>curDegree; *new { | scale, startDegree = 0 | ^super.newCopyArgs(scale, startDegree) } chooseScale { |scaleDegree | if (scaleDegree >= curDegree) { curDegree = scaleDegree; ^scale } { curDegree = scaleDegree; ^scale.descScale } } performDegreeToKey { | degree, stepsPerOctave, accidental = 0 | ^this.chooseScale(degree).performDegreeToKey(degree, stepsPerOctave, accidental); } performKeyToDegree { | degree, stepsPerOctave = 12 | ^this.chooseScale(degree).performKeyToDegree(degree, stepsPerOctave) } performNearestInList { | degree | ^this.chooseScale(degree).performNearestInList(degree) } performNearestInScale { | degree, stepsPerOctave=12 | // collection is sorted ^this.chooseScale(degree).performNearestInScale(degree, stepsPerOctave) } } + Scale { *initClass { Class.initClassTree(Tuning); all = IdentityDictionary[ // TWELVE TONES PER OCTAVE // 5 note scales \minorPentatonic -> Scale.new(#[0,3,5,7,10], 12, name: "Minor Pentatonic"), \majorPentatonic -> Scale.new(#[0,2,4,7,9], 12, name: "Major Pentatonic"), // another mode of major pentatonic \ritusen -> Scale.new(#[0,2,5,7,9], 12, name: "Ritusen"), // another mode of major pentatonic \egyptian -> Scale.new(#[0,2,5,7,10], 12, name: "Egyptian"), \kumoi -> Scale.new(#[0,2,3,7,9], 12, name: "Kumai"), \hirajoshi -> Scale.new(#[0,2,3,7,8], 12, name: "Hirajoshi"), \iwato -> Scale.new(#[0,1,5,6,10], 12, name: "Iwato"), // mode of hirajoshi \chinese -> Scale.new(#[0,4,6,7,11], 12, name: "Chinese"), // mode of hirajoshi \indian -> Scale.new(#[0,4,5,7,10], 12, name: "Indian"), \pelog -> Scale.new(#[0,1,3,7,8], 12, name: "Pelog"), \prometheus -> Scale.new(#[0,2,4,6,11], 12, name: "Prometheus"), \scriabin -> Scale.new(#[0,1,4,7,9], 12, name: "Scriabin"), // han chinese pentatonic scales \gong -> Scale.new(#[0,2,4,7,9], 12, name: "Gong"), \shang -> Scale.new(#[0,2,5,7,10], 12, name: "Shang"), \jiao -> Scale.new(#[0,3,5,8,10], 12, name: "Jiao"), \zhi -> Scale.new(#[0,2,5,7,9], 12, name: "Zhi"), \yu -> Scale.new(#[0,3,5,7,10], 12, name: "Yu"), // 6 note scales \whole -> Scale.new((0,2..10), 12, name: "Whole Tone"), \augmented -> Scale.new(#[0,3,4,7,8,11], 12, name: "Augmented"), \augmented2 -> Scale.new(#[0,1,4,5,8,9], 12, name: "Augmented 2"), // Partch's Otonalities and Utonalities \partch_o1 -> Scale.new(#[0,8,14,20,25,34], 43, Tuning.partch, "Partch Otonality 1"), \partch_o2 -> Scale.new(#[0,7,13,18,27,35], 43, Tuning.partch, "Partch Otonality 2"), \partch_o3 -> Scale.new(#[0,6,12,21,29,36], 43, Tuning.partch, "Partch Otonality 3"), \partch_o4 -> Scale.new(#[0,5,15,23,30,37], 43, Tuning.partch, "Partch Otonality 4"), \partch_o5 -> Scale.new(#[0,10,18,25,31,38], 43, Tuning.partch, "Partch Otonality 5"), \partch_o6 -> Scale.new(#[0,9,16,22,28,33], 43, Tuning.partch, "Partch Otonality 6"), \partch_u1 -> Scale.new(#[0,9,18,23,29,35], 43, Tuning.partch, "Partch Utonality 1"), \partch_u2 -> Scale.new(#[0,8,16,25,30,36], 43, Tuning.partch, "Partch Utonality 2"), \partch_u3 -> Scale.new(#[0,7,14,22,31,37], 43, Tuning.partch, "Partch Utonality 3"), \partch_u4 -> Scale.new(#[0,6,13,20,28,38], 43, Tuning.partch, "Partch Utonality 4"), \partch_u5 -> Scale.new(#[0,5,12,18,25,33], 43, Tuning.partch, "Partch Utonality 5"), \partch_u6 -> Scale.new(#[0,10,15,21,27,34], 43, Tuning.partch, "Partch Utonality 6"), // hexatonic modes with no tritone \hexMajor7 -> Scale.new(#[0,2,4,7,9,11], 12, name: "Hex Major 7"), \hexDorian -> Scale.new(#[0,2,3,5,7,10], 12, name: "Hex Dorian"), \hexPhrygian -> Scale.new(#[0,1,3,5,8,10], 12, name: "Hex Phrygian"), \hexSus -> Scale.new(#[0,2,5,7,9,10], 12, name: "Hex Sus"), \hexMajor6 -> Scale.new(#[0,2,4,5,7,9], 12, name: "Hex Major 6"), \hexAeolian -> Scale.new(#[0,3,5,7,8,10], 12, name: "Hex Aeolian"), // 7 note scales \major -> Scale.new(#[0,2,4,5,7,9,11], 12, name: "Major"), \ionian -> Scale.new(#[0,2,4,5,7,9,11], 12, name: "Ionian"), \dorian -> Scale.new(#[0,2,3,5,7,9,10], 12, name: "Dorian"), \phrygian -> Scale.new(#[0,1,3,5,7,8,10], 12, name: "Phrygian"), \lydian -> Scale.new(#[0,2,4,6,7,9,11], 12, name: "Lydian"), \mixolydian -> Scale.new(#[0,2,4,5,7,9,10], 12, name: "Mixolydian"), \aeolian -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Aeolian"), \minor -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Natural Minor"), \locrian -> Scale.new(#[0,1,3,5,6,8,10], 12, name: "Locrian"), \harmonicMinor -> Scale.new(#[0,2,3,5,7,8,11], 12, name: "Harmonic Minor"), \harmonicMajor -> Scale.new(#[0,2,4,5,7,8,11], 12, name: "Harmonic Major"), \melodicMinor -> Scale.new(#[0,2,3,5,7,9,11], 12, name: "Melodic Minor"), \melodicMinorDesc -> Scale.new(#[0,2,3,5,7,8,10], 12, name: "Melodic Minor Descending"), \melodicMajor -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Melodic Major"), \bartok -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Bartok"), \hindu -> Scale.new(#[0,2,4,5,7,8,10], 12, name: "Hindu"), // raga modes \todi -> Scale.new(#[0,1,3,6,7,8,11], 12, name: "Todi"), \purvi -> Scale.new(#[0,1,4,6,7,8,11], 12, name: "Purvi"), \marva -> Scale.new(#[0,1,4,6,7,9,11], 12, name: "Marva"), \bhairav -> Scale.new(#[0,1,4,5,7,8,11], 12, name: "Bhairav"), \ahirbhairav -> Scale.new(#[0,1,4,5,7,9,10], 12, name: "Ahirbhairav"), \superLocrian -> Scale.new(#[0,1,3,4,6,8,10], 12, name: "Super Locrian"), \romanianMinor -> Scale.new(#[0,2,3,6,7,9,10], 12, name: "Romanian Minor"), \hungarianMinor -> Scale.new(#[0,2,3,6,7,8,11], 12, name: "Hungarian Minor"), \neapolitanMinor -> Scale.new(#[0,1,3,5,7,8,11], 12, name: "Neapolitan Minor"), \enigmatic -> Scale.new(#[0,1,4,6,8,10,11], 12, name: "Enigmatic"), \spanish -> Scale.new(#[0,1,4,5,7,8,10], 12, name: "Spanish"), // modes of whole tones with added note -> \leadingWhole -> Scale.new(#[0,2,4,6,8,10,11], 12, name: "Leading Whole Tone"), \lydianMinor -> Scale.new(#[0,2,4,6,7,8,10], 12, name: "Lydian Minor"), \neapolitanMajor -> Scale.new(#[0,1,3,5,7,9,11], 12, name: "Neapolitan Major"), \locrianMajor -> Scale.new(#[0,2,4,5,6,8,10], 12, name: "Locrian Major"), // 8 note scales \diminished -> Scale.new(#[0,1,3,4,6,7,9,10], 12, name: "Diminished"), \diminished2 -> Scale.new(#[0,2,3,5,6,8,9,11], 12, name: "Diminished 2"), // 12 note scales \chromatic -> Scale.new((0..11), 12, name: "Chromatic"), // TWENTY-FOUR TONES PER OCTAVE \chromatic24 -> Scale.new((0..23), 24, name: "Chromatic 24"), // maqam ajam \ajam -> Scale.new(#[0,4,8,10,14,18,22], 24, name: "Ajam"), \jiharkah -> Scale.new(#[0,4,8,10,14,18,21], 24, name: "Jiharkah"), \shawqAfza -> Scale.new(#[0,4,8,10,14,16,22], 24, name: "Shawq Afza"), // maqam sikah \sikah -> Scale.new(#[0,3,7,11,14,17,21], 24, name: "Sikah"), \sikahDesc -> Scale.new(#[0,3,7,11,13,17,21], 24, name: "Sikah Descending"), \huzam -> Scale.new(#[0,3,7,9,15,17,21], 24, name: "Huzam"), \iraq -> Scale.new(#[0,3,7,10,13,17,21], 24, name: "Iraq"), \bastanikar -> Scale.new(#[0,3,7,10,13,15,21], 24, name: "Bastanikar"), \mustar -> Scale.new(#[0,5,7,11,13,17,21], 24, name: "Mustar"), // maqam bayati \bayati -> Scale.new(#[0,3,6,10,14,16,20], 24, name: "Bayati"), \karjighar -> Scale.new(#[0,3,6,10,12,18,20], 24, name: "Karjighar"), \husseini -> Scale.new(#[0,3,6,10,14,17,21], 24, name: "Husseini"), // maqam nahawand \nahawand -> Scale.new(#[0,4,6,10,14,16,22], 24, name: "Nahawand"), \nahawandDesc -> Scale.new(#[0,4,6,10,14,16,20], 24, name: "Nahawand Descending"), \farahfaza -> Scale.new(#[0,4,6,10,14,16,20], 24, name: "Farahfaza"), \murassah -> Scale.new(#[0,4,6,10,12,18,20], 24, name: "Murassah"), \ushaqMashri -> Scale.new(#[0,4,6,10,14,17,21], 24, name: "Ushaq Mashri"), // maqam rast \rast -> Scale.new(#[0,4,7,10,14,18,21], 24, name: "Rast"), \rastDesc -> Scale.new(#[0,4,7,10,14,18,20], 24, name: "Rast Descending"), \suznak -> Scale.new(#[0,4,7,10,14,16,22], 24, name: "Suznak"), \nairuz -> Scale.new(#[0,4,7,10,14,17,20], 24, name: "Nairuz"), \yakah -> Scale.new(#[0,4,7,10,14,18,21], 24, name: "Yakah"), \yakahDesc -> Scale.new(#[0,4,7,10,14,18,20], 24, name: "Yakah Descending"), \mahur -> Scale.new(#[0,4,7,10,14,18,22], 24, name: "Mahur"), // maqam hijaz \hijaz -> Scale.new(#[0,2,8,10,14,17,20], 24, name: "Hijaz"), \hijazDesc -> Scale.new(#[0,2,8,10,14,16,20], 24, name: "Hijaz Descending"), \zanjaran -> Scale.new(#[0,2,8,10,14,18,20], 24, name: "Zanjaran"), // maqam hijazKar \hijazKar -> Scale.new(#[0,2,8,10,14,16,22], 24, name: "hijazKar"), // maqam saba \saba -> Scale.new(#[0,3,6,8,12,16,20], 24, name: "Saba"), \zamzam -> Scale.new(#[0,2,6,8,14,16,20], 24, name: "Zamzam"), // maqam kurd \kurd -> Scale.new(#[0,2,6,10,14,16,20], 24, name: "Kurd"), \kijazKarKurd -> Scale.new(#[0,2,8,10,14,16,22], 24, name: "Kijaz Kar Kurd"), // maqam nawa Athar \nawaAthar -> Scale.new(#[0,4,6,12,14,16,22], 24, name: "Nawa Athar"), \nikriz -> Scale.new(#[0,4,6,12,14,18,20], 24, name: "Nikriz"), \atharKurd -> Scale.new(#[0,2,6,12,14,16,22], 24, name: "Athar Kurd"), // Ascending/descending scales \melodicMinor -> ScaleAD(#[0,2,3,5,7,9,11], 12, #[0,2,3,5,7,8,10], name: "Melodic Minor"), \sikah -> ScaleAD(#[0,3,7,11,14,17,21], 24, #[0,3,7,11,13,17,21], name: "Sikah"), \nahawand -> ScaleAD(#[0,4,6,10,14,16,22], 24, #[0,4,6,10,14,16,20], name: "Nahawand"), ]; all = all.freezeAsParent; } } + Tuning { *initClass { all = IdentityDictionary[ //TWELVE-TONE TUNINGS \et12 -> Tuning.new((0..11), 2, "ET12"), \pythagorean -> Tuning.new([1, 256/243, 9/8, 32/27, 81/64, 4/3, 729/512, 3/2, 128/81, 27/16, 16/9, 243/128].ratiomidi, 2, "Pythagorean"), \just -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 45/32, 3/2, 8/5, 5/3, 9/5, 15/8].ratiomidi, 2, "5-Limit Just Intonation"), \sept1 -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 7/5, 3/2, 8/5, 5/3, 9/5, 15/8].ratiomidi, 2, "Septimal Tritone Just Intonation"), \sept2 -> Tuning.new([1, 16/15, 9/8, 6/5, 5/4, 4/3, 7/5, 3/2, 8/5, 5/3, 7/4, 15/8].ratiomidi, 2, "7-Limit Just Intonation"), \mean4 -> Tuning.new(#[0, 0.755, 1.93, 3.105, 3.86, 5.035, 5.79, 6.965, 7.72, 8.895, 10.07, 10.82], 2, "Meantone, 1/4 Syntonic Comma"), \mean5 -> Tuning.new(#[0, 0.804, 1.944, 3.084, 3.888, 5.028, 5.832, 6.972, 7.776, 8.916, 10.056, 10.86], 2, "Meantone, 1/5 Pythagorean Comma"), \mean6 -> Tuning.new(#[0, 0.86, 1.96, 3.06, 3.92, 5.02, 5.88, 6.98, 7.84, 8.94, 10.04, 10.9], 2, "Meantone, 1/6 Pythagorean Comma"), \kirnberger -> Tuning.new([1, 256/243, (5.sqrt)/2, 32/27, 5/4, 4/3, 45/32, 5 ** 0.25, 128/81, (5 ** 0.75)/2, 16/9, 15/8].ratiomidi, 2, "Kirnberger III"), \werckmeister -> Tuning.new(#[0, 0.92, 1.93, 2.94, 3.915, 4.98, 5.9, 6.965, 7.93, 8.895, 9.96, 10.935], 2, "Werckmeister III"), \vallotti -> Tuning.new(#[0, 0.94135, 1.9609, 2.98045, 3.92180, 5.01955, 5.9218, 6.98045, 7.9609, 8.94135, 10, 10.90225], 2, "Vallotti"), \young -> Tuning.new(#[0, 0.9, 1.96, 2.94, 3.92, 4.98, 5.88, 6.98, 7.92, 8.94, 9.96, 10.9], 2, "Young"), \reinhard -> Tuning.new([1, 14/13, 13/12, 16/13, 13/10, 18/13, 13/9, 20/13, 13/8, 22/13, 13/7, 208/105].ratiomidi, 2, "Mayumi Reinhard"), \wcHarm -> Tuning.new([1, 17/16, 9/8, 19/16, 5/4, 21/16, 11/8, 3/2, 13/8, 27/16, 7/4, 15/8].ratiomidi, 2, "Wendy Carlos Harmonic"), \wcSJ -> Tuning.new([1, 17/16, 9/8, 6/5, 5/4, 4/3, 11/8, 3/2, 13/8, 5/3, 7/4, 15/8].ratiomidi, 2, "Wendy Carlos Super Just"), \lu ->Tuning( [ 1, 2187/2048, 9/8, 19683/16384, 81/64, 177147/131072, 729/612, 3/2, 6561/4096, 27/16, 59049/32768, 243/128 ].ratiomidi, 2, "Chinese Shi-er-lu scale"), //MORE THAN TWELVE-TONE ET \et19 -> Tuning.new((0 .. 18) * 12/19, 2, "ET19"), \et22 -> Tuning.new((0 .. 21) * 6/11, 2, "ET22"), \et24 -> Tuning.new((0 .. 23) * 0.5, 2, "ET24"), \et31 -> Tuning.new((0 .. 30) * 12/31, 2, "ET31"), \et41 -> Tuning.new((0 .. 40) * 12/41, 2, "ET41"), \et53 -> Tuning.new((0 .. 52) * 12/53, 2, "ET53"), //NON-TWELVE-TONE JI \johnston -> Tuning.new([1, 25/24, 135/128, 16/15, 10/9, 9/8, 75/64, 6/5, 5/4, 81/64, 32/25, 4/3, 27/20, 45/32, 36/25, 3/2, 25/16, 8/5, 5/3, 27/16, 225/128, 16/9, 9/5, 15/8, 48/25].ratiomidi, 2, "Ben Johnston"), \partch -> Tuning.new([1, 81/80, 33/32, 21/20, 16/15, 12/11, 11/10, 10/9, 9/8, 8/7, 7/6, 32/27, 6/5, 11/9, 5/4, 14/11, 9/7, 21/16, 4/3, 27/20, 11/8, 7/5, 10/7, 16/11, 40/27, 3/2, 32/21, 14/9, 11/7, 8/5, 18/11, 5/3, 27/16, 12/7, 7/4, 16/9, 9/5, 20/11, 11/6, 15/8, 40/21, 64/33, 160/81].ratiomidi, 2, "Harry Partch"), \catler -> Tuning.new([1, 33/32, 16/15, 9/8, 8/7, 7/6, 6/5, 128/105, 16/13, 5/4, 21/16, 4/3, 11/8, 45/32, 16/11, 3/2, 8/5, 13/8, 5/3, 27/16, 7/4, 16/9, 24/13, 15/8].ratiomidi, 2, "Jon Catler"), \chalmers -> Tuning.new([1, 21/20, 16/15, 9/8, 7/6, 6/5, 5/4, 21/16, 4/3, 7/5, 35/24, 3/2, 63/40, 8/5, 5/3, 7/4, 9/5, 28/15, 63/32].ratiomidi, 2, "John Chalmers"), \harrison -> Tuning.new([1, 16/15, 10/9, 8/7, 7/6, 6/5, 5/4, 4/3, 17/12, 3/2, 8/5, 5/3, 12/7, 7/4, 9/5, 15/8].ratiomidi, 2, "Lou Harrison"), \sruti -> Tuning.new([1, 256/243, 16/15, 10/9, 9/8, 32/27, 6/5, 5/4, 81/64, 4/3, 27/20, 45/32, 729/512, 3/2, 128/81, 8/5, 5/3, 27/16, 16/9, 9/5, 15/8, 243/128].ratiomidi, 2, "Sruti"), \perret -> Tuning([1, 21/20, 35/32, 9/8, 7/6, 6/5, 5/4, 21/16, 4/3, 7/5, 35/24, 3/2, 63/40, 8/5, 5/3, 7/4, 9/5, 15/8, 63/32].ratiomidi, 2, "Wilfrid Perret"), \michael_harrison -> Tuning( [1, 28/27, 135/128, 16/15, 243/224, 9/8, 8/7, 7/6, 32/27, 6/5, 135/112, 5/4, 81/64, 9/7, 21/16, 4/3, 112/81, 45/32, 64/45, 81/56, 3/2, 32/21, 14/9, 128/81, 8/5, 224/135, 5/3, 27/16, 12/7, 7/4, 16/9, 15/8, 243/128, 27/14].ratiomidi, 2, "Michael Harrison 24 tone 7-limit"), //HARMONIC SERIES -- length arbitary \harmonic -> Tuning.new((1 .. 24).ratiomidi, 2, "Harmonic Series 24"), //STRETCHED/SHRUNK OCTAVE //Bohlen-Pierce \bp -> Tuning.new((0 .. 12) * (3.ratiomidi/13), 3.0, "Bohlen-Pierce"), \wcAlpha -> Tuning.new((0 .. 14) * 0.78, (15 * 0.78).midiratio, "Wendy Carlos Alpha"), \wcBeta -> Tuning.new((0 .. 18) * 0.638, (19 * 0.638).midiratio, "Wendy Carlos Beta"), \wcGamma -> Tuning.new((0 .. 33) * 0.351, (34 * 0.351).midiratio, "Wendy Carlos Gamma") ]; all = all.freezeAsParent; } } SuperCollider-Source/SCClassLibrary/Common/Collections/SequenceableCollection.sc000644 000765 000024 00000106477 12766171707 031177 0ustar00crucialstaff000000 000000 SequenceableCollection : Collection { // synonyms |@| { arg index; ^this.clipAt(index) } @@ { arg index; ^this.wrapAt(index) } @|@ { arg index; ^this.foldAt(index) } // fill with ramp of values *series { arg size, start=0, step=1; var obj = this.new(size); size.do {|i| obj.add(start + (step * i)); }; ^obj } // fill with geometric series *geom { arg size, start, grow; var i=0; var obj = this.new(size); while ({ i < size },{ obj.add(start); start = start * grow; i = i + 1; }); ^obj } // fill with fibonacci series *fib { arg size, a=0.0, b=1.0; var i=0, temp; var obj = this.new(size); while { i < size }{ obj.add(b); temp = b; b = a + b; a = temp; i = i + 1; }; ^obj } *rand { arg size, minVal, maxVal; var i=0; var obj = this.new(size); while ({ i < size },{ obj.add(rrand(minVal, maxVal)); i = i + 1; }); ^obj } *exprand { arg size, minVal, maxVal; var i=0; var obj = this.new(size); while ({ i < size },{ obj.add(exprand(minVal, maxVal)); i = i + 1; }); ^obj } *rand2 { arg size, val; var i=0; var obj = this.new(size); while ({ i < size },{ obj.add(val.rand2); i = i + 1; }); ^obj } *linrand { arg size, minVal, maxVal; var i=0; var range = maxVal - minVal; var obj = this.new(size); while ({ i < size },{ obj.add(minVal + range.linrand); i = i + 1; }); ^obj } // fill with interpolation of values between start and end *interpolation { arg size, start=0.0, end=1.0; var obj = this.new(size), step; if(size == 1) { ^obj.add(start) }; step = (end - start) / (size - 1); size.do {|i| obj.add(start + (i * step)); }; ^obj } ++ { arg aSequenceableCollection; var newlist = this.species.new(this.size + aSequenceableCollection.size); newlist = newlist.addAll(this).addAll(aSequenceableCollection); ^newlist } +++ { arg aSequenceableCollection, adverb; aSequenceableCollection = aSequenceableCollection.asSequenceableCollection; if(adverb.notNil) { if(adverb == 0) { ^this ++ aSequenceableCollection }; if(adverb == 1) { ^this +++ aSequenceableCollection }; if(adverb < 0) { ^aSequenceableCollection.perform('+++', this, adverb.neg) }; ^this.deepCollect(adverb - 1, { |sublist| sublist.asSequenceableCollection.collect {|item, i| item.asSequenceableCollection ++ aSequenceableCollection.wrapAt(i) } }) }; ^this.collect {|item, i| item.asSequenceableCollection ++ aSequenceableCollection.wrapAt(i) } } asSequenceableCollection { ^this } // select an element at random choose { ^this.at(this.size.rand) } // select an element at random using an array of weights wchoose { arg weights; ^this.at(weights.windex) } == { | aCollection | if (aCollection.class != this.class) { ^false }; if (this.size != aCollection.size) { ^false }; this.do { | item, i | if (item != aCollection[i]) { ^false }; }; ^true } hash { var hash = this.class.hash; this.do { | item | hash = hash << 1 bitXor: item.hash // encode item order by left shifting }; ^hash } copyRange { arg start, end; var newColl; var i = start; newColl = this.species.new(end - start); while ({ i <= end },{ newColl.add(this.at(i)); i = i + 1; }); ^newColl } keep { arg n; var size; if (n>=0) { ^this.copyRange(0, n-1) }{ size = this.size; ^this.copyRange(size+n, size-1) } } drop { arg n; var size = this.size; if (n>=0) { ^this.copyRange(n, size-1) }{ ^this.copyRange(0, size+n-1) } } copyToEnd { arg start; ^this.copyRange(start, this.size - 1) } copyFromStart { arg end; ^this.copyRange(0, end) } indexOf { arg item; this.do({ arg elem, i; if ( item === elem, { ^i }) }); ^nil } indexOfEqual { arg item, offset=0; (this.size - offset).do ({ arg i; i = i + offset; if ( item == this[i], { ^i }) }); ^nil } indicesOfEqual { |item| var indices; this.do { arg val, i; if (item == val) { indices = indices.add(i) } }; ^indices } find { |sublist, offset=0| var subSize_1 = sublist.size - 1, first = sublist.first, index; (this.size - offset).do { |i| index = i + offset; if (this[index] == first) { if (this.copyRange(index, index + subSize_1) == sublist) { ^index } }; }; ^nil } findAll { arg arr, offset=0; var indices, i=0; while { i = this.find(arr, offset); i.notNil }{ indices = indices.add(i); offset = i + 1; } ^indices } indexOfGreaterThan { arg val; ^this.detectIndex { |item| item > val }; } indexIn { arg val; // collection is sorted, returns closest index var i, a, b; var j = this.indexOfGreaterThan(val); if(j.isNil) { ^this.size - 1 }; if(j == 0) { ^j }; i = j - 1; ^if((val - this[i]) < (this[j] - val)) { i } { j } } indexInBetween { arg val; // collection is sorted, returns linearly interpolated index var a, b, div, i; if(this.isEmpty) { ^nil }; i = this.indexOfGreaterThan(val); if(i.isNil) { ^this.size - 1 }; if(i == 0) { ^i }; a = this[i-1]; b = this[i]; div = b - a; if(div == 0) { ^i }; ^((val - a) / div) + i - 1 } selectIndices { | function | ^this.selectIndicesAs(function, this.species); } selectIndicesAs { | function, class | var res = class.new(this.size); this.do {|elem, i| if (function.value(elem, i)) { res.add(i) } } ^res; } rejectIndices { | function | ^this.rejectIndicesAs(function, this.species); } rejectIndicesAs { | function, class | var res = class.new(this.size); this.do {|elem, i| if (function.value(elem, i).not) { res.add(i) } } ^res; } isSeries { arg step; if(this.size <= 1) { ^true }; this.doAdjacentPairs { |a, b| var diff = b - a; if(step.isNil) { step = diff } { if(step != diff) { ^false } } }; ^true } resamp0 { arg newSize; var factor = this.size - 1 / (newSize - 1).max(1); ^this.species.fill(newSize, { |i| this.at((i * factor).round(1.0).asInteger) }) } resamp1 { arg newSize; var factor = this.size - 1 / (newSize - 1).max(1); ^this.species.fill(newSize, { |i| this.blendAt(i * factor) }) } remove { arg item; var index = this.indexOf(item); ^if ( index.notNil, { this.removeAt(index); },{ nil }); } removing { arg item; var coll = this.copy; coll.remove(item); ^coll } take { arg item; var index = this.indexOf(item); ^if ( index.notNil, { this.takeAt(index); },{ nil }); } // accessing lastIndex { ^if(this.size > 0) { this.size - 1 } { nil } } middleIndex { ^if(this.size > 0) { (this.size - 1) div: 2 } { nil } } first { if (this.size > 0, { ^this.at(0) }, { ^nil }) } last { if (this.size > 0, { ^this.at(this.size - 1) }, { ^nil }) } middle { if (this.size > 0, { ^this.at((this.size - 1) div: 2) }, { ^nil }) } top { ^this.last } putFirst { arg obj; if (this.size > 0, { ^this.put(0, obj) }) } putLast { arg obj; if (this.size > 0, { ^this.put(this.size - 1, obj) }) } // compatibility with isolated objects obtain { arg index, default; ^this[index] ? default } instill { arg index, item, default; var res = if (index >= this.size) { this.extend(index + 1, default) }{ this.copy }; ^res.put(index, item) } // ordering pairsDo { arg function; forBy(0, this.size-2, 2) {|i| function.value(this[i], this[i+1], i); } } keysValuesDo { arg function; ^this.pairsDo(function) } doAdjacentPairs { arg function; (this.size - 1).do({ arg i; function.value(this.at(i), this.at(i+1), i); }) } separate { arg function = true; var list = Array.new; var sublist = this.species.new; this.doAdjacentPairs({ arg a, b, i; sublist = sublist.add(a); if ( function.value(a, b, i), { list = list.add(sublist); sublist = this.species.new; }); }); if(this.notEmpty) { sublist = sublist.add(this.last) }; list = list.add(sublist); ^list } delimit { arg function; var list, sublist; list = Array.new; sublist = this.species.new; this.do({ arg item, i; if ( function.value(item, i), { list = list.add(sublist); sublist = this.species.new; },{ sublist = sublist.add(item); }); }); list = list.add(sublist); ^list } clump { arg groupSize; var list = Array.new((this.size / groupSize).roundUp.asInteger); var sublist = this.species.new(groupSize); this.do({ arg item; sublist.add(item); if (sublist.size >= groupSize, { list.add(sublist); sublist = this.species.new(groupSize); }); }); if (sublist.size > 0, { list = list.add(sublist); }); ^list } clumps { arg groupSizeList; var i = 0; var list = Array.new(groupSizeList.size); // still better estimate than default var subSize = groupSizeList.at(0); var sublist = this.species.new(subSize); this.do({ arg item; sublist = sublist.add(item); if (sublist.size >= subSize, { i = i + 1; list = list.add(sublist); subSize = groupSizeList.wrapAt(i); sublist = this.species.new(subSize); }); }); if (sublist.size > 0, { list = list.add(sublist); }); ^list } curdle { arg probability; ^this.separate({ probability.coin }); } flatten { arg numLevels=1; var list; if (numLevels <= 0, { ^this }); numLevels = numLevels - 1; list = this.species.new; this.do({ arg item; if (item.respondsTo('flatten'), { list = list.addAll(item.flatten(numLevels)); },{ list = list.add(item); }); }); ^list } flat { ^this.prFlat(this.species.new(this.flatSize)) } prFlat { |list| this.do({ arg item, i; if (item.respondsTo('prFlat'), { list = item.prFlat(list); },{ list = list.add(item); }); }); ^list } flatIf { |func| var list = this.species.new(this.size); // as we don't know the size, just guess this.do({ arg item, i; if (item.respondsTo('flatIf') and: { func.value(item, i) }, { list = list.addAll(item.flatIf(func)); },{ list = list.add(item); }); }); ^list } flop { var list, size, maxsize; size = this.size; maxsize = 0; this.do({ arg sublist; var sz; sz = if(sublist.isSequenceableCollection, { sublist.size }, { 1 }); if (sz > maxsize, { maxsize = sz }); }); list = this.species.fill(maxsize, { this.species.new(size) }); this.do({ arg isublist, i; if(isublist.isSequenceableCollection, { list.do({ arg jsublist, j; jsublist.add( isublist.wrapAt(j) ); }); },{ list.do({ arg jsublist, j; jsublist.add( isublist ); }); }); }); ^list } flopWith { |func| var maxsize = this.maxValue { |sublist| if(sublist.isSequenceableCollection) { sublist.size } { 1 } }; ^this.species.fill(maxsize, { |i| func.value( *this.collect { |sublist| if(sublist.isSequenceableCollection) { sublist.wrapAt(i) } { sublist } }) }) } flopTogether { arg ... moreArrays; var standIn, maxSize = 0, array; array = [this] ++ moreArrays; array.do { |sublist| sublist.do { |each| maxSize = max(maxSize, each.size) } }; standIn = 0.dup(maxSize); array = array.collect { |sublist| sublist.add(standIn) }; ^array.collect { |sublist| sublist.flop.collect { |each| each.drop(-1) } // remove stand-in }; } flopDeep { arg rank; var size, maxsize; if(rank.isNil) { rank = this.maxDepth - 1 }; if(rank <= 1) { ^this.flop }; size = this.size; maxsize = this.maxSizeAtDepth(rank); ^this.species.fill(maxsize, { |i| this.wrapAtDepth(rank, i) }) } wrapAtDepth { arg rank, index; if(rank == 0) { ^this.wrapAt(index) }; ^this.collect { |item, i| if(item.isSequenceableCollection) { item.wrapAtDepth(rank - 1, index) } { item } } } unlace { arg numlists, clumpSize=1, clip=false; var size, list, sublist, self; size = (this.size + numlists - 1) div: numlists; list = this.species.fill(numlists, { this.species.new(size) }); self = if(clip) { this.keep(this.size.trunc(clumpSize * numlists).postln)} { this }; self.do({ arg item, i; sublist = list.at(i div: clumpSize % numlists); sublist.add(item); }); ^list } integrate { var list, sum = 0; list = this.class.new(this.size); this.do {|item| sum = sum + item; list.add( sum ); }; ^list } differentiate { var list, prev = 0; list = this.class.new(this.size); this.do {|item| list.add( item - prev ); prev = item; }; ^list } // complement to Integer:asDigits convertDigits { arg base=10; var lastIndex = this.lastIndex; ^this.sum { |x, i| if(x >= base) { Error("digit too large for base").throw }; base ** (lastIndex - i) * x }.asInteger } hammingDistance { |that| // if this is shorter than that, size difference should be included // (if this is longer, the do loop will take care of it) var count = (that.size - this.size).max(0); this.do({ |elem, i| if(elem != that[i]) { count = count + 1 }; }); ^count } // pitch operations degreeToKey { arg scale, stepsPerOctave=12; ^this.collect({ arg scaleDegree; scaleDegree.degreeToKey(scale, stepsPerOctave); }); } keyToDegree { arg scale, stepsPerOctave=12; ^this.collect { arg val; val.keyToDegree(scale, stepsPerOctave) } } nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted var key, root; root = this.trunc(stepsPerOctave); key = this % stepsPerOctave; ^key.nearestInList(scale) + root } nearestInList { arg list; // collection is sorted ^this.collect({ arg item; list.at(list.indexIn(item)) }) } transposeKey { arg amount, octave=12; ^((this + amount) % octave).sort } mode { arg degree, octave=12; ^(rotate(this, degree.neg) - this.wrapAt(degree)) % octave } performDegreeToKey { arg scaleDegree, stepsPerOctave = 12, accidental = 0; var baseKey = (stepsPerOctave * (scaleDegree div: this.size)) + this.wrapAt(scaleDegree); ^if(accidental == 0) { baseKey } { baseKey + (accidental * (stepsPerOctave / 12.0)) } } performKeyToDegree { | degree, stepsPerOctave = 12 | var n = degree div: stepsPerOctave * this.size; var key = degree % stepsPerOctave; ^this.indexInBetween(key) + n } performNearestInList { | degree | ^this.at(this.indexIn(degree)) } performNearestInScale { arg degree, stepsPerOctave=12; // collection is sorted var root = degree.trunc(stepsPerOctave); var key = degree % stepsPerOctave; ^key.nearestInList(this) + root } // supports a variation of Mikael Laurson's rhythm list RTM-notation. convertRhythm { var list, tie; list = List.new; tie = this.convertOneRhythm(list); if (tie > 0.0, { list.add(tie) }); // check for tie at end of rhythm ^list } sumRhythmDivisions { var sum = 0; this.do {|beats| sum = sum + abs(if (beats.isSequenceableCollection) { beats[0]; }{ beats }); }; ^sum } convertOneRhythm { arg list, tie = 0.0, stretch = 1.0; var beats, divisions, repeats; #beats, divisions, repeats = this; repeats = repeats ? 1; stretch = stretch * beats / divisions.sumRhythmDivisions; repeats.do({ divisions.do { |val| if (val.isSequenceableCollection) { tie = val.convertOneRhythm(list, tie, stretch) }{ val = val * stretch; if (val > 0.0) { list.add(val + tie); tie = 0.0; }{ tie = tie - val }; }; }; }); ^tie } isSequenceableCollection { ^true } containsSeqColl { ^this.any(_.isSequenceableCollection) } isAssociationArray { ^this.at(0).isKindOf(Association) } // unary math ops neg { ^this.performUnaryOp('neg') } bitNot { ^this.performUnaryOp('bitNot') } abs { ^this.performUnaryOp('abs') } ceil { ^this.performUnaryOp('ceil') } floor { ^this.performUnaryOp('floor') } frac { ^this.performUnaryOp('frac') } sign { ^this.performUnaryOp('sign') } squared { ^this.performUnaryOp('squared') } cubed { ^this.performUnaryOp('cubed') } sqrt { ^this.performUnaryOp('sqrt') } exp { ^this.performUnaryOp('exp') } reciprocal { ^this.performUnaryOp('reciprocal') } midicps { ^this.performUnaryOp('midicps') } cpsmidi { ^this.performUnaryOp('cpsmidi') } midiratio { ^this.performUnaryOp('midiratio') } ratiomidi { ^this.performUnaryOp('ratiomidi') } ampdb { ^this.performUnaryOp('ampdb') } dbamp { ^this.performUnaryOp('dbamp') } octcps { ^this.performUnaryOp('octcps') } cpsoct { ^this.performUnaryOp('cpsoct') } log { ^this.performUnaryOp('log') } log2 { ^this.performUnaryOp('log2') } log10 { ^this.performUnaryOp('log10') } sin { ^this.performUnaryOp('sin') } cos { ^this.performUnaryOp('cos') } tan { ^this.performUnaryOp('tan') } asin { ^this.performUnaryOp('asin') } acos { ^this.performUnaryOp('acos') } atan { ^this.performUnaryOp('atan') } sinh { ^this.performUnaryOp('sinh') } cosh { ^this.performUnaryOp('cosh') } tanh { ^this.performUnaryOp('tanh') } rand { ^this.performUnaryOp('rand') } rand2 { ^this.performUnaryOp('rand2') } linrand { ^this.performUnaryOp('linrand') } bilinrand { ^this.performUnaryOp('bilinrand') } sum3rand { ^this.performUnaryOp('sum3rand') } distort { ^this.performUnaryOp('distort') } softclip { ^this.performUnaryOp('softclip') } coin { ^this.performUnaryOp('coin') } even { ^this.performUnaryOp('even') } odd { ^this.performUnaryOp('odd') } isPositive { ^this.performUnaryOp('isPositive') } isNegative { ^this.performUnaryOp('isNegative') } isStrictlyPositive { ^this.performUnaryOp('isStrictlyPositive') } rectWindow { ^this.performUnaryOp('rectWindow') } hanWindow { ^this.performUnaryOp('hanWindow') } welWindow { ^this.performUnaryOp('welWindow') } triWindow { ^this.performUnaryOp('triWindow') } scurve { ^this.performUnaryOp('scurve') } ramp { ^this.performUnaryOp('ramp') } asFloat { ^this.performUnaryOp('asFloat') } asInteger { ^this.performUnaryOp('asInteger') } nthPrime { ^this.performUnaryOp('nthPrime') } prevPrime { ^this.performUnaryOp('prevPrime') } nextPrime { ^this.performUnaryOp('nextPrime') } indexOfPrime { ^this.performUnaryOp('indexOfPrime') } real { ^this.performUnaryOp('real') } imag { ^this.performUnaryOp('imag') } magnitude { ^this.performUnaryOp('magnitude') } magnitudeApx { ^this.performUnaryOp('magnitudeApx') } phase { ^this.performUnaryOp('phase') } angle { ^this.performUnaryOp('angle') } rho { ^this.performUnaryOp('rho') } theta { ^this.performUnaryOp('theta') } degrad { ^this.performUnaryOp('degrad') } raddeg { ^this.performUnaryOp('raddeg') } // binary math ops + { arg aNumber, adverb; ^this.performBinaryOp('+', aNumber, adverb) } - { arg aNumber, adverb; ^this.performBinaryOp('-', aNumber, adverb) } * { arg aNumber, adverb; ^this.performBinaryOp('*', aNumber, adverb) } / { arg aNumber, adverb; ^this.performBinaryOp('/', aNumber, adverb) } div { arg aNumber, adverb; ^this.performBinaryOp('div', aNumber, adverb) } mod { arg aNumber, adverb; ^this.performBinaryOp('mod', aNumber, adverb) } pow { arg aNumber, adverb; ^this.performBinaryOp('pow', aNumber, adverb) } min { arg aNumber, adverb; ^this.performBinaryOp('min', aNumber, adverb) } max { arg aNumber=0, adverb; ^this.performBinaryOp('max', aNumber, adverb) } < { arg aNumber, adverb; ^this.performBinaryOp('<', aNumber, adverb) } <= { arg aNumber, adverb; ^this.performBinaryOp('<=', aNumber, adverb) } > { arg aNumber, adverb; ^this.performBinaryOp('>', aNumber, adverb) } >= { arg aNumber, adverb; ^this.performBinaryOp('>=', aNumber, adverb) } bitAnd { arg aNumber, adverb; ^this.performBinaryOp('bitAnd', aNumber, adverb) } bitOr { arg aNumber, adverb; ^this.performBinaryOp('bitOr', aNumber, adverb) } bitXor { arg aNumber, adverb; ^this.performBinaryOp('bitXor', aNumber, adverb) } bitHammingDistance { arg aNumber, adverb; ^this.performBinaryOp('hammingDistance', aNumber, adverb) } lcm { arg aNumber, adverb; ^this.performBinaryOp('lcm', aNumber, adverb) } gcd { arg aNumber, adverb; ^this.performBinaryOp('gcd', aNumber, adverb) } round { arg aNumber=1, adverb; ^this.performBinaryOp('round', aNumber, adverb) } roundUp { arg aNumber=1, adverb; ^this.performBinaryOp('roundUp', aNumber, adverb) } trunc { arg aNumber=1, adverb; ^this.performBinaryOp('trunc', aNumber, adverb) } atan2 { arg aNumber, adverb; ^this.performBinaryOp('atan2', aNumber, adverb) } hypot { arg aNumber, adverb; ^this.performBinaryOp('hypot', aNumber, adverb) } hypotApx { arg aNumber, adverb; ^this.performBinaryOp('hypotApx', aNumber, adverb) } leftShift { arg aNumber, adverb; ^this.performBinaryOp('leftShift', aNumber, adverb) } rightShift { arg aNumber, adverb; ^this.performBinaryOp('rightShift', aNumber, adverb) } unsignedRightShift { arg aNumber, adverb; ^this.performBinaryOp('unsignedRightShift', aNumber, adverb) } ring1 { arg aNumber, adverb; ^this.performBinaryOp('ring1', aNumber, adverb) } ring2 { arg aNumber, adverb; ^this.performBinaryOp('ring2', aNumber, adverb) } ring3 { arg aNumber, adverb; ^this.performBinaryOp('ring3', aNumber, adverb) } ring4 { arg aNumber, adverb; ^this.performBinaryOp('ring4', aNumber, adverb) } difsqr { arg aNumber, adverb; ^this.performBinaryOp('difsqr', aNumber, adverb) } sumsqr { arg aNumber, adverb; ^this.performBinaryOp('sumsqr', aNumber, adverb) } sqrsum { arg aNumber, adverb; ^this.performBinaryOp('sqrsum', aNumber, adverb) } sqrdif { arg aNumber, adverb; ^this.performBinaryOp('sqrdif', aNumber, adverb) } absdif { arg aNumber, adverb; ^this.performBinaryOp('absdif', aNumber, adverb) } thresh { arg aNumber, adverb; ^this.performBinaryOp('thresh', aNumber, adverb) } amclip { arg aNumber, adverb; ^this.performBinaryOp('amclip', aNumber, adverb) } scaleneg { arg aNumber, adverb; ^this.performBinaryOp('scaleneg', aNumber, adverb) } clip2 { arg aNumber=1, adverb; ^this.performBinaryOp('clip2', aNumber, adverb) } fold2 { arg aNumber, adverb; ^this.performBinaryOp('fold2', aNumber, adverb) } wrap2 { arg aNumber, adverb; ^this.performBinaryOp('wrap2', aNumber, adverb) } excess { arg aNumber, adverb; ^this.performBinaryOp('excess', aNumber, adverb) } firstArg { arg aNumber, adverb; ^this.performBinaryOp('firstArg', aNumber, adverb) } rrand { arg aNumber, adverb; ^this.performBinaryOp('rrand', aNumber, adverb) } exprand { arg aNumber, adverb; ^this.performBinaryOp('exprand', aNumber, adverb) } // math op dispatch support performUnaryOp { arg aSelector; ^this.collect({ arg item; item.perform(aSelector) }); } performBinaryOp { arg aSelector, theOperand, adverb; ^theOperand.performBinaryOpOnSeqColl(aSelector, this, adverb); } performBinaryOpOnSeqColl { arg aSelector, theOperand, adverb; var size, newList; if (adverb == nil) { size = this.size max: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i))); }); ^newList }; if (adverb.isInteger) { if (adverb == 0) { size = this.size max: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i))); }); ^newList }{ if (adverb > 0) { ^theOperand.collect {|item, i| item.perform(aSelector, this, adverb-1) } }{ ^this.collect {|item, i| theOperand.perform(aSelector, item, adverb+1) } } } }; if (adverb == 't') { // size = this.size; // newList = this.species.new(size); // size.do({ arg i; // newList.add(theOperand.perform(aSelector, this.at(i))); // }); // ^newList size = theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.at(i).perform(aSelector, this)); }); ^newList }; if (adverb == 'x') { // size = this.size; // newList = this.species.new(size); // size.do({ arg i; // newList.add(theOperand.perform(aSelector, this.at(i))); // }); // ^newList size = theOperand.size * this.size; newList = this.species.new(size); theOperand.do({ arg a; this.do({ arg b; newList.add(a.perform(aSelector, b)); }); }); ^newList }; if (adverb == 's') { size = this.size min: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.wrapAt(i).perform(aSelector, this.wrapAt(i))); }); ^newList }; if (adverb == 'f') { size = this.size max: theOperand.size; newList = this.species.new(size); size.do({ arg i; newList.add(theOperand.foldAt(i).perform(aSelector, this.foldAt(i))); }); ^newList }; Error("unrecognized adverb: '" ++ adverb ++ "' for operator '" ++ aSelector ++ "'\n").throw; ^nil } performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb; ^this.collect({ arg item; aNumber.perform(aSelector, item, adverb) }) } performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^this.collect({ arg item; aComplex.perform(aSelector, item, adverb) }) } asFraction { arg denominator=100, fasterBetter=true; ^this.collect { |item| item.asFraction(denominator, fasterBetter) } } asPoint { ^Point(this[0] ? 0, this[1] ? 0) } asRect { ^Rect(this[0] ? 0, this[1] ? 0, this[2] ? 0, this[3] ? 0) } ascii { ^this.collect { arg item; item.ascii } } // support UGen rate access rate { var rate, rates; if(this.size == 1) { ^this.first.rate }; ^this.collect({ arg item; item.rate ? 'scalar' }).minItem // 'scalar' > 'control' > 'audio' } // if we don't catch the special case of an empty array, // Object:multiChannelPerform goes into infinite recursion multiChannelPerform { arg selector ... args; if(this.size > 0) { ^super.multiChannelPerform(selector, *args); } { ^this.class.new } } // this method is for UGen inputs that require Refs to block direct multichannel expansion. // here, we assume this is already an array of Refs, which we simply return. multichannelExpandRef { arg rank; ^this } // support some UGen convenience methods. // NOTE: don't forget to add a wrapper here when adding a method to UGen or AbstractFunction clip { arg ... args; ^this.multiChannelPerform('clip', *args) } wrap { arg ... args; ^this.multiChannelPerform('wrap', *args) } fold { arg ... args; ^this.multiChannelPerform('fold', *args) } linlin { arg ... args; ^this.multiChannelPerform('linlin', *args) } linexp { arg ... args; ^this.multiChannelPerform('linexp', *args) } explin { arg ... args; ^this.multiChannelPerform('explin', *args) } expexp { arg ... args; ^this.multiChannelPerform('expexp', *args) } lincurve { arg ... args; ^this.multiChannelPerform('lincurve', *args) } curvelin { arg ... args; ^this.multiChannelPerform('curvelin', *args) } bilin { arg ... args; ^this.multiChannelPerform('bilin', *args) } biexp { arg ... args; ^this.multiChannelPerform('biexp', *args) } moddif { arg ... args; ^this.multiChannelPerform('moddif', *args) } range { arg ... args; ^this.multiChannelPerform('range', *args) } exprange { arg ... args; ^this.multiChannelPerform('exprange', *args) } curverange { arg ... args; ^this.multiChannelPerform('curverange', *args) } unipolar { arg ... args; ^this.multiChannelPerform('unipolar', *args) } bipolar { arg ... args; ^this.multiChannelPerform('bipolar', *args) } lag { arg ... args; ^this.multiChannelPerform('lag', *args) } lag2 { arg ... args; ^this.multiChannelPerform('lag2', *args) } lag3 { arg ... args; ^this.multiChannelPerform('lag3', *args) } lagud { arg ... args; ^this.multiChannelPerform('lagud', *args) } lag2ud { arg ... args; ^this.multiChannelPerform('lag2ud', *args) } lag3ud { arg ... args; ^this.multiChannelPerform('lag3ud', *args) } varlag { arg ... args; ^this.multiChannelPerform('varlag', *args) } slew { arg ... args; ^this.multiChannelPerform('slew', *args) } blend { arg ... args; ^this.multiChannelPerform('blend', *args) } checkBadValues { arg ... args; ^this.multiChannelPerform('checkBadValues', *args) } prune { arg ... args; ^this.multiChannelPerform('prune', *args) } minNyquist { ^min(this, SampleRate.ir * 0.5) } // sorting sort { arg function; if (function.isNil) { function = { arg a, b; a <= b }; }; ^this.mergeSort(function) } sortBy { arg key; ^this.sort({| a, b | a[key] <= b[key] }) } sortMap { arg function; ^this.sort({| a, b | function.value(a) <= function.value(b) }) } sortedMedian { var index; if (this.size.odd) { ^this.middle }{ index = this.middleIndex; ^(this[index] + this[index+1]) / 2; } } median { arg function; //^this.sort(function).sortedMedian // Note the copy, to prevent changing the input. ^this.copy.hoareMedian(function) } quickSort { arg function; this.quickSortRange(0, this.size - 1, function) } order { arg function; var array, orderFunc; // returns an array of indices that would sort the collection into order. if(this.isEmpty) { ^[] }; if (function.isNil) { function = { arg a, b; a <= b }; }; array = [this, (0..this.lastIndex)].flop; orderFunc = {|a,b| function.value(a[0], b[0]) }; ^array.mergeSort(orderFunc).flop[1] } swap { arg i, j; var temp; temp = this[i]; this[i] = this[j]; this[j] = temp; } quickSortRange { arg i, j, function; //Sort elements i through j of this to be nondescending according to // function. var di, dij, dj, tt, ij, k, l, n; // The prefix d means the data at that index. if ((n = j + 1 - i) <= 1, { ^this }); // Nothing to sort. //Sort di,dj. di = this.at(i); dj = this.at(j); if (function.value(di, dj).not, { // i.e., should di precede dj? this.swap(i,j); tt = di; di = dj; dj = tt; }); if ( n > 2, { // More than two elements. ij = (i + j) div: 2; // ij is the midpoint of i and j. dij = this.at(ij); // Sort di,dij,dj. Make dij be their median. if (function.value(di, dij), { // i.e. should di precede dij? if (function.value(dij, dj).not, { // i.e., should dij precede dj? this.swap(j, ij); dij = dj; }) },{ // i.e. di should come after dij" this.swap(i, ij); dij = di; }); if ( n > 3, { // More than three elements. // Find k>i and l> 1; this.mergeSortTemp(function, tempArray, left, mid); this.mergeSortTemp(function, tempArray, mid+1, right); this.mergeTemp(function, tempArray, left, mid+1, right); } mergeTemp { arg function, tempArray, left, mid, right; var i, leftEnd, size, tempPos; leftEnd = mid - 1; tempPos = left; size = right - left + 1; while { (left <= leftEnd) && (mid <= right) } { if (function.value( this[left], this[mid] )) { tempArray[tempPos] = this[left]; tempPos = tempPos + 1; left = left + 1; } { tempArray[tempPos] = this[mid]; tempPos = tempPos + 1; mid = mid + 1; } }; while { left <= leftEnd } { tempArray[tempPos] = this[left]; tempPos = tempPos + 1; left = left + 1; }; while { mid <= right } { tempArray[tempPos] = this[mid]; tempPos = tempPos + 1; mid = mid + 1; }; size.do { this[right] = tempArray[right]; right = right - 1; }; } insertionSort { arg function; ^this.insertionSortRange(function, 0, this.size - 1) } insertionSortRange { arg function, left, right; var i, j, test; i = left + 1; while { i <= right } { test = this[i]; j = i; while { (j > left) && { function.value(this[j-1], test).not } } { this[j] = this[j-1]; j = j - 1; }; this[j] = test; i = i + 1; } } // Finds the median efficiently, by rearranging the array IN-PLACE. hoareMedian { |function| if(this.isEmpty) { ^nil }; ^if(this.size.even, { [this.hoareFind(this.size/ 2 - 1, function), this.hoareFind(this.size/ 2, function)].mean; }, { this.hoareFind(this.size - 1 / 2, function); }); } // Finds the kth element in the array, according to a given sorting function. // This is typically fast (order is O(n) rather than O(n log n)) because it // doesn't attempt to completely sort the array. Method is due to C. A. F. Hoare. // Note: this rearranges array elements IN PLACE. hoareFind { |k, function, left, right| var i,j,p,r,l; if (function.isNil) { function = { | a, b | a < b } }; i = left ? 0; j = right ?? {this.size-1}; while{ i < j }{ p = this[k]; # l, r = this.hoarePartition(i,j,p, function); if(r < k, { // kth smallest is in right split i = l; }); if(k < l, { // kth smallest is in left split j = r; }); }; // The desired element is in desired position ^this[k]; } // In-place partitioning method used by hoareFind. // Note: for efficiency this doesn't check that function is defined, so you // must supply a function! See hoareFind for example hoarePartition { |l0, r0, p, function| var l, r, tmp; l = l0; r = r0; while({ l <= r }, { // left_scan while { (l < this.size) and: { function.value(this[l], p) } }{ l = l + 1; }; // right_scan while { (r >= 0) and: { function.value(p, this[r]) } }{ r = r - 1; }; // check and exchange if(l <= r){ tmp = this[l]; this[l] = this[r]; this[r] = tmp; // then l = l + 1; r = r - 1; }; }); ^[l,r]; } // streaming *streamContents { arg function; var stream; stream = CollStream.on(this.new(100)); function.value(stream); ^stream.contents } *streamContentsLimit { arg function, limit=2000; var stream; stream = LimitedWriteStream.on(this.new(100 min: limit)); stream.limit_(limit).limitFunc_({ ^stream.contents }); function.value(stream); ^stream.contents } wrapAt { arg index; index = index % this.size; ^this.at(index) } wrapPut { arg index, value; index = index % this.size; ^this.put(index, value) } reduce { arg operator; var once = true, result; if(this.size==1){ ^this[0] }; this.doAdjacentPairs {|a, b| if (once) { once = false; result = operator.applyTo(a, b); }{ result = operator.applyTo(result, b); }; }; ^result } join { arg joiner; ^String.streamContents { arg stream; var stop; if(joiner.isNil) { this.do { arg item; stream << item }; } { stop = this.size - 1; this.do { arg item,i; stream << item; if(i < stop) { stream << joiner }; }; } } } // TempoClock play quantization nextTimeOnGrid { arg clock; ^clock.nextTimeOnGrid(*this); } // we break up the array so that missing elements are set to nil in the Quant asQuant { ^Quant(*this) } // asUGenInput { ^this.asArray.asUGenInput } schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency| latency = latency ? server.latency; if (lag != 0) { lag = lag.asArray; this.do { |time, i| clock.sched(time, { SystemClock.sched(lag.wrapAt(i), { server.sendBundle(latency, bundleArray.wrapAt(i)) }) }) } } { this.do { |time, i| clock.sched(time, { server.sendBundle(latency, bundleArray.wrapAt(i)) }) } } } unixCmd { arg action, postOutput = true; var pid; if(this.notEmpty) { pid = this.prUnixCmd(postOutput); if(action.notNil) { String.unixCmdActions.put(pid, action); }; ^pid } { Error("Collection should have at least the filepath of the program to run.").throw } } prUnixCmd { arg postOutput = true; _ArrayPOpen ^this.primitiveFailed } } SuperCollider-Source/SCClassLibrary/Common/Collections/Set.sc000644 000765 000024 00000010616 12756534416 025306 0ustar00crucialstaff000000 000000 Set : Collection { var <>array, 0, { array.do({ arg item; if (item.notNil, { function.value(item, i); i = i + 1; }) }) }) } clear { array.fill; size=0 } makeEmpty { this.clear; } includes { arg item; ^array.at(this.scanFor(item)).notNil; } findMatch { arg item; // return an item that matches a given item ^array.at(this.scanFor(item)); } add { arg item; var index; if (item.isNil, { Error("A Set cannot contain nil.\n").throw; }); index = this.scanFor(item); if ( array.at(index).isNil, { this.putCheck(index, item) }); } remove { arg item; var index = this.scanFor(item); if ( array.at(index).notNil, { array.put(index, nil); size = size - 1; this.fixCollisionsFrom(index); }); } choose { var index, val; if (size <= 0, { ^nil }); while({ index = array.size.rand; (val = array.at(index)).isNil; }); ^val } pop { var index = 0, val; while({ (index < array.size) and: { (val = array.at(index)).isNil } },{ index = index + 1 }); if (index < array.size, { this.remove(val); ^val }, { ^nil }); } // powerset { // ^this.asArray.sort.powerset // } unify { var result = this.species.new; this.do {|x| result.addAll(x) } ^result } sect { arg that; var result = this.species.new; this.do({ arg item; if (that.includes(item), { result.add(item); }); }); ^result } union { arg that; var result = this.species.new; result.addAll(this); result.addAll(that); ^result } difference { arg that; ^this.copy.removeAll(that); } symmetricDifference { arg that; var result = this.species.new; this.do({ arg item; if (that.includes(item).not, { result.add(item); }); }); that.do({ arg item; if (this.includes(item).not, { result.add(item); }); }); ^result; } isSubsetOf { | that | ^that.includesAll(this) } & { arg that; ^this.sect(that) } | { arg that; ^this.union(that) } - { arg that; ^this.difference(that) } -- { arg that; ^this.symmetricDifference(that) } // PRIVATE IMPLEMENTATION initSet { arg n; array = Array.newClear(n); size = 0; } putCheck { arg index, item; array.put(index, item); size = size + 1; this.fullCheck; } fullCheck { if (array.size < (size * 2), { this.grow }); } grow { var oldElements = array; array = Array.newClear(array.size * 2); size = 0; oldElements.do({ arg item; if ( item.notNil, { this.noCheckAdd(item) }) }); } noCheckAdd { arg item; array.put(this.scanFor(item), item); size = size + 1; } scanFor { arg obj; var elem; var start = obj.hash % array.size; var end = array.size; var i = start; while ({ i < end }, { elem = array.at(i); if ( elem.isNil or: { elem == obj }, { ^i }); i = i + 1; }); end = start - 1; i = 0; while ({ i <= end }, { elem = array.at(i); if ( elem.isNil or: { elem == obj }, { ^i }); i = i + 1; }); error("There is no free space in this set!\n"); array.postln; ^-1 } fixCollisionsFrom { arg index; var newIndex, element; var oldIndex = index; var lastKeyIndex = array.size - 1; while ({ if (oldIndex == lastKeyIndex, { oldIndex = 0 }, { oldIndex = oldIndex + 1 }); (element = this.keyAt(oldIndex)).notNil },{ newIndex = this.scanFor(element); if ( oldIndex != newIndex, { array.swap(oldIndex, newIndex) }) }) } keyAt { arg index; ^array.at(index) } asSet { ^this } } IdentitySet : Set { scanFor { arg argKey; ^array.atIdentityHash(argKey) /* var i, start, end, elem; start = obj.identityHash % array.size; end = array.size; i = start; while ({ i < end }, { elem = array.at(i); if ( elem.isNil or: { elem === obj }, { ^i }); i = i + 1; }); end = start - 1; i = 0; while ({ i < end }, { elem = array.at(i); if ( elem.isNil or: { elem === obj }, { ^i }); i = i + 1; }); ^-1 */ } } OrderedIdentitySet : IdentitySet { var >items; copy { ^this.shallowCopy .array_( array.copy ) .items_( items.copy ) } do { arg function; items.do(function) } clear { super.clear; items = nil; } remove { arg item; super.remove(item); items.remove(item); } sort { arg func; items.sort(func) } // private putCheck { arg index, item; super.putCheck(index, item); items = items.add(item); } } SuperCollider-Source/SCClassLibrary/Common/Collections/SortedList.sc000644 000765 000024 00000005443 12766171707 026652 0ustar00crucialstaff000000 000000 SortedList : List { var <>function; *new { arg size = 8, function; function = function ? { arg a, b; a < b } ^super.new(size).function_(function) } add { arg item; var nextIndex; if ( this.isEmpty, { ^super.add(item); }); nextIndex = this.indexForInserting(item); this.insert(nextIndex, item); } addAll { arg aCollection; aCollection = aCollection.asCollection; if ( aCollection.size > (this.size div: 3), { // Faster to add the new elements and resort aCollection.do({ arg each; super.add(each) }); this.sort },{ // Faster to add the elements individually in their proper places aCollection.do({ arg each; this.add(each) }); }); } copyRange { arg start, end; ^this.class.newUsing(array.copyRange(start, end)).function_(function) } copySeries { arg first, second, last; ^this.class.newUsing(array.copySeries(first, second, last)).function_(function) } // PRIVATE indexForInserting { arg newObject; var index; var low = 0; var high = this.size-1; while ({ index = high + low div: 2; low <= high; },{ if (function.value(array.at(index), newObject), { low = index + 1; },{ high = index - 1; }); }); ^low } sort { this.sortRange(0, array.size - 1) } sortRange { arg i, j; //Sort elements i through j of this to be nondescending according to // function. var di, dij, dj, tt, ij, k, l, n; // The prefix d means the data at that index. if ((n = j + 1 - i) <= 1, { ^this }); // Nothing to sort. //Sort di,dj. di = array.at(i); dj = array.at(j); if (function.value(di, dj).not, { // i.e., should di precede dj? array.swap(i,j); tt = di; di = dj; dj = tt; }); if ( n > 2, { // More than two elements. ij = (i + j) div: 2; // ij is the midpoint of i and j. dij = array.at(ij); // Sort di,dij,dj. Make dij be their median. if (function.value(di, dij), { // i.e. should di precede dij? if (function.value(dij, dj).not, { // i.e., should dij precede dj? array.swap(j, ij); dij = dj; }) },{ // i.e. di should come after dij" array.swap(i, ij); dij = di; }); if ( n > 3, { // More than three elements. // Find k>i and larray, <>indices; *new { arg size = 8; ^super.new.clear(size) } *newFromIndices { arg array, indices; ^super.newCopyArgs(array, indices) } clear { arg size; array = Array.new(size); indices = Array.new(size); } makeEmpty { this.clear } copy { ^this.class.newCopyArgs(array.copy, indices.copy) } asArray { ^array.copy } species { ^this.class } do { arg function; indices.do { |index, i| function.value(array.at(i), index, i) }; } doRange { arg function, from = 0, to; if(from <= indices.last) { if(to.isNil) { to = indices.size - 1 } { to = min(to, this.lastIndex) }; for(this.slotFor(from), to) { |i| function.value(array.at(i), indices.at(i), i) } } } keysValuesDo { arg function; indices.do { |index, i| function.value(index, array.at(i), i) } } size { ^indices.size } lastIndex { ^indices.last } // current write position pos { var index = this.lastIndex; ^if(index.isNil) { 0 } { index + 1 } } add { arg obj; array = array.add(obj); indices = indices.add(this.pos); } put { arg index, obj; this.prPutSlot(this.nextSlotFor(index), index, obj) } at { arg index; var slot = this.slotFor(index); ^if(slot.notNil) { if(indices.at(slot) == index) { array.at(slot) } } } removeAt { arg index, obj; var nextSlot = this.nextSlotFor(index), slot; ^if(nextSlot.notNil) { slot = max(0, nextSlot - 1); if(indices.at(slot) == index) { this.removeAtSlot(slot) } } } removeAtSlot { arg slot; indices.removeAt(slot); ^array.removeAt(slot) } pop { indices.pop; ^array.pop } collect { arg function; ^this.copy.array_(array.collect(function)); } select { arg function; var res = this.class.new; this.indicesDo { |item, i| if(function.value(item, i)) { res.put(i, item) } } ^res } reject { arg function; var res = this.class.new; this.indicesDo { |item, i| if(function.value(item, i).not) { res.put(i, item) } } ^res } removeAllSuchThat { arg function; var removedItems = this.class.new; var copy = this.copy; copy.indicesDo { | item, i | if ( function.value(item, i) ) { this.remove(item); removedItems = removedItems.put(i, item); } }; ^removedItems } selectInPlace { arg function; indices.copy.do { |index, i| if(function.value(array.at(i), index).not) { this.removeAtSlot(i) } } } rejectInPlace { arg function; indices.copy.do { |index, i| if(function.value(array.at(i), index)) { this.removeAtSlot(i) } } } indicesDo { arg function; indices.do { |slot, i| function.value(array.at(i), slot, i) } } // private implementation resetIndices { arg step = 1, offset = 0; indices = (offset, step .. indices.size - 1); } nextSlotFor { arg index; ^indices.indexOfGreaterThan(index) ?? { indices.size } } slotFor { arg index; ^max(0, this.nextSlotFor(index) - 1) } prPutSlot { arg nextSlot, index, obj; var slot = max(0, nextSlot - 1); if(indices.at(slot) == index) { array.put(slot, obj) } { array = array.insert(nextSlot, obj); indices = indices.insert(nextSlot, index); } } choose { ^array.choose } storeOn { arg stream; stream << this.class.name; stream << ".newFromIndices( " <<<* [ array, indices ] << " )"; } } SparseArray : Order { var <>default, <>defaultSize; *newClear { arg size, default; ^super.new(size).defaultSize_(size).default_(default) } *reduceArray { arg array, default; var res = this.new.default_(default); array.do { |item, i| res.putIfNotDefault(i, item) }; res.defaultSize = if(default.isNil) { res.size } { array.size }; ^res } clear { arg size; size = size.min(67108864 / 2); // For very large data we must assume sparse indices or we can't initialise the indices here array = Array.new(size); indices = Array.new(size); } putIfNotDefault { arg i, item; if(item != default) { this.put(i, item) } } copy { ^this.class.newCopyArgs(array.copy, indices.copy, default, defaultSize) } asArray { ^this[_] ! this.size } at { arg index; ^super.at(index) ? default } do { arg function; if(this.isEmpty) { ^this }; this.size.do { |i| function.value(this.at(i), i) } } size { var last = super.lastIndex ? (-1); ^if(defaultSize.isNil) { last + 1 } { max(last + 1, defaultSize) } } lastIndex { var last = super.lastIndex ? 0; ^if(defaultSize.isNil) { last } { max(last, defaultSize) } } // current write position pos { var index = super.lastIndex; ^if(index.isNil) { 0 } { index + 1 } } collect { arg function; ^this.class.reduceArray( this.asArray.collect(function), default !? { function.value(default, 0) } ) } select { arg function; ^this.class.reduceArray( this.asArray.select(function), if(default.notNil and: { function.value(default, 0) }) { default } ) } reject { arg function; ^this.class.reduceArray( this.asArray.reject(function), if(default.notNil and: { function.value(default, 0).not }) { default } ) } sum { | function | var sum = 0; ^if (function.isNil or: {function.numArgs < 2}) { // optimized version if no function, or if index is irrelevant this.sparseSum }{ this.do {|elem, i| sum = sum + function.value(elem, i); }; sum } } // if index is irrelevant, assume that the result for all implicit elements is the same sparseSum { | function | var sum = 0; if (function.isNil) { // optimized version if no function array.do { | elem | sum = sum + elem; }; sum = sum + (default * (this.size-array.size)); }{ array.do {|elem| sum = sum + function.value(elem); }; sum = sum + (function.value(default) * (this.size-array.size)); } ^sum; } // does not pass the index to each default item: faster than collect sparseCollect { arg function; var res = super.collect(function); default !? { res.default = function.value(default) }; ^res } sparseSelect { arg function; var res = super.select(function); if(default.notNil and: { function.value(default, 0) }) { res.default = default } ^res } sparseReject { arg function; var res = super.reject(function); if(default.notNil and: { function.value(default, 0).not }) { res.default = default } ^res } sparseRemoveAt { arg index; ^super.removeAt(index) } sparseRemove { arg item; var index = super.indexOf(item); ^if(index.notNil) { super.removeAt(index) } { nil } } removeAt { arg index; var res, slot = this.slotFor(index), size = indices.size; if(index >= this.size) { ^nil }; if(indices[slot] == index) { res = this.removeAtSlot(slot); slot = slot - 1; } { if(size > 0) { res = default }; if(indices.first > index) { slot = -1 }; }; indices = indices[..slot] ++ (indices[slot+1..] - 1); if(defaultSize.notNil and: { defaultSize > 0 } and: { index < defaultSize }) { defaultSize = defaultSize - 1; }; ^res } firstGap { arg from = 0, to; if(indices.first == 0) { ^nil }; to = to ?? { indices.size }; (from..to).do { |i| if(indices[i] != i) { ^i }; }; ^nil } indexOf { arg item; var slot = array.indexOf(item), res; if(item == default) { res = this.firstGap(0, slot); if(res.notNil) { ^res }; }; ^if(slot.isNil) { nil } { indices[slot] } } compress { var ind, list, size = defaultSize ?? { this.size }; array.do { |item, i| if(item != default) { list = list.add(item); ind = ind.add(indices.at(i)) }; }; ^this.class.newFromIndices(list, ind).default_(default).defaultSize_(size) } pop { ^if(defaultSize.notNil and: { defaultSize > indices.last }) { defaultSize = defaultSize - 1; default } { super.pop } } ++ { arg coll; var res = this.copy.sparseAddAll(coll); if(defaultSize.notNil) { res.defaultSize_(this.size + coll.size) }; ^res } sparseAddAll { arg coll; var slot = this.size; coll.do { |item, i| if(item != default) { this.put(slot + i, item) } }; } putSeries { arg first, second, last, value; (first, second..last).do { |index| this.put(index, value) } } atSeries { arg first, second, last; ^(first, second..last).collect { |index| this.at(index) } } minItem { |function| ^if(function.isNil or: {function.numArgs < 2}){ if(array.size == this.size){ // full up! default not used (weird) array.minItem(function) }{ array.minItem(function).min(if(function.isNil, default, function.value(default))) } }{ super.minItem(function); } } maxItem { |function| ^if(function.isNil or: {function.numArgs < 2}){ if(array.size == this.size){ // full up! default not used (weird) array.maxItem(function) }{ array.maxItem(function).max(if(function.isNil, default, function.value(default))) } }{ super.maxItem(function); } } storeOn { | stream | if (stream.atLimit) { ^this }; stream << this.class.name << "[ " ; this.storeItemsOn(stream); stream << " ]" ; } // private implementation prPutSlot { arg nextSlot, index, obj; var slot = max(0, nextSlot - 1); index = index.asInteger; // SparseArray supports only integer indices if(indices.at(slot) == index) { array.put(slot, obj) } { array = array.insert(nextSlot, obj); indices = indices.insert(nextSlot, index); } } } SuperCollider-Source/SCClassLibrary/Common/Collections/String.sc000644 000765 000024 00000027666 13007174002 026013 0ustar00crucialstaff000000 000000 String[char] : RawArray { classvar <>unixCmdActions; *initClass { unixCmdActions = IdentityDictionary.new; } *doUnixCmdAction { arg res, pid; unixCmdActions[pid].value(res, pid); unixCmdActions.removeAt(pid); } prUnixCmd { arg postOutput = true; _String_POpen ^this.primitiveFailed } // runs a unix command and sends stdout to the post window unixCmd { arg action, postOutput = true; var pid; pid = this.prUnixCmd(postOutput); if(action.notNil) { unixCmdActions.put(pid, action); }; ^pid; } // Like unixCmd but gets the result into a string unixCmdGetStdOut { arg maxLineLength=1024; var pipe, lines, line; pipe = Pipe.new(this, "r"); lines = ""; line = pipe.getLine(maxLineLength); while({line.notNil}, {lines = lines ++ line ++ "\n"; line = pipe.getLine; }); pipe.close; ^lines; } asSymbol { _StringAsSymbol ^this.primitiveFailed } asInteger { _String_AsInteger ^this.primitiveFailed } asFloat { _String_AsFloat ^this.primitiveFailed } ascii { ^Array.fill(this.size, { |i| this[i].ascii }) } stripRTF { _StripRtf ^this.primitiveFailed } stripHTML { _StripHtml ^this.primitiveFailed } *scDir { ^Platform.resourceDir } compare { arg aString, ignoreCase=false; _StringCompare this.primitiveFailed; } < { arg aString; if(aString.isString.not) { ^false }; ^this.compare(aString, false) < 0 } > { arg aString; if(aString.isString.not) { ^false }; ^this.compare(aString, false) > 0 } <= { arg aString; if(aString.isString.not) { ^false }; ^this.compare(aString, false) <= 0 } >= { arg aString; if(aString.isString.not) { ^false }; ^this.compare(aString, false) >= 0 } == { arg aString; if(aString.isString.not) { ^false }; ^this.compare(aString, false) == 0 } != { arg aString; if(aString.isString.not) { ^true } ^this.compare(aString, false) != 0 } hash { _StringHash } // no sense doing collect as per superclass collection performBinaryOpOnSimpleNumber { arg aSelector, aNumber; ^aNumber.asString.perform(aSelector, this); } performBinaryOpOnComplex { arg aSelector, aComplex; ^aComplex.asString.perform(aSelector, this); } multiChannelPerform { arg selector ... args; Error("String:multiChannelPerform. Cannot expand strings.").throw; } isString { ^true } asString { ^this } asCompileString { _String_AsCompileString; } species { ^String } postln { _PostLine } post { _PostString } postcln { "// ".post; this.postln; } postc { "// ".post; this.post; } postf { arg ... items; ^this.prFormat( items.collect(_.asString) ).post } format { arg ... items; ^this.prFormat( items.collect(_.asString) ) } prFormat { arg items; _String_Format ^this.primitiveFailed } matchRegexp { arg string, start = 0, end; _String_Regexp ^this.primitiveFailed } fformat { arg ... args; var str, resArgs, val, func; var suffixes, sig = false; this.do { |char| if(sig) { val = args.removeAt(0); func = Post.formats[char]; if(func.isNil) { resArgs = resArgs.add(val); str = str ++ char } { resArgs = resArgs.add(func.value(val)) }; sig = false; } { str = str ++ char }; if(char == $%) { sig = true }; }; ^str.format(*resArgs) } die { arg ... culprits; if(culprits.notEmpty,{ ("\n\nFATAL ERROR: ").postln; culprits.do({ arg c; if(c.isString,{c.postln},{c.dump}) }); }); Error(this).throw; } error { "ERROR: ".post; this.postln; } warn { "WARNING: ".post; this.postln } inform { ^this.postln } ++ { arg anObject; ^this prCat: anObject.asString; } + { arg anObject; ^this prCat: " " prCat: anObject.asString; } catArgs { arg ... items; ^this.catList(items) } scatArgs { arg ... items; ^this.scatList(items) } ccatArgs { arg ... items; ^this.ccatList(items) } catList { arg list; // concatenate this with a list as a string var string = this.copy; list.do({ arg item, i; string = string ++ item; }); ^string } scatList { arg list; var string = this.copy; list.do({ arg item, i; string = string prCat: " " ++ item; }); ^string } ccatList { arg list; var string = this.copy; list.do({ arg item, i; string = string prCat: ", " ++ item; }); ^string } split { arg separator=$/; var word=""; var array=[]; separator=separator.ascii; this.do({arg let,i; if(let.ascii != separator ,{ word=word++let; },{ array=array.add(word); word=""; }); }); ^array.add(word); } containsStringAt { arg index, string; ^compare( this[index..index + string.size-1], string, false) == 0 } icontainsStringAt { arg index, string; ^compare( this[index..index + string.size-1], string, true) == 0 } contains { arg string, offset = 0; ^this.find(string, false, offset).notNil } containsi { arg string, offset = 0; ^this.find(string, true, offset).notNil } findRegexpAt { arg regexp, offset = 0; _String_FindRegexpAt ^this.primitiveFailed } findRegexp { arg regexp, offset = 0; _String_FindRegexp ^this.primitiveFailed } findAllRegexp { arg string, offset = 0; ^this.findRegexp(string, offset).collect { |pair| pair[0] } } find { arg string, ignoreCase = false, offset = 0; _String_Find ^this.primitiveFailed } findBackwards { arg string, ignoreCase = false, offset = 0x7FFFFFFE; _String_FindBackwards ^this.primitiveFailed } endsWith { arg string; ^this.contains(string, this.size - string.size) } beginsWith { arg string; ^this.containsStringAt(0, string) } findAll { arg string, ignoreCase = false, offset=0; var indices, i=0; while { i = this.find(string, ignoreCase, offset); i.notNil }{ indices = indices.add(i); offset = i + 1; } ^indices } replace { arg find, replace = ""; var index, out = "", array = this, findSize = max(find.size, 1); while { (index = array.find(find)).notNil }{ out = out ++ array.keep(index) ++ replace; array = array.drop(index + findSize); }; ^out ++ array } escapeChar { arg charToEscape; // $" _String_EscapeChar ^this.primitiveFailed; } shellQuote { ^"'"++this.replace("'","'\\''")++"'" } quote { ^"\"" ++ this ++ "\"" } tr { arg from,to; ^this.collect({ arg char; if(char == from,{to},{char}) }) } insert { arg index, string; ^this.keep(index) ++ string ++ this.drop(index) } wrapExtend { arg size; ^this.dup(size div: this.size).join ++ this.keep(size % this.size) } zeroPad { ^" " ++ this ++ " " } padLeft { arg size, string = " "; ^string.wrapExtend(max(0, size - this.size)) ++ this } padRight { arg size, string = " "; ^this ++ string.wrapExtend(max(0, size - this.size)) } underlined { arg char = $-; ^this ++ "\n" ++ String.fill(this.size, char) } scramble { ^this.as(Array).scramble.as(String) } rotate { arg n = 1; ^this.as(Array).rotate(n).as(String) } compile { ^thisProcess.interpreter.compile(this); } interpret { ^thisProcess.interpreter.interpret(this); } interpretPrint { ^thisProcess.interpreter.interpretPrint(this); } *readNew { arg file; ^file.readAllString; } prCat { arg aString; _ArrayCat; ^this.primitiveFailed; } printOn { arg stream; stream.putAll(this); } storeOn { arg stream; stream.putAll(this.asCompileString); } inspectorClass { ^StringInspector } /// unix standardizePath { _String_StandardizePath ^this.primitiveFailed } realPath { _String_RealPath ^this.primitiveFailed } withTrailingSlash { var sep = thisProcess.platform.pathSeparator; if(this.last != sep, { ^this ++ sep },{ ^this }) } withoutTrailingSlash { var sep = thisProcess.platform.pathSeparator; if(this.last == sep,{ ^this.copyRange(0, this.size-2) },{ ^this }) } absolutePath { var first, sep; sep = thisProcess.platform.pathSeparator; first = this[0]; if(first == sep){^this}; if(first == $~){^this.standardizePath}; ^File.getcwd ++ sep ++ this; } pathMatch { _StringPathMatch ^this.primitiveFailed } // glob load { ^thisProcess.interpreter.executeFile(this); } loadPaths { arg warn = true, action; var paths = this.pathMatch; if(warn and:{paths.isEmpty}) { ("no files found for this path:" + this.quote).warn }; ^paths.collect({ arg path; var result = thisProcess.interpreter.executeFile(path); action.value(path, result); result }); } loadRelative { arg warn = true, action; var path = thisProcess.nowExecutingPath; if(path.isNil) { Error("can't load relative to an unsaved file").throw}; if(path.basename == this) { Error("should not load a file from itself").throw }; ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this).loadPaths(warn, action) } resolveRelative { var path, caller; caller = thisMethod.getBackTrace.caller.functionDef; if(caller.isKindOf(Method) && (caller != Interpreter.findMethod(\interpretPrintCmdLine)), { path = caller.filenameSymbol.asString; }, { path = thisProcess.nowExecutingPath; }); if(this[0] == thisProcess.platform.pathSeparator, {^this}); if(path.isNil) { Error("can't resolve relative to an unsaved file").throw}; ^(path.dirname ++ thisProcess.platform.pathSeparator ++ this) } include { if(Quarks.isInstalled(this).not) { Quarks.install(this); "... the class library may have to be recompiled.".postln; // maybe check later whether there are .sc files included. } } exclude { if(Quarks.isInstalled(this)) { Quarks.uninstall(this); "... the class library may have to be recompiled.".postln; } } basename { _String_Basename; ^this.primitiveFailed } dirname { _String_Dirname; ^this.primitiveFailed } splitext { this.reverseDo({ arg char, i; if (char == $\., { ^[this.copyFromStart(this.size - 2 - i), this.copyToEnd(this.size - i)] }); }); ^[this, nil] } // path concatenate +/+ { arg path; var pathSeparator = thisProcess.platform.pathSeparator; if (path.respondsTo(\fullPath)) { ^PathName(this +/+ path.fullPath) }; if (this.last == pathSeparator or: { path.first == pathSeparator }) { ^this ++ path }; ^this ++ pathSeparator ++ path } asRelativePath { |relativeTo| ^PathName(this).asRelativePath(relativeTo) } asAbsolutePath { // changed because there is no need to create a separate object // when String already knows how to make an absolute path ^this.absolutePath; // was ^PathName(this).asAbsolutePath } // runs a unix command and returns the result code. systemCmd { _String_System ^this.primitiveFailed } gethostbyname { _GetHostByName ^this.primitiveFailed } // gets value of environment variable getenv { _String_Getenv ^this.primitiveFailed } // sets value of environment variable // value may be nil to unset the variable setenv { arg value; _String_Setenv ^this.primitiveFailed } unsetenv { ^this.setenv(nil) } /// code gen codegen_UGenCtorArg { arg stream; stream << this.asCompileString; } ugenCodeString { arg ugenIndex, isDecl, inputNames=#[], inputStrings=#[]; _UGenCodeString ^this.primitiveFailed } asSecs { |maxDays = 365| // assume a timeString of ddd:hh:mm:ss.sss. see asTimeString. var time = 0, sign = 1, str = this; var limits = [inf, 60, 60, 24, maxDays]; var scaling = [0.001, 1.0, 60.0, 3600.0, 86400.0]; var padding = [3, 2, 2, 2, 3]; if (this.first == $-) { str = this.drop(1); sign = -1 }; str.split($:).reverseDo { |num, i| num = num.padRight(padding[i], "0").asInteger; if (num > limits[i]) { ("asSecs: number greater than allowed:" + this).warn; num = limits[i]; }; if (num < 0) { ("asSecs: negative numbers within slots not supported:" + this).warn; num = 0; }; time = time + (num * scaling[i]); }; ^time * sign; } speak { arg channel = 0, force = false; // FIXME: this should better be handled by Platform than GUI var speech = GUI.current.speech; if( speech.initialized.not, { speech.init }); speech.channels[ channel ].speak( this, force ); } toLower { ^this.collect(_.toLower) } toUpper { ^this.collect(_.toUpper) } mkdir { File.mkdir(this); } parseYAML { _String_ParseYAML ^this.primitiveFailed } parseYAMLFile { _String_ParseYAMLFile ^this.primitiveFailed } } SuperCollider-Source/SCClassLibrary/Common/Collections/linux/extString_linux.sc000644 000765 000024 00000000314 12756534416 031112 0ustar00crucialstaff000000 000000 + String { runInTerminal {|shell="sh"| ("xterm -hold -T 'SuperCollider runInTerminal' -e" + shell + "-c" + this.shellQuote).unixCmd; } openOS { ("xdg-open " ++ this.escapeChar($ )).systemCmd } } SuperCollider-Source/SCClassLibrary/Common/Audio/AudioIn.sc000644 000765 000024 00000001353 12756534416 024664 0ustar00crucialstaff000000 000000 SoundIn { *ar { arg bus = 0, mul=1.0, add=0.0; var chanOffset; chanOffset = this.channelOffset; if(bus.isArray.not,{ ^In.ar(chanOffset + bus, 1).madd(mul,add) }); // check to see if channels array is consecutive [n,n+1,n+2...] if(bus.every({arg item, i; (i==0) or: {item == (bus.at(i-1)+1)} }),{ ^In.ar(chanOffset + bus.first, bus.size).madd(mul,add) },{ // allow In to multi channel expand ^In.ar(chanOffset + bus).madd(mul,add) }) } *channelOffset { ^NumOutputBuses.ir } } // backward compatible version. Only difference: starts counting from channel 1 AudioIn : SoundIn { *ar { arg channel = 0, mul=1.0, add=0.0; ^super.ar(channel, mul, add) } *channelOffset { ^NumOutputBuses.ir - 1 } } SuperCollider-Source/SCClassLibrary/Common/Audio/BasicOpsUGen.sc000644 000765 000024 00000024455 12756534416 025626 0ustar00crucialstaff000000 000000 // These Unit Generators are instantiated by math operations on UGens BasicOpUGen : UGen { var a - b if (b.descendants.size == 1) { buildSynthDef.removeUGen(b); } { b.descendants.remove(this); }; ^(a - b.inputs[0]) }; if (a.isKindOf(UnaryOpUGen) and: { a.operator == 'neg' }) { // a.neg + b -> b - a if (a.descendants.size == 1) { buildSynthDef.removeUGen(a); } { a.descendants.remove(this); }; ^(b - a.inputs[0]) }; ^nil } optimizeToMulAdd { var a, b; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { a.operator == '*' and: { a.descendants.size == 1 }}) { if (MulAdd.canBeMulAdd(a.inputs[0], a.inputs[1], b)) { buildSynthDef.removeUGen(a); ^MulAdd.new(a.inputs[0], a.inputs[1], b); }; if (MulAdd.canBeMulAdd(a.inputs[1], a.inputs[0], b)) { buildSynthDef.removeUGen(a); ^MulAdd.new(a.inputs[1], a.inputs[0], b) }; }; if (b.isKindOf(BinaryOpUGen) and: { b.operator == '*' and: { b.descendants.size == 1 }}) { if (MulAdd.canBeMulAdd(b.inputs[0], b.inputs[1], a)) { buildSynthDef.removeUGen(b); ^MulAdd.new(b.inputs[0], b.inputs[1], a) }; if (MulAdd.canBeMulAdd(b.inputs[1], b.inputs[0], a)) { buildSynthDef.removeUGen(b); ^MulAdd.new(b.inputs[1], b.inputs[0], a) }; }; ^nil } optimizeToSum3 { var a, b; #a, b = inputs; if(a.rate == \demand or: { b.rate == \demand }) { ^nil }; if (a.isKindOf(BinaryOpUGen) and: { a.operator == '+' and: { a.descendants.size == 1 }}) { buildSynthDef.removeUGen(a); ^Sum3(a.inputs[0], a.inputs[1], b); }; if (b.isKindOf(BinaryOpUGen) and: { b.operator == '+' and: { b.descendants.size == 1 }}) { buildSynthDef.removeUGen(b); ^Sum3(b.inputs[0], b.inputs[1], a); }; ^nil } optimizeToSum4 { var a, b; #a, b = inputs; if(a.rate == \demand or: { b.rate == \demand }) { ^nil }; if (a.isKindOf(Sum3) and: { a.descendants.size == 1 }) { buildSynthDef.removeUGen(a); ^Sum4(a.inputs[0], a.inputs[1], a.inputs[2], b); }; if (b.isKindOf(Sum3) and: { b.descendants.size == 1 }) { buildSynthDef.removeUGen(b); ^Sum4(b.inputs[0], b.inputs[1], b.inputs[2], a); }; ^nil } optimizeSub { var a, b, replacement; #a, b = inputs; if (b.isKindOf(UnaryOpUGen) and: { b.operator == 'neg' }) { // a - b.neg -> a + b if (b.descendants.size == 1) { buildSynthDef.removeUGen(b); } { b.descendants.remove(this); }; replacement = BinaryOpUGen('+', a, b.inputs[0]); synthDef.replaceUGen(this, replacement); replacement.optimizeGraph }; ^nil } constantFolding { var a, b, aa, bb, cc, dd, temp, ac_ops, value; // associative & commutative operators ac_ops = #['+','*','min','max','&&','||']; if (ac_ops.includes(operator).not) { ^this }; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { operator == a.operator and: { b.isKindOf(BinaryOpUGen) and: { operator == b.operator } }}) { #aa, bb = a.inputs; #cc, dd = b.inputs; if (aa.isKindOf(SimpleNumber)) { if (cc.isKindOf(SimpleNumber)) { b.inputs[0] = bb; this.inputs[0] = aa.perform(operator, cc); synthDef.removeUGen(a); }{ if (dd.isKindOf(SimpleNumber)) { b.inputs[1] = bb; this.inputs[0] = aa.perform(operator, dd); synthDef.removeUGen(a); }} }{ if (bb.isKindOf(SimpleNumber)) { if (cc.isKindOf(SimpleNumber)) { b.inputs[0] = aa; this.inputs[0] = bb.perform(operator, cc); synthDef.removeUGen(a); }{ if (dd.isKindOf(SimpleNumber)) { b.inputs[1] = aa; this.inputs[0] = bb.perform(operator, dd); synthDef.removeUGen(a); }} }}; }; #a, b = inputs; if (a.isKindOf(BinaryOpUGen) and: { operator == a.operator }) { #aa, bb = a.inputs; if (b.isKindOf(SimpleNumber)) { if (aa.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(a); this.inputs[0] = aa.perform(operator, b); this.inputs[1] = bb; ^this }; if (bb.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(a); this.inputs[0] = bb.perform(operator, b); this.inputs[1] = aa; ^this }; }; // percolate constants upward so that a subsequent folding may occur if (aa.isKindOf(SimpleNumber)) { this.inputs[1] = aa; a.inputs[0] = b; }{ if (bb.isKindOf(SimpleNumber)) { this.inputs[1] = bb; a.inputs[1] = b; }}; }; #a, b = inputs; if (b.isKindOf(BinaryOpUGen) and: { operator == b.operator }) { #cc, dd = b.inputs; if (a.isKindOf(SimpleNumber)) { if (cc.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(b); this.inputs[0] = a.perform(operator, cc); this.inputs[1] = dd; ^this }; if (dd.isKindOf(SimpleNumber)) { buildSynthDef.removeUGen(b); this.inputs[0] = a.perform(operator, dd); this.inputs[1] = cc; ^this }; }; // percolate constants upward so that a subsequent folding may occur if (cc.isKindOf(SimpleNumber)) { this.inputs[0] = cc; b.inputs[0] = a; }{ if (dd.isKindOf(SimpleNumber)) { this.inputs[0] = dd; b.inputs[1] = a; }}; }; #a, b = inputs; if (a.isKindOf(SimpleNumber) and: { b.isKindOf(SimpleNumber) }) { synthDef.replaceUGen(this, a.perform(operator, b)); synthDef.removeUGen(this); }; } } MulAdd : UGen { *new { arg in, mul = 1.0, add = 0.0; var args = [in, mul, add].asUGenInput(this); var rate = args.rate; ^this.multiNewList([rate] ++ args) } *new1 { arg rate, in, mul, add; var minus, nomul, noadd; // eliminate degenerate cases if (mul == 0.0, { ^add }); minus = mul == -1.0; nomul = mul == 1.0; noadd = add == 0.0; if (nomul && noadd, { ^in }); if (minus && noadd, { ^in.neg }); if (noadd, { ^in * mul }); if (minus, { ^add - in }); if (nomul, { ^in + add }); if (this.canBeMulAdd(in, mul, add)) { ^super.new1(rate, in, mul, add) }; if (this.canBeMulAdd(mul, in, add)) { ^super.new1(rate, mul, in, add) }; ^( (in * mul) + add) } init { arg in, mul, add; inputs = [in, mul, add]; rate = inputs.rate; } *canBeMulAdd { arg in, mul, add; // see if these inputs satisfy the constraints of a MulAdd ugen. if (in.rate == \audio, { ^true }); if (in.rate == \control and: { mul.rate == \control || { mul.rate == \scalar }} and: { add.rate == \control || { add.rate == \scalar }}, { ^true }); ^false } } Sum3 : UGen { *new { arg in0, in1, in2; ^this.multiNew(nil, in0, in1, in2) } *new1 { arg dummyRate, in0, in1, in2; var argArray, rate, sortedArgs; if (in2 == 0.0) { ^(in0 + in1) }; if (in1 == 0.0) { ^(in0 + in2) }; if (in0 == 0.0) { ^(in1 + in2) }; argArray = [in0, in1, in2]; rate = argArray.rate; sortedArgs = argArray.sort {|a b| a.rate < b.rate}; ^super.new1(rate, *sortedArgs) } } Sum4 : UGen { *new { arg in0, in1, in2, in3; ^this.multiNew(nil, in0, in1, in2, in3) } *new1 { arg dummyRate, in0, in1, in2, in3; var argArray, rate, sortedArgs; if (in0 == 0.0) { ^Sum3.new1(nil, in1, in2, in3) }; if (in1 == 0.0) { ^Sum3.new1(nil, in0, in2, in3) }; if (in2 == 0.0) { ^Sum3.new1(nil, in0, in1, in3) }; if (in3 == 0.0) { ^Sum3.new1(nil, in0, in1, in2) }; argArray = [in0, in1, in2, in3]; rate = argArray.rate; sortedArgs = argArray.sort {|a b| a.rate < b.rate}; ^super.new1(rate, *sortedArgs) } } SuperCollider-Source/SCClassLibrary/Common/Audio/BEQSuite.sc000644 000765 000024 00000012052 12756534416 024753 0ustar00crucialstaff000000 000000 BEQSuite : Filter {} BLowPass : BEQSuite { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0; var w0, cos_w0, i, alpha, a0, a1, b0rz, b1, b2, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; i = 1 - cos_w0; alpha = w0.sin * 0.5 * rq; b0rz = (1 + alpha).reciprocal; a0 = i * 0.5 * b0rz; a1 = i * b0rz; b1 = cos_w0 * 2 * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[a0, a1, a0, b1, b2]; } } BHiPass : BEQSuite { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0; var i, w0, cos_w0, alpha, a0, a1, b0rz, b1, b2, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; i = 1 + cos_w0; alpha = w0.sin * 0.5 * rq; b0rz = (1 + alpha).reciprocal; a0 = i * 0.5 * b0rz; a1 = i.neg * b0rz; b1 = cos_w0 * 2 * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[a0, a1, a0, b1, b2]; } } BAllPass : BEQSuite { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0; var w0, alpha, a0, b1, b0rz, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; alpha = w0.sin * 0.5 * rq; b0rz = (1 + alpha).reciprocal; a0 = (1 - alpha) * b0rz; b1 = 2.0 * w0.cos * b0rz; ^[a0, b1.neg, 1.0, b1, a0.neg]; } } BBandPass : BEQSuite { *ar {arg in, freq = 1200.0, bw = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, bw).madd(mul, add); } *sc { arg dummy, freq = 1200.0, bw = 1.0; var w0, sin_w0, alpha, a0, b0rz, b1, b2, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; sin_w0 = w0.sin; // alpha = w0.sin * 0.5 * rq; alpha = sin_w0 * sinh(0.34657359027997 * bw * w0 / sin_w0); b0rz = (1 + alpha).reciprocal; a0 = alpha * b0rz; b1 = w0.cos * 2 * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[a0, 0.0, a0.neg, b1, b2]; } } BBandStop : BEQSuite { *ar {arg in, freq = 1200.0, bw = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, bw).madd(mul, add); } *sc { arg dummy, freq = 1200.0, bw = 1.0; var w0, sin_w0, alpha, b1, b2, b0rz, sr; sr = SampleRate.ir; w0 = pi * 2 * freq * SampleDur.ir; sin_w0 = w0.sin; // alpha = w0.sin * 0.5 * rq; alpha = sin_w0 * sinh(0.34657359027997 * bw * w0 / sin_w0); b0rz = (1 + alpha).reciprocal; b1 = 2.0 * w0.cos * b0rz; b2 = (1 - alpha) * b0rz.neg; ^[b0rz, b1.neg, b0rz, b1, b2]; } } BPeakEQ : BEQSuite { *ar {arg in, freq = 1200.0, rq = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq, db).madd(mul, add); } *sc { arg dummy, freq = 1200.0, rq = 1.0, db = 0.0; var a, w0, alpha, a0, a2, b1, b2, b0rz, sr; sr = SampleRate.ir; a = pow(10, db/40); w0 = pi * 2 * freq * SampleDur.ir; alpha = w0.sin * 0.5 * rq; b0rz = (1 + (alpha / a)).reciprocal; a0 = (1 + (alpha * a)) * b0rz; a2 = (1 - (alpha * a)) * b0rz; b1 = 2.0 * w0.cos * b0rz; b2 = (1 - (alpha / a)) * b0rz.neg; ^[a0, b1.neg, a2, b1, b2]; } } BLowShelf : BEQSuite { *ar {arg in, freq = 1200.0, rs = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rs, db).madd(mul, add); } *sc { arg dummy, freq = 120.0, rs = 1.0, db = 0.0; var a, w0, sin_w0, cos_w0, alpha, i, j, k, a0, a1, a2, b0rz, b1, b2, sr; sr = SampleRate.ir; a = pow(10, db/40); w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; sin_w0 = w0.sin; alpha = sin_w0 * 0.5 * sqrt((a + a.reciprocal) * (rs - 1) + 2.0); i = (a+1) * cos_w0; j = (a-1) * cos_w0; k = 2 * sqrt(a) * alpha; b0rz = ((a+1) + j + k).reciprocal; a0 = a * ((a+1) - j + k) * b0rz; a1 = 2 * a * ((a-1) - i) * b0rz; a2 = a * ((a+1) - j - k) * b0rz; b1 = 2.0 * ((a-1) + i) * b0rz; b2 = ((a+1) + j - k) * b0rz.neg; ^[a0, a1, a2, b1, b2]; } } BHiShelf : BEQSuite { *ar {arg in, freq = 1200.0, rs = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rs, db).madd(mul, add); } *sc { arg dummy, freq = 120.0, rs = 1.0, db = 0.0; var a, w0, sin_w0, cos_w0, alpha, i, j, k, a0, a1, a2, b0rz, b1, b2, sr; sr = SampleRate.ir; a = pow(10, db/40); w0 = pi * 2 * freq * SampleDur.ir; cos_w0 = w0.cos; sin_w0 = w0.sin; alpha = sin_w0 * 0.5 * sqrt((a + a.reciprocal) * (rs - 1) + 2.0); i = (a+1) * cos_w0; j = (a-1) * cos_w0; k = 2 * sqrt(a) * alpha; b0rz = ((a+1) - j + k).reciprocal; a0 = a * ((a+1) + j + k) * b0rz; a1 = -2.0 * a * ((a-1) + i) * b0rz; a2 = a * ((a+1) + j - k) * b0rz; b1 = -2.0 * ((a-1) - i) * b0rz; b2 = ((a+1) - j - k) * b0rz.neg; ^[a0, a1, a2, b1, b2]; } } // pseudo UGens BLowPass4 { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; var coefs; rq = sqrt(rq); coefs = BLowPass.sc(nil, freq, rq); ^SOS.ar(SOS.ar(in, *coefs), *coefs ++ [mul, add]); } } BHiPass4 { *ar { arg in, freq = 1200.0, rq = 1.0, mul = 1.0, add = 0.0; var coefs; rq = sqrt(rq); coefs = BHiPass.sc(nil, freq, rq); ^SOS.ar(SOS.ar(in, *coefs), *coefs ++ [mul, add]); } } SuperCollider-Source/SCClassLibrary/Common/Audio/BufIO.sc000644 000765 000024 00000011644 12766171707 024305 0ustar00crucialstaff000000 000000 /* PlayBuf - sample player */ PlayBuf : MultiOutUGen { *ar { arg numChannels, bufnum=0, rate=1.0, trigger=1.0, startPos=0.0, loop = 0.0, doneAction=0; ^this.multiNew('audio', numChannels, bufnum, rate, trigger, startPos, loop, doneAction) } *kr { arg numChannels, bufnum=0, rate=1.0, trigger=1.0, startPos=0.0, loop = 0.0, doneAction=0; ^this.multiNew('control', numChannels, bufnum, rate, trigger, startPos, loop, doneAction) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } TGrains : MultiOutUGen { *ar { arg numChannels, trigger=0, bufnum=0, rate=1, centerPos=0, dur=0.1, pan=0, amp=0.1, interp=4; ^this.multiNew('audio', numChannels, trigger, bufnum, rate, centerPos, dur, pan, amp, interp) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } /* // exception in GrafDef_Load: UGen 'SimpleLoopBuf' not installed. SimpleLoopBuf : MultiOutUGen { *ar { arg numChannels, bufnum=0, loopStart=0.0, loopEnd=99999.0, trigger=0.0; ^this.multiNew('audio', numChannels, bufnum, loopStart, loopEnd, trigger) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } } */ BufRd : MultiOutUGen { *ar { arg numChannels, bufnum=0, phase=0.0, loop=1.0, interpolation=2; ^this.multiNew('audio', numChannels, bufnum, phase, loop, interpolation) } *kr { arg numChannels, bufnum=0, phase=0.0, loop=1.0, interpolation=2; ^this.multiNew('control', numChannels, bufnum, phase, loop, interpolation) } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } checkInputs { if (rate == 'audio' and: {inputs.at(1).rate != 'audio'}, { ^("phase input is not audio rate: " + inputs.at(1) + inputs.at(1).rate); }); ^this.checkValidInputs } } BufWr : UGen { *ar { arg inputArray, bufnum=0, phase=0.0, loop=1.0; ^this.multiNewList(['audio', bufnum, phase, loop] ++ inputArray.asArray) } *kr { arg inputArray, bufnum=0, phase=0.0, loop=1.0; ^this.multiNewList(['control', bufnum, phase, loop] ++ inputArray.asArray) } checkInputs { if (rate == 'audio' and: {inputs.at(1).rate != 'audio'}, { ^("phase input is not audio rate: " + inputs.at(1) + inputs.at(1).rate); }); ^this.checkValidInputs } } RecordBuf : UGen { *ar { arg inputArray, bufnum=0, offset=0.0, recLevel=1.0, preLevel=0.0, run=1.0, loop=1.0, trigger=1.0, doneAction=0; ^this.multiNewList( ['audio', bufnum, offset, recLevel, preLevel, run, loop, trigger, doneAction ] ++ inputArray.asArray ) } *kr { arg inputArray, bufnum=0, offset=0.0, recLevel=1.0, preLevel=0.0, run=1.0, loop=1.0, trigger=1.0, doneAction=0; ^this.multiNewList( ['control', bufnum, offset, recLevel, preLevel, run, loop, trigger, doneAction ] ++ inputArray.asArray ) } } ScopeOut : UGen { *ar { arg inputArray , bufnum=0; this.multiNewList(['audio', bufnum] ++ inputArray.asArray); ^0.0 } *kr { arg inputArray , bufnum=0; this.multiNewList(['control', bufnum] ++ inputArray.asArray); ^0.0 } } ScopeOut2 : UGen { *ar { arg inputArray, scopeNum=0, maxFrames = 4096, scopeFrames; this.multiNewList(['audio', scopeNum, maxFrames, scopeFrames ? maxFrames] ++ inputArray.asArray); ^0.0 } *kr { arg inputArray, scopeNum=0, maxFrames = 4096, scopeFrames; this.multiNewList(['control', scopeNum, maxFrames, scopeFrames ? maxFrames] ++ inputArray.asArray); ^0.0 } } Tap : UGen { *ar { arg bufnum = 0, numChannels = 1, delaytime = 0.2; var n; n = delaytime * SampleRate.ir.neg; // this depends on the session sample rate, not buffer. ^PlayBuf.ar(numChannels, bufnum, 1, 0, n, 1); } } LocalBuf : WidthFirstUGen { *new { arg numFrames = 1, numChannels = 1; ^this.multiNew('scalar', numChannels, numFrames) } *new1 { arg rate ... args; var maxLocalBufs = UGen.buildSynthDef.maxLocalBufs; if(maxLocalBufs.isNil) { maxLocalBufs = MaxLocalBufs.new; UGen.buildSynthDef.maxLocalBufs = maxLocalBufs; }; maxLocalBufs.increment; ^super.new.rate_(rate).addToSynth.init( *args ++ maxLocalBufs ) } *newFrom { arg list; var shape, buf; shape = list.shape; if(shape.size == 1) { shape = [1, list.size] }; if(shape.size > 2) { Error("LocalBuf: list has not the right shape").throw }; buf = this.new(*shape.reverse); buf.set(list.flop.flat); ^buf } numFrames { ^inputs[1] } numChannels { ^inputs[0] } set { arg values, offset = 0; SetBuf(this, values.asArray, offset); } clear { ClearBuf(this); } } MaxLocalBufs : UGen { *new { ^this.multiNew('scalar', 0); } increment { inputs[0] = inputs[0] + 1; } } SetBuf : WidthFirstUGen { *new { arg buf, values, offset = 0; ^this.multiNewList(['scalar', buf, offset, values.size] ++ values) } } ClearBuf : WidthFirstUGen { *new { arg buf; ^this.multiNew('scalar', buf) } } SuperCollider-Source/SCClassLibrary/Common/Audio/canFreeSynth.sc000644 000765 000024 00000002621 12756534416 025724 0ustar00crucialstaff000000 000000 /////////// query whether some UGen can possibly free its synth from within + Object { canFreeSynth { ^false } } +SequenceableCollection { canFreeSynth { ^this.any({ arg item; item.canFreeSynth }) } } + EnvGen { canFreeSynth { ^(inputs.at(4).isNumber.not or: {inputs.at(4) > 1}) and: //doneAction { // it can happen that the gate is 1 and the envelope runs out inputs.at(0).isNumber.not or: //variable gate { inputs.at(7) == -99 } //or self releasing envelope } } } + Linen { canFreeSynth { ^(inputs.at(4).isNumber.not or: { inputs.at(4) > 1 }) and: { inputs.at(0).isNumber.not } } } + Line { canFreeSynth { ^inputs.at(3).isNumber.not or: { inputs.at(3) > 1 } } } + XLine { canFreeSynth { ^inputs.at(3).isNumber.not or: { inputs.at(3) > 1 } } } + Free { canFreeSynth { ^true } } + FreeSelf { canFreeSynth { ^true } } + DetectSilence { canFreeSynth { ^inputs.at(3).isNumber.not or: { inputs.at(3) > 1 } } } + Duty { canFreeSynth { ^inputs.at(2).isNumber.not or: { inputs.at(2) > 1 } } } + DemandEnvGen { canFreeSynth { ^inputs.at(9).isNumber.not or: { inputs.at(9) > 1 } } } + SynthDef { canFreeSynth { ^children.canFreeSynth } canReleaseSynth { ^this.hasGateControl and: { this.canFreeSynth } } hasGateControl { if(allControlNames.isNil) { ^false }; ^allControlNames.any { arg cn; cn.notNil and: { cn.name == 'gate' } and: { cn.rate !== 'scalar' } }; } } SuperCollider-Source/SCClassLibrary/Common/Audio/Chaos.sc000644 000765 000024 00000005543 12756534416 024376 0ustar00crucialstaff000000 000000 /* Non-linear Dynamic Sound Generators Lance Putnam 2004 lance@uwalumni.com This is a set of iterative functions and differential equations that are known to exhibit chaotic behavior. Internal calculations are done with 64-bit words to ensure greater accuracy. The name of the function is followed by one of N, L, or C. These represent the interpolation method used between function iterations. N -> None L -> Linear C -> Cubic */ ChaosGen : UGen { } // General Quadratic Map QuadN : ChaosGen { const buffer.numFrames; // catch buffer overrun by switching to a zero length series brd = Dswitch1([brd, Dseries(length:0)], overrun); } { index = Dseq([Dseries(0, 1, buffer.numFrames)], inf) }; ^Dbufrd(brd, index, 1); } } SuperCollider-Source/SCClassLibrary/Common/Audio/DiskIO.sc000644 000765 000024 00000001575 12756534416 024464 0ustar00crucialstaff000000 000000 DiskOut : UGen { *ar { arg bufnum, channelsArray; ^this.multiNewList(['audio', bufnum] ++ channelsArray.asArray) } checkInputs { if (rate == 'audio', { for(1, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^("input was not audio rate: " + inputs.at(i)); }); }); }); ^this.checkValidInputs } } DiskIn : MultiOutUGen { *ar { arg numChannels, bufnum, loop = 0; ^this.multiNew('audio', numChannels, bufnum, loop) } init { arg numChannels, bufnum, loop = 0; inputs = [bufnum, loop]; ^this.initOutputs(numChannels, rate) } } VDiskIn : MultiOutUGen { *ar { arg numChannels, bufnum, rate = 1, loop = 0, sendID = 0; ^this.multiNew('audio', numChannels, bufnum, rate, loop, sendID) } init { arg numChannels, bufnum, argRate = 1, loop = 0, sendID = 0; inputs = [bufnum, argRate, loop, sendID]; ^this.initOutputs(numChannels, rate) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Env.sc000644 000765 000024 00000024307 12756534416 024070 0ustar00crucialstaff000000 000000 Env { var 0, \lin -> 1, \linear -> 1, \exp -> 2, \exponential -> 2, \sin -> 3, \sine -> 3, \wel -> 4, \welch -> 4, \sqr -> 6, \squared -> 6, \cub -> 7, \cubed -> 7, \hold -> 8, ]; shapeNames.freeze; } kr { arg doneAction = 0, gate = 1.0, timeScale = 1.0, mul = 1.0, add = 0.0; ^EnvGen.kr(this, gate, mul, add, timeScale, doneAction) } ar { arg doneAction = 0, gate = 1.0, timeScale = 1.0, mul = 1.0, add = 0.0; ^EnvGen.ar(this, gate, mul, add, timeScale, doneAction) } levels_ { arg z; levels = z; array = nil; } times_ { arg z; times = z; array = nil; } curves_ { arg z; curves = z; array = nil; } releaseNode_ { arg z; releaseNode = z; array = nil; } loopNode_ { arg z; loopNode = z; array = nil; } offset_ { arg z; offset = z; array = nil; } duration_ { arg dur; times = times * this.totalDuration.reciprocal * dur } duration { ^times.sum } totalDuration { var duration = times.sum; ^duration.asArray.maxItem; } range { arg lo = 0.0, hi = 1.0; ^this.copy.levels_(levels.linlin(levels.minItem, levels.maxItem, lo, hi)) } exprange { arg lo = 0.01, hi = 1.0; ^this.copy.levels_(levels.linexp(levels.minItem, levels.maxItem, lo, hi)) } curverange { arg lo = 0.0, hi = 1.0, curve = -4; ^this.copy.levels_(levels.lincurve(levels.minItem, levels.maxItem, lo, hi, curve)) } // methods to make some typical shapes : // fixed duration envelopes *triangle { arg dur=1.0, level=1.0; dur = dur * 0.5; ^this.new( [0, level, 0], [dur, dur] ) } *sine { arg dur=1.0, level=1.0; dur = dur * 0.5; ^this.new( [0, level, 0], [dur, dur], \sine ) } *perc { arg attackTime=0.01, releaseTime=1.0, level=1.0, curve = -4.0; ^this.new( [0, level, 0], [attackTime, releaseTime], curve ) } *linen { arg attackTime=0.01, sustainTime=1.0, releaseTime=1.0, level=1.0, curve = \lin; ^this.new( [0, level, level, 0], [attackTime, sustainTime, releaseTime], curve ) } *xyc { arg xyc; var times, levels, curves, offset, order; #times, levels, curves = xyc.flop; if(times.every(_.isKindOf(Magnitude))) { // sort triplets, if possible. order = times.order; times = times[order]; levels = levels[order]; curves = curves[order]; }; offset = times[0]; times = times.differentiate.drop(1); curves.asArray.drop(-1); ^this.new(levels, times, curves, offset: offset); } *pairs { arg pairs, curve; if(curve.isNil) { ^this.xyc(pairs) }; ^this.xyc(pairs +++ curve); } *step { |levels = #[0,1], times = #[1,1], releaseNode, loopNode, offset = 0| if( levels.size != times.size ) { Error("Env#*step : levels and times must have same size").throw }; ^Env([levels[0]]++levels, times, \step, releaseNode, loopNode, offset) } // envelopes with sustain *cutoff { arg releaseTime = 0.1, level = 1.0, curve = \lin; var curveNo = this.shapeNumber(curve); var releaseLevel = if(curveNo == 2) { -100.dbamp } { 0 }; ^this.new([level, releaseLevel], [releaseTime], curve, 0) } *dadsr { arg delayTime=0.1, attackTime=0.01, decayTime=0.3, sustainLevel=0.5, releaseTime=1.0, peakLevel=1.0, curve = -4.0, bias = 0.0; ^this.new( [0, 0, peakLevel, peakLevel * sustainLevel, 0] + bias, [delayTime, attackTime, decayTime, releaseTime], curve, 3 ) } *adsr { arg attackTime=0.01, decayTime=0.3, sustainLevel=0.5, releaseTime=1.0, peakLevel=1.0, curve = -4.0, bias = 0.0; ^this.new( [0, peakLevel, peakLevel * sustainLevel, 0] + bias, [attackTime, decayTime, releaseTime], curve, 2 ) } *asr { arg attackTime=0.01, sustainLevel=1.0, releaseTime=1.0, curve = -4.0; ^this.new( [0, sustainLevel, 0], [attackTime, releaseTime], curve, 1 ) } *circle { arg levels, times, curve = \lin; times = times.asArray.wrapExtend(levels.size); curve = curve.asArray.wrapExtend(levels.size); ^this.new(levels, times.drop(-1), curve.drop(-1)).circle(times.last, curve.last); } releaseTime { if(releaseNode.isNil) { ^0.0 }; ^times.copyRange(releaseNode, times.size - 1).sum } isSustained { ^releaseNode.notNil } asMultichannelSignal { arg length = 400, class = (Signal); var multiChannelArray = this.asMultichannelArray; var channelCount = multiChannelArray.size; var totalDur = this.totalDuration; length = max(length, levels.size); ^multiChannelArray.collect { |chan| var signal, ratio; ratio = totalDur / (length - 1); signal = class.new(length); length.do { arg i; signal.add(chan.envAt(i * ratio)) }; signal } } asSignal { arg length = 400; ^this.asMultichannelSignal(length).unbubble } discretize { arg n = 1024; ^this.asSignal(n); } storeArgs { ^[levels, times, curves, releaseNode, loopNode] } == { arg that; ^this.compareObject(that, [\levels, \times, \curves, \releaseNode, \loopNode, \offset]) } hash { ^this.instVarHash([\levels, \times, \curves, \releaseNode, \loopNode, \offset]) } at { arg time; var data = this.asMultichannelArray; time = (time - offset).max(0); ^if(time.isSequenceableCollection) { if(data.size <= 1) { data = data[0]; time.collect { |t| data.envAt(t) } } { time.collect { |t| data.collect { |channel| channel.envAt(t) } } } } { if(data.size <= 1) { data[0].envAt(time) } { data.collect { |channel| channel.envAt(time) } } } } embedInStream { arg inval; var startTime = thisThread.endBeat ? thisThread.beats; thisThread.endBeat = this.duration + startTime; loop { inval = yield(this.at(thisThread.beats - startTime)); } } asStream { ^Routine({ arg inval; this.embedInStream(inval) }) } asPseg { var c = if(curves.isSequenceableCollection.not) { curves } { Pseq(curves, inf) }; ^Pseg(Pseq(levels), Pseq(times ++ [1.0]), c) // last time is a dummy } // blend two envelopes blend { arg argAnotherEnv, argBlendFrac=0.5; ^this.class.new( levels.blend(argAnotherEnv.levels, argBlendFrac), times.blend(argAnotherEnv.times, argBlendFrac), curves.blend(argAnotherEnv.curves, argBlendFrac), releaseNode, loopNode ) } // delay the onset of the envelope delay { arg delay; ^Env([levels[0]] ++ levels, [delay] ++ times, if (curves.isArray) { [\lin] ++ curves } { curves }, if(releaseNode.notNil) { releaseNode = releaseNode + 1 }, if(loopNode.notNil) { loopNode = loopNode + 1 } ) } // connect releaseNode (or end) to first node of envelope circle { arg timeFromLastToFirst = 0.0, curve = \lin; var first0Then1; if(UGen.buildSynthDef.isNil) { ^this }; first0Then1 = Latch.kr(1.0, Impulse.kr(0.0)); if(releaseNode.isNil) { levels = [0.0] ++ levels ++ 0.0; curves = [curve] ++ curves.asArray.wrapExtend(times.size) ++ \lin; times = [first0Then1 * timeFromLastToFirst] ++ times ++ inf; releaseNode = levels.size - 2; } { levels = [0.0] ++ levels; curves = [curve] ++ curves.asArray.wrapExtend(times.size); times = [first0Then1 * timeFromLastToFirst] ++ times; releaseNode = releaseNode + 1; }; loopNode = 0; } test { arg releaseTime = 3.0; var s = Server.default; if(s.serverRunning.not) { "Server not running.".warn; ^this }; fork { var synth = { arg gate=1; SinOsc.ar(800, pi/2, 0.3) * EnvGen.ar(this, gate, doneAction:2) }.play; if(this.isSustained) { s.sendBundle(s.latency + releaseTime, [15, synth.nodeID, \gate, 0]) }; }; } *shapeNumber { arg shapeName; ^shapeName.asArray.collect { |name| var shape; if(name.isValidUGenInput) { 5 } { shape = shapeNames.at(name); if(shape.isNil) { Error("Env shape not defined.").throw }; shape } }.unbubble } curveValue { arg curve; ^if(curve.isSequenceableCollection) { curve.collect { |x| if(x.isValidUGenInput) { x } { 0 } } } { if(curve.isValidUGenInput) { curve } { 0 } } } asArray { if (array.isNil) { array = this.prAsArray } ^array.unbubble // keep backward compatibility } asMultichannelArray { if (array.isNil) { array = this.prAsArray } ^array } // this version is for IEnvGen and has a special format. // don't cache this version for now, but instead return it directly. asArrayForInterpolation { var contents, size; var levelArray = levels.asUGenInput; var timeArray = times.asUGenInput; var curvesArray = curves.asArray.asUGenInput; size = timeArray.size; contents = Array.new((size + 1) * 4); contents.add(offset.asUGenInput ? 0); contents.add(levelArray.at(0)); contents.add(size); contents.add(timeArray.sum); curvesArray = curves.asArray; times.size.do { arg i; contents.add(timeArray[i]); contents.add(this.class.shapeNumber(curvesArray.wrapAt(i))); contents.add(this.curveValue(curvesArray.wrapAt(i))); contents.add(levelArray[i+1]); }; ^contents.flop } prAsArray { var contents, size; var levelArray = levels.asUGenInput; var timeArray = times.asUGenInput; var curvesArray = curves.asArray.asUGenInput; size = times.size; contents = Array.new((size + 1) * 4); contents.add(levelArray.at(0)); contents.add(size); contents.add(releaseNode.asUGenInput ? -99); contents.add(loopNode.asUGenInput ? -99); size.do { arg i; contents.add(levelArray.at(i+1)); contents.add(timeArray.at(i)); contents.add(this.class.shapeNumber(curvesArray.wrapAt(i))); contents.add(this.curveValue(curvesArray.wrapAt(i))); }; ^contents.flop; } } SuperCollider-Source/SCClassLibrary/Common/Audio/EnvGen.sc000644 000765 000024 00000003441 12756534416 024516 0ustar00crucialstaff000000 000000 Done : UGen { *kr { arg src; ^this.multiNew('control', src) } } FreeSelf : UGen { *kr { arg in; this.multiNew('control', in); ^in } } PauseSelf : UGen { *kr { arg in; this.multiNew('control', in); ^in } } FreeSelfWhenDone : UGen { *kr { arg src; ^this.multiNew('control', src) } } PauseSelfWhenDone : UGen { *kr { arg src; ^this.multiNew('control', src) } } Pause : UGen { *kr { arg gate, id; ^this.multiNew('control', gate, id) } } Free : UGen { *kr { arg trig, id; ^this.multiNew('control', trig, id) } } EnvGen : UGen { // envelope generator *ar { arg envelope, gate = 1.0, levelScale = 1.0, levelBias = 0.0, timeScale = 1.0, doneAction = 0; envelope = this.convertEnv(envelope); ^this.multiNewList(['audio', gate, levelScale, levelBias, timeScale, doneAction, envelope]) } *kr { arg envelope, gate = 1.0, levelScale = 1.0, levelBias = 0.0, timeScale = 1.0, doneAction = 0; envelope = this.convertEnv(envelope); ^this.multiNewList(['control', gate, levelScale, levelBias, timeScale, doneAction, envelope]) } *convertEnv { arg env; if(env.isSequenceableCollection) { if (env.shape.size == 1) { ^env.reference } { // multi-channel envelope ^env.collect(_.reference) }; }; ^env.asMultichannelArray.collect(_.reference).unbubble } *new1 { arg rate, gate, levelScale, levelBias, timeScale, doneAction, envArray; ^super.new.rate_(rate).addToSynth.init([gate, levelScale, levelBias, timeScale, doneAction] ++ envArray.dereference); } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } Linen : UGen { *kr { arg gate = 1.0, attackTime = 0.01, susLevel = 1.0, releaseTime = 1.0, doneAction = 0; ^this.multiNew('control', gate, attackTime, susLevel, releaseTime, doneAction) } } SuperCollider-Source/SCClassLibrary/Common/Audio/FFT.sc000644 000765 000024 00000010223 12756534416 023747 0ustar00crucialstaff000000 000000 // fft uses a local buffer for holding the buffered audio. // wintypes are defined in the C++ source. 0 is default, Welch; 1 is Hann; -1 is rect. WidthFirstUGen : UGen { addToSynth { synthDef = buildSynthDef; if (synthDef.notNil, { synthDef.addUGen(this); synthDef.widthFirstUGens = synthDef.widthFirstUGens.add(this); }); } addCopiesIfNeeded { } } FFT : PV_ChainUGen { *new { | buffer, in = 0.0 , hop = 0.5, wintype = 0 , active = 1, winsize=0| ^this.multiNew('control', buffer, in, hop, wintype, active, winsize) } fftSize { ^BufFrames.ir(inputs[0]) } } IFFT : WidthFirstUGen { *new { | buffer, wintype = 0, winsize=0| ^this.ar(buffer, wintype, winsize) } *ar { | buffer, wintype = 0, winsize=0| ^this.multiNew('audio', buffer, wintype, winsize) } *kr { | buffer, wintype = 0, winsize=0| ^this.multiNew('control', buffer, wintype, winsize) } } PV_MagAbove : PV_ChainUGen { *new { arg buffer, threshold = 0.0; ^this.multiNew('control', buffer, threshold) } } PV_MagBelow : PV_MagAbove {} PV_MagClip : PV_MagAbove {} PV_LocalMax : PV_MagAbove {} PV_MagSmear : PV_ChainUGen { *new { arg buffer, bins = 0.0; ^this.multiNew('control', buffer, bins) } } PV_BinShift : PV_ChainUGen { *new { arg buffer, stretch = 1.0, shift = 0.0, interp = 0; ^this.multiNew('control', buffer, stretch, shift, interp) } } PV_MagShift : PV_ChainUGen { *new { arg buffer, stretch = 1.0, shift = 0.0; ^this.multiNew('control', buffer, stretch, shift) } } PV_MagSquared : PV_ChainUGen { *new { arg buffer; ^this.multiNew('control', buffer) } } PV_MagNoise : PV_MagSquared {} PV_PhaseShift90 : PV_MagSquared {} PV_PhaseShift270 : PV_MagSquared {} PV_Conj : PV_MagSquared {} PV_PhaseShift : PV_ChainUGen { *new { arg buffer, shift, integrate=0; ^this.multiNew('control', buffer, shift, integrate) } } PV_BrickWall : PV_ChainUGen { *new { arg buffer, wipe = 0.0; ^this.multiNew('control', buffer, wipe) } } PV_BinWipe : PV_ChainUGen { *new { arg bufferA, bufferB, wipe = 0.0; ^this.multiNew('control', bufferA, bufferB, wipe) } } PV_MagMul : PV_ChainUGen { *new { arg bufferA, bufferB; ^this.multiNew('control', bufferA, bufferB) } } PV_CopyPhase : PV_MagMul {} PV_Copy : PV_MagMul {} PV_Max : PV_MagMul {} PV_Min : PV_MagMul {} PV_Mul : PV_MagMul {} PV_Div : PV_MagMul {} PV_Add : PV_MagMul {} PV_MagDiv : PV_ChainUGen { *new { arg bufferA, bufferB, zeroed = 0.0001; ^this.multiNew('control', bufferA, bufferB, zeroed) } } PV_RandComb : PV_ChainUGen { *new { arg buffer, wipe = 0.0, trig = 0.0; ^this.multiNew('control', buffer, wipe, trig) } } PV_RectComb : PV_ChainUGen { *new { arg buffer, numTeeth = 0.0, phase = 0.0, width = 0.5; ^this.multiNew('control', buffer, numTeeth, phase, width) } } PV_RectComb2 : PV_ChainUGen { *new { arg bufferA, bufferB, numTeeth = 0.0, phase = 0.0, width = 0.5; ^this.multiNew('control', bufferA, bufferB, numTeeth, phase, width) } } PV_RandWipe : PV_ChainUGen { *new { arg bufferA, bufferB, wipe = 0.0, trig = 0.0; ^this.multiNew('control', bufferA, bufferB, wipe, trig) } } PV_Diffuser : PV_ChainUGen { *new { arg buffer, trig = 0.0; ^this.multiNew('control', buffer, trig) } } PV_MagFreeze : PV_ChainUGen { *new { arg buffer, freeze = 0.0; ^this.multiNew('control', buffer, freeze) } } PV_BinScramble : PV_ChainUGen { *new { arg buffer, wipe = 0.0, width = 0.2, trig = 0.0; ^this.multiNew('control', buffer, wipe, width, trig) } } FFTTrigger : PV_ChainUGen { *new { | buffer, hop = 0.5, polar = 0.0| ^this.multiNew('control', buffer, hop, polar) } } //////////////////////////////////////////////////// /* PV_OscBank : PV_ChainUGen { *new { arg buffer, scale; ^this.multiNew('control', buffer) } } PV_Scope : PV_ChainUGen {} PV_TimeAverageScope : PV_Scope {} PV_MagAllTimeAverage : PV_MagSquared {} PV_MagOnePole : PV_ChainUGen { *new { arg buffer, feedback = 0.0; ^this.multiNew('control', buffer, feedback) } } PV_MagPeakDecay : PV_ChainUGen { *new { arg buffer, decay = 0.0; ^this.multiNew('control', buffer, decay) } } PV_TimeSmear : PV_MagSmear {} PV_LoBitEncoder : PV_ChainUGen { *new { arg buffer, levels = 4.0; ^this.multiNew('control', buffer, levels) } } */ SuperCollider-Source/SCClassLibrary/Common/Audio/FFT2.sc000644 000765 000024 00000004721 12756534416 024037 0ustar00crucialstaff000000 000000 //third party FFT UGens //sick lincoln remembers complex analysis courses PV_ConformalMap : PV_ChainUGen { *new { arg buffer, areal = 0.0, aimag = 0.0; ^this.multiNew('control', buffer, areal, aimag) } } //in and kernel are both audio rate changing signals Convolution : UGen { *ar { arg in, kernel, framesize=512,mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, framesize).madd(mul, add); } } //fixed kernel convolver with fix by nescivi to update the kernel on receipt of a trigger message Convolution2 : UGen { *ar { arg in, kernel, trigger = 0, framesize=2048,mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, trigger, framesize).madd(mul, add); } } //fixed kernel convolver with linear crossfade Convolution2L : UGen { *ar { arg in, kernel, trigger = 0, framesize=2048, crossfade=1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, trigger, framesize, crossfade).madd(mul, add); } } //fixed kernel stereo convolver with linear crossfade StereoConvolution2L : MultiOutUGen { *ar { arg in, kernelL, kernelR, trigger=0, framesize=2048, crossfade=1, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernelL, kernelR, trigger, framesize, crossfade).madd(mul, add); } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } } //time based convolution by nescivi Convolution3 : UGen { *ar { arg in, kernel, trigger=0, framesize=2048, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, kernel, trigger, framesize).madd(mul, add); } *kr { arg in, kernel, trigger=0, framesize=2048, mul = 1.0, add = 0.0; ^this.multiNew('control', in, kernel, trigger, framesize).madd(mul, add); } } //jensen andersen inspired FFT feature detector PV_JensenAndersen : PV_ChainUGen { *ar { arg buffer, propsc=0.25, prophfe=0.25, prophfc=0.25, propsf=0.25, threshold=1.0, waittime=0.04; ^this.multiNew('audio', buffer, propsc, prophfe, prophfc, propsf, threshold, waittime); } } PV_HainsworthFoote : PV_ChainUGen { *ar { arg buffer, proph=0.0, propf=0.0, threshold=1.0, waittime=0.04; ^this.multiNew('audio', buffer, proph, propf, threshold, waittime); } } //not FFT but useful for time domain onset detection RunningSum : UGen { *ar { arg in, numsamp=40; ^this.multiNew('audio', in, numsamp); } *kr { arg in, numsamp=40; ^this.multiNew('control', in, numsamp); } *rms { arg in, numsamp=40; ^(RunningSum.ar(in.squared,numsamp)*(numsamp.reciprocal)).sqrt; } } SuperCollider-Source/SCClassLibrary/Common/Audio/FFTUnpacking.sc000644 000765 000024 00000010367 12766171707 025621 0ustar00crucialstaff000000 000000 /** "Unpack FFT" UGens (c) 2007 Dan Stowell. Magical UGens for treating FFT data as demand-rate streams. */ // Actually this just wraps up a bundle of Unpack1FFT UGens UnpackFFT : MultiOutUGen { *new { | chain, bufsize, frombin=0, tobin | var upperlimit = bufsize/2; tobin = if(tobin.isNil, upperlimit, {tobin.min(upperlimit)}); ^[Unpack1FFT(chain, bufsize, (frombin..tobin), 0), Unpack1FFT(chain, bufsize, (frombin..tobin), 1)].flop.flatten; } } Unpack1FFT : UGen { *new { | chain, bufsize, binindex, whichmeasure=0 | //("bufsize:"+bufsize).postln; ^this.multiNew('demand', chain, bufsize, binindex, whichmeasure); } } // This does the demanding, to push the data back into an FFT buffer. PackFFT : PV_ChainUGen { *new { | chain, bufsize, magsphases, frombin=0, tobin, zeroothers=0 | tobin = tobin ?? {bufsize/2}; ^this.multiNewList(['control', chain, bufsize, frombin, tobin, zeroothers, magsphases.size] ++ magsphases.asArray) } fftSize {^this.inputs[1]} } // Conveniences to apply calculations to an FFT chain PV_ChainUGen : WidthFirstUGen { // Give it a func to apply to whole set of vals: func(mags, phases) pvcalc { |numframes, func, frombin=0, tobin, zeroothers=0| var origmagsphases, magsphases, ret; origmagsphases = UnpackFFT(this, numframes, frombin, tobin).clump(2).flop; magsphases = func.value(origmagsphases[0], origmagsphases[1]); // Add phases back if they've been ignored magsphases = magsphases.size.switch( 1, {magsphases ++ origmagsphases[1]}, 2, {magsphases}, // any larger than 2 and we assume it's a list of magnitudes {[magsphases, origmagsphases[1]]} ); magsphases = magsphases.flop.flatten; ^PackFFT(this, numframes, magsphases, frombin, tobin, zeroothers); } // The same but for two chains together pvcalc2 { |chain2, numframes, func, frombin=0, tobin, zeroothers=0| var origmagsphases, origmagsphases2, magsphases, ret; origmagsphases = UnpackFFT(this, numframes, frombin, tobin).clump(2).flop; origmagsphases2 = UnpackFFT(chain2, numframes, frombin, tobin).clump(2).flop; magsphases = func.value(origmagsphases[0], origmagsphases[1], origmagsphases2[0], origmagsphases2[1]); // Add phases back if they've been ignored magsphases = magsphases.size.switch( 1, {magsphases ++ origmagsphases[1]}, 2, {magsphases}, // any larger than 2 and we assume it's a list of magnitudes {[magsphases, origmagsphases[1]]} ); magsphases = magsphases.flop.flatten; ^PackFFT(this, numframes, magsphases, frombin, tobin, zeroothers); } // Give it a func to apply to each bin in turn: func(mag, phase, index) pvcollect { |numframes, func, frombin=0, tobin, zeroothers=0| var magsphases, ret; magsphases = UnpackFFT(this, numframes, frombin, tobin).clump(2); magsphases = magsphases.collect({ |mp, index| ret = func.value(mp[0], mp[1], index + frombin, index).asArray; ret = if(ret.size==1, {ret ++ mp[1]}, ret); // Add phase if it's been ignored }).flatten; ^PackFFT(this, numframes, magsphases, frombin, tobin, zeroothers); } addCopiesIfNeeded { var directDescendants, frames, buf, copy; // find UGens that have me as an input directDescendants = buildSynthDef.children.select ({ |child| var inputs; child.isKindOf(PV_Copy).not and: { child.isKindOf(Unpack1FFT).not } and: { inputs = child.inputs; inputs.notNil and: { inputs.includes(this) } } }); if(directDescendants.size > 1, { // insert a PV_Copy for all but the last one directDescendants.drop(-1).do({|desc| desc.inputs.do({ arg input, j; if (input === this, { frames = this.fftSize; frames.widthFirstAntecedents = nil; buf = LocalBuf(frames); buf.widthFirstAntecedents = nil; copy = PV_Copy(this, buf); copy.widthFirstAntecedents = widthFirstAntecedents ++ [buf]; desc.inputs[j] = copy; buildSynthDef.children = buildSynthDef.children.drop(-3).insert(this.synthIndex + 1, frames); buildSynthDef.children = buildSynthDef.children.insert(this.synthIndex + 2, buf); buildSynthDef.children = buildSynthDef.children.insert(this.synthIndex + 3, copy); buildSynthDef.indexUGens; }); }); }); }); } // return a BufFrames // any PV UGens which don't take the chain as first arg will need to override fftSize { ^inputs[0].fftSize } } SuperCollider-Source/SCClassLibrary/Common/Audio/Filter.sc000644 000765 000024 00000023420 12756534416 024560 0ustar00crucialstaff000000 000000 Filter : PureUGen { checkInputs { ^this.checkSameRateAsFirstInput } } Resonz : Filter { *ar { arg in = 0.0, freq = 440.0, bwr = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, bwr).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, bwr = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, bwr).madd(mul, add) } } OnePole : Filter { *ar { arg in = 0.0, coef = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, coef).madd(mul, add) } *kr { arg in = 0.0, coef = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', in, coef).madd(mul, add) } } OneZero : OnePole {} TwoPole : Filter { *ar { arg in = 0.0, freq = 440.0, radius = 0.8, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, radius).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, radius = 0.8, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, radius).madd(mul, add) } } TwoZero : TwoPole {} APF : TwoPole {} Integrator : Filter { *ar { arg in = 0.0, coef = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, coef).madd(mul, add) } *kr { arg in = 0.0, coef = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, coef).madd(mul, add) } } Decay : Filter { *ar { arg in = 0.0, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, decayTime).madd(mul, add) } *kr { arg in = 0.0, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, decayTime).madd(mul, add) } } Decay2 : Filter { *ar { arg in = 0.0, attackTime = 0.01, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, attackTime, decayTime).madd(mul, add) } *kr { arg in = 0.0, attackTime = 0.01, decayTime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, attackTime, decayTime).madd(mul, add) } } Lag : Filter { *ar { arg in = 0.0, lagTime = 0.1, mul = 1.0, add = 0.0; if ( (in.rate == \scalar) || (lagTime == 0) ) { ^in.madd(mul, add) } { ^this.multiNew('audio', in, lagTime).madd(mul, add) } } *kr { arg in = 0.0, lagTime = 0.1, mul = 1.0, add = 0.0; if ( (in.rate == \scalar) || (lagTime == 0) ) { ^in.madd(mul, add) } { ^this.multiNew('control', in, lagTime).madd(mul, add) } } } Lag2 : Lag {} Lag3 : Lag {} Ramp : Lag {} LagUD : Filter { *ar { arg in = 0.0, lagTimeU = 0.1, lagTimeD = 0.1, mul = 1.0, add = 0.0; if (in.rate == \scalar) { ^in.madd(mul, add) } { ^this.multiNew('audio', in, lagTimeU, lagTimeD).madd(mul, add) } } *kr { arg in = 0.0, lagTimeU = 0.1, lagTimeD = 0.1, mul = 1.0, add = 0.0; if (in.rate == \scalar) { ^in.madd(mul, add) } { ^this.multiNew('control', in, lagTimeU, lagTimeD).madd(mul, add) } } } Lag2UD : LagUD {} Lag3UD : LagUD {} VarLag : Filter { *ar { arg in = 0.0, time = 0.1, curvature = 0, warp = 5, start, mul = 1.0, add = 0.0; if ( (in.rate == \scalar) || (time == 0) ) { ^in.madd(mul, add) } { ^this.multiNew('audio', in, time, curvature, warp, start).madd(mul, add); } } *kr { arg in = 0.0, time = 0.1, curvature = 0, warp = 5, start, mul = 1.0, add = 0.0; if ( (in.rate == \scalar) || (time == 0) ) { ^in.madd(mul, add) } { ^this.multiNew('control', in, time, curvature, warp, start).madd(mul, add); } } // FIXME: Implement 'curve' input on VLag ugen instead of using EnvGen. // Then \exp warp should probably behave as Lag ugen. *new1 { arg rate, in, time, curvature, warp, start; var e, curve, trig, sel = if(rate==\audio,\ar,\kr); start = start ? in; curve = Env.shapeNames[warp] ? warp; ^if(curve != 1) { e = Env([start, in], [time], warp).asArray; e[6] = curve; e[7] = curvature; trig = Changed.perform(sel, in) + Impulse.perform(sel, 0); if(time.rate != \scalar) { trig = trig + Changed.kr(time) }; EnvGen.perform(sel, e, trig); } { ^super.new.rate_(rate).addToSynth.init(in, time, start); } } } LeakDC : Filter { *ar { arg in = 0.0, coef = 0.995, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, coef).madd(mul, add) } *kr { arg in = 0.0, coef = 0.9, mul = 1.0, add = 0.0; ^this.multiNew('control', in, coef).madd(mul, add) } } RLPF : Filter { *ar { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, rq).madd(mul, add) } } RHPF : RLPF {} LPF : Filter { *ar { arg in = 0.0, freq = 440.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq).madd(mul, add) } } HPF : LPF {} BPF : Filter { *ar { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, rq = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, rq).madd(mul, add) } } BRF : BPF {} MidEQ : Filter { *ar { arg in = 0.0, freq = 440.0, rq = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, rq, db).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, rq = 1.0, db = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, rq, db).madd(mul, add) } } LPZ1 : Filter { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } HPZ1 : LPZ1 {} Slope : Filter { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } Changed : Filter { *kr { arg input, threshold = 0; ^HPZ1.kr(input).abs > threshold } *ar { arg input, threshold = 0; ^HPZ1.ar(input).abs > threshold } } LPZ2 : Filter { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } HPZ2 : LPZ2 {} BPZ2 : LPZ2 {} BRZ2 : LPZ2 {} Median : Filter { *ar { arg length=3, in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', length, in).madd(mul, add) } *kr { arg length=3, in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', length, in).madd(mul, add) } checkInputs { if (rate == 'audio', { if (inputs.at(1).rate != 'audio', { ^"input was not audio rate"; }); }); ^this.checkValidInputs } } //exception in GrafDef_Load: UGen 'AvgAbsAmp' not installed. //AvgAbsAmp : Filter { // // *ar { arg in = 0.0, coef = 0.999, mul = 1.0, add = 0.0; // ^this.multiNew('audio', in, coef).madd(mul, add) // } // *kr { arg in = 0.0, coef = 0.999, mul = 1.0, add = 0.0; // ^this.multiNew('control', in, coef).madd(mul, add) // } //} Slew : Filter { *ar { arg in = 0.0, up = 1.0, dn = 1.0, mul = 1.0, add = 0.0; if (in.rate == \scalar) { ^in.madd(mul, add) } { ^this.multiNew('audio', in, up, dn).madd(mul, add) } } *kr { arg in = 0.0, up = 1.0, dn = 1.0, mul = 1.0, add = 0.0; if (in.rate == \scalar) { ^in.madd(mul, add) } { ^this.multiNew('control', in, up, dn).madd(mul, add) } } } // not installed //RLPF4 : Filter { // // *ar { arg in = 0.0, freq = 0.5, res = 0.5, mul = 1.0, add = 0.0; // ^this.multiNew('audio', in, freq, res).madd(mul, add) // } //} FOS : Filter { *ar { arg in = 0.0, a0 = 0.0, a1 = 0.0, b1 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, a0, a1, b1).madd(mul, add) } *kr { arg in = 0.0, a0 = 0.0, a1 = 0.0, b1 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, a0, a1, b1).madd(mul, add) } } SOS : Filter { *ar { arg in = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0, b1 = 0.0, b2 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, a0, a1, a2, b1, b2).madd(mul, add) } *kr { arg in = 0.0, a0 = 0.0, a1 = 0.0, a2 = 0.0, b1 = 0.0, b2 = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, a0, a1, a2, b1, b2).madd(mul, add) } } Ringz : Filter { *ar { arg in = 0.0, freq = 440.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, decaytime).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, decaytime).madd(mul, add) } } Formlet : Filter { *ar { arg in = 0.0, freq = 440.0, attacktime = 1.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, freq, attacktime, decaytime).madd(mul, add) } *kr { arg in = 0.0, freq = 440.0, attacktime = 1.0, decaytime = 1.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in, freq, attacktime, decaytime).madd(mul, add) } } // the doneAction arg lets you cause the EnvGen to stop or end the // synth without having to use a PauseSelfWhenDone or FreeSelfWhenDone ugen. // It is more efficient to use a doneAction. // doneAction = 0 do nothing when the envelope has ended. // doneAction = 1 pause the synth running, it is still resident. // doneAction = 2 remove the synth and deallocate it. // doneAction = 3 remove and deallocate both this synth and the preceeding node. // doneAction = 4 remove and deallocate both this synth and the following node. // doneAction = 5 remove and deallocate this synth and free all children in the preceeding group (if it is a group). // doneAction = 6 remove and deallocate this synth and free all children in the following group (if it is a group). DetectSilence : Filter { optimizeGraph { } *ar { arg in = 0.0, amp = 0.0001, time = 0.1, doneAction = 0; ^this.multiNew('audio', in, amp, time, doneAction) // ^0.0 // DetectSilence has no output } *kr { arg in = 0.0, amp = 0.0001, time = 0.1, doneAction = 0; ^this.multiNew('control', in, amp, time, doneAction) // ^0.0 // DetectSilence has no output } } //exception in GrafDef_Load: UGen 'FlagNaN' not installed. //FlagNaN : Filter { // // *ar { arg in = 0.0; // ^this.multiNew('audio', in) // } // *kr { arg in = 0.0; // ^this.multiNew('control', in) // } //} SuperCollider-Source/SCClassLibrary/Common/Audio/FreeVerb.sc000755 000765 000024 00000001054 12756534416 025035 0ustar00crucialstaff000000 000000 // blackrain's freeverb ugen. FreeVerb : Filter { *ar { arg in, mix = 0.33, room = 0.5, damp = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, mix, room, damp).madd(mul, add) } } FreeVerb2 : MultiOutUGen { *ar { arg in, in2, mix = 0.33, room = 0.5, damp = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, in2, mix, room, damp).madd(mul, add) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } checkInputs { ^this.checkNInputs(2); } } SuperCollider-Source/SCClassLibrary/Common/Audio/FSinOsc.sc000644 000765 000024 00000010025 12756534416 024634 0ustar00crucialstaff000000 000000 /* FSinOsc - fixed frequency sine oscillator arguments : freq - frequency in cycles per second. Must be a scalar. mul - multiply by signal or scalar add - add to signal or scalar This unit generator uses a very fast algorithm for generating a sine wave at a fixed frequency. */ FSinOsc : UGen { *ar { arg freq=440.0, iphase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, iphase).madd(mul, add) } *kr { arg freq=440.0, iphase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, iphase).madd(mul, add) } } Klang : UGen { *ar { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; specificationsArrayRef = specificationsArrayRef.multichannelExpandRef(2); ^this.multiNewList(['audio', freqscale, freqoffset, specificationsArrayRef] ) } *new1 { arg rate, freqscale, freqoffset, arrayRef; var specs, freqs, amps, phases; # freqs, amps, phases = arrayRef.dereference; specs = [freqs, amps ?? {Array.fill(freqs.size,1.0)}, phases ?? {Array.fill(freqs.size,0.0)} ].flop.flat; ^super.new.rate_(rate).addToSynth.init([freqscale,freqoffset] ++ specs); } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } Klank : UGen { *ar { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; specificationsArrayRef = specificationsArrayRef.multichannelExpandRef(2); ^this.multiNewList(['audio', input, freqscale, freqoffset, decayscale, specificationsArrayRef] ) } *new1 { arg rate, input, freqscale, freqoffset, decayscale, arrayRef; var specs, freqs, amps, times; # freqs, amps, times = arrayRef.dereference; specs = [freqs, amps ?? {Array.fill(freqs.size,1.0)}, times ?? {Array.fill(freqs.size,1.0)} ].flop.flat; ^super.new.rate_(rate).addToSynth.init([input,freqscale,freqoffset,decayscale] ++ specs); } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } DynKlank : UGen { *ar { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; ^this.multiNew(\audio, specificationsArrayRef, input, freqscale, freqoffset, decayscale) } *kr { arg specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; ^this.multiNew(\control, specificationsArrayRef, input, freqscale, freqoffset, decayscale) } *new1 { arg rate, specificationsArrayRef, input, freqscale = 1.0, freqoffset = 0.0, decayscale = 1.0; var spec = specificationsArrayRef.value; var selector = this.methodSelectorForRate(rate); ^Ringz.perform(selector, input, spec[0] ? #[440.0] * freqscale + freqoffset, spec[2] ? #[1.0] * decayscale, spec[1] ? #[1.0] ).sum } } DynKlang : UGen { *ar { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; ^this.multiNew(\audio, specificationsArrayRef, freqscale, freqoffset); } *kr { arg specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; ^this.multiNew(\control, specificationsArrayRef, freqscale, freqoffset); } *new1 { arg rate, specificationsArrayRef, freqscale = 1.0, freqoffset = 0.0; var spec = specificationsArrayRef.value; var selector = this.methodSelectorForRate(rate); ^SinOsc.perform(selector, spec[0] ? #[440.0] * freqscale + freqoffset, spec[2] ? #[0.0], spec[1] ? #[1.0] ).sum } } Blip : UGen { *ar { arg freq=440.0, numharm = 200.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, numharm).madd(mul, add) } *kr { arg freq=440.0, numharm = 200.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, numharm).madd(mul, add) } } Saw : UGen { *ar { arg freq=440.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq).madd(mul, add) } *kr { arg freq=440.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq).madd(mul, add) } } Pulse : UGen { *ar { arg freq=440.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, width).madd(mul, add) } *kr { arg freq=440.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, width).madd(mul, add) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Gendyn.sc000644 000765 000024 00000003565 12756534416 024567 0ustar00crucialstaff000000 000000 //GENDYN by Iannis Xenakis implemented for SC3 by sicklincoln with some refinements Gendy1 : UGen { *ar { arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=440, maxfreq=660, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, mul=1.0,add=0.0; ^this.multiNew('audio', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } *kr {arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=20, maxfreq=1000, ampscale= 0.5, durscale=0.5, initCPs= 12, knum,mul=1.0,add=0.0; ^this.multiNew('control', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } } Gendy2 : UGen { *ar { arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=440, maxfreq=660, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, a=1.17, c=0.31, mul=1.0,add=0.0; ^this.multiNew('audio', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs, a, c).madd( mul, add ) } *kr {arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, minfreq=20, maxfreq=1000, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, a=1.17, c=0.31, mul=1.0,add=0.0; ^this.multiNew('control', ampdist, durdist, adparam, ddparam, minfreq, maxfreq, ampscale, durscale, initCPs, knum ? initCPs, a, c).madd( mul, add ) } } Gendy3 : UGen { *ar { arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, freq=440, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, mul=1.0,add=0.0; ^this.multiNew('audio', ampdist, durdist, adparam, ddparam, freq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } *kr {arg ampdist=1, durdist=1, adparam=1.0, ddparam=1.0, freq=440, ampscale= 0.5, durscale=0.5, initCPs= 12, knum, mul=1.0,add=0.0; ^this.multiNew('control', ampdist, durdist, adparam, ddparam, freq, ampscale, durscale, initCPs, knum ? initCPs).madd( mul, add ) } } SuperCollider-Source/SCClassLibrary/Common/Audio/GrainUGens.sc000644 000765 000024 00000004213 12756534416 025334 0ustar00crucialstaff000000 000000 GrainSin : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, freq = 440, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, freq, pan, envbufnum, maxGrains) .madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } GrainFM : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, carfreq = 440, modfreq = 200, index = 1, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, carfreq, modfreq, index, pan, envbufnum, maxGrains).madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } GrainBuf : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, sndbuf, rate = 1, pos = 0, interp = 2, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, sndbuf, rate, pos, interp, pan, envbufnum, maxGrains).madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } GrainIn : MultiOutUGen { *ar { arg numChannels = 1, trigger = 0, dur = 1, in, pan = 0, envbufnum = -1, maxGrains = 512, mul = 1, add = 0; ^this.multiNew('audio', numChannels, trigger, dur, in, pan, envbufnum, maxGrains) .madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } Warp1 : MultiOutUGen { *ar { arg numChannels = 1, bufnum=0, pointer=0, freqScale = 1, windowSize = 0.2, envbufnum = -1, overlaps = 8, windowRandRatio = 0.0, interp=1, mul = 1, add = 0; ^this.multiNew('audio', numChannels, bufnum, pointer, freqScale, windowSize, envbufnum, overlaps, windowRandRatio, interp).madd(mul, add); } init { arg argNumChannels ... theInputs; inputs = theInputs; ^this.initOutputs(argNumChannels, rate); } argNamesInputsOffset { ^2 } } SuperCollider-Source/SCClassLibrary/Common/Audio/GVerb.sc000755 000765 000024 00000001354 12756534416 024345 0ustar00crucialstaff000000 000000 GVerb : MultiOutUGen { *ar { arg in, roomsize = 10, revtime = 3, damping = 0.5, inputbw = 0.5, spread = 15, drylevel = 1, earlyreflevel = 0.7, taillevel = 0.5, maxroomsize = 300, mul = 1, add = 0; ^this.multiNew('audio', in, roomsize, revtime, damping, inputbw, spread, drylevel, earlyreflevel, taillevel, maxroomsize).madd(mul, add); } init {arg ... theInputs; inputs = theInputs; ^this.initOutputs(2, rate); } checkInputs { ^this.checkNInputs(1); } } /* s.options.memSize_(32768 * 4); s.boot; SynthDef(\test, { Out.ar(0, GVerb.ar(In.ar(24), 50, 100, MouseX.kr(0, 1), 0.15, 0.4, 1, 0.4, 0.7, 500))}).load(s) s.sendMsg(\s_new, \test, 1000, 0, 1); s.sendMsg(\n_free, 1000); s.boot; {GVerb.ar(In.ar(24))}.play s.quit; */ SuperCollider-Source/SCClassLibrary/Common/Audio/Hilbert.sc000644 000765 000024 00000002357 12756534416 024732 0ustar00crucialstaff000000 000000 Hilbert : MultiOutUGen { *ar { arg in, mul = 1, add = 0; ^this.multiNew('audio', in).madd(mul, add); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(2, rate); } } // class using FFT (with a delay) for better results than the above UGen // buffer should be 2048 or 1024 // 2048, better results, more delay // 1024, less delay, little choppier results HilbertFIR : UGen { *ar { arg in, buffer; var fft, delay; fft = FFT(buffer, in); fft = PV_PhaseShift90(fft); delay = BufDur.kr(buffer); // return [source, shift90] ^[DelayN.ar(in, delay, delay), IFFT(fft)]; } } // single sideband amplitude modulation, using optimized Hilbert phase differencing network // basically coded by Joe Anderson, except Sean Costello changed the word HilbertIIR.ar // to Hilbert.ar FreqShift : UGen { *ar { arg in, // input signal freq = 0.0, // shift, in cps phase = 0.0, // phase of SSB mul = 1.0, add = 0.0; // var shifts; // freq = freq.asArray; // shifts = Array.fill(freq.size, {arg i; // // multiply by quadrature // // and add together. . . // (Hilbert.ar(in) * SinOsc.ar(freq[i], (phase + [ 0.5*pi, 0.0 ]))).sum}); // ^(shifts).madd(mul, add) ^this.multiNew('audio', in, freq, phase).madd(mul, add) } } SuperCollider-Source/SCClassLibrary/Common/Audio/IEnvGen.sc000644 000765 000024 00000001355 12756534416 024631 0ustar00crucialstaff000000 000000 IEnvGen : UGen { // envelope index generator *ar { arg envelope, index, mul = 1, add = 0; envelope = this.convertEnv(envelope); ^this.multiNewList(['audio', index, envelope]).madd(mul, add) } *kr { arg envelope, index, mul = 1, add = 0; envelope = this.convertEnv(envelope); ^this.multiNewList(['control', index, envelope]).madd(mul, add) } *convertEnv { arg env; if(env.isSequenceableCollection) { ^env.reference }; // raw envelope data ^env.asArrayForInterpolation.collect(_.reference).unbubble } *new1 { arg rate, index, envArray; ^super.new.rate_(rate).addToSynth.init([index] ++ envArray.dereference) } init { arg theInputs; // store the inputs as an array inputs = theInputs; } argNamesInputsOffset { ^2 } } SuperCollider-Source/SCClassLibrary/Common/Audio/InfoUGens.sc000644 000765 000024 00000002034 12756534416 025166 0ustar00crucialstaff000000 000000 InfoUGenBase : UGen { *ir { ^this.multiNew('scalar') } } BufInfoUGenBase : UGen { *kr { arg bufnum; ^this.multiNew('control', bufnum) } // the .ir method is not the safest choice. Since a buffer can be reallocated at any time, // using .ir will not track the changes. *ir { arg bufnum; ^this.multiNew('scalar',bufnum) } } SampleRate : InfoUGenBase {} SampleDur : InfoUGenBase {} RadiansPerSample : InfoUGenBase {} BlockSize : InfoUGenBase {} ControlRate : InfoUGenBase {} ControlDur : InfoUGenBase {} SubsampleOffset : InfoUGenBase {} NumOutputBuses : InfoUGenBase {} NumInputBuses : InfoUGenBase {} NumAudioBuses : InfoUGenBase {} NumControlBuses : InfoUGenBase {} NumBuffers : InfoUGenBase {} NodeID : InfoUGenBase {} NumRunningSynths : InfoUGenBase { *kr { ^this.multiNew('control') } } BufSampleRate : BufInfoUGenBase {} BufRateScale : BufInfoUGenBase {} BufFrames : BufInfoUGenBase {} BufSamples : BufInfoUGenBase {} BufDur : BufInfoUGenBase {} BufChannels : BufInfoUGenBase {} //////////////////////////////////////////// SuperCollider-Source/SCClassLibrary/Common/Audio/InOut.sc000644 000765 000024 00000016606 12766171707 024402 0ustar00crucialstaff000000 000000 ControlName { var <>name, <>index, <>rate, <>defaultValue, <>argNum, <>lag; *new { arg name, index, rate, defaultValue, argNum, lag; ^super.newCopyArgs(name.asSymbol, index, rate, defaultValue, argNum, lag ? 0.0) } numChannels { ^defaultValue.asArray.size; } printOn { arg stream; stream << "ControlName P " << index.asString; if (name.notNil) { stream << " " << name; }; if (rate.notNil) { stream << " " << rate; }; if (defaultValue.notNil) { stream << " " << defaultValue; }; //stream << "\n" } } Control : MultiOutUGen { var 0) { // the current control is always the last added, so: lastControl = synthDef.controlNames.last; if(lastControl.defaultValue.isNil) { // only write if not there yet: lastControl.defaultValue_(values.unbubble); } }; synthDef.controlIndex = synthDef.controlIndex + values.size; }; ^this.initOutputs(values.size, rate) } *isControlUGen { ^true } } AudioControl : MultiOutUGen { var > 1; values = stuff[ .. size2-1]; inputs = stuff[size2 .. size-1]; if (synthDef.notNil, { specialIndex = synthDef.controls.size; synthDef.controls = synthDef.controls.addAll(values); synthDef.controlIndex = synthDef.controlIndex + values.size; }); ^this.initOutputs(values.size, rate) } } AbstractIn : MultiOutUGen { *isInputUGen { ^true } } In : AbstractIn { *ar { arg bus = 0, numChannels = 1; ^this.multiNew('audio', numChannels, bus) } *kr { arg bus = 0, numChannels = 1; ^this.multiNew('control', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } LocalIn : AbstractIn { *ar { arg numChannels = 1, default = 0.0; ^this.multiNew('audio', numChannels, *default) } *kr { arg numChannels = 1, default = 0.0; ^this.multiNew('control', numChannels, *default) } init { arg numChannels ... default; inputs = default.wrapExtend(numChannels); ^this.initOutputs(numChannels, rate) } } LagIn : AbstractIn { *kr { arg bus = 0, numChannels = 1, lag = 0.1; ^this.multiNew('control', numChannels, bus, lag) } init { arg numChannels ... argInputs; inputs = argInputs.asArray; ^this.initOutputs(numChannels, rate) } } InFeedback : AbstractIn { *ar { arg bus = 0, numChannels = 1; ^this.multiNew('audio', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } InTrig : AbstractIn { *kr { arg bus = 0, numChannels = 1; ^this.multiNew('control', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } AbstractOut : UGen { numOutputs { ^0 } writeOutputSpecs {} checkInputs { if (rate == 'audio', { for(this.class.numFixedArgs, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^(" input at index " + i + "(" + inputs.at(i) + ") is not audio rate"); }); }); }, { if(inputs.size <= 1, { ^"missing input at index 1" }) }); ^this.checkValidInputs } *isOutputUGen { ^true } *numFixedArgs { ^this.subclassResponsibility(thisMethod) } numAudioChannels { ^inputs.size - this.class.numFixedArgs } writesToBus { ^this.subclassResponsibility(thisMethod) } } Out : AbstractOut { *ar { arg bus, channelsArray; channelsArray = this.replaceZeroesWithSilence(channelsArray.asUGenInput(this).asArray); this.multiNewList(['audio', bus] ++ channelsArray) ^0.0 // Out has no output } *kr { arg bus, channelsArray; this.multiNewList(['control', bus] ++ channelsArray.asArray) ^0.0 // Out has no output } *numFixedArgs { ^1 } writesToBus { ^true } } ReplaceOut : Out {} OffsetOut : Out { *kr { ^this.shouldNotImplement(thisMethod) } } LocalOut : AbstractOut { *ar { arg channelsArray; channelsArray = this.replaceZeroesWithSilence(channelsArray.asUGenInput(this).asArray); this.multiNewList(['audio'] ++ channelsArray) ^0.0 // LocalOut has no output } *kr { arg channelsArray; this.multiNewList(['control'] ++ channelsArray.asArray) ^0.0 // LocalOut has no output } *numFixedArgs { ^0 } writesToBus { ^false } } XOut : AbstractOut { *ar { arg bus, xfade, channelsArray; channelsArray = this.replaceZeroesWithSilence(channelsArray.asUGenInput(this).asArray); this.multiNewList(['audio', bus, xfade] ++ channelsArray) ^0.0 // Out has no output } *kr { arg bus, xfade, channelsArray; this.multiNewList(['control', bus, xfade] ++ channelsArray.asArray) ^0.0 // Out has no output } *numFixedArgs { ^2 } checkInputs { if (rate == 'audio', { for(2, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^(" input at index " + i + "(" + inputs.at(i) + ") is not audio rate"); }); }); }); ^this.checkValidInputs } writesToBus { ^true } } SharedOut : AbstractOut { *kr { arg bus, channelsArray; warn("SharedOut is deprecated and will be removed. Please use Bus-getSynchronous instead."); this.multiNewList(['control', bus] ++ channelsArray.asArray) ^0.0 // Out has no output } *numFixedArgs { ^1 } writesToBus { ^false } } SharedIn : AbstractIn { *kr { arg bus = 0, numChannels = 1; warn("SharedIn is deprecated and will be removed. Please use Bus-setSynchronous instead."); ^this.multiNew('control', numChannels, bus) } init { arg numChannels ... argBus; inputs = argBus.asArray; ^this.initOutputs(numChannels, rate) } } SuperCollider-Source/SCClassLibrary/Common/Audio/InterplEnv.sc000644 000765 000024 00000001504 12774256244 025420 0ustar00crucialstaff000000 000000 // InterplEnvs are a fixed duration // Envelope specification for an IEnvGen, InterplEnv is not a UGen itself InterplEnv { *new { arg levels=#[0,1,0], times=#[1,1], curve='lin', offset = 0.0; "InterplEnv is deprecated, please use Env.new instead.".warn; ^Env.new(levels, times, curve, nil, nil, offset) } } // InterplXYC([0, 0, \lin], [1, 2, \sin], [2, 0]) // at time 0, value 0, lin to time 1, value 2, sin to time 2, value 0 InterplXYC { *new { arg ... xyc; "InterplXYC is deprecated, please use Env.xyc instead.".warn; ^Env.xyc(xyc) } } InterplPairs { *new { arg pairs, curve; "InterplPairs is deprecated, please use Env.pairs instead.".warn; ^Env.pairs(pairs, curve) } } InterplChord { *new { arg pairs; "InterplChord is deprecated, please use Env.pairs instead.".warn; ^Env.pairs(pairs) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Line.sc000644 000765 000024 00000006101 12756534416 024217 0ustar00crucialstaff000000 000000 Line : UGen { *ar { arg start=0.0, end = 1.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('audio', start, end, dur, doneAction).madd(mul, add) } *kr { arg start=0.0, end = 1.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('control', start, end, dur, doneAction).madd(mul, add) } } XLine : UGen { *ar { arg start=1.0, end = 2.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('audio', start, end, dur, doneAction).madd(mul, add) } *kr { arg start=1.0, end = 2.0, dur = 1.0, mul = 1.0, add = 0.0, doneAction = 0; ^this.multiNew('control', start, end, dur, doneAction).madd(mul, add) } } LinExp : PureUGen { checkInputs { ^this.checkSameRateAsFirstInput } *ar { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; ^this.multiNew('audio', in, srclo, srchi, dstlo, dsthi) } *kr { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; ^this.multiNew('control', in, srclo, srchi, dstlo, dsthi) } } LinLin { *ar { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; var scale = (dsthi - dstlo) / (srchi - srclo); var offset = dstlo - (scale * srclo); ^MulAdd(in, scale, offset) } *kr { arg in=0.0, srclo = 0.0, srchi = 1.0, dstlo = 1.0, dsthi = 2.0; var scale = (dsthi - dstlo) / (srchi - srclo); var offset = dstlo - (scale * srclo); ^(in * scale + offset) } } AmpComp : PureUGen { *ir { arg freq = 60.midicps, root = 60.midicps, exp = 0.3333; ^this.multiNew('scalar', freq, root, exp) } *ar { arg freq = 60.midicps, root = 60.midicps, exp = 0.3333; ^this.multiNew('audio', freq, root, exp) } *kr { arg freq = 60.midicps, root = 60.midicps, exp = 0.3333; ^this.multiNew('control', freq, root, exp) } checkInputs { ^if(rate === \audio) { this.checkSameRateAsFirstInput } } } AmpCompA : AmpComp { *ir { arg freq = 1000, root = 0, minAmp = 0.32, rootAmp = 1.0; ^this.multiNew('scalar', freq, root, minAmp, rootAmp) } *ar { arg freq = 1000, root = 0, minAmp = 0.32, rootAmp = 1.0; ^this.multiNew('audio', freq, root, minAmp, rootAmp) } *kr { arg freq = 1000, root = 0, minAmp = 0.32, rootAmp = 1.0; ^this.multiNew('control', freq, root, minAmp, rootAmp) } } K2A : PureUGen { // control rate to audio rate converter *ar { arg in = 0.0; ^this.multiNew('audio', in) } } A2K : PureUGen { // audio rate to control rate converter. only needed in specific cases *kr { arg in = 0.0; ^this.multiNew('control', in) } } T2K : A2K { // audio rate to control rate trigger converter. checkInputs { if(inputs.at(0).rate != \audio) { ^"first input is not audio rate" }; ^nil } } T2A : K2A { // control rate to audio rate trigger converter. *ar { arg in = 0.0, offset = 0; ^this.multiNew('audio', in, offset) } } DC : PureMultiOutUGen { *ar { arg in=0.0; ^this.multiNew('audio', in) } *kr { arg in=0.0; ^this.multiNew('control', in) } init { arg ... argInputs; inputs = argInputs; ^this.initOutputs(inputs.size, rate) } } Silent { *ar { arg numChannels = 1; var sig = DC.ar(0); if (numChannels == 1) { ^sig } { ^(sig ! numChannels) } } } SuperCollider-Source/SCClassLibrary/Common/Audio/MachineListening.sc000644 000765 000024 00000004176 12756534416 026563 0ustar00crucialstaff000000 000000 //4 outs BeatTrack : MultiOutUGen { *kr { arg chain, lock=0; if(chain.isKindOf(FFT).not){ // Automatically drop in an FFT, possible now that we have LocalBuf chain = FFT(LocalBuf(if(SampleRate.ir>48000, 2048, 1024)), chain); }; ^this.multiNew('control',chain, lock); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(4, rate); } } //loudness output in sones Loudness : UGen { *kr { arg chain, smask=0.25, tmask=1; ^this.multiNew('control',chain, smask, tmask); } } Onsets : UGen { *kr { |chain, threshold=0.5, odftype=\rcomplex, relaxtime=1, floor=0.1, mingap=10, medianspan=11, whtype=1, rawodf=0| if(odftype.class == Symbol){ odftype = #[\power, \magsum, \complex, \rcomplex, \phase, \wphase,\mkl] .indexOf(odftype) }; // mingap of 10 frames, @ 44100 & 512 & 50%, is about 0.058 seconds ^this.multiNew('control', chain, threshold, odftype, relaxtime, floor, mingap, medianspan, whtype, rawodf) } } //transient input not currently used but reserved for future use in downweighting frames which have high transient content KeyTrack : UGen { *kr { arg chain,keydecay=2.0,chromaleak= 0.5; //transient=0.0; ^this.multiNew('control',chain,keydecay,chromaleak); //transient; } } //a bufnum could be added as third argument for passing arbitrary band spacing data MFCC : MultiOutUGen { *kr { arg chain, numcoeff=13; ^this.multiNew('control', chain, numcoeff); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(theInputs[1], rate); } } //6 outs BeatTrack2 : MultiOutUGen { *kr { arg busindex, numfeatures, windowsize=2.0, phaseaccuracy=0.02, lock=0, weightingscheme; ^this.multiNew('control',busindex, numfeatures,windowsize, phaseaccuracy, lock, weightingscheme ? (-2.1)); } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(6, rate); } } SpecFlatness : UGen { *kr { | buffer | ^this.multiNew('control', buffer) } } SpecPcile : UGen { *kr { | buffer, fraction = 0.5, interpolate = 0 | ^this.multiNew('control', buffer, fraction, interpolate) } } SpecCentroid : UGen { *kr { | buffer | ^this.multiNew('control', buffer) } } SuperCollider-Source/SCClassLibrary/Common/Audio/MacUGens.sc000644 000765 000024 00000001144 12756534416 024774 0ustar00crucialstaff000000 000000 MouseX : UGen { // warp 0 = linear // warp 1 = exponential *kr { arg minval=0, maxval=1, warp=0, lag=0.2; if (warp === \linear, { warp = 0 }); if (warp === \exponential, { warp = 1 }); ^this.multiNew('control', minval, maxval, warp, lag) } signalRange { ^\unipolar } } MouseY : MouseX {} MouseButton : UGen { *kr { arg minval=0, maxval=1, lag=0.2; ^this.multiNew('control', minval, maxval, lag) } signalRange { ^\unipolar } } KeyState : UGen { *kr { arg keycode=0, minval=0, maxval=1, lag=0.2; ^this.multiNew('control', keycode, minval, maxval, lag) } signalRange { ^\unipolar } } SuperCollider-Source/SCClassLibrary/Common/Audio/Mix.sc000644 000765 000024 00000004044 12766171707 024072 0ustar00crucialstaff000000 000000 Mix { *new { arg array; var reducedArray = array.asArray.clump(4); var mixedArray = reducedArray.collect {|a| if (a.size == 4) { Sum4(*a) } { if (a.size == 3) { Sum3(*a) } { a.sum } } }; if (mixedArray.size < 3) { ^mixedArray.sum }; if (mixedArray.size == 3) { ^Sum3(*mixedArray) } { ^Mix(mixedArray) } } // support this common idiom *fill { arg n, function; var array = Array.fill(n, function); ^this.new(array); } // and these common idioms *ar { |array| var result = this.new(array); ^switch(result.rate) { \audio } { result } { \control } { K2A.ar(result) } { \scalar } { DC.ar(result) } { Error("Unsupported rate % for Mix.ar".format(result.rate)).throw }; } *kr { |array| var result; // 'rate' on an array returns the fastest rate // ('audio' takes precedence over 'control' over 'scalar') if(array.rate == \audio) { "Audio rate input(s) to Mix.kr will result in signal degradation.".warn; array.do { |unit| if(unit.rate == \audio) { (unit + unit.rate).postln; unit.dumpArgs; }; }; array = array.collect { |unit| if(unit.rate == \audio) { A2K.kr(unit) } { unit }; }; }; result = this.new(array); ^switch(result.rate) { \control } { result } { \scalar } { DC.kr(result) } { Error("Unsupported rate % for Mix.kr".format(result.rate)).throw }; } *arFill { |n, function| ^this.ar(Array.fill(n, function)) } *krFill { |n, function| ^this.kr(Array.fill(n, function)) } } NumChannels { *ar { arg input, numChannels = 2, mixdown = true; if(input.size > 1) { // collection ^input .clump(roundUp(input.size / numChannels)) .collect { arg chan, i; if(chan.size == 1) { chan.at(0) } { if(mixdown) { Mix.new(chan) } { chan.at(0) } } } } { // single ugen or single item collection if(input.isSequenceableCollection) { input = input.at(0); }; if(numChannels == 1) { ^input } { ^Array.fill(numChannels, input) } } } } SuperCollider-Source/SCClassLibrary/Common/Audio/MoogFF.sc000755 000765 000024 00000001214 12756534416 024450 0ustar00crucialstaff000000 000000 /** "MoogFF" - Moog VCF digital implementation. As described in the paper entitled "Preserving the Digital Structure of the Moog VCF" by Federico Fontana appeared in the Proc. ICMC07, Copenhagen, 25-31 August 2007 Original Java code created by F. Fontana - August 2007 federico.fontana@univr.it Ported to C++ for SuperCollider by Dan Stowell - August 2007 http://www.mcld.co.uk/ */ MoogFF : Filter { *ar { | in, freq=100, gain=2, reset=0, mul=1, add=0 | ^this.multiNew('audio', in, freq, gain, reset).madd(mul, add) } *kr { | in, freq=100, gain=2, reset=0, mul=1, add=0 | ^this.multiNew('control', in, freq, gain, reset).madd(mul, add) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Noise.sc000644 000765 000024 00000014310 12756534416 024406 0ustar00crucialstaff000000 000000 /* Noise Generators WhiteNoise.ar(mul, add) BrownNoise.ar(mul, add) PinkNoise.ar(mul, add) Crackle.ar(chaosParam, mul, add) LFNoise0.ar(freq, mul, add) LFNoise1.ar(freq, mul, add) LFNoise2.ar(freq, mul, add) Dust.ar(density, mul, add) Dust2.ar(density, mul, add) White, Brown, Pink generators have no modulatable parameters other than multiply and add inputs. The chaos param for ChaosNoise should be from 1.0 to 2.0 */ RandSeed : WidthFirstUGen { *ar { arg trig = 0.0, seed=56789; this.multiNew('audio', trig, seed) ^0.0 // RandSeed has no output } *kr { arg trig = 0.0, seed=56789; this.multiNew('control', trig, seed) ^0.0 // RandSeed has no output } *ir { arg trig = 0.0, seed=56789; this.multiNew('scalar', trig, seed) ^0.0 // RandSeed has no output } } RandID : WidthFirstUGen { // choose which random number generator to use for this synth . *kr { arg id=0; this.multiNew('control', id) ^0.0 // RandID has no output } *ir { arg id=0; this.multiNew('scalar', id) ^0.0 // RandID has no output } } Rand : UGen { // uniform distribution *new { arg lo = 0.0, hi = 1.0; ^this.multiNew('scalar', lo, hi) } } IRand : UGen { // uniform distribution of integers *new { arg lo = 0, hi = 127; ^this.multiNew('scalar', lo, hi) } } TRand : UGen { // uniform distribution *ar { arg lo = 0.0, hi = 1.0, trig = 0.0; ^this.multiNew('audio', lo, hi, trig) } *kr { arg lo = 0.0, hi = 1.0, trig = 0.0; ^this.multiNew('control', lo, hi, trig) } } TIRand : UGen { // uniform distribution of integers *kr { arg lo = 0, hi = 127, trig = 0.0; ^this.multiNew('control', lo, hi, trig) } *ar { arg lo = 0, hi = 127, trig = 0.0; ^this.multiNew('audio', lo, hi, trig) } } LinRand : UGen { // linear distribution // if minmax <= 0 then skewed towards lo. // else skewed towards hi. *new { arg lo = 0.0, hi = 1.0, minmax = 0; ^this.multiNew('scalar', lo, hi, minmax) } } NRand : UGen { // sum of N uniform distributions. // n = 1 : uniform distribution - same as Rand // n = 2 : triangular distribution // n = 3 : smooth hump // as n increases, distribution converges towards gaussian *new { arg lo = 0.0, hi = 1.0, n = 0; ^this.multiNew('scalar', lo, hi, n) } } ExpRand : UGen { // exponential distribution *new { arg lo = 0.01, hi = 1.0; ^this.multiNew('scalar', lo, hi) } } TExpRand : UGen { // uniform distribution *ar { arg lo = 0.01, hi = 1.0, trig = 0.0; ^this.multiNew('audio', lo, hi, trig) } *kr { arg lo = 0.01, hi = 1.0, trig = 0.0; ^this.multiNew('control', lo, hi, trig) } } CoinGate : UGen { *ar { arg prob, in; ^this.multiNew('audio', prob, in) } *kr { arg prob, in; ^this.multiNew('control', prob, in) } } TWindex : UGen { *ar { arg in, array, normalize=0; ^this.multiNewList(['audio', in, normalize] ++ array) } *kr { arg in, array, normalize=0; ^this.multiNewList(['control', in, normalize] ++ array) } } WhiteNoise : UGen { *ar { arg mul = 1.0, add = 0.0; // support this idiom from SC2. if (mul.isArray, { ^{ this.multiNew('audio') }.dup(mul.size).madd(mul, add) },{ ^this.multiNew('audio').madd(mul, add) }); } *kr { arg mul = 1.0, add = 0.0; if (mul.isArray, { ^{ this.multiNew('control') }.dup(mul.size).madd(mul, add) },{ ^this.multiNew('control').madd(mul, add) }); } } BrownNoise : WhiteNoise { } PinkNoise : WhiteNoise { } ClipNoise : WhiteNoise { } GrayNoise : WhiteNoise { } //NoahNoise : WhiteNoise { //} Crackle : UGen { *ar { arg chaosParam=1.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', chaosParam).madd(mul, add) } *kr { arg chaosParam=1.5, mul = 1.0, add = 0.0; ^this.multiNew('control', chaosParam).madd(mul, add) } } Logistic : UGen { *ar { arg chaosParam=3.0, freq = 1000.0, init= 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', chaosParam, freq, init).madd(mul, add) } *kr { arg chaosParam=3.0, freq = 1000.0, init=0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', chaosParam, freq, init).madd(mul, add) } } /* not installed Rossler : UGen { *ar { arg chaosParam=1.5, dt = 0.04, mul = 1.0, add = 0.0; ^this.multiNew('audio', chaosParam, dt).madd(mul, add) } *kr { arg chaosParam=1.5, dt = 0.04, mul = 1.0, add = 0.0; ^this.multiNew('control', chaosParam, dt).madd(mul, add) } } */ LFNoise0 : UGen { *ar { arg freq=500.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq).madd(mul, add) } *kr { arg freq=500.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq).madd(mul, add) } } LFNoise1 : LFNoise0 { } LFNoise2 : LFNoise0 { } LFClipNoise : LFNoise0 { } LFDNoise0 : LFNoise0 { } LFDNoise1 : LFNoise0 { } LFDNoise3 : LFNoise0 { } LFDClipNoise : LFNoise0 { } Hasher : UGen { *ar { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in).madd(mul, add) } *kr { arg in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', in).madd(mul, add) } } MantissaMask : UGen { *ar { arg in = 0.0, bits=3, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, bits).madd(mul, add) } *kr { arg in = 0.0, bits=3, mul = 1.0, add = 0.0; ^this.multiNew('control', in, bits).madd(mul, add) } } Dust : UGen { *ar { arg density = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', density).madd(mul, add) } *kr { arg density = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', density).madd(mul, add) } signalRange { ^\unipolar } } Dust2 : UGen { *ar { arg density = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', density).madd(mul, add) } *kr { arg density = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', density).madd(mul, add) } } /* not installed LinCong : UGen { var iseed, imul, iadd, imod; *ar { arg iseed, imul, iadd, imod, mul = 1.0, add = 0.0; ^this.multiNew('audio', iseed, imul, iadd, imod).madd(mul, add) } *kr { arg iseed, imul, iadd, imod, mul = 1.0, add = 0.0; ^this.multiNew('control', iseed, imul, iadd, imod).madd(mul, add) } init { arg jseed, jmul, jadd, jmod ... theInputs; inputs = theInputs; iseed = jseed; imul = jmul; iadd = jadd; imod = jmod; } } */ // //Latoocarfian : UGen { // // *ar { arg a, b, c, d, mul = 1.0, add = 0.0; // ^this.multiNew('audio', a, b, c, d).madd(mul, add) // } // *kr { arg a, b, c, d, mul = 1.0, add = 0.0; // ^this.multiNew('control', a, b, c, d).madd(mul, add) // } //} SuperCollider-Source/SCClassLibrary/Common/Audio/Osc.sc000644 000765 000024 00000017135 12756534416 024065 0ustar00crucialstaff000000 000000 /* Osc - oscillator arguments : bufnum - an index to a buffer freq - frequency in cycles per second pm - phase modulation mul - multiply by signal or scalar add - add to signal or scalar */ Osc : PureUGen { *ar { arg bufnum, freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('audio', bufnum, freq, phase).madd(mul, add) } *kr { arg bufnum, freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('control', bufnum, freq, phase).madd(mul, add) } } SinOsc : PureUGen { *ar { arg freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('audio', freq, phase).madd(mul, add) } *kr { arg freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('control', freq, phase).madd(mul, add) } } SinOscFB : PureUGen { *ar { arg freq=440.0, feedback=0.0, mul=1.0, add=0.0; ^this.multiNew('audio', freq, feedback).madd(mul, add) } *kr { arg freq=440.0, feedback=0.0, mul=1.0, add=0.0; ^this.multiNew('control', freq, feedback).madd(mul, add) } } OscN : PureUGen { *ar { arg bufnum, freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('audio', bufnum, freq, phase).madd(mul, add) } *kr { arg bufnum, freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('control', bufnum, freq, phase).madd(mul, add) } } VOsc : PureUGen { *ar { arg bufpos, freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('audio', bufpos, freq, phase).madd(mul, add) } *kr { arg bufpos, freq=440.0, phase=0.0, mul=1.0, add=0.0; ^this.multiNew('control', bufpos, freq, phase).madd(mul, add) } } VOsc3 : PureUGen { *ar { arg bufpos, freq1=110.0, freq2=220.0, freq3=440.0, mul=1.0, add=0.0; ^this.multiNew('audio', bufpos, freq1, freq2, freq3).madd(mul, add) } *kr { arg bufpos, freq1=110.0, freq2=220.0, freq3=440.0, mul=1.0, add=0.0; ^this.multiNew('control', bufpos, freq1, freq2, freq3).madd(mul, add) } } COsc : PureUGen { *ar { arg bufnum, freq=440.0, beats=0.5, mul=1.0, add=0.0; ^this.multiNew('audio', bufnum, freq, beats).madd(mul, add) } *kr { arg bufnum, freq=440.0, beats=0.5, mul=1.0, add=0.0; ^this.multiNew('control', bufnum, freq, beats).madd(mul, add) } } Formant : PureUGen { *ar { arg fundfreq = 440.0, formfreq = 1760.0, bwfreq = 880.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', fundfreq, formfreq, bwfreq).madd(mul, add) } } LFSaw : PureUGen { *ar { arg freq = 440.0, iphase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, iphase).madd(mul, add) } *kr { arg freq = 440.0, iphase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, iphase).madd(mul, add) } } LFPar : LFSaw { } LFCub : LFSaw { } LFTri : LFSaw { } LFGauss : UGen { *ar { arg duration = 1, width = 0.1, iphase = 0.0, loop = 1, doneAction = 0; ^this.multiNew('audio', duration, width, iphase, loop, doneAction) } *kr { arg duration = 1, width = 0.1, iphase = 0.0, loop = 1, doneAction = 0; ^this.multiNew('control', duration, width, iphase, loop, doneAction) } range { arg min = 0, max = 1; ^this.linlin(this.minval, 1, min, max) } minval { var width = inputs[1]; ^exp(1.0 / (-2.0 * squared(width))) } } LFPulse : PureUGen { *ar { arg freq = 440.0, iphase = 0.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, iphase, width).madd(mul, add) } *kr { arg freq = 440.0, iphase = 0.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, iphase, width).madd(mul, add) } signalRange { ^\unipolar } } VarSaw : PureUGen { *ar { arg freq = 440.0, iphase = 0.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, iphase, width).madd(mul, add) } *kr { arg freq = 440.0, iphase = 0.0, width = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, iphase, width).madd(mul, add) } } Impulse : PureUGen { *ar { arg freq = 440.0, phase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', freq, phase).madd(mul, add) } *kr { arg freq = 440.0, phase = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', freq, phase).madd(mul, add) } signalRange { ^\unipolar } } SyncSaw : PureUGen { *ar { arg syncFreq = 440.0, sawFreq = 440.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', syncFreq, sawFreq).madd(mul, add) } *kr { arg syncFreq = 440.0, sawFreq = 440.0, mul = 1.0, add = 0.0; ^this.multiNew('control', syncFreq, sawFreq).madd(mul, add) } } // //TPulse : UGen {//exception in GrafDef_Load: UGen 'TPulse' not installed. // *ar { // arg trig = 0.0, freq = 440.0, width = 0.5, mul = 1.0, add = 0.0; // ^this.multiNew('audio', trig, freq, width).madd(mul, add) // } // *kr { // arg trig = 0.0, freq = 440.0, width = 0.5, mul = 1.0, add = 0.0; // ^this.multiNew('control', trig, freq, width).madd(mul, add) // } // signalRange { ^\unipolar } //} Index : PureUGen { *ar { arg bufnum, in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', bufnum, in).madd(mul, add) } *kr { arg bufnum, in = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('control', bufnum, in).madd(mul, add) } } WrapIndex : Index { } IndexInBetween : Index { } DetectIndex : Index { } Shaper : Index { } IndexL : Index { } DegreeToKey : PureUGen { *ar { arg bufnum, in = 0.0, octave = 12.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', bufnum, in, octave).madd(mul, add) } *kr { arg bufnum, in = 0.0, octave = 12.0, mul = 1.0, add = 0.0; ^this.multiNew('control', bufnum, in, octave).madd(mul, add) } } Select : PureUGen { *ar { arg which, array; ^this.multiNewList(['audio', which] ++ array) } *kr { arg which, array; ^this.multiNewList(['control', which] ++ array) } checkInputs { if (rate == 'audio', { for(1, inputs.size - 1, { arg i; if (inputs.at(i).rate != 'audio', { ^("input was not audio rate: " + inputs.at(i)); }); }); }); ^this.checkValidInputs } } SelectX { *new1 { arg rate, which, array; var selector = UGen.methodSelectorForRate(rate); ^this.crossfadeClass.perform(selector, Select.perform(selector, which.round(2), array), Select.perform(selector, which.trunc(2) + 1, array), (which * 2 - 1).fold2(1) ); } *ar { arg which, array, wrap=1; ^this.new1(\audio, which, array, wrap); } *kr { arg which, array, wrap=1; ^this.new1(\control, which, array, wrap); } *crossfadeClass { ^XFade2 } } LinSelectX : SelectX { *crossfadeClass { ^LinXFade2 } } SelectXFocus { *new { arg which, array, focus=1, wrap = false; if(wrap) { ^Mix(array.collect({ arg in, i; (1 - (moddif(which, i, array.size) * focus)).max(0) * in })) } { ^Mix(array.collect({ arg in, i; (1 - (absdif(which, i) * focus)).max(0) * in; })) } } *ar { arg which, array, focus=1, wrap = false; ^this.new(which, array, focus, wrap); } *kr { arg which, array, focus=1, wrap = false; ^this.new(which, array, focus, wrap); } } Vibrato : PureUGen { *ar { arg freq = 440.0, rate = 6, depth = 0.02, delay = 0.0, onset = 0.0, rateVariation = 0.04, depthVariation = 0.1, iphase = 0.0, trig = 0.0; ^this.multiNew('audio', freq, rate, depth, delay, onset, rateVariation, depthVariation, iphase, trig) } *kr { arg freq = 440.0, rate = 6, depth = 0.02, delay = 0.0, onset = 0.0, rateVariation = 0.04, depthVariation = 0.1, iphase = 0.0, trig = 0.0; ^this.multiNew('control', freq, rate, depth, delay, onset, rateVariation, depthVariation, iphase, trig) } } TChoose { *ar { arg trig, array; ^Select.ar(TIRand.ar(0, array.lastIndex, trig), array) } *kr { arg trig, array; ^Select.kr(TIRand.kr(0, array.lastIndex, trig), array) } } TWChoose { *ar { arg trig, array, weights, normalize=0; ^Select.ar(TWindex.ar(trig, weights, normalize), array) } *kr { arg trig, array, weights, normalize=0; ^Select.kr(TWindex.kr(trig, weights, normalize), array) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Pan.sc000644 000765 000024 00000010641 12756534416 024052 0ustar00crucialstaff000000 000000 Pan2 : MultiOutUGen { *ar { arg in, pos = 0.0, level = 1.0; ^this.multiNew('audio', in, pos, level ) } *kr { arg in, pos = 0.0, level = 1.0; ^this.multiNew('control', in, pos, level ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } checkInputs { ^this.checkNInputs(1) } } LinPan2 : Pan2 {} Pan4 : MultiOutUGen { *ar { arg in, xpos = 0.0, ypos = 0.0, level = 1.0; ^this.multiNew('audio', in, xpos, ypos, level ) } *kr { arg in, xpos = 0.0, ypos = 0.0, level = 1.0; ^this.multiNew('control', in, xpos, ypos, level ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate,this, 0), OutputProxy(rate,this, 1), OutputProxy(rate,this, 2), OutputProxy(rate,this, 3) ]; ^channels } checkInputs { ^this.checkNInputs(1) } } Balance2 : MultiOutUGen { *ar { arg left, right, pos = 0.0, level = 1.0; ^this.multiNew('audio', left, right, pos, level ) } *kr { arg left, right, pos = 0.0, level = 1.0; ^this.multiNew('control', left, right, pos, level ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } checkInputs { ^this.checkNInputs(2) } } Rotate2 : MultiOutUGen { *ar { arg x, y, pos = 0.0; ^this.multiNew('audio', x, y, pos ) } *kr { arg x, y, pos = 0.0; ^this.multiNew('control', x, y, pos ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate, this, 0), OutputProxy(rate, this, 1) ]; ^channels } checkInputs { ^this.checkNInputs(2) } } PanB : MultiOutUGen { *ar { arg in, azimuth=0, elevation=0, gain=1; ^this.multiNew('audio', in, azimuth, elevation, gain ) } *kr { arg in, azimuth=0, elevation=0, gain=1; ^this.multiNew('control', in, azimuth, elevation, gain ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate,this,0), OutputProxy(rate,this,1), OutputProxy(rate,this,2), OutputProxy(rate,this,3) ]; ^channels } checkInputs { ^this.checkNInputs(1) } } PanB2 : MultiOutUGen { *ar { arg in, azimuth=0, gain=1; ^this.multiNew('audio', in, azimuth, gain ) } *kr { arg in, azimuth=0, gain=1; ^this.multiNew('control', in, azimuth, gain ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate,this,0), OutputProxy(rate,this,1), OutputProxy(rate,this,2) ]; ^channels } checkInputs { ^this.checkNInputs(1) } } BiPanB2 : MultiOutUGen { *ar { arg inA, inB, azimuth, gain=1; ^this.multiNew('audio', inA, inB, azimuth, gain ) } *kr { arg inA, inB, azimuth, gain=1; ^this.multiNew('control', inA, inB, azimuth, gain ) } init { arg ... theInputs; inputs = theInputs; channels = [ OutputProxy(rate,this,0), OutputProxy(rate,this,1), OutputProxy(rate,this,2) ]; ^channels } checkInputs { ^this.checkNInputs(2) } } DecodeB2 : MultiOutUGen { *ar { arg numChans, w, x, y, orientation = 0.5; ^this.multiNew('audio', numChans, w, x, y, orientation = 0.5 ) } *kr { arg numChans, w, x, y, orientation = 0.5; ^this.multiNew('control', numChans, w, x, y, orientation = 0.5 ) } init { arg numChans ... theInputs; inputs = theInputs; channels = Array.fill(numChans, { arg i; OutputProxy(rate,this, i) }); ^channels } checkInputs { ^this.checkNInputs(3) } } PanAz : MultiOutUGen { *ar { arg numChans, in, pos = 0.0, level = 1.0, width = 2.0, orientation = 0.5; ^this.multiNew('audio', numChans, in, pos, level, width, orientation ) } *kr { arg numChans, in, pos = 0.0, level = 1.0, width = 2.0, orientation = 0.5; ^this.multiNew('control', numChans, in, pos, level, width, orientation ) } init { arg numChans ... theInputs; inputs = theInputs; channels = Array.fill(numChans, { arg i; OutputProxy(rate,this, i) }); ^channels } checkInputs { ^this.checkNInputs(1) } } XFade2 : UGen { // equal power two channel cross fade *ar { arg inA, inB = 0.0, pan = 0.0, level = 1.0; ^this.multiNew('audio', inA, inB, pan, level) } *kr { arg inA, inB = 0.0, pan = 0.0, level = 1.0; ^this.multiNew('control', inA, inB, pan, level) } checkInputs { ^this.checkNInputs(2) } } LinXFade2 : UGen { // linear two channel cross fade *ar { arg inA, inB = 0.0, pan = 0.0, level = 1.0; ^this.multiNew('audio', inA, inB, pan) * level } *kr { arg inA, inB = 0.0, pan = 0.0, level = 1.0; ^this.multiNew('control', inA, inB, pan) * level } checkInputs { ^this.checkNInputs(2) } } SuperCollider-Source/SCClassLibrary/Common/Audio/PartConv.sc000644 000765 000024 00000001153 12756534416 025066 0ustar00crucialstaff000000 000000 //Partitioned Convolution PartConv : UGen { *ar { arg in, fftsize, irbufnum,mul = 1.0, add = 0.0; ^this.multiNew('audio', in, fftsize, irbufnum).madd(mul, add); } *calcNumPartitions {arg fftsize, irbuffer; var siz, partitionsize; partitionsize=fftsize.div(2); siz= irbuffer.numFrames; ^((siz/partitionsize).roundUp); //bufsize = numpartitions*fftsize; } *calcBufSize {arg fftsize, irbuffer; ^ fftsize* (PartConv.calcNumPartitions(fftsize,irbuffer)); } } + Buffer { preparePartConv { arg buf, fftsize; server.listSendMsg(["/b_gen", bufnum, "PreparePartConv", buf.bufnum, fftsize]); } } SuperCollider-Source/SCClassLibrary/Common/Audio/PhysicalModel.sc000644 000765 000024 00000001362 12756534416 026071 0ustar00crucialstaff000000 000000 Spring : UGen { *ar { arg in=0.0, spring=1, damp=0; ^this.multiNew('audio', in, spring, damp) } *kr { arg in=0.0, spring=1, damp=0; ^this.multiNew('control', in, spring, damp) } } //Friction : UGen { // *ar { arg in=0.0, spring=1, thresh=0.5; // ^this.multiNew('audio', in, spring, thresh) // } // //} Ball : UGen { *ar { arg in=0.0, g=1, damp=0, friction=0.01; ^this.multiNew('audio', in, g, damp, friction) } *kr { arg in=0.0, g=1, damp=0, friction=0.01; ^this.multiNew('control', in, g, damp, friction) } } TBall : UGen { *ar { arg in=0.0, g=10, damp=0, friction=0.01; ^this.multiNew('audio', in, g, damp, friction) } *kr { arg in=0.0, g=10, damp=0, friction=0.01; ^this.multiNew('control', in, g, damp, friction) } } SuperCollider-Source/SCClassLibrary/Common/Audio/PitchShift.sc000644 000765 000024 00000000462 12756534416 025401 0ustar00crucialstaff000000 000000 PitchShift : UGen { checkInputs { ^this.checkSameRateAsFirstInput } *ar { arg in = 0.0, windowSize = 0.2, pitchRatio = 1.0, pitchDispersion = 0.0, timeDispersion = 0.0, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, windowSize, pitchRatio, pitchDispersion, timeDispersion).madd(mul, add) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Pluck.sc000644 000765 000024 00000000355 12756534416 024413 0ustar00crucialstaff000000 000000 Pluck : UGen { *ar { arg in = 0.0, trig = 1.0, maxdelaytime = 0.2, delaytime = 0.2, decaytime = 1.0, coef = 0.5, mul = 1.0, add = 0.0; ^this.multiNew('audio', in, trig, maxdelaytime, delaytime, decaytime, coef).madd(mul, add)} } SuperCollider-Source/SCClassLibrary/Common/Audio/Poll.sc000644 000765 000024 00000002220 12756534416 024234 0ustar00crucialstaff000000 000000 Poll : UGen { *ar { arg trig, in, label, trigid = -1; this.multiNewList(['audio', trig, in, label, trigid]); ^in; } *kr { arg trig, in, label, trigid = -1; this.multiNewList(['control', trig, in, label, trigid]); ^in; } *new { arg trig, in, label, trigid = -1; var rate = in.asArray.collect(_.rate).unbubble; this.multiNewList([rate, trig, in, label, trigid]); ^in; } *new1 { arg rate, trig, in, label, trigid; label = label ?? { "UGen(%)".format(in.class) }; label = label.asString.collectAs(_.ascii, Array); if(rate === \scalar) { rate = \control }; if(trig.isNumber) { trig = Impulse.multiNew(rate, trig, 0) }; ^super.new.rate_(rate).addToSynth.init([trig, in, trigid, label.size] ++ label); } checkInputs { ^this.checkSameRateAsFirstInput } init { arg theInputs; // store the inputs as an array inputs = theInputs; } } /* s.boot; {Poll.ar(Impulse.ar(5), Line.ar(0, 1, 1), \test2)}.play(s); {SinOsc.ar(220, 0, 1).poll(Impulse.ar(15), "test")}.play(s); o = OSCresponderNode(s.addr, '/tr', {arg time, resp, msg; msg.postln; }).add {Poll.ar(Impulse.ar(5), Line.ar(0, 1, 1), \test2, 1234)}.play(s); o.remove; s.quit; */ SuperCollider-Source/SCClassLibrary/Common/Audio/PSinGrain.sc000644 000765 000024 00000000602 12756534416 025162 0ustar00crucialstaff000000 000000 /* PSinGrain - fixed frequency sine oscillator arguments : freq - frequency in cycles per second. Must be a scalar. dur - grain duration amp - amplitude of grain This unit generator uses a very fast algorithm for generating a sine wave at a fixed frequency. */ PSinGrain : UGen { *ar { arg freq = 440.0, dur = 0.2, amp = 1.0; ^this.multiNew('audio', freq, dur, amp) } } SuperCollider-Source/SCClassLibrary/Common/Audio/Splay.sc000644 000765 000024 00000005067 12756534416 024432 0ustar00crucialstaff000000 000000 Splay : UGen { *new1 { arg rate, spread = 1, level = 1, center = 0.0, levelComp = true ... inArray; var n = max(2, inArray.size); var n1 = n - 1; var positions = ((0 .. n1) * (2 / n1) - 1) * spread + center; if (levelComp) { if(rate == \audio) { level = level * n.reciprocal.sqrt } { level = level / n } }; ^Mix(Pan2.perform(this.methodSelectorForRate(rate), inArray, positions)) * level; } *kr { arg inArray, spread = 1, level = 1, center = 0.0, levelComp = true; ^this.multiNewList([\control, spread, level, center, levelComp] ++ inArray) } *ar { arg inArray, spread = 1, level = 1, center = 0.0, levelComp = true; ^this.multiNewList([\audio, spread, level, center, levelComp] ++ inArray) } *arFill { arg n, function, spread = 1, level = 1, center = 0.0, levelComp = true; ^this.ar((function ! n), spread, level, center, levelComp) } } SplayAz : UGen { *kr { arg numChans = 4, inArray, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; var n = max(1, inArray.size); var pos = if(n == 1) { center } { [ center - spread, center + spread ].resamp1(n) }; if (levelComp) { level = level * n.reciprocal.sqrt }; ^PanAz.kr(numChans, inArray.asArray, pos, level, width, orientation).flop.collect(Mix(_)) } *ar { arg numChans = 4, inArray, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; var n = max(1, inArray.size); var pos = if(n == 1) { center } { [ center - spread, center + spread ].resamp1(n) }; if (levelComp) { level = level * n.reciprocal.sqrt }; ^PanAz.ar(numChans, inArray.asArray, pos, level, width, orientation).flop.collect(Mix(_)) } *arFill { arg numChans = 4, n, function, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; ^this.ar(numChans, function ! n, spread, level, width, center, orientation, levelComp) } } SplayZ { *ar { arg numChans = 4, inArray, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; var n = inArray.size.max(2); var n1 = n - 1; if (levelComp) { level = level * n.reciprocal.sqrt }; "SplayZ is deprecated, because its geometry is wrong. Please convert to SplayAz.".inform; ^Mix(PanAz.ar( numChans, inArray, ((0 .. n1) * (2 / n1) - 1) * spread + center, 1, width, orientation )) * level; } *arFill { arg numChans = 4, n, function, spread = 1, level = 1, width = 2, center = 0.0, orientation = 0.5, levelComp = true; ^this.ar(numChans, function ! n, spread, level, width, center, orientation, levelComp) } } SuperCollider-Source/SCClassLibrary/Common/Audio/SynthDef.sc000644 000765 000024 00000043753 12756534416 025072 0ustar00crucialstaff000000 000000 SynthDef { var <>name, <>func; var <>controls, <>controlNames; // ugens add to this var <>allControlNames; var <>controlIndex=0; var <>children; var <>constants; var <>constantSet; var <>maxLocalBufs; // topo sort var <>available; var <>variants; var <>widthFirstUGens; var rewriteInProgress; var <>desc, <>metadata; classvar 0) { nonControlNames.do {|cn| arguments[cn.argNum] = cn.defaultValue; }; }; if (irControlNames.size > 0) { values = nil; irControlNames.do {|cn| values = values.add(cn.defaultValue); }; index = controlIndex; controlUGens = Control.ir(values.flat).asArray.reshapeLike(values); irControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; if (trControlNames.size > 0) { values = nil; trControlNames.do {|cn| values = values.add(cn.defaultValue); }; index = controlIndex; controlUGens = TrigControl.kr(values.flat).asArray.reshapeLike(values); trControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; if (arControlNames.size > 0) { values = nil; arControlNames.do {|cn| values = values.add(cn.defaultValue); }; index = controlIndex; controlUGens = AudioControl.ar(values.flat).asArray.reshapeLike(values); arControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; if (krControlNames.size > 0) { values = nil; lags = nil; krControlNames.do {|cn| valsize = cn.defaultValue.asArray.size; values = values.add(cn.defaultValue); lags = lags.addAll(cn.lag.asArray.wrapExtend(valsize)); }; index = controlIndex; if (lags.any {|lag| lag != 0 }) { controlUGens = LagControl.kr(values.flat, lags).asArray.reshapeLike(values); }{ controlUGens = Control.kr(values.flat).asArray.reshapeLike(values); }; krControlNames.do {|cn, i| cn.index = index; index = index + cn.defaultValue.asArray.size; arguments[cn.argNum] = controlUGens[i]; this.setControlNames(controlUGens[i], cn); }; }; controlNames = controlNames.reject {|cn| cn.rate == 'noncontrol' }; ^arguments } setControlNames {arg controlUGens, cn; controlUGens.isArray.if({ controlUGens.do({arg thisCtrl; thisCtrl.name_(cn.name); }) }, { controlUGens.name_(cn.name) }); } finishBuild { this.addCopiesIfNeeded; this.optimizeGraph; this.collectConstants; this.checkInputs;// will die on error // re-sort graph. reindex. this.topologicalSort; this.indexUGens; UGen.buildSynthDef = nil; } addCopiesIfNeeded { // could also have PV_UGens store themselves in a separate collection widthFirstUGens.do({|child| if(child.isKindOf(PV_ChainUGen), { child.addCopiesIfNeeded; }); }); } asBytes { var stream = CollStream.on(Int8Array.new(256)); this.asArray.writeDef(stream); ^stream.collection; } writeDefFile { arg dir, overwrite(true), mdPlugin; var desc, defFileExistedBefore; if((metadata.tryPerform(\at, \shouldNotSend) ? false).not) { dir = dir ? SynthDef.synthDefDir; defFileExistedBefore = File.exists(dir +/+ name ++ ".scsyndef"); super.writeDefFile(name, dir, overwrite); if(overwrite or: { defFileExistedBefore.not }) { desc = this.asSynthDesc; desc.metadata = metadata; SynthDesc.populateMetadataFunc.value(desc); desc.writeMetadata(dir +/+ name, mdPlugin); }; } { // actual error, not just warning as in .send and .load, // because you might try to write the file somewhere other than // the default location - could be fatal later, so crash now MethodError("This SynthDef (%) was reconstructed from a .scsyndef file. It does not contain all the required structure to write back to disk. File was not written." .format(name), this).throw } } writeDef { arg file; // This describes the file format for the synthdef files. var allControlNamesTemp, allControlNamesMap; file.putPascalString(name.asString); this.writeConstants(file); //controls have been added by the Control UGens file.putInt32(controls.size); controls.do { | item | file.putFloat(item); }; allControlNamesTemp = allControlNames.reject { |cn| cn.rate == \noncontrol }; file.putInt32(allControlNamesTemp.size); allControlNamesTemp.do { | item | if (item.name.notNil) { file.putPascalString(item.name.asString); file.putInt32(item.index); }; }; file.putInt32(children.size); children.do { | item | item.writeDef(file); }; file.putInt16(variants.size); if (variants.size > 0) { allControlNamesMap = (); allControlNamesTemp.do { |cn| allControlNamesMap[cn.name] = cn; }; variants.keysValuesDo {|varname, pairs| var varcontrols; varname = name ++ "." ++ varname; if (varname.size > 32) { Post << "variant '" << varname << "' name too long.\n"; ^nil }; varcontrols = controls.copy; pairs.pairsDo { |cname, values| var cn, index; cn = allControlNamesMap[cname]; if (cn.notNil) { values = values.asArray; if (values.size > cn.defaultValue.asArray.size) { postf("variant: '%' control: '%' size mismatch.\n", varname, cname); ^nil }{ index = cn.index; values.do {|val, i| varcontrols[index + i] = val; } } }{ postf("variant: '%' control: '%' not found.\n", varname, cname); ^nil } }; file.putPascalString(varname); varcontrols.do { | item | file.putFloat(item); }; }; }; } writeConstants { arg file; var array = FloatArray.newClear(constants.size); constants.keysValuesDo { arg value, index; array[index] = value; }; file.putInt32(constants.size); array.do { | item | file.putFloat(item) }; } checkInputs { var firstErr; children.do { arg ugen; var err; if ((err = ugen.checkInputs).notNil) { err = ugen.class.asString + err; err.postln; ugen.dumpArgs; if(firstErr.isNil) { firstErr = err }; }; }; if(firstErr.notNil) { "SynthDef % build failed".format(this.name).postln; Error(firstErr).throw }; ^true } // UGens do these addUGen { arg ugen; if (rewriteInProgress.isNil) { // we don't add ugens, if a rewrite operation is in progress ugen.synthIndex = children.size; ugen.widthFirstAntecedents = widthFirstUGens.copy; children = children.add(ugen); } } removeUGen { arg ugen; // lazy removal: clear entry and later remove all nil enties children[ugen.synthIndex] = nil; } replaceUGen { arg a, b; if (b.isKindOf(UGen).not) { Error("replaceUGen assumes a UGen").throw; }; b.widthFirstAntecedents = a.widthFirstAntecedents; b.descendants = a.descendants; b.synthIndex = a.synthIndex; children[a.synthIndex] = b; children.do { arg item, i; if (item.notNil) { item.inputs.do { arg input, j; if (input === a) { item.inputs[j] = b }; }; }; }; } addConstant { arg value; if (constantSet.includes(value).not) { constantSet.add(value); constants[value] = constants.size; }; } // multi channel expansion causes a non optimal breadth-wise ordering of the graph. // the topological sort below follows branches in a depth first order, // so that cache performance of connection buffers is optimized. optimizeGraph { var oldSize; this.initTopoSort; rewriteInProgress = true; children.copy.do { arg ugen; ugen.optimizeGraph; }; rewriteInProgress = nil; // fixup removed ugens oldSize = children.size; children.removeEvery(#[nil]); if (oldSize != children.size) { this.indexUGens }; } collectConstants { children.do { arg ugen; ugen.collectConstants; }; } initTopoSort { available = nil; children.do { arg ugen; ugen.antecedents = Set.new; ugen.descendants = Set.new; }; children.do { arg ugen; // this populates the descendants and antecedents ugen.initTopoSort; }; children.reverseDo { arg ugen; ugen.descendants = ugen.descendants.asArray.sort( { arg a, b; a.synthIndex < b.synthIndex } ); ugen.makeAvailable; // all ugens with no antecedents are made available }; } cleanupTopoSort { children.do { arg ugen; ugen.antecedents = nil; ugen.descendants = nil; ugen.widthFirstAntecedents = nil; }; } topologicalSort { var outStack; this.initTopoSort; while { available.size > 0 } { outStack = available.pop.schedule(outStack); }; children = outStack; this.cleanupTopoSort; } indexUGens { children.do { arg ugen, i; ugen.synthIndex = i; }; } dumpUGens { name.postln; children.do { arg ugen, i; var inputs, ugenName; if (ugen.inputs.notNil) { inputs = ugen.inputs.collect {|in| if (in.respondsTo(\dumpName)) { in.dumpName }{ in }; }; }; [ugen.dumpName, ugen.rate, inputs].postln; }; } // make SynthDef available to all servers add { arg libname, completionMsg, keepDef = true; var servers, desc = this.asSynthDesc(libname ? \global, keepDef); if(libname.isNil) { servers = Server.allRunningServers } { servers = SynthDescLib.getLib(libname).servers }; servers.do { |each| this.doSend(each.value, completionMsg.value(each)) } } *removeAt { arg name, libname = \global; var lib = SynthDescLib.getLib(libname); lib.removeAt(name); lib.servers.do { |each| each.value.sendMsg("/d_free", name) }; } // methods for special optimizations // only send to servers send { arg server, completionMsg; var servers = (server ?? { Server.allRunningServers }).asArray; servers.do { |each| if(each.serverRunning.not) { "Server % not running, could not send SynthDef.".format(server.name).warn }; if(metadata.trueAt(\shouldNotSend)) { this.loadReconstructed(each, completionMsg); } { this.doSend(each, completionMsg); } } } doSend { |server, completionMsg| var bytes = this.asBytes; if (bytes.size < (65535 div: 4)) { server.sendMsg("/d_recv", bytes, completionMsg) } { if (server.isLocal) { "SynthDef % too big for sending. Retrying via synthdef file".format(name).warn; this.writeDefFile(synthDefDir); server.sendMsg("/d_load", synthDefDir ++ name ++ ".scsyndef", completionMsg) } { "SynthDef % too big for sending.".format(name).warn; } } } // send to server and write file load { arg server, completionMsg, dir(synthDefDir); server = server ? Server.default; if(metadata.trueAt(\shouldNotSend)) { this.loadReconstructed(server, completionMsg); } { // should remember what dir synthDef was written to dir = dir ? synthDefDir; this.writeDefFile(dir); server.sendMsg("/d_load", dir ++ name ++ ".scsyndef", completionMsg) }; } // write to file and make synth description store { arg libname=\global, dir(synthDefDir), completionMsg, mdPlugin; var lib = SynthDescLib.getLib(libname); var file, path = dir ++ name ++ ".scsyndef"; if(metadata.falseAt(\shouldNotSend)) { protect { var bytes, desc; file = File(path, "w"); bytes = this.asBytes; file.putAll(bytes); file.close; lib.read(path); lib.servers.do { arg server; this.doSend(server.value, completionMsg) }; desc = lib[this.name]; desc.metadata = metadata; SynthDesc.populateMetadataFunc.value(desc); desc.writeMetadata(path, mdPlugin); } { file.close } } { lib.read(path); lib.servers.do { arg server; this.loadReconstructed(server, completionMsg); }; }; } asSynthDesc { |libname=\global, keepDef = true| var lib, stream = CollStream(this.asBytes); libname ?? { libname = \global }; lib = SynthDescLib.getLib(libname); desc = lib.readDescFromDef(stream, keepDef, this, metadata); ^desc } // this method warns and does not halt // because loading existing def from disk is a viable alternative // to get the synthdef to the server loadReconstructed { arg server, completionMsg; "SynthDef (%) was reconstructed from a .scsyndef file, " "it does not contain all the required structure to send back to the server." .format(name).warn; if(server.isLocal) { "Loading from disk instead.".postln; server.sendBundle(nil, ["/d_load", metadata[\loadPath], completionMsg]); } { MethodError("Server is remote, cannot load from disk.", this).throw; }; } // this method needs a reconsideration storeOnce { arg libname=\global, dir(synthDefDir), completionMsg, mdPlugin; var path = dir ++ name ++ ".scsyndef", lib; if(File.exists(path).not) { this.store(libname, dir, completionMsg, mdPlugin); } { // load synthdesc from disk // because SynthDescLib still needs to have the info lib = SynthDescLib.getLib(libname); lib.read(path); }; } play { arg target,args,addAction=\addToHead; var synth, msg; // this.deprecated(thisMethod, Function.findRespondingMethodFor(\play)); target = target.asTarget; synth = Synth.basicNew(name,target.server); msg = synth.newMsg(target, args, addAction); this.send(target.server, msg); ^synth } } SuperCollider-Source/SCClassLibrary/Common/Audio/SynthDefOld.sc000644 000765 000024 00000011111 12766171707 025511 0ustar00crucialstaff000000 000000 SynthDefOld : SynthDef { *new { arg name, ugenGraphFunc, rates, prependArgs, variants, metadata; ^super.new.name_(name.asSymbol).variants_(variants).metadata_(metadata).children_(Array.new(64)) .build(ugenGraphFunc, rates, prependArgs) } writeDefFile { arg dir, overwrite(true); if((metadata.tryPerform(\at, \shouldNotSend) ? false).not) { super.writeDefFileOld(name, dir, overwrite); } { // actual error, not just warning as in .send and .load, // because you might try to write the file somewhere other than // the default location - could be fatal later, so crash now MethodError("This SynthDef (%) was reconstructed from a .scsyndef file. It does not contain all the required structure to write back to disk. File was not written." .format(name), this).throw } } writeDef { arg file; // This describes the file format for the synthdef files. var allControlNamesTemp, allControlNamesMap; file.putPascalString(name.asString); this.writeConstants(file); //controls have been added by the Control UGens file.putInt16(controls.size); controls.do { | item | file.putFloat(item); }; allControlNamesTemp = allControlNames.reject { |cn| cn.rate == \noncontrol }; file.putInt16(allControlNamesTemp.size); allControlNamesTemp.do { | item | if (item.name.notNil) { file.putPascalString(item.name.asString); file.putInt16(item.index); }; }; file.putInt16(children.size); children.do { | item | item.writeDefOld(file); }; file.putInt16(variants.size); if (variants.size > 0) { allControlNamesMap = (); allControlNamesTemp.do { |cn| allControlNamesMap[cn.name] = cn; }; variants.keysValuesDo {|varname, pairs| var varcontrols; varname = name ++ "." ++ varname; if (varname.size > 32) { Post << "variant '" << varname << "' name too long.\n"; ^nil }; varcontrols = controls.copy; pairs.pairsDo { |cname, values| var cn, index; cn = allControlNamesMap[cname]; if (cn.notNil) { values = values.asArray; if (values.size > cn.defaultValue.asArray.size) { postf("variant: '%' control: '%' size mismatch.\n", varname, cname); ^nil }{ index = cn.index; values.do {|val, i| varcontrols[index + i] = val; } } }{ postf("variant: '%' control: '%' not found.\n", varname, cname); ^nil } }; file.putPascalString(varname); varcontrols.do { | item | file.putFloat(item); }; }; } } writeConstants { arg file; var array = FloatArray.newClear(constants.size); constants.keysValuesDo { arg value, index; array[index] = value; }; file.putInt16(constants.size); array.do { | item | file.putFloat(item) }; } asBytes { var stream = CollStream.on(Int8Array.new(256)); this.asArray.writeDefOld(stream); ^stream.collection; } } + Collection { writeDefOld { | file | file.putString("SCgf"); file.putInt32(1); // file version file.putInt16(this.size); // number of defs in file. this.do { | item | item.writeDef(file); } } writeInputSpecOld { | file, synthDef | this.do { | item | item.writeInputSpecOld(file, synthDef) }; } } + UGen { writeDefOld { arg file; //[\WR, this.class.name, rate, this.numInputs, this.numOutputs].postln; file.putPascalString(this.name); file.putInt8(this.rateNumber); file.putInt16(this.numInputs); file.putInt16(this.numOutputs); file.putInt16(this.specialIndex); // write wire spec indices. inputs.do({ arg input; input.writeInputSpecOld(file, synthDef); }); this.writeOutputSpecs(file); //[this.class.name, file.length].postln; } writeInputSpecOld { arg file, synthDef; file.putInt16(synthIndex); file.putInt16(this.outputIndex); } } + SimpleNumber { writeInputSpecOld { arg file, synth; var constIndex = synth.constants.at(this.asFloat); if (constIndex.isNil) { Error("SimpleNumber-writeInputSpec constant not found: " ++ this.asFloat).throw; }; //[\inpspc, this.class.name, constIndex, this].postln; file.putInt16(-1); file.putInt16(constIndex); } } + Object { writeDefFileOld { arg name, dir, overwrite = (true); StartUp.defer { // make sure the synth defs are written to the right path var file; dir = dir ? SynthDef.synthDefDir; if (name.isNil) { Error("missing SynthDef file name").throw } { name = dir +/+ name ++ ".scsyndef"; if(overwrite or: { pathMatch(name).isEmpty }) { file = File(name, "w"); protect { AbstractMDPlugin.clearMetadata(name); this.asArray.writeDefOld(file); }{ file.close; } } } } } } SuperCollider-Source/SCClassLibrary/Common/Audio/SynthDesc.sc000644 000765 000024 00000045367 12766171707 025256 0ustar00crucialstaff000000 000000 IODesc { var <>rate, <>numberOfChannels, <>startingChannel, <>type; *new { arg rate, numberOfChannels, startingChannel="?", type; ^super.newCopyArgs(rate, numberOfChannels, startingChannel, type) } printOn { arg stream; stream << rate.asString << " " << type.name << " " << startingChannel << " " << numberOfChannels } } SynthDesc { classvar <>mdPlugin, <>populateMetadataFunc; var <>name, <>controlNames, <>controlDict; var <>controls, <>inputs, <>outputs; var <>metadata; var <>constants, <>def; var <>msgFunc, <>hasGate = false, <>hasArrayArgs, <>hasVariants, <>canFreeSynth = false; var = 2, { desc = SynthDesc.new.readSynthDef2(stream, keepDefs); },{ desc = SynthDesc.new.readSynthDef(stream, keepDefs); }); dict.put(desc.name.asSymbol, desc); // AbstractMDPlugin dynamically determines the md archive type // from the file extension if(path.notNil) { desc.metadata = AbstractMDPlugin.readMetadata(path); }; this.populateMetadataFunc.value(desc); if(desc.def.notNil and: { stream.isKindOf(CollStream).not }) { desc.def.metadata ?? { desc.def.metadata = () }; desc.def.metadata.put(\shouldNotSend, true) .put(\loadPath, path); }; } ^dict } readSynthDef { arg stream, keepDef=false; var numControls, numConstants, numControlNames, numUGens, numVariants; protect { inputs = []; outputs = []; controlDict = IdentityDictionary.new; name = stream.getPascalString; def = SynthDef.prNew(name); UGen.buildSynthDef = def; numConstants = stream.getInt16; constants = FloatArray.newClear(numConstants); stream.read(constants); numControls = stream.getInt16; def.controls = FloatArray.newClear(numControls); stream.read(def.controls); controls = Array.fill(numControls) { |i| ControlName('?', i, '?', def.controls[i]); }; numControlNames = stream.getInt16; numControlNames.do { var controlName, controlIndex; controlName = stream.getPascalString.asSymbol; controlIndex = stream.getInt16; controls[controlIndex].name = controlName; controlNames = controlNames.add(controlName); controlDict[controlName] = controls[controlIndex]; }; numUGens = stream.getInt16; numUGens.do { this.readUGenSpec(stream); }; controls.inject(nil) {|z,y| if(y.name=='?') { z.defaultValue = z.defaultValue.asArray.add(y.defaultValue); z } { y } }; def.controlNames = controls.select {|x| x.name.notNil }; hasArrayArgs = controls.any { |cn| cn.name == '?' }; numVariants = stream.getInt16; hasVariants = numVariants > 0; // maybe later, read in variant names and values // this is harder than it might seem at first def.constants = Dictionary.new; constants.do {|k,i| def.constants.put(k,i) }; if (keepDef.not) { // throw away unneeded stuff def = nil; constants = nil; }; this.makeMsgFunc; } { UGen.buildSynthDef = nil; } } // synthdef ver 2 readSynthDef2 { arg stream, keepDef=false; var numControls, numConstants, numControlNames, numUGens, numVariants; protect { inputs = []; outputs = []; controlDict = IdentityDictionary.new; name = stream.getPascalString; def = SynthDef.prNew(name); UGen.buildSynthDef = def; numConstants = stream.getInt32; constants = FloatArray.newClear(numConstants); stream.read(constants); numControls = stream.getInt32; def.controls = FloatArray.newClear(numControls); stream.read(def.controls); controls = Array.fill(numControls) { |i| ControlName('?', i, '?', def.controls[i]); }; numControlNames = stream.getInt32; numControlNames.do { var controlName, controlIndex; controlName = stream.getPascalString.asSymbol; controlIndex = stream.getInt32; controls[controlIndex].name = controlName; controlNames = controlNames.add(controlName); controlDict[controlName] = controls[controlIndex]; }; numUGens = stream.getInt32; numUGens.do { this.readUGenSpec2(stream); }; controls.inject(nil) {|z,y| if(y.name=='?') { z.defaultValue = z.defaultValue.asArray.add(y.defaultValue); z } { y } }; def.controlNames = controls.select {|x| x.name.notNil }; hasArrayArgs = controls.any { |cn| cn.name == '?' }; numVariants = stream.getInt16; hasVariants = numVariants > 0; // maybe later, read in variant names and values // this is harder than it might seem at first def.constants = Dictionary.new; constants.do {|k,i| def.constants.put(k,i) }; if (keepDef.not) { // throw away unneeded stuff def = nil; constants = nil; }; this.makeMsgFunc; } { UGen.buildSynthDef = nil; } } readUGenSpec { arg stream; var ugenClass, rateIndex, rate, numInputs, numOutputs, specialIndex; var inputSpecs, outputSpecs; var addIO; var ugenInputs, ugen; var control; ugenClass = stream.getPascalString.asSymbol; if(ugenClass.asClass.isNil,{ Error("No UGen class found for" + ugenClass + "which was specified in synth def file: " + this.name ++ ".scsyndef").throw; }); ugenClass = ugenClass.asClass; rateIndex = stream.getInt8; numInputs = stream.getInt16; numOutputs = stream.getInt16; specialIndex = stream.getInt16; inputSpecs = Int16Array.newClear(numInputs * 2); outputSpecs = Int8Array.newClear(numOutputs); stream.read(inputSpecs); stream.read(outputSpecs); ugenInputs = []; forBy (0,inputSpecs.size-1,2) {|i| var ugenIndex, outputIndex, input, ugen; ugenIndex = inputSpecs[i]; outputIndex = inputSpecs[i+1]; input = if (ugenIndex < 0) { constants[outputIndex] }{ ugen = def.children[ugenIndex]; if (ugen.isKindOf(MultiOutUGen)) { ugen.channels[outputIndex] }{ ugen } }; ugenInputs = ugenInputs.add(input); }; rate = #[\scalar,\control,\audio][rateIndex]; ugen = ugenClass.newFromDesc(rate, numOutputs, ugenInputs, specialIndex).source; ugen.addToSynth(ugen); addIO = {|list, nchan| var b = ugen.inputs[0]; if (b.class == OutputProxy and: {b.source.isKindOf(Control)}) { control = controls.detect {|item| item.index == (b.outputIndex+b.source.specialIndex) }; if (control.notNil) { b = control.name }; }; list.add( IODesc(rate, nchan, b, ugenClass)) }; if (ugenClass.isControlUGen) { // Control.newFromDesc does not set the specialIndex, since it doesn't call Control-init. // Therefore we fill it in here: ugen.specialIndex = specialIndex; numOutputs.do { |i| controls[i+specialIndex].rate = rate; } } { case {ugenClass.isInputUGen} {inputs = addIO.value(inputs, ugen.channels.size)} {ugenClass.isOutputUGen} {outputs = addIO.value(outputs, ugen.numAudioChannels)} { canFreeSynth = canFreeSynth or: { ugen.canFreeSynth }; }; }; } // synthdef ver 2 readUGenSpec2 { arg stream; var ugenClass, rateIndex, rate, numInputs, numOutputs, specialIndex; var inputSpecs, outputSpecs; var addIO; var ugenInputs, ugen; var control; ugenClass = stream.getPascalString.asSymbol; if(ugenClass.asClass.isNil,{ Error("No UGen class found for" + ugenClass + "which was specified in synth def file: " + this.name ++ ".scsyndef").throw; }); ugenClass = ugenClass.asClass; rateIndex = stream.getInt8; numInputs = stream.getInt32; numOutputs = stream.getInt32; specialIndex = stream.getInt16; inputSpecs = Int32Array.newClear(numInputs * 2); outputSpecs = Int8Array.newClear(numOutputs); stream.read(inputSpecs); stream.read(outputSpecs); ugenInputs = []; forBy (0,inputSpecs.size-1,2) {|i| var ugenIndex, outputIndex, input, ugen; ugenIndex = inputSpecs[i]; outputIndex = inputSpecs[i+1]; input = if (ugenIndex < 0) { constants[outputIndex] }{ ugen = def.children[ugenIndex]; if (ugen.isKindOf(MultiOutUGen)) { ugen.channels[outputIndex] }{ ugen } }; ugenInputs = ugenInputs.add(input); }; rate = #[\scalar,\control,\audio][rateIndex]; ugen = ugenClass.newFromDesc(rate, numOutputs, ugenInputs, specialIndex).source; ugen.addToSynth(ugen); addIO = {|list, nchan| var b = ugen.inputs[0]; if (b.class == OutputProxy and: {b.source.isKindOf(Control)}) { control = controls.detect {|item| item.index == (b.outputIndex+b.source.specialIndex) }; if (control.notNil) { b = control.name }; }; list.add( IODesc(rate, nchan, b, ugenClass)) }; if (ugenClass.isControlUGen) { // Control.newFromDesc does not set the specialIndex, since it doesn't call Control-init. // Therefore we fill it in here: ugen.specialIndex = specialIndex; numOutputs.do { |i| controls[i+specialIndex].rate = rate; } } { case {ugenClass.isInputUGen} {inputs = addIO.value(inputs, ugen.channels.size)} {ugenClass.isOutputUGen} {outputs = addIO.value(outputs, ugen.numAudioChannels)} { canFreeSynth = canFreeSynth or: { ugen.canFreeSynth }; }; }; } makeMsgFunc { var string, comma=false; var names = IdentitySet.new, suffix = this.hash.asHexString(8); // if a control name is duplicated, the msgFunc will be invalid // that "shouldn't" happen but it might; better to check for it // and throw a proper error controls.do({ |controlName| var name; if(controlName.name.asString.first.isAlpha) { name = controlName.name.asSymbol; if(names.includes(name)) { "Could not build msgFunc for this SynthDesc: duplicate control name %" .format(name).warn; comma = true; } { names.add(name); }; }; }); if(names.size > 255) { Error("A synthDef cannot have more than 255 control names.").throw }; // reusing variable to know if I should continue or not if(comma) { "\nYour synthdef has been saved in the library and loaded on the server, if running. Use of this synth in Patterns will not detect argument names automatically because of the duplicate name(s).".postln; msgFunc = nil; ^this }; comma = false; names = 0; // now, count the args actually added to the func string = String.streamContents {|stream| stream << "#{ "; if (controlNames.size > 0) { stream << "arg " ; }; controls.do {|controlName, i| var name, name2; name = controlName.name.asString; if (name != "?") { if (name == "gate") { hasGate = true; if(msgFuncKeepGate) { if (comma) { stream << ", " } { comma = true }; stream << name; names = names + 1; } }{ if (name[1] == $_) { name2 = name.drop(2) } { name2 = name }; if (comma) { stream << ", " } { comma = true }; stream << name2; names = names + 1; }; }; }; if (controlNames.size > 0) { stream << ";\n" ; }; stream << "\tvar\tx" << suffix << " = Array.new(" << (names*2) << ");\n"; comma = false; controls.do {|controlName, i| var name, name2; name = controlName.name.asString; if (name != "?") { if (msgFuncKeepGate or: { name != "gate" }) { if (name[1] == $_) { name2 = name.drop(2) } { name2 = name }; stream << "\t" << name2 << " !? { x" << suffix << ".add('" << name << "').add(" << name2 << ") };\n"; names = names + 1; }; }; }; stream << "\tx" << suffix << "\n}" }; // do not compile the string if no argnames were added if(names > 0) { msgFunc = string.compile.value }; } msgFuncKeepGate_ { |bool = false| if(bool != msgFuncKeepGate) { msgFuncKeepGate = bool; this.makeMsgFunc; } } writeMetadata { arg path, mdPlugin; if(metadata.isNil) { AbstractMDPlugin.clearMetadata(path); ^this }; (mdPlugin ?? { this.class.mdPlugin }).writeMetadata(metadata, def, path); } // parse the def name out of the bytes array sent with /d_recv *defNameFromBytes { arg int8Array; var stream, n, numDefs, size; stream = CollStream(int8Array); stream.getInt32; stream.getInt32; numDefs = stream.getInt16; size = stream.getInt8; n = String.newClear(size); ^Array.fill(size, { stream.getChar.asAscii }).as(String) } outputData { var ugens = def.children; var outs = ugens.select(_.writesToBus); ^outs.collect { |outUgen| (rate: outUgen.rate, numChannels: outUgen.numAudioChannels) } } } SynthDescLib { classvar <>all, <>global; var <>name, <>synthDescs, <>servers; *new { arg name, servers; if (name.isNil) { "SynthDescLib must have a name".error; ^nil } ^super.new.name_(name).init(servers); } init { |inServers| all.put(name.asSymbol, this); synthDescs = IdentityDictionary.new; servers = IdentitySet.with(*inServers ? { Server.default }) } *initClass { Class.initClassTree(Server); all = IdentityDictionary.new; global = this.new(\global); ServerBoot.add { |server| // tryToLoadReconstructedDefs = false: // since this is done automatically, w/o user action, // it should not try to do things that will cause warnings // (or errors, if one of the servers is not local) this.send(server, false) } } *getLib { arg libname; ^all[libname] ?? { Error("library % not found".format(libname)).throw }; } *default { ^global } *send { |server, tryToLoadReconstructedDefs = true| global.send(server, tryToLoadReconstructedDefs); } *read { arg path; global.read(path); } at { arg i; ^synthDescs.at(i) } *at { arg i; ^global.at(i) } add { |synthdesc| synthDescs.put(synthdesc.name.asSymbol, synthdesc); this.changed(\synthDescAdded, synthdesc); } removeAt { |name| ^synthDescs.removeAt(name.asSymbol); } addServer { |server| servers = servers.add(server); // IdentitySet = one server only once. } removeServer { |server| servers.remove(server); } match { |key| var keyString = key.asString, dotIndex = keyString.indexOf($.), desc; if(dotIndex.isNil) { ^synthDescs.at(key.asSymbol) }; if((desc = synthDescs[keyString[..dotIndex-1].asSymbol]).notNil and: { desc.hasVariants }) { ^desc } { ^synthDescs.at(key.asSymbol) } } *match { |key| ^global.match(key) } send { |aServer, tryToLoadReconstructedDefs = true| // sent to all (aServer ? servers).do { |server| server = server.value; synthDescs.do { |desc| if(desc.def.metadata.trueAt(\shouldNotSend).not) { desc.send(server.value) } { if(tryToLoadReconstructedDefs) { desc.def.loadReconstructed(server); }; }; }; }; } read { arg path, keepDefs=true; if (path.isNil) { path = SynthDef.synthDefDir ++ "*.scsyndef"; }; path.pathMatch.do { |filename| var file, result; file = File(filename, "r"); protect { this.readStream(file, keepDefs, filename); }{ file.close; }; }; } readStream { arg stream, keepDefs=true, path; var numDefs, version, resultSet; stream.getInt32; // 'SCgf' version = stream.getInt32; // version numDefs = stream.getInt16; resultSet = Set.new(numDefs); numDefs.do { var desc; if(version >= 2, { desc = SynthDesc.new.readSynthDef2(stream, keepDefs); },{ desc = SynthDesc.new.readSynthDef(stream, keepDefs); }); synthDescs.put(desc.name.asSymbol, desc); resultSet.add(desc); // AbstractMDPlugin dynamically determines the md archive type // from the file extension if(path.notNil) { desc.metadata = AbstractMDPlugin.readMetadata(path); }; SynthDesc.populateMetadataFunc.value(desc); if(desc.def.notNil and: { stream.isKindOf(CollStream).not }) { desc.def.metadata ?? { desc.def.metadata = () }; desc.def.metadata.put(\shouldNotSend, true) .put(\loadPath, path); }; }; resultSet.do({|newDesc| this.changed(\synthDescAdded, newDesc); }); ^resultSet } readDescFromDef {arg stream, keepDef=true, def, metadata; var desc, numDefs, version; stream.getInt32; // 'SCgf' version = stream.getInt32; // version numDefs = stream.getInt16; // should be 1 if(version >= 2, { desc = SynthDesc.new.readSynthDef2(stream, keepDef); },{ desc = SynthDesc.new.readSynthDef(stream, keepDef); }); if(keepDef) { desc.def = def }; if(metadata.notNil) { desc.metadata = metadata }; synthDescs.put(desc.name.asSymbol, desc); this.changed(\synthDescAdded, desc); ^desc } } // Basic metadata plugins // to disable metadata read/write AbstractMDPlugin { *clearMetadata { |path| ^thisProcess.platform.clearMetadata(path) } *writeMetadata { |metadata, synthdef, path| this.clearMetadata(path); if(metadata.notNil and: { metadata.size > 0 }) { path = this.applyExtension(path); this.writeMetadataFile(metadata, synthdef, path); }; } *writeMetadataFile {} // clearMetadata should ensure that only one MD file ever exists // therefore we can check the subclasses in turn // and return the first MD found // every subclass should have a unique extension *readMetadata { |path| var pathTmp, classList, i; path = path.splitext[0] ++ "."; classList = this.allSubclasses; // ensure that SynthDescLib.mdPlugin is preferred for reading, // with other plugins as a fallback // it will also be possible to use Events or Protos as plugins this way if((i = classList.indexOf(SynthDesc.mdPlugin)).notNil and: { i > 0 }) { classList = classList.copy.swap(0, i); } { classList = [SynthDesc.mdPlugin] ++ classList; }; classList.do({ |class| if(class.notNil and: { File.exists(pathTmp = path ++ class.mdExtension) }) { ^class.readMetadataFile(pathTmp) } }); ^nil } *readMetadataFile { ^nil } *applyExtension { |path| ^path.splitext[0] ++ "." ++ this.mdExtension } *mdExtension { ^"" } // nothing is written anyway } // simple archiving of the dictionary TextArchiveMDPlugin : AbstractMDPlugin { *writeMetadataFile { |metadata, synthdef, path| metadata.writeArchive(path) } *readMetadataFile { |path| ^Object.readArchive(path) } *mdExtension { ^"txarcmeta" } } SuperCollider-Source/SCClassLibrary/Common/Audio/SystemSynthDefs.sc000644 000765 000024 00000003632 12756534416 026452 0ustar00crucialstaff000000 000000 // synthdefs needed by classes SystemSynthDefs { classvar <>numChannels = 16; classvar <>tempNamePrefix = "temp__"; classvar tempDefCount = 0; classvar <>maxTempDefNames = 512; *generateTempName { var name = tempNamePrefix ++ tempDefCount; tempDefCount = tempDefCount + 1 % maxTempDefNames; ^name } *initClass { StartUp.add { // clean up any written synthdefs starting with "temp__" var path = SynthDef.synthDefDir ++ tempNamePrefix ++ "*"; "Cleaning up temp synthdefs...".inform; pathMatch(path).do { |file| File.delete(file) }; // add system synth defs (1..numChannels).do { arg i; SynthDef("system_link_audio_" ++ i, { arg out=0, in=16, vol=1, level=1, lag=0.05, doneAction=2; var env = EnvGate(doneAction:doneAction, curve:'sin') * Lag.kr(vol * level, lag); Out.ar(out, InFeedback.ar(in, i) * env) }, [\kr, \kr, \kr, \kr, \kr, \ir]).add; SynthDef("system_link_control_" ++ i, { arg out=0, in=16, doneAction=2; var env = EnvGate(doneAction:doneAction, curve:'lin'); Out.kr(out, In.kr(in, i) * env) }, [\kr, \kr, \ir]).add; SynthDef("system_diskout_" ++ i, { arg i_in, i_bufNum=0; DiskOut.ar(i_bufNum, InFeedback.ar(i_in, i)); }).add; SynthDef("system_setbus_audio_" ++ i, { arg out = 0, fadeTime = 0, curve = 0, gate = 1; var values = NamedControl.ir(\values, 0 ! i); var env = Env([In.ar(out, i), values, values], [1, 0], curve, 1); var sig = EnvGen.ar(env, gate + Impulse.kr(0), timeScale: fadeTime, doneAction: 2); ReplaceOut.ar(out, sig); }, [\ir, \kr, \ir, \kr]).add; SynthDef("system_setbus_control_" ++ i, { arg out = 0, fadeTime = 0, curve = 0; var values = NamedControl.ir(\values, 0 ! i); var env = Env([In.kr(out, i), values], [1], curve); var sig = EnvGen.kr(env, timeScale: fadeTime, doneAction: 2); ReplaceOut.kr(out, sig); }, [\ir, \kr, \ir]).add; }; }; } } SuperCollider-Source/SCClassLibrary/Common/Audio/Trig.sc000644 000765 000024 00000014726 12756534416 024251 0ustar00crucialstaff000000 000000 Trig1 : UGen { *ar { arg in = 0.0, dur = 0.1; ^this.multiNew('audio', in, dur) } *kr { arg in = 0.0, dur = 0.1; ^this.multiNew('control', in, dur) } signalRange { ^\unipolar } } Trig : Trig1 { } SendTrig : UGen { *ar { arg in = 0.0, id = 0, value = 0.0; this.multiNew('audio', in, id, value); ^0.0 // SendTrig has no output } *kr { arg in = 0.0, id = 0, value = 0.0; this.multiNew('control', in, id, value); ^0.0 // SendTrig has no output } checkInputs { ^this.checkSameRateAsFirstInput } numOutputs { ^0 } writeOutputSpecs {} } SendReply : SendTrig { *kr { arg trig = 0.0, cmdName = '/reply', values, replyID = -1; if(values.containsSeqColl.not) { values = values.bubble }; [trig, cmdName, values, replyID].flop.do { |args| this.new1('control', *args); }; ^0.0 // SendReply has no output } *ar { arg trig = 0.0, cmdName = '/reply', values, replyID = -1; if(values.containsSeqColl.not) { values = values.bubble }; [trig, cmdName, values, replyID].flop.do { |args| this.new1('audio', *args); }; ^0.0 // SendReply has no output } *new1 { arg rate, trig = 0.0, cmdName = '/reply', values, replyID = -1; var ascii = cmdName.ascii; ^super.new1(*[rate, trig, replyID, ascii.size].addAll(ascii).addAll(values)); } } TDelay : Trig1 { checkInputs { ^this.checkSameRateAsFirstInput } } Latch : UGen { *ar { arg in = 0.0, trig = 0.0; ^this.multiNew('audio', in, trig) } *kr { arg in = 0.0, trig = 0.0; ^this.multiNew('control', in, trig) } } Gate : Latch { } PulseCount : UGen { *ar { arg trig = 0.0, reset = 0.0; ^this.multiNew('audio', trig, reset) } *kr { arg trig = 0.0, reset = 0.0; ^this.multiNew('control', trig, reset) } checkInputs { ^this.checkSameRateAsFirstInput } } Peak : UGen { *ar { arg in = 0.0, trig = 0.0; ^this.multiNew('audio', in, trig) } *kr { arg in = 0.0, trig = 0.0; ^this.multiNew('control', in, trig) } checkInputs { if (rate == 'control' && inputs.at(0).rate == 'audio', { ^this.checkValidInputs }, { ^this.checkSameRateAsFirstInput }); } } RunningMin : Peak { } RunningMax : Peak { } Stepper : UGen { *ar { arg trig=0, reset=0, min=0, max=7, step=1, resetval; ^this.multiNew('audio', trig, reset, min, max, step, resetval ? min) } *kr { arg trig=0, reset=0, min=0, max=7, step=1, resetval; ^this.multiNew('control', trig, reset, min, max, step, resetval ? min) } checkInputs { ^this.checkSameRateAsFirstInput } } PulseDivider : UGen { *ar { arg trig = 0.0, div = 2.0, start = 0.0; ^this.multiNew('audio', trig, div, start) } *kr { arg trig = 0.0, div = 2.0, start = 0.0; ^this.multiNew('control', trig, div, start) } } SetResetFF : PulseCount { } ToggleFF : UGen { *ar { arg trig = 0.0; ^this.multiNew('audio', trig) } *kr { arg trig = 0.0; ^this.multiNew('control', trig) } } ZeroCrossing : UGen { *ar { arg in = 0.0; ^this.multiNew('audio', in) } *kr { arg in = 0.0; ^this.multiNew('control', in) } checkInputs { ^this.checkSameRateAsFirstInput } } Timer : UGen { // output is the time between two triggers *ar { arg trig = 0.0; ^this.multiNew('audio', trig) } *kr { arg trig = 0.0; ^this.multiNew('control', trig) } checkInputs { ^this.checkSameRateAsFirstInput } } Sweep : UGen { // output sweeps up in value at rate per second // the trigger resets to zero *ar { arg trig = 0.0, rate = 1.0; ^this.multiNew('audio', trig, rate) } *kr { arg trig = 0.0, rate = 1.0; ^this.multiNew('control', trig, rate) } } Phasor : UGen { *ar { arg trig = 0.0, rate = 1.0, start = 0.0, end = 1.0, resetPos = 0.0; ^this.multiNew('audio', trig, rate, start, end, resetPos) } *kr { arg trig = 0.0, rate = 1.0, start = 0.0, end = 1.0, resetPos = 0.0; ^this.multiNew('control', trig, rate, start, end, resetPos) } } PeakFollower : UGen { *ar { arg in = 0.0, decay = 0.999; ^this.multiNew('audio', in, decay) } *kr { arg in = 0.0, decay = 0.999; ^this.multiNew('control', in, decay) } } Pitch : MultiOutUGen { *kr { arg in = 0.0, initFreq = 440.0, minFreq = 60.0, maxFreq = 4000.0, execFreq = 100.0, maxBinsPerOctave = 16, median = 1, ampThreshold = 0.01, peakThreshold = 0.5, downSample = 1, clar=0; ^this.multiNew('control', in, initFreq, minFreq, maxFreq, execFreq, maxBinsPerOctave, median, ampThreshold, peakThreshold, downSample, clar) } init { arg ... theInputs; inputs = theInputs; ^this.initOutputs(2, rate); } } InRange : UGen { *ar { arg in = 0.0, lo = 0.0, hi = 1.0; ^this.multiNew('audio', in, lo, hi) } *kr { arg in = 0.0, lo = 0.0, hi = 1.0; ^this.multiNew('control', in, lo, hi) } *ir { arg in = 0.0, lo = 0.0, hi = 1.0; ^this.multiNew('scalar', in, lo, hi) } } InRect : UGen { *ar { arg x = 0.0, y = 0.0, rect; ^this.multiNew('audio', x, y, rect.left, rect.top, rect.right, rect.bottom) } *kr { arg x = 0.0, y = 0.0, rect; ^this.multiNew('control', x, y, rect.left, rect.top, rect.right, rect.bottom) } } //Trapezoid : UGen //{ // *ar { arg in = 0.0, a = 0.2, b = 0.4, c = 0.6, d = 0.8; // ^this.multiNew('audio', in, a, b, c, d) // } // *kr { arg in = 0.0, a = 0.2, b = 0.4, c = 0.6, d = 0.8; // ^this.multiNew('control', in, a, b, c, d) // } //} Fold : InRange {} Clip : InRange {} Wrap : InRange {} Schmidt : InRange {} ModDif : UGen { *ar { arg x = 0.0, y = 0.0, mod = 1.0; ^this.multiNew('audio', x, y, mod) } *kr { arg x = 0.0, y = 0.0, mod = 1.0; ^this.multiNew('control', x, y, mod) } *ir { arg x = 0.0, y = 0.0, mod = 1.0; ^this.multiNew('scalar', x, y, mod) } } MostChange : UGen { *ar { arg a = 0.0, b = 0.0; ^this.multiNew('audio', a, b) } *kr { arg a = 0.0, b = 0.0; ^this.multiNew('control', a, b) } } LeastChange : MostChange {} LastValue : UGen { *ar { arg in=0.0, diff=0.01; ^this.multiNew('audio', in, diff) } *kr { arg in=0.0, diff=0.01; ^this.multiNew('control', in, diff) } } SendPeakRMS : UGen { *kr { arg sig, replyRate = 20.0, peakLag = 3, cmdName = '/reply', replyID = -1; this.new1('control', sig.asArray, replyRate, peakLag, cmdName, replyID); ^0.0 // SendPeakRMS has no output } *ar { arg sig, replyRate = 20.0, peakLag = 3, cmdName = '/reply', replyID = -1; this.new1('audio', sig.asArray, replyRate, peakLag, cmdName, replyID); ^0.0 // SendPeakRMS has no output } *new1 { arg rate, sig, replyRate, peakLag, cmdName, replyID; var ascii = cmdName.ascii; var args = [rate, replyRate, peakLag, replyID, sig.size] .addAll(sig.flatten) .add(ascii.size) .addAll(ascii); ^super.new1(*args); } numOutputs { ^0 } writeOutputSpecs {} } SuperCollider-Source/SCClassLibrary/Common/Audio/UGen.sc000644 000765 000024 00000032257 12766171707 024202 0ustar00crucialstaff000000 000000 UGen : AbstractFunction { classvar <>buildSynthDef; // the synth currently under construction var <>synthDef; var <>inputs; var <>rate = 'audio'; var <>synthIndex = -1, <>specialIndex=0; var <>antecedents, <>descendants, <>widthFirstAntecedents; // topo sorting // instance creation *new1 { arg rate ... args; if (rate.isKindOf(Symbol).not) { Error("rate must be Symbol.").throw }; ^super.new.rate_(rate).addToSynth.init( *args ) } *newFromDesc { arg rate, numOutputs, inputs, specialIndex; ^super.new.rate_(rate).inputs_(inputs).specialIndex_(specialIndex) } *multiNew { arg ... args; ^this.multiNewList(args); } *multiNewList { arg args; var size = 0, newArgs, results; args = args.asUGenInput(this); args.do({ arg item; (item.class == Array).if({ size = max(size, item.size) }); }); if (size == 0) { ^this.new1( *args ) }; newArgs = Array.newClear(args.size); results = Array.newClear(size); size.do({ arg i; args.do({ arg item, j; newArgs.put(j, if (item.class == Array, { item.wrapAt(i) },{ item })); }); results.put(i, this.multiNewList(newArgs)); }); ^results } init { arg ... theInputs; // store the inputs as an array inputs = theInputs; } copy { // you can't really copy a UGen without disturbing the Synth. // Usually you want the same object. This makes .dup work ^this } madd { arg mul = 1.0, add = 0.0; ^MulAdd(this, mul, add); } range { arg lo = 0.0, hi = 1.0; var mul, add; if (this.signalRange == \bipolar, { mul = (hi - lo) * 0.5; add = mul + lo; },{ mul = (hi - lo) ; add = lo; }); ^MulAdd(this, mul, add); } exprange { arg lo = 0.01, hi = 1.0; ^if (this.signalRange == \bipolar) { this.linexp(-1, 1, lo, hi, nil) } { this.linexp(0, 1, lo, hi, nil) }; } curverange { arg lo = 0.00, hi = 1.0, curve = -4; ^if (this.signalRange == \bipolar) { this.lincurve(-1, 1, lo, hi, curve, nil) } { this.lincurve(0, 1, lo, hi, curve, nil) }; } unipolar { arg mul = 1; ^this.range(0, mul) } bipolar { arg mul = 1; ^this.range(mul.neg, mul) } clip { arg lo = 0.0, hi = 1.0; ^if(rate == \demand){ max(lo, min(hi, this)) }{ Clip.perform(Clip.methodSelectorForRate(rate), this, lo, hi) } } fold { arg lo = 0.0, hi = 0.0; ^if(rate == \demand) { this.notYetImplemented(thisMethod) } { Fold.perform(Fold.methodSelectorForRate(rate), this, lo, hi) } } wrap { arg lo = 0.0, hi = 1.0; ^if(rate == \demand) { this.notYetImplemented(thisMethod) } { Wrap.perform(Wrap.methodSelectorForRate(rate), this, lo, hi) } } blend { arg that, blendFrac = 0.5; var pan; ^if (rate == \demand || that.rate == \demand) { this.notYetImplemented(thisMethod) } { pan = blendFrac.linlin(0.0, 1.0, -1, 1); if (rate == \audio) { ^XFade2.ar(this, that, pan) }; if (that.rate == \audio) { ^XFade2.ar(that, this, pan.neg) }; ^LinXFade2.perform(LinXFade2.methodSelectorForRate(rate), this, that, pan) } } minNyquist { ^min(this, SampleRate.ir * 0.5) } lag { arg t1=0.1, t2; ^if(t2.isNil) { Lag.multiNew(this.rate, this, t1) } { LagUD.multiNew(this.rate, this, t1, t2) } } lag2 { arg t1=0.1, t2; ^if(t2.isNil) { Lag2.multiNew(this.rate, this, t1) } { Lag2UD.multiNew(this.rate, this, t1, t2) } } lag3 { arg t1=0.1, t2; ^if(t2.isNil) { Lag3.multiNew(this.rate, this, t1) } { Lag3UD.multiNew(this.rate, this, t1, t2) } } lagud { arg lagTimeU=0.1, lagTimeD=0.1; ^LagUD.multiNew(this.rate, this, lagTimeU, lagTimeD) } lag2ud { arg lagTimeU=0.1, lagTimeD=0.1; ^Lag2UD.multiNew(this.rate, this, lagTimeU, lagTimeD) } lag3ud { arg lagTimeU=0.1, lagTimeD=0.1; ^Lag3UD.multiNew(this.rate, this, lagTimeU, lagTimeD) } varlag { arg time=0.1, curvature=0, warp=5, start; ^VarLag.multiNew(this.rate, this, time, curvature, warp, start) } slew { arg up = 1, down = 1; ^Slew.multiNew(this.rate, this, up, down) } prune { arg min, max, type; switch(type, \minmax, { ^this.clip(min, max); }, \min, { ^this.max(min); }, \max, { ^this.min(max); } ); ^this } linlin { arg inMin, inMax, outMin, outMax, clip = \minmax; if (this.rate == \audio) { ^LinLin.ar(this.prune(inMin, inMax, clip), inMin, inMax, outMin, outMax) } { ^LinLin.kr(this.prune(inMin, inMax, clip), inMin, inMax, outMin, outMax) } } linexp { arg inMin, inMax, outMin, outMax, clip = \minmax; ^LinExp.multiNew(this.rate, this.prune(inMin, inMax, clip), inMin, inMax, outMin, outMax) } explin { arg inMin, inMax, outMin, outMax, clip = \minmax; ^(log(this.prune(inMin, inMax, clip)/inMin)) / (log(inMax/inMin)) * (outMax-outMin) + outMin; // no separate ugen yet } expexp { arg inMin, inMax, outMin, outMax, clip = \minmax; ^pow(outMax/outMin, log(this.prune(inMin, inMax, clip)/inMin) / log(inMax/inMin)) * outMin; } lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled, curvedResult; if (curve.isNumber and: { abs(curve) < 0.125 }) { ^this.linlin(inMin, inMax, outMin, outMax, clip) }; grow = exp(curve); a = outMax - outMin / (1.0 - grow); b = outMin + a; scaled = (this.prune(inMin, inMax, clip) - inMin) / (inMax - inMin); curvedResult = b - (a * pow(grow, scaled)); if (curve.rate == \scalar) { ^curvedResult } { ^Select.perform(this.methodSelectorForRate, abs(curve) >= 0.125, [ this.linlin(inMin, inMax, outMin, outMax, clip), curvedResult ]) } } curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax; var grow, a, b, scaled, linResult; if (curve.isNumber and: { abs(curve) < 0.125 }) { ^this.linlin(inMin, inMax, outMin, outMax, clip) }; grow = exp(curve); a = inMax - inMin / (1.0 - grow); b = inMin + a; linResult = log( (b - this.prune(inMin, inMax, clip)) / a ) * (outMax - outMin) / curve + outMin; if (curve.rate == \scalar) { ^linResult } { ^Select.perform(this.methodSelectorForRate, abs(curve) >= 0.125, [ this.linlin(inMin, inMax, outMin, outMax, clip), linResult ]) } } bilin { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax; ^Select.perform(this.methodSelectorForRate, this < inCenter, [ this.linlin(inCenter, inMax, outCenter, outMax, clip), this.linlin(inMin, inCenter, outMin, outCenter, clip) ] ) } moddif { |that = 0.0, mod = 1.0| ^ModDif.multiNew(this.rate, this, that, mod) } signalRange { ^\bipolar } @ { arg y; ^Point.new(this, y) } // dynamic geometry support addToSynth { synthDef = buildSynthDef; if (synthDef.notNil, { synthDef.addUGen(this) }); } collectConstants { inputs.do({ arg input; if (input.isNumber, { synthDef.addConstant(input.asFloat) }); }); } isValidUGenInput { ^true } asUGenInput { ^this } asControlInput { Error("can't set a control to a UGen").throw } numChannels { ^1 } checkInputs { ^this.checkValidInputs } checkValidInputs { inputs.do({arg in,i; var argName; if(in.isValidUGenInput.not,{ argName = this.argNameForInputAt(i) ? i; ^"arg: '" ++ argName ++ "' has bad input:" + in; }) }); ^nil } checkNInputs { arg n; if (rate == 'audio') { n.do {| i | if (inputs.at(i).rate != 'audio') { //"failed".postln; ^("input " ++ i ++ " is not audio rate: " + inputs.at(i) + inputs.at(0).rate); }; }; }; ^this.checkValidInputs } checkSameRateAsFirstInput { if (rate !== inputs.at(0).rate) { ^("first input is not" + rate + "rate: " + inputs.at(0) + inputs.at(0).rate); }; ^this.checkValidInputs } argNameForInputAt { arg i; var method = this.class.class.findMethod(this.methodSelectorForRate); if(method.isNil or: {method.argNames.isNil},{ ^nil }); ^method.argNames.at(i + this.argNamesInputsOffset) } argNamesInputsOffset { ^1 } dumpArgs { " ARGS:".postln; inputs.do({ arg in,ini; (" " ++ (this.argNameForInputAt(ini) ? ini.asString)++":" + in + in.class).postln }); } degreeToKey { arg scale, stepsPerOctave=12; ^DegreeToKey.kr(scale, this, stepsPerOctave) } outputIndex { ^0 } writesToBus { ^false } isUGen { ^true } poll { arg trig = 10, label, trigid = -1; ^Poll(trig, this, label, trigid) } dpoll { arg label, run = 1, trigid = -1; ^Dpoll(this, label, run, trigid) } checkBadValues { arg id = 0, post = 2; // add the UGen to the tree but keep "this" as the output CheckBadValues.perform(this.methodSelectorForRate, this, id, post); } *methodSelectorForRate { arg rate; if(rate == \audio,{ ^\ar }); if(rate == \control, { ^\kr }); if(rate == \scalar, { if(this.respondsTo(\ir),{ ^\ir },{ ^\new }); }); if(rate == \demand, { ^\new }); ^nil } *replaceZeroesWithSilence { arg array; // this replaces zeroes with audio rate silence. // sub collections are deep replaced var numZeroes, silentChannels, pos = 0; numZeroes = array.count({ arg item; item == 0.0 }); if (numZeroes == 0, { ^array }); silentChannels = Silent.ar(numZeroes).asCollection; array.do({ arg item, i; var res; if (item == 0.0, { array.put(i, silentChannels.at(pos)); pos = pos + 1; }, { if(item.isSequenceableCollection, { res = this.replaceZeroesWithSilence(item); array.put(i, res); }); }); }); ^array; } // PRIVATE // function composition composeUnaryOp { arg aSelector; ^UnaryOpUGen.new(aSelector, this) } composeBinaryOp { arg aSelector, anInput; if (anInput.isValidUGenInput, { ^BinaryOpUGen.new(aSelector, this, anInput) },{ anInput.performBinaryOpOnUGen(aSelector, this); }); } reverseComposeBinaryOp { arg aSelector, aUGen; ^BinaryOpUGen.new(aSelector, aUGen, this) } composeNAryOp { arg aSelector, anArgList; ^thisMethod.notYetImplemented } // complex support asComplex { ^Complex.new(this, 0.0) } performBinaryOpOnComplex { arg aSelector, aComplex; ^aComplex.perform(aSelector, this.asComplex) } if { arg trueUGen, falseUGen; ^(this * (trueUGen - falseUGen)) + falseUGen; } rateNumber { if (rate == \audio, { ^2 }); if (rate == \control, { ^1 }); if (rate == \demand, { ^3 }); ^0 // scalar } methodSelectorForRate { if(rate == \audio,{ ^\ar }); if(rate == \control, { ^\kr }); if(rate == \scalar, { if(this.class.respondsTo(\ir),{ ^\ir },{ ^\new }); }); if(rate == \demand, { ^\new }); ^nil } writeInputSpec { arg file, synthDef; file.putInt32(synthIndex); file.putInt32(this.outputIndex); } writeOutputSpec { arg file; file.putInt8(this.rateNumber); } writeOutputSpecs { arg file; this.writeOutputSpec(file); } numInputs { ^inputs.size } numOutputs { ^1 } name { ^this.class.name.asString; } writeDef { arg file; file.putPascalString(this.name); file.putInt8(this.rateNumber); file.putInt32(this.numInputs); file.putInt32(this.numOutputs); file.putInt16(this.specialIndex); // write wire spec indices. inputs.do({ arg input; input.writeInputSpec(file, synthDef); }); this.writeOutputSpecs(file); } initTopoSort { inputs.do({ arg input; if (input.isKindOf(UGen), { antecedents.add(input.source); input.source.descendants.add(this); }); }); widthFirstAntecedents.do({ arg ugen; antecedents.add(ugen); ugen.descendants.add(this); }) } makeAvailable { if (antecedents.size == 0, { synthDef.available = synthDef.available.add(this); }); } removeAntecedent { arg ugen; antecedents.remove(ugen); this.makeAvailable; } schedule { arg outStack; descendants.reverseDo({ arg ugen; ugen.removeAntecedent(this); }); ^outStack.add(this); } optimizeGraph {} dumpName { ^synthIndex.asString ++ "_" ++ this.class.name.asString } performDeadCodeElimination { if (descendants.size == 0) { this.inputs.do {|a| if (a.isKindOf(UGen)) { a.descendants.remove(this); a.optimizeGraph } }; buildSynthDef.removeUGen(this); ^true; }; ^false } } // ugen which has no side effect and can therefore be considered for a dead code elimination // read access to buffers/busses are allowed PureUGen : UGen { optimizeGraph { super.performDeadCodeElimination } } MultiOutUGen : UGen { // a class for UGens with multiple outputs var source, <>outputIndex, <>name; *new { arg rate, itsSourceUGen, index; ^super.new1(rate, itsSourceUGen, index) } addToSynth { synthDef = buildSynthDef; } init { arg argSource, argIndex; source = argSource; outputIndex = argIndex; synthIndex = source.synthIndex; } dumpName { ^this.source.dumpName ++ "[" ++ outputIndex ++ "]" } } SuperCollider-Source/SCClassLibrary/backwards_compatibility/PMOsc.sc000644 000765 000024 00000002365 12756534417 026723 0ustar00crucialstaff000000 000000 // these pseudo ugens replicate some SC2 ugens // still useful as shorthands PMOsc { *ar { arg carfreq,modfreq,pmindex=0.0,modphase=0.0,mul=1.0,add=0.0; ^SinOsc.ar(carfreq, SinOsc.ar(modfreq, modphase, pmindex),mul,add) } *kr { arg carfreq,modfreq,pmindex=0.0,modphase=0.0,mul=1.0,add=0.0; ^SinOsc.kr(carfreq, SinOsc.kr(modfreq, modphase, pmindex),mul,add) } } MultiTap { *ar { arg timesArray, levelsArray, in = 0.0, mul = 1.0, add = 0.0,bufnum; var sampleRate; timesArray = timesArray.dereference; levelsArray = levelsArray.dereference; RecordBuf.ar(in,bufnum,0.0, run: -1.0); sampleRate = BufSampleRate.kr(bufnum); ^Mix.fill(timesArray.size,{ arg i; PlayBuf.ar(in.numChannels, bufnum, -1.0,1.0, timesArray.at(i) * sampleRate, loop: 1) .madd(levelsArray.at(i) ? 1.0) }).madd(mul,add); } } /* GrainTap { // overlap determines density *ar { arg bufnum, grainDur = 0.2, pchRatio = 1.0, pchDispersion = 0.0, timeDispersion = 0.0, overlap = 2.0, mul = 1.0, add = 0.0; var sampleRate; sampleRate = BufSampleRate.kr(bufnum); pchRatio = pchRatio * BufRateScale.kr(bufnum); ^Mix.fill( howMany ? ,{ arg i; PlayBuf.ar(buf.numChannels, bufnum,1.0,1.0, loop: 1) }).madd(mul,add); } } */ SuperCollider-Source/QtCollider/CMakeLists.txt000644 000765 000024 00000014360 12756531745 022502 0ustar00crucialstaff000000 000000 cmake_minimum_required(VERSION 2.8.11) set(required_qt_version 5.2) find_package(Qt5Core) find_package(Qt5Widgets) find_package(Qt5Network) find_package(Qt5WebKit) find_package(Qt5WebKitWidgets) find_package(Qt5PrintSupport) find_package(Qt5OpenGL) find_package(Qt5Sensors) find_package(Qt5Quick) find_package(Qt5Qml) find_package(Qt5Sql) find_package(Qt5Positioning) mark_as_advanced(Qt5Concurrent_DIR Qt5Core_DIR Qt5Gui_DIR Qt5LinguistTools_DIR Qt5Location_DIR Qt5Network_DIR Qt5OpenGL_DIR Qt5Positioning_DIR Qt5PrintSupport_DIR Qt5Qml_DIR Qt5Quick_DIR Qt5Sensors_DIR Qt5Sql_DIR Qt5WebKitWidgets_DIR Qt5WebKit_DIR Qt5Widgets_DIR Qt5X11Extras_DIR) set (QT_COLLIDER_LIBS Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network Qt5::WebKit Qt5::WebKitWidgets Qt5::PrintSupport Qt5::OpenGL Qt5::Sensors Qt5::Quick Qt5::Qml Qt5::Sql Qt5::Positioning ${MATH_LIBRARY}) if (APPLE) find_package(Qt5MacExtras) mark_as_advanced(Qt5MacExtras_DIR) list(APPEND QT_COLLIDER_LIBS Qt5::MacExtras) endif() set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DQC_DEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DQC_DEBUG") set(QT_COLLIDER_DIR ${CMAKE_SOURCE_DIR}/QtCollider) include_directories( ${QT_COLLIDER_DIR} ) set( QT_COLLIDER_HDRS ${QT_COLLIDER_DIR}/QcApplication.h ${QT_COLLIDER_DIR}/QObjectProxy.h ${QT_COLLIDER_DIR}/QWidgetProxy.h ${QT_COLLIDER_DIR}/QtDownload.h ${QT_COLLIDER_DIR}/widgets/BasicWidgets.h ${QT_COLLIDER_DIR}/widgets/QcButton.h ${QT_COLLIDER_DIR}/widgets/QcCheckBox.h ${QT_COLLIDER_DIR}/widgets/QcTextField.h ${QT_COLLIDER_DIR}/widgets/QcListWidget.h ${QT_COLLIDER_DIR}/widgets/QcPopUpMenu.h ${QT_COLLIDER_DIR}/widgets/QcTreeWidget.h ${QT_COLLIDER_DIR}/widgets/QcScrollArea.h ${QT_COLLIDER_DIR}/widgets/QcNumberBox.h ${QT_COLLIDER_DIR}/widgets/QcSlider.h ${QT_COLLIDER_DIR}/widgets/QcSlider2D.h ${QT_COLLIDER_DIR}/widgets/QcRangeSlider.h ${QT_COLLIDER_DIR}/widgets/QcMultiSlider.h ${QT_COLLIDER_DIR}/widgets/QcKnob.hpp ${QT_COLLIDER_DIR}/widgets/QcTextEdit.h ${QT_COLLIDER_DIR}/widgets/QcScope.h ${QT_COLLIDER_DIR}/widgets/QcScopeShm.h ${QT_COLLIDER_DIR}/widgets/QcGraph.h ${QT_COLLIDER_DIR}/widgets/QcLevelIndicator.h ${QT_COLLIDER_DIR}/widgets/QcCanvas.h ${QT_COLLIDER_DIR}/widgets/soundfileview/view.hpp ${QT_COLLIDER_DIR}/widgets/QcFileDialog.h ${QT_COLLIDER_DIR}/widgets/QcPenPrinter.h ${QT_COLLIDER_DIR}/widgets/QcWebView.h ${QT_COLLIDER_DIR}/widgets/web_page.hpp ${QT_COLLIDER_DIR}/widgets/QcWindow.h ${QT_COLLIDER_DIR}/layouts/layouts.hpp ${QT_COLLIDER_DIR}/layouts/stack_layout.hpp ${QT_COLLIDER_DIR}/style/style.hpp ) set( QT_COLLIDER_SRCS ${QT_COLLIDER_DIR}/type_codec.cpp ${QT_COLLIDER_DIR}/metatype.cpp ${QT_COLLIDER_DIR}/debug.cpp ${QT_COLLIDER_DIR}/interface.cpp ${QT_COLLIDER_DIR}/factories.cpp ${QT_COLLIDER_DIR}/QcApplication.cpp ${QT_COLLIDER_DIR}/Common.cpp ${QT_COLLIDER_DIR}/QObjectProxy.cpp ${QT_COLLIDER_DIR}/QWidgetProxy.cpp ${QT_COLLIDER_DIR}/QcObjectFactory.cpp ${QT_COLLIDER_DIR}/QtDownload.cpp ${QT_COLLIDER_DIR}/hacks/hacks_x11.cpp ${QT_COLLIDER_DIR}/primitives/primitives.cpp ${QT_COLLIDER_DIR}/primitives/prim_QObject.cpp ${QT_COLLIDER_DIR}/primitives/prim_QPen.cpp ${QT_COLLIDER_DIR}/primitives/prim_misc.cpp ${QT_COLLIDER_DIR}/primitives/prim_QWidget.cpp ${QT_COLLIDER_DIR}/primitives/prim_QPalette.cpp ${QT_COLLIDER_DIR}/primitives/prim_QImage.cpp ${QT_COLLIDER_DIR}/widgets/BasicWidgets.cpp ${QT_COLLIDER_DIR}/widgets/QcButton.cpp ${QT_COLLIDER_DIR}/widgets/QcCheckBox.h ${QT_COLLIDER_DIR}/widgets/QcTextField.h ${QT_COLLIDER_DIR}/widgets/QcListWidget.cpp ${QT_COLLIDER_DIR}/widgets/QcPopUpMenu.cpp ${QT_COLLIDER_DIR}/widgets/QcTreeWidget.cpp ${QT_COLLIDER_DIR}/widgets/QcScrollArea.cpp ${QT_COLLIDER_DIR}/widgets/QcAbstractStepValue.cpp ${QT_COLLIDER_DIR}/widgets/QcNumberBox.cpp ${QT_COLLIDER_DIR}/widgets/QcSlider.cpp ${QT_COLLIDER_DIR}/widgets/QcSlider2D.cpp ${QT_COLLIDER_DIR}/widgets/QcRangeSlider.cpp ${QT_COLLIDER_DIR}/widgets/QcMultiSlider.cpp ${QT_COLLIDER_DIR}/widgets/QcKnob.cpp ${QT_COLLIDER_DIR}/widgets/QcTextEdit.cpp ${QT_COLLIDER_DIR}/widgets/QcScope.cpp ${QT_COLLIDER_DIR}/widgets/QcScopeShm.cpp ${QT_COLLIDER_DIR}/widgets/QcLevelIndicator.cpp ${QT_COLLIDER_DIR}/widgets/QcWindow.cpp ${QT_COLLIDER_DIR}/widgets/QcGraph.cpp ${QT_COLLIDER_DIR}/widgets/QcCanvas.cpp ${QT_COLLIDER_DIR}/widgets/soundfileview/view.cpp ${QT_COLLIDER_DIR}/widgets/soundfileview/filestream.cpp ${QT_COLLIDER_DIR}/widgets/soundfileview/cachestream.cpp ${QT_COLLIDER_DIR}/widgets/QcFileDialog.cpp ${QT_COLLIDER_DIR}/widgets/QcPenPrinter.cpp ${QT_COLLIDER_DIR}/widgets/QcWebView.cpp ${QT_COLLIDER_DIR}/widgets/web_page.cpp ${QT_COLLIDER_DIR}/layouts/layouts.cpp ${QT_COLLIDER_DIR}/layouts/stack_layout.cpp ${QT_COLLIDER_DIR}/style/ProxyStyle.cpp ${QT_COLLIDER_DIR}/style/style.cpp ) if(QT_COLLIDER_LANG_CLIENT) list(APPEND QT_COLLIDER_HDRS ${QT_COLLIDER_DIR}/LanguageClient.h) list(APPEND QT_COLLIDER_SRCS ${QT_COLLIDER_DIR}/LanguageClient.cpp) endif() set( QT_USE_QTWEBKIT TRUE ) qt5_wrap_cpp( QT_COLLIDER_MOC_SRCS ${QT_COLLIDER_HDRS} ) qt5_add_resources( QT_COLLIDER_RCC ${QT_COLLIDER_DIR}/resources.qrc ) if(APPLE) qt5_wrap_cpp( QT_COLLIDER_OBJ_MOC_SRCS ${QT_COLLIDER_DIR}/widgets/QcQuartzComposerView.h ) list(APPEND QT_COLLIDER_HDRS ${QT_COLLIDER_DIR}/widgets/QcQuartzComposerView.h ) set( QT_COLLIDER_OBJCPP_SRCS ${QT_COLLIDER_OBJ_MOC_SRCS} ${QT_COLLIDER_DIR}/hacks/hacks_mac.mm ${QT_COLLIDER_DIR}/widgets/QcQuartzComposerView.mm ${QT_COLLIDER_DIR}/primitives/prim_QQuartzComposer.mm ) endif() set_source_files_properties( ${QT_COLLIDER_OBJCPP_SRCS} PROPERTIES COMPILE_FLAGS "-x objective-c++ -fobjc-exceptions" ) list( APPEND QT_COLLIDER_SRCS ${QT_COLLIDER_OBJCPP_SRCS} ${QT_COLLIDER_MOC_SRCS} ${QT_COLLIDER_RCC} ) add_definitions(-DSC_QT -DQT_COLLIDER_EXPORTING -DQT_NO_KEYWORDS) if(APPLE) list(APPEND QT_COLLIDER_LIBS "-framework Cocoa" ) list(APPEND QT_COLLIDER_LIBS "-framework Quartz" ) list(APPEND QT_COLLIDER_LIBS "-framework AppKit" ) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -F/Library/Frameworks") endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(X11 REQUIRED) include_directories(X11_INCLUDE_DIR) list(APPEND QT_COLLIDER_LIBS ${X11_X11_LIB}) endif() SuperCollider-Source/QtCollider/Common.cpp000644 000765 000024 00000003403 12321461510 021646 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "Common.h" #include "metatype.hpp" #include #include #include // WARNING: QtCollider::lockLang() must be called before void QtCollider::runLang ( PyrObjectHdr *receiver, PyrSymbol *method, const QList & args, PyrSlot *result ) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, receiver); Q_FOREACH( QVariant var, args ) { ++g->sp; if( !QtCollider::set( g->sp, var ) ) { qcErrorMsg("Failed to write a slot when trying to run interpreter!"); SetNil( g->sp ); } } runInterpreter(g, method, args.size() + 1); g->canCallOS = false; if (result) slotCopy(result, &g->result); } int QtCollider::wrongThreadError () { qcErrorMsg( "You can not use this Qt functionality in the current thread. " "Try scheduling on AppClock instead." ); return errFailed; } SuperCollider-Source/QtCollider/Common.h000644 000765 000024 00000005415 12321461510 021320 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef _SC_QT_COMMON_H #define _SC_QT_COMMON_H #include "debug.h" #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE( PyrObject * ); Q_DECLARE_METATYPE( QVector ); Q_DECLARE_METATYPE( QVector ); namespace QtCollider { enum EventType { Event_SCRequest_Work = QEvent::User, Event_SCRequest_Tick, Event_SCRequest_Quit, Event_ScMethodCall, Event_Refresh, Event_Proxy_SetProperty, Event_Proxy_Destroy, Event_Proxy_BringFront, Event_Proxy_SetFocus, Event_Proxy_SetAlwaysOnTop, Event_Proxy_Release }; enum Synchronicity { Synchronous, Asynchronous }; inline void lockLang() { qcDebugMsg(2,"locking lang!"); gLangMutex.lock(); qcDebugMsg(2,"locked"); } inline void unlockLang() { gLangMutex.unlock(); qcDebugMsg(2,"unlocked"); } void runLang ( PyrObjectHdr *receiver, PyrSymbol *method, const QList & args = QList(), PyrSlot *result = 0 ); int wrongThreadError (); QPalette systemPalette(); #define QC_DO_SYMBOLS \ QC_DO_SYMBOL(interpretCmdLine); \ QC_DO_SYMBOL(interpretPrintCmdLine); \ QC_DO_SYMBOL(doFunction); \ QC_DO_SYMBOL(doDrawFunc); \ QC_DO_SYMBOL(prRelease); \ QC_DO_SYMBOL(Rect); \ QC_DO_SYMBOL(Point); \ QC_DO_SYMBOL(Color); \ QC_DO_SYMBOL(Size); \ QC_DO_SYMBOL(QPalette); \ QC_DO_SYMBOL(Font); \ QC_DO_SYMBOL(QObject); \ QC_DO_SYMBOL(Layout); \ QC_DO_SYMBOL(TreeViewItem); \ QC_DO_SYMBOL(Gradient); \ QC_DO_SYMBOL(HiliteGradient); \ QC_DO_SYMBOL(Image); #define QC_DO_SYMBOL(SYM) extern PyrSymbol * sym_##SYM QC_DO_SYMBOLS #undef QC_DO_SYMBOL #define SC_SYM( SYM ) QtCollider::sym_##SYM #define SC_CLASS( SYM ) SC_SYM(SYM)->u.classobj } #endif //_SC_QT_COMMON_H SuperCollider-Source/QtCollider/debug.cpp000644 000765 000024 00000002235 12524671172 021522 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "debug.h" #include static QAtomicInt& debugLevelInt() { static QAtomicInt *i = new QAtomicInt(0); return *i; } int QtCollider::debugLevel() { int l = debugLevelInt().load(); return l; } void QtCollider::setDebugLevel( int i ) { debugLevelInt() = i; } SuperCollider-Source/QtCollider/debug.h000644 000765 000024 00000003222 12756531745 021174 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ namespace QtCollider { int debugLevel(); void setDebugLevel( int ); } #include extern void postfl(const char *fmt, ...); extern void error(const char *fmt, ...); #ifdef QC_DEBUG #define qcDebugMsg( LEVEL, MSG ) \ if( LEVEL <= QtCollider::debugLevel() ) { \ postfl( "Qt: %s\n", QString(MSG).toStdString().c_str() ); \ } #else #define qcDebugMsg( LEVEL, MSG ) #endif #define qcSCObjectDebugMsg( LEVEL, OBJ, MSG ) \ qcDebugMsg( LEVEL, QStringLiteral("[%1] %2") \ .arg( OBJ ? slotRawSymbol( &OBJ->classptr->name )->name : "null" ) \ .arg(MSG) ) #define qcErrorMsg( MSG ) error( "Qt: %s\n", QString(MSG).toStdString().c_str() ) #define qcWarningMsg( MSG ) postfl( "Qt: %s\n", QString(MSG).toStdString().c_str() ) SuperCollider-Source/QtCollider/factories.cpp000644 000765 000024 00000004474 12756531745 022432 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcObjectFactory.h" #include "QcWidgetFactory.h" #include QC_DECLARE_QWIDGET_FACTORY( QLabel ); static void doLoadFactories () { QC_ADD_FACTORY( QcDefaultWidget ); QC_ADD_FACTORY( QcHLayoutWidget ); QC_ADD_FACTORY( QcVLayoutWidget ); QC_ADD_FACTORY( QLabel ); QC_ADD_FACTORY( QcTextField ); QC_ADD_FACTORY( QcCheckBox ); QC_ADD_FACTORY( QcListWidget ); QC_ADD_FACTORY( QcPopUpMenu ); QC_ADD_FACTORY( QcButton ); QC_ADD_FACTORY( QcCustomPainted ); QC_ADD_FACTORY( QcFileDialog ); QC_ADD_FACTORY( QcGraph ); QC_ADD_FACTORY( QcKnob ); QC_ADD_FACTORY( QcLevelIndicator ); QC_ADD_FACTORY( QcMultiSlider ); QC_ADD_FACTORY( QcNumberBox ); QC_ADD_FACTORY( QcPenPrinter ); QC_ADD_FACTORY( QcRangeSlider ); QC_ADD_FACTORY( QcScope ); QC_ADD_FACTORY( QcScopeShm ); QC_ADD_FACTORY( QcScrollWidget ); QC_ADD_FACTORY( QcScrollArea ); QC_ADD_FACTORY( QcSlider ); QC_ADD_FACTORY( QcSlider2D ); QC_ADD_FACTORY( QcWaveform ); QC_ADD_FACTORY( QcTextEdit ); QC_ADD_FACTORY( QcTreeWidget ); QC_ADD_FACTORY( WebView ); QC_ADD_FACTORY( QcWindow ); QC_ADD_FACTORY( QcScrollWindow ); QC_ADD_FACTORY( QcHBoxLayout ); QC_ADD_FACTORY( QcVBoxLayout ); QC_ADD_FACTORY( QcGridLayout ); QC_ADD_FACTORY( QcStackLayout ); QC_ADD_FACTORY( QtDownload ); #ifdef __APPLE__ QC_ADD_FACTORY( QcQuartzComposerView ); #endif } namespace QtCollider { void loadFactories() { doLoadFactories(); } } // namespace QtCollider SuperCollider-Source/QtCollider/hacks/000755 000765 000024 00000000000 13007315613 021007 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/image.h000644 000765 000024 00000011767 12321461510 021161 0ustar00crucialstaff000000 000000 /************************************************************************ * * This file is part of SuperCollider Qt GUI. * * Copyright 2013 Jakob Leben (jakob.leben@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QT_COLLIDER_IMAGE_INCLUDED #define QT_COLLIDER_IMAGE_INCLUDED #include #include #include #include #include #include namespace QtCollider { class Image { enum State { Null, ImageState, PixmapState }; public: Image(): m_state(Null), m_painting(false), transformationMode(Qt::FastTransformation) { } void setImage( const QImage & image ) { assert(!m_painting); m_pixmap = QPixmap(); m_image = image; m_state = ImageState; } void setPixmap( const QPixmap & pixmap ) { assert(!m_painting); m_image = QImage(); m_pixmap = pixmap; m_state = PixmapState; } QImage & image() { if (m_state == ImageState) return m_image; assert(!m_painting); if (m_state == PixmapState) { m_image = m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); m_pixmap = QPixmap(); } m_state = ImageState; return m_image; } QPixmap & pixmap() { assert(!m_painting); if (m_state == PixmapState) return m_pixmap; if (m_state == ImageState) { m_pixmap = QPixmap::fromImage(m_image); m_image = QImage(); } m_state = PixmapState; return m_pixmap; } void clear() { assert(!m_painting); m_image = QImage(); m_pixmap = QPixmap(); m_state = Null; } bool isNull() const { return m_state == Null; } int width() const { switch (m_state) { case ImageState: return m_image.width(); case PixmapState: return m_pixmap.width(); default: return 0; } } int height() const { switch (m_state) { case ImageState: return m_image.height(); case PixmapState: return m_pixmap.height(); default: return 0; } } QRect rect() const { switch (m_state) { case ImageState: return m_image.rect(); case PixmapState: return m_pixmap.rect(); default: return QRect(); } } void resize( const QSize &new_size, int resize_mode ) { assert(!m_painting); if (m_state == Null) return; switch (resize_mode) { case 0: { if (m_state == ImageState) { QImage new_image( new_size, QImage::Format_ARGB32_Premultiplied ); new_image.fill( Qt::transparent ); QPainter painter(&new_image); painter.drawImage( QPointF(0,0), m_image ); painter.end(); m_image = new_image; } else { QPixmap new_pixmap( new_size ); new_pixmap.fill( Qt::transparent ); QPainter painter(&new_pixmap); painter.drawPixmap( QPointF(0,0), m_pixmap ); painter.end(); m_pixmap = new_pixmap; } break; } case 1: case 2: case 3: { Qt::AspectRatioMode aspectRatioMode = (Qt::AspectRatioMode)(resize_mode - 1); if (m_state == ImageState) { m_image = m_image.scaled( new_size, aspectRatioMode, transformationMode ); } else { m_pixmap = m_pixmap.scaled( new_size, aspectRatioMode, transformationMode ); } break; } default: break; } } bool isPainting() const { return m_painting; } void setPainting( bool painting ) { m_painting = painting; } Qt::TransformationMode transformationMode; private: QImage m_image; QPixmap m_pixmap; State m_state; bool m_painting; }; typedef QSharedPointer SharedImage; } // namespace QtCollider Q_DECLARE_METATYPE( QtCollider::SharedImage ); #endif // QT_COLLIDER_IMAGE_INCLUDED SuperCollider-Source/QtCollider/interface.cpp000644 000765 000024 00000005015 12724357043 022373 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QtCollider.h" #include "QcApplication.h" #include "Common.h" #include "style/ProxyStyle.hpp" #include "style/style.hpp" #include "metatype.hpp" #include #include #include #include #ifdef Q_WS_X11 # include #endif #include namespace QtCollider { void loadFactories (); } inline void initResources() { Q_INIT_RESOURCE(resources); } static QPalette gSystemPalette; QPalette QtCollider::systemPalette() { return gSystemPalette; } void QtCollider::init() { if( !QApplication::instance() ) { qcDebugMsg( 1, "Initializing QtCollider" ); initResources(); QtCollider::loadFactories(); QtCollider::MetaType::initAll(); QLocale::setDefault( QLocale::c() ); #ifdef Q_WS_X11 XInitThreads(); #endif #ifdef Q_OS_MAC QApplication::setAttribute( Qt::AA_MacPluginApplication, true ); #endif static int qcArgc = 1; static char qcArg0[] = "SuperCollider"; static char *qcArgv[1] = {qcArg0}; QcApplication *qcApp = new QcApplication( qcArgc, qcArgv ); qcApp->setQuitOnLastWindowClosed( false ); //qcApp->setStyle( new QtCollider::Style::StyleImpl( new QPlastiqueStyle ) ); gSystemPalette = qcApp->palette(); // Enable javascript localStorage for WebViews QWebSettings::globalSettings()->setAttribute( QWebSettings::LocalStorageEnabled, true ); // NOTE: Qt may tamper with the C language locale, affecting POSIX number-string conversions. // Revert the locale to default: setlocale( LC_NUMERIC, "C" ); } } int QtCollider::exec( int argc, char** argv ) { QtCollider::init(); Q_ASSERT( qApp ); return qApp->exec(); } SuperCollider-Source/QtCollider/LanguageClient.cpp000644 000765 000024 00000005540 12756531745 023330 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "LanguageClient.h" #include "QcApplication.h" #include "QtCollider.h" #include "QObjectProxy.h" #include #include #include #include extern double elapsedTime(); using namespace QtCollider; LangClient::LangClient( const char* name ) : SC_TerminalClient( name ) { } void LangClient::commandLoop() { int exit_code = QcApplication::instance()->exec(); SC_TerminalClient::quit(exit_code); } void LangClient::daemonLoop() { commandLoop(); } void LangClient::sendSignal( Signal sig ) { if (sig == sig_sched) { QApplication::postEvent( this, new SCRequestEvent(Event_SCRequest_Tick) ); } else { SC_TerminalClient::sendSignal( sig ); QApplication::postEvent( this, new SCRequestEvent(Event_SCRequest_Work) ); } } void LangClient::onQuit( int exitCode ) { QApplication::postEvent( this, new SCRequestEvent( Event_SCRequest_Quit, exitCode ) ); } void LangClient::onLibraryShutdown() { QWidgetList windows = QApplication::topLevelWidgets(); Q_FOREACH( QWidget *w, windows ) w->hide(); } void LangClient::customEvent( QEvent *e ) { int type = e->type(); switch( type ) { case Event_SCRequest_Tick: tick(); case Event_SCRequest_Work: QApplication::removePostedEvents( this, Event_SCRequest_Work ); mIoService.poll(); break; case Event_SCRequest_Quit: { int code = static_cast(e)->data.toInt(); qcDebugMsg( 1, QStringLiteral("Quit requested with code %1").arg(code) ); qApp->exit( code ); break; } default: ; } } void LangClient::tick() { double secs; lock(); bool haveNext = tickLocked( &secs ); unlock(); flush(); if( haveNext ) { secs -= elapsedTime(); secs *= 1000; int ti = qMax(0, qCeil(secs)); qcDebugMsg(2, QStringLiteral("next at %1").arg(ti) ); appClockTimer.start( ti, this ); } else appClockTimer.stop(); } void LangClient::timerEvent(QTimerEvent * e) { if( e->timerId() == appClockTimer.timerId() ) tick(); } SuperCollider-Source/QtCollider/LanguageClient.h000644 000765 000024 00000003421 12321461510 022745 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_LANGUAGE_CLIENT_H #define QC_LANGUAGE_CLIENT_H #include "SC_TerminalClient.h" #include "Common.h" #include #include #include namespace QtCollider { struct SCRequestEvent : public QEvent { SCRequestEvent( QtCollider::EventType type, const QVariant & d = QVariant() ) : QEvent( (QEvent::Type) type ), data( d ) {} QVariant data; }; class LangClient : public QObject, public SC_TerminalClient { Q_OBJECT public: LangClient( const char* name ); virtual ~LangClient() {} virtual void sendSignal( Signal ); protected: virtual void commandLoop(); virtual void daemonLoop(); virtual void onQuit( int exitCode ); virtual void onLibraryShutdown(); virtual void customEvent( QEvent * ); virtual void timerEvent( QTimerEvent * ); private: void tick(); QBasicTimer appClockTimer; }; } // namespace QtCollider #endif // QC_LANGUAGE_CLIENT_H SuperCollider-Source/QtCollider/layouts/000755 000765 000024 00000000000 13007315613 021416 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/metatype.cpp000644 000765 000024 00000011502 12756531745 022271 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 - 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "metatype.hpp" #include "type_codec.hpp" #include "Common.h" // Make sure PyrObject* is declared to QMetaType #include namespace QtCollider { static QVector gMetaTypes; template MetaTypeImpl * MetaTypeImpl::instance = 0; template void qc_init_metatype() { MetaTypeImpl::instance = new MetaTypeImpl(); gMetaTypes.append( MetaTypeImpl::instance ); } void MetaType::initAll() { qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType< QVector >(); qRegisterMetaType< QVector >(); qRegisterMetaType(); gMetaTypes.reserve(20); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype(); qc_init_metatype< QVector >(); qc_init_metatype< QVector >(); qc_init_metatype< QVariantList >(); } MetaType *MetaType::find( PyrSlot *slot ) { switch (GetTag(slot)) { case tagNil : return 0; case tagInt : return metaType(); case tagSym : return metaType(); case tagChar : return metaType(); case tagFalse : case tagTrue : return metaType(); case tagObj : { PyrObject *obj = slotRawObject(slot); PyrClass *klass = obj->classptr; unsigned char format = obj->obj_format; if( format == obj_double || format == obj_float ) return metaType< QVector >(); else if( format == obj_int32 || format == obj_int16 || format == obj_int8 ) return metaType< QVector >(); else if( isKindOfSlot( slot, class_string ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(Point) ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(Rect) ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(Size) ) ) { return metaType(); } else if( klass == SC_CLASS(Color) || klass == SC_CLASS(Gradient) || klass == SC_CLASS(HiliteGradient) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(Font) ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(QPalette) ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(QObject) ) ) { return metaType(); } else if( isKindOfSlot( slot, class_array ) || isKindOfSlot( slot, class_symbolarray ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(TreeViewItem) ) ) { return metaType(); } else if( isKindOfSlot( slot, SC_CLASS(Image) ) ) { return metaType(); } else { QString className = TypeCodec::read( &slotRawObject(slot)->classptr->name ); qcWarningMsg(QStringLiteral("WARNING: Do not know how to use an instance of class '%1'").arg(className)); return 0; } } default: return metaType(); } } MetaType * MetaType::find( int id ) { int n = gMetaTypes.count(); MetaType * const * d = gMetaTypes.constData(); int i; for(i = 0; i < n; ++i) { if((*d)->mId == id) return *d; ++d; } return 0; } } // namespace QtCollider SuperCollider-Source/QtCollider/metatype.hpp000644 000765 000024 00000010733 12321461510 022257 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 - 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QT_COLLIDER_META_TYPE_INCLUDED #define QT_COLLIDER_META_TYPE_INCLUDED #include "type_codec.hpp" #include #include #include namespace QtCollider { template struct TypeCodec; struct MetaType { public: static void initAll(); static MetaType *find( PyrSlot * ); static MetaType *find( int id ); // Generic algorithms template static void * read( PyrSlot *slot, void *ptr ) { if(slot) return new(ptr) T( TypeCodec::read(slot) ); else return new(ptr) T(); } template static QVariant read( PyrSlot *slot ) { return QVariant::fromValue( TypeCodec::read(slot) ); } template static void write( PyrSlot *slot, void *ptr ) { TypeCodec::write( slot, *reinterpret_cast(ptr) ); } template static void write( PyrSlot *slot, const QVariant & var ) { TypeCodec::write( slot, var.value() ); } template static void destruct( void *ptr ) { T *typed_ptr = reinterpret_cast(ptr); typed_ptr->~T(); } // Abstract access to generic algorithms virtual size_t size() = 0; virtual void * read( PyrSlot *, void *ptr ) = 0; virtual QVariant read( PyrSlot * ) = 0; virtual void write( PyrSlot *, void *ptr ) = 0; virtual void write( PyrSlot *, const QVariant & ) = 0; virtual void destruct( void *ptr ) = 0; const int & id() const { return mId; } protected: MetaType(int a_id): mId(a_id) {} int mId; }; template struct MetaTypeImpl : MetaType { MetaTypeImpl(): MetaType( qMetaTypeId() ) {} size_t size() { return sizeof(T); } void * read( PyrSlot *slot, void *ptr ) { return MetaType::read(slot, ptr); } QVariant read( PyrSlot *slot ) { return MetaType::read(slot); } void write( PyrSlot *slot, void *ptr ) { MetaType::write(slot, ptr); } void write( PyrSlot *slot, const QVariant & var ) { MetaType::write(slot, var); } void destruct( void *ptr ) { MetaType::destruct(ptr); } ///////////// static MetaTypeImpl * instance; }; class MetaValue { public: MetaValue() : mType(0), mData(0) {} ~MetaValue() { if( mType ) mType->destruct(mData); } MetaType *type() const { return mType; } void read( void *mem, MetaType * type, PyrSlot * slot ) { mData = mem; mType = type; mType->read( slot, mData ); } void write( PyrSlot *slot ) { if (mType) mType->write(slot, mData); } template T value() { if( mType && qMetaTypeId() == mType->id() ) return *reinterpret_cast(mData); else return T(); } QGenericArgument toGenericArgument() { if(mType) return QGenericArgument( QMetaType::typeName(mType->id()), mData ); else return QGenericArgument(); } QGenericReturnArgument toGenericReturnArgument() { if(mType) return QGenericReturnArgument( QMetaType::typeName(mType->id()), mData ); else return QGenericReturnArgument(); } private: MetaType *mType; void *mData; }; template inline MetaType *metaType() { return MetaTypeImpl::instance; } template<> struct TypeCodec { static QVariant safeRead( PyrSlot * slot ) { MetaType *mt = MetaType::find(slot); return mt ? mt->read(slot) : QVariant(); } }; inline bool set( PyrSlot *s, const QVariant &var ) { MetaType *mt = MetaType::find(var.userType()); if(!mt) return false; mt->write(s, var); return true; } } // namespace QtCollider #endif // QT_COLLIDER_META_TYPE_INCLUDED SuperCollider-Source/QtCollider/painting.h000644 000765 000024 00000002500 12756531745 021715 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_PAINTING_H #define QC_PAINTING_H class QPainter; class QWidget; class QObject; namespace QtCollider { // WARNING these can be called only from Qt thread (no locking needed): void announcePainting(); bool paintingAnnounced(); // WARNING language must be locked to call these: bool beginPainting( QPainter *, QObject* obj = 0 ); void endPainting(); bool isPaintingObject( QObject* obj ); QPainter * globalPainter(); } #endif SuperCollider-Source/QtCollider/primitives/000755 000765 000024 00000000000 13007315613 022111 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/QcApplication.cpp000644 000765 000024 00000010212 12756531745 023165 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcApplication.h" #include "widgets/QcTreeWidget.h" #include #include #include #include #include #include #include #include #include #ifdef Q_OS_MAC #include "../../common/SC_Apple.hpp" #endif extern bool compiledOK; extern const char * gIdeName; QcApplication * QcApplication::_instance = 0; QMutex QcApplication::_mutex; #ifdef Q_WS_X11 #include #endif /* on x11, we need to check, if we can actually connect to the X server */ static bool QtColliderUseGui(void) { #ifdef Q_WS_X11 Display *dpy = XOpenDisplay(NULL); if (!dpy) return false; XCloseDisplay(dpy); return true; #else return true; #endif } // undefine some interfering X11 definitions #undef KeyPress bool QcApplication::_systemHasMouseWheel = false; QcApplication::QcApplication( int & argc, char ** argv ) : QApplication( argc, argv, QtColliderUseGui() ) { _mutex.lock(); _instance = this; _mutex.unlock(); if (QtColliderUseGui()) { // avoid a crash on linux, if x is not available QIcon icon; icon.addFile(":/icons/sc-cube-128"); icon.addFile(":/icons/sc-cube-48"); icon.addFile(":/icons/sc-cube-32"); icon.addFile(":/icons/sc-cube-16"); setWindowIcon(icon); } #ifdef Q_OS_MAC // On Mac, we may need to disable "App Nap", so we aren't put to sleep unexpectedly SC::Apple::disableAppNap(); #endif _handleCmdPeriod = strcmp(gIdeName, "scapp") != 0; } QcApplication::~QcApplication() { _mutex.lock(); _instance = 0; _mutex.unlock(); } bool QcApplication::compareThread() { return gMainVMGlobals->canCallOS; } void QcApplication::interpret( const QString &str, bool print ) { QtCollider::lockLang(); if( compiledOK ) { VMGlobals *g = gMainVMGlobals; PyrString *strObj = newPyrString( g->gc, str.toStdString().c_str(), 0, true ); SetObject(&slotRawInterpreter(&g->process->interpreter)->cmdLine, strObj); g->gc->GCWriteNew(slotRawObject(&g->process->interpreter), strObj); // we know strObj is white so we can use GCWriteNew runLibrary( print ? SC_SYM(interpretPrintCmdLine) : SC_SYM(interpretCmdLine) ); } QtCollider::unlockLang(); } bool QcApplication::event( QEvent *event ) { switch (event->type()) { case QEvent::FileOpen: { // open the file dragged onto the application icon on Mac QFileOpenEvent *fe = static_cast(event); interpret( QStringLiteral("Document.open(\"%1\")").arg(fe->file()), false ); event->accept(); return true; } default: break; } return QApplication::event( event ); } bool QcApplication::notify( QObject * object, QEvent * event ) { switch (event->type()) { case QEvent::KeyPress: { QKeyEvent *kevent = static_cast(event); if ( _handleCmdPeriod && (kevent->key() == Qt::Key_Period) && (kevent->modifiers() & Qt::ControlModifier) ) { static QString cmdPeriodCommand("CmdPeriod.run"); interpret(cmdPeriodCommand, false); } break; } case QEvent::Wheel: { _systemHasMouseWheel = true; break; } default: break; } return QApplication::notify( object, event ); } SuperCollider-Source/QtCollider/QcApplication.h000644 000765 000024 00000004061 12756531745 022637 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_APPLICATION_H #define QC_APPLICATION_H #include "Common.h" #include #include #include namespace QtCollider { class EventProcessor : public QObject { public: void work() { QApplication::postEvent( this, new QEvent(QEvent::User) ); _loop.exec(); } void customEvent( QEvent *e ) { _loop.exit(); } private: QEventLoop _loop; }; } // namespace QtCollider class QcApplication : public QApplication { Q_OBJECT public: QcApplication( int & argc, char ** argv ); virtual ~QcApplication(); static bool compareThread(); // NOTE: language must be locked static void processEvents() { if( _instance ) _instance->_eventProc.work(); } static inline bool SystemHasMouseWheel() { return _systemHasMouseWheel; } public Q_SLOTS: void interpret( const QString & code, bool printResult = true ); protected: virtual bool event( QEvent * ); virtual bool notify( QObject *, QEvent * ); private: QtCollider::EventProcessor _eventProc; static QMutex _mutex; static QcApplication *_instance; static bool _systemHasMouseWheel; bool _handleCmdPeriod; }; #endif // QC_APPLICATION_H SuperCollider-Source/QtCollider/QcHelper.h000644 000765 000024 00000001036 12321461510 021566 0ustar00crucialstaff000000 000000 #ifndef QC_HELPER #define QC_HELPER #include "Common.h" #include #include #include #include struct QcHelper { protected: QcHelper() {} float dummyFloat() const { return 0; } int dummyInt() const { return 0; } bool dummyBool() const { return false; } QString dummyString() const { return QString(); } QColor dummyColor() const { return QColor(); } QFont dummyFont() const { return QFont(); } QVariantList dummyVariantList() const { return QVariantList(); } }; #endif SuperCollider-Source/QtCollider/QcObjectFactory.cpp000644 000765 000024 00000002065 12321461510 023443 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcObjectFactory.h" namespace QtCollider { QcFactoryHash & factories () { static QcFactoryHash *factoryHash = new QcFactoryHash(); return *factoryHash; } } SuperCollider-Source/QtCollider/QcObjectFactory.h000644 000765 000024 00000006776 12756531745 023151 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_OBJECT_FACTORY_H #define QC_OBJECT_FACTORY_H #include "QObjectProxy.h" #include "Common.h" #include "metatype.hpp" #include #include #include #include #include class QcAbstractFactory; typedef QHash QcFactoryHash; namespace QtCollider { QcFactoryHash & factories (); } class QcAbstractFactory { public: virtual const QMetaObject *metaObject() = 0; virtual QObjectProxy *newInstance( PyrObject *, QtCollider::MetaValue arg[10] ) = 0; }; static void qcNoConstructorMsg( const QMetaObject *metaObject, int argc, QtCollider::MetaValue *argv ) { QString str = QStringLiteral("No appropriate constructor found for %1 (") .arg( metaObject->className() ); for (int i = 0; i < argc; ++i) { MetaType *type = argv[i].type(); if (type) { if (i > 0) str += ", "; str += QMetaType::typeName( type->id() ); } else break; } str += ")"; qcErrorMsg( str ); } template class QcObjectFactory : public QcAbstractFactory { public: const QMetaObject *metaObject() { return &QOBJECT::staticMetaObject; } virtual QObjectProxy *newInstance( PyrObject *scObject, QtCollider::MetaValue arg[10] ) { QOBJECT *qObject; if( !arg[0].type() ) { qObject = new QOBJECT; } else { QObject *obj = QOBJECT::staticMetaObject.newInstance( arg[0].toGenericArgument(), arg[1].toGenericArgument(), arg[2].toGenericArgument(), arg[3].toGenericArgument(), arg[4].toGenericArgument(), arg[5].toGenericArgument(), arg[6].toGenericArgument(), arg[7].toGenericArgument(), arg[8].toGenericArgument(), arg[9].toGenericArgument() ); qObject = qobject_cast(obj); if( !qObject ) { qcNoConstructorMsg( metaObject(), 10, arg ); return 0; } } return proxy( qObject, scObject ); } protected: virtual QObjectProxy *proxy( QOBJECT *obj, PyrObject *sc_obj ) { QObjectProxy *prox( new QObjectProxy(obj, sc_obj) ); initialize( prox, obj ); return prox; } virtual void initialize( QObjectProxy *proxy, QOBJECT *obj ) {}; }; #define QC_DECLARE_FACTORY( QOBJECT, FACTORY ) \ void add_factory_##QOBJECT () { \ QcAbstractFactory *factory = new FACTORY; \ factories().insert( factory->metaObject()->className(), factory ); \ } #define QC_DECLARE_QOBJECT_FACTORY( QOBJECT ) QC_DECLARE_FACTORY( QOBJECT, QcObjectFactory ) #define QC_ADD_FACTORY( QOBJECT ) \ void add_factory_##QOBJECT(); \ add_factory_##QOBJECT() #endif //QC_OBJECT_FACTORY_H SuperCollider-Source/QtCollider/QcSignalSpy.h000644 000765 000024 00000011511 12524671172 022273 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SIGNALSPY_H #define QC_SIGNALSPY_H #include "Common.h" #include "QObjectProxy.h" #include #include #include #include #include #include #include #include #include #include class QcSignalSpy: public QObject { public: QcSignalSpy( QObjectProxy *proxy, const char *sigName, Qt::ConnectionType conType = Qt::QueuedConnection ) : QObject( proxy ), _proxy( proxy ), _sigId( -1 ) { Q_ASSERT( sigName ); const QMetaObject *mo = _proxy->object()->metaObject(); QByteArray signal = QMetaObject::normalizedSignature( sigName ); int sigId = mo->indexOfSignal( signal ); if( sigId < 0 ) { qcDebugMsg( 0, QString("WARNING: No such signal to connect: '%1'").arg(signal.constData()) ); return; } int slotId = QObject::staticMetaObject.methodCount(); if( !QMetaObject::connect( _proxy->object(), sigId, this, slotId, conType, 0) ) { qcErrorMsg( "QMetaObject::connect returned false. Unable to connect." ); return; } QMetaMethod mm = mo->method( sigId ); QList params = mm.parameterTypes(); for( int i = 0; i < params.count(); ++i ) { int type = QMetaType::type( params.at(i).constData() ); if( type == QMetaType::Void ) qcErrorMsg( QString("QObject:connect: Don't know how to handle '%1', " "use qRegisterMetaType to register it.") .arg(params.at(i).constData()) ); _argTypes << type; } _sigId = sigId; } int qt_metacall( QMetaObject::Call call, int methodId, void **argData ) { methodId = QObject::qt_metacall( call, methodId, argData ); if( methodId < 0 ) return methodId; if( call == QMetaObject::InvokeMetaMethod ) { Q_ASSERT( methodId == 0 ); QList args; args.reserve( _argTypes.count() ); for (int i = 0; i < _argTypes.count(); ++i) { QMetaType::Type type = static_cast(_argTypes.at(i)); args << QVariant( type, argData[i + 1] ); } react( args ); methodId = -1; } return methodId; } inline int indexOfSignal () const { return _sigId; } inline bool isValid () const { return _sigId > 0; } protected: virtual void react( QList & args ) = 0; QObjectProxy *_proxy; int _sigId; QList _argTypes; }; class QcMethodSignalHandler : public QcSignalSpy { public: QcMethodSignalHandler( QObjectProxy *proxy, const char *sigName, PyrSymbol *handler, Qt::ConnectionType conType = Qt::QueuedConnection ) : QcSignalSpy( proxy, sigName, conType ), _handler( handler ) { } inline PyrSymbol *method() { return _handler; } protected: virtual void react( QList & args ) { qcDebugMsg( 1, QString("SIGNAL: '%1' handled by method '%2'") .arg( _proxy->object() ? QString(_proxy->object()->metaObject()->method( _sigId ).methodSignature()) : "unknown" ) .arg(_handler->name) ); _proxy->invokeScMethod( _handler, args ); } PyrSymbol * _handler; }; class QcFunctionSignalHandler : public QcSignalSpy { public: QcFunctionSignalHandler( QObjectProxy *proxy, const char *sigName, PyrObject *handler, Qt::ConnectionType conType = Qt::QueuedConnection ) : QcSignalSpy( proxy, sigName, conType ), _handler( handler ) { } inline PyrObject *function() { return _handler; } protected: virtual void react( QList & args ) { qcDebugMsg( 1, QString("SIGNAL: '%1' handled by a Function") .arg( _proxy->object() ? QString(_proxy->object()->metaObject()->method( _sigId ).methodSignature()) : "unknown" ) ); args.prepend( QVariant::fromValue( _handler ) ); _proxy->invokeScMethod( SC_SYM(doFunction), args ); } PyrObject * _handler; }; #endif //QC_SIGNALSPY_H SuperCollider-Source/QtCollider/QcWidgetFactory.h000644 000765 000024 00000007065 12321461510 023132 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_WIDGET_FACTORY_H #define QC_WIDGET_FACTORY_H #include "QcObjectFactory.h" #include "QWidgetProxy.h" #include #include template class QcWidgetFactory : public QcObjectFactory { public: virtual QObjectProxy *newInstance( PyrObject *scObject, QtCollider::MetaValue arg[10] ) { // Omit the first two arguments - parent and bounds QWIDGET *w; if( !arg[2].type() ) { w = new QWIDGET; } else { QObject *obj = QWIDGET::staticMetaObject.newInstance( arg[2].toGenericArgument(), arg[3].toGenericArgument(), arg[4].toGenericArgument(), arg[5].toGenericArgument(), arg[6].toGenericArgument(), arg[7].toGenericArgument(), arg[8].toGenericArgument(), arg[9].toGenericArgument() ); w = qobject_cast(obj); if( !w ) { qcNoConstructorMsg( QcObjectFactory::metaObject(), 8, &arg[2] ); return 0; } } // NOTE: performance: it is completely equal if parent is passed // in constructor, or set later, but for some reason it is cheaper // if it is set here, before setting other stuff like geometry, etc. QObjectProxy *parentProxy( arg[0].value() ); QWidget *parent = parentProxy ? qobject_cast( parentProxy->object() ) : 0; if( parent ) { const QMetaObject *mo = parent->metaObject(); int mi = mo->indexOfMethod( "addChild(QWidget*)" ); bool ok; if( mi >= 0 ) { QMetaMethod mm = mo->method( mi ); ok = mm.invoke( parent, Q_ARG(QWidget*, w) ); if(!ok) { qcErrorMsg("Could not set parent!"); delete w; return 0; } } else { if(parent->layout()) parent->layout()->addWidget(w); else w->setParent( parent ); } } // set requested geometry QRect r( arg[1].value().toRect() ); if( r.size().isEmpty() ) r.setSize( w->sizeHint() ); w->setGeometry( r ); // automatically support drag and drop w->setAcceptDrops( true ); // ensure visible: if(parent && parent->isVisible()) w->show(); // create the proxy: QObjectProxy *prox( proxy(w, scObject) ); return prox; } protected: virtual QObjectProxy * proxy( QWIDGET *w, PyrObject *sc_obj ) { QWidgetProxy *prox( new QWidgetProxy( w, sc_obj ) ); initialize( prox, w ); return prox; } virtual void initialize( QWidgetProxy *proxy, QWIDGET *obj ) {}; }; #define QC_DECLARE_QWIDGET_FACTORY( QWIDGET ) QC_DECLARE_FACTORY( QWIDGET, QcWidgetFactory ) #endif SuperCollider-Source/QtCollider/QObjectProxy.cpp000644 000765 000024 00000035401 12756531745 023036 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include "QObjectProxy.h" #include "QcApplication.h" #include "Common.h" #include "QcSignalSpy.h" #include "type_codec.hpp" #include "metatype.hpp" #include #include #include #include #include #include #ifdef _WIN32 # include "SC_Win32Utils.h" #else # include #endif using namespace QtCollider; void interpretMouseEvent( QEvent *e, QList &args ); void interpretKeyEvent( QEvent *e, QList &args ); QObjectProxy::QObjectProxy( QObject *qObject_, PyrObject *scObject_ ) : qObject( qObject_ ), _scObject( scObject_ ), _scClassName( slotRawSymbol( &scObject_->classptr->name )->name ) { ProxyToken *token = new ProxyToken( this, qObject ); // WARNING: make sure the signal is already in normalized signature, // to avoid triggering very expensive normalization! connect( qObject, SIGNAL(destroyed(QObject*)), this, SLOT(invalidate()) ); qObject->installEventFilter( this ); _eventHandlers.reserve(10); } QObjectProxy::~QObjectProxy() { qcProxyDebugMsg( 1, QStringLiteral("Proxy is being deleted.") ); } bool QObjectProxy::compareThread() { return gMainVMGlobals->canCallOS; } void QObjectProxy::invalidate() { qcProxyDebugMsg( 1, QStringLiteral("Object has been deleted. Invalidating proxy.") ); mutex.lock(); qObject = 0; mutex.unlock(); QApplication::postEvent( this, new QEvent((QEvent::Type) QtCollider::Event_Proxy_Release) ); } static bool serializeSignature( QVarLengthArray & dst, const char *method, int argc, MetaValue *argv ) { // serialize method name int len = qstrlen( method ); if( len <= 0 ) { qcErrorMsg("Method name appears to be empty."); return false; } dst.append( method, len ); dst.append( '(' ); // serialize argument types int i; for( i = 0; i < argc; ++i ) { int typeId = argv[i].type()->id(); const char *typeName = QMetaType::typeName( typeId ); int len = qstrlen( typeName ); if( len <= 0 ) { qcErrorMsg("Could not get argument type name."); return false; } dst.append( typeName, len ); dst.append( ',' ); } // finalize the signature if( i==0 ) dst.append( ')' ); else dst[dst.size() - 1] = ')'; dst.append('\0'); return true; } bool QObjectProxy::invokeMethod( const char *method, PyrSlot *retSlot, PyrSlot *argSlot, Qt::ConnectionType ctype ) { QMutexLocker locker(&mutex); if( !qObject ) return true; MetaValue args[10]; PyrSlot *argslots; int argc; if( isKindOfSlot( argSlot, class_array ) ) { argslots = slotRawObject( argSlot )->slots; argc = slotRawObject( argSlot )->size; } else if(argSlot && NotNil(argSlot)) { argslots = argSlot; argc = 1; } else { argslots = 0; argc = 0; } // translate args for( int i = 0; i < argc; ++i ) { MetaType *type = MetaType::find(argslots + i); if(!type) return false; void *mem = alloca(type->size()); if(!mem) { qcErrorMsg("Could not allocate stack space for argument!"); return false; } args[i].read(mem, type, argslots + i); } // serialize signature QVarLengthArray sig; if ( !serializeSignature( sig, method, argc, args ) ) return false; // get the meta method const QMetaObject *mo = qObject->metaObject(); int mi = mo->indexOfMethod( sig.constData() ); if( mi < 0 ) { QByteArray mnorm = QMetaObject::normalizedSignature( sig.constData() ); mi = mo->indexOfMethod( mnorm.constData() ); } if( mi < 0 || mi >= mo->methodCount() ) { qcProxyDebugMsg( 1, QStringLiteral("WARNING: No such method: %1::%2").arg( mo->className() ) .arg( sig.constData() ) ); return false; } QMetaMethod mm = mo->method( mi ); // construct the return data object QGenericReturnArgument rarg; const char *rtype_name = mm.typeName(); int rtype_id = QMetaType::type( rtype_name ); MetaValue returnVal; if( retSlot && rtype_id != QMetaType::Void ) { MetaType *type = MetaType::find(rtype_id); if(!type) { qcErrorMsg(QStringLiteral("No translation for return type '%1'").arg(rtype_name)); return false; } void *mem = alloca(type->size()); if (!mem) { qcErrorMsg("Could not allocate stack space for return value"); return false; } returnVal.read(mem, type, 0); // default construction rarg = returnVal.toGenericReturnArgument(); } //do it! bool success = mm.invoke( qObject, ctype, rarg, args[0].toGenericArgument(), args[1].toGenericArgument(), args[2].toGenericArgument(), args[3].toGenericArgument(), args[4].toGenericArgument(), args[5].toGenericArgument(), args[6].toGenericArgument(), args[7].toGenericArgument(), args[8].toGenericArgument(), args[9].toGenericArgument() ); // store the return data into the return slot if( success && retSlot ) returnVal.write( retSlot ); // done return success; } void QObjectProxy::invokeScMethod ( PyrSymbol *method, const QList & args, PyrSlot *result, bool locked ) { qcProxyDebugMsg(1, QStringLiteral("SC METHOD CALL [+++]: ") + QString(method->name) ); if( !locked ) { QtCollider::lockLang(); } if( _scObject ) { QtCollider::runLang( _scObject, method, args, result ); } else { if(result) SetNil( result ); qcDebugMsg(1, "WARNING: no SC object"); } if( !locked ) QtCollider::unlockLang(); qcProxyDebugMsg(1, QStringLiteral("SC METHOD CALL [---]: ") + QString(method->name) ); } void QObjectProxy::customEvent( QEvent *event ) { switch ( (int)event->type() ) { case QtCollider::Event_ScMethodCall: scMethodCallEvent( static_cast(event) ); return; case QtCollider::Event_Proxy_SetProperty: setPropertyEvent( static_cast(event) ); return; case QtCollider::Event_Proxy_Destroy: destroyEvent( static_cast(event) ); return; case QtCollider::Event_Proxy_Release: invokeScMethod(SC_SYM(prRelease)); return; default: ; } } bool QObjectProxy::setParent( QObjectProxy *parentProxy ) { if( qObject && parentProxy->object() ) qObject->setParent( parentProxy->object() ); return true; } bool QObjectProxy::setProperty( const char *property, const QVariant & val ) { if( !qObject ) return true; if( !qObject->setProperty( property, val ) ) { qcProxyDebugMsg(1, QStringLiteral("WARNING: Property '%1' not found. Setting dynamic property.") .arg( property ) ); } return false; } bool QObjectProxy::setPropertyEvent( SetPropertyEvent *e ) { return setProperty( e->property->name, e->value ); } QVariant QObjectProxy::property( const char *property ) { return qObject ? qObject->property( property ) : QVariant(); } bool QObjectProxy::setEventHandler( int type, PyrSymbol *method, QtCollider::Synchronicity sync, bool enable ) { EventHandlerData data; data.type = type; data.method = method; data.sync = sync; data.enabled = enable; EventHandlerData *d = _eventHandlers.data(); int n = _eventHandlers.size(); while(n--) { if(d->type == type) { *d = data; break; } ++d; } if(n < 0) _eventHandlers.append(data); return true; } bool QObjectProxy::setEventHandlerEnabled( int type, bool enabled ) { EventHandlerData *d = _eventHandlers.data(); int n = _eventHandlers.size(); while(n--) { if(d->type == type) { d->enabled = enabled; break; } ++d; } return n >= 0; } bool QObjectProxy::connectObject( const char *signal, PyrObject *object, Qt::ConnectionType ctype ) { if( !qObject ) return true; QcFunctionSignalHandler *handler = new QcFunctionSignalHandler( this, signal, object, ctype ); if( !handler->isValid() ) { delete handler; return false; } funcSigHandlers.append( handler ); return true; } bool QObjectProxy::connectMethod( const char *signal, PyrSymbol *method, Qt::ConnectionType ctype ) { if( !qObject ) return true; QcMethodSignalHandler *handler = new QcMethodSignalHandler( this, signal, method, ctype ); if( handler->isValid() ) { methodSigHandlers.append( handler ); return true; } else { delete handler; return false; } } bool QObjectProxy::disconnectObject( const char *sig, PyrObject *object ) { if( !qObject ) return true; const QMetaObject *mo = qObject->metaObject(); QByteArray signal = QMetaObject::normalizedSignature( sig ); int sigId = mo->indexOfSignal( signal ); if( sigId < 0 ) { qcDebugMsg( 1, QStringLiteral("WARNING: No such signal: '%1'").arg(signal.constData()) ); return false; } for( int i = 0; i < funcSigHandlers.size(); ++i ) { QcFunctionSignalHandler *h = funcSigHandlers[i]; if( h->indexOfSignal() == sigId && h->function() == object ) { funcSigHandlers.removeAt(i); delete h; return true; } } return false; } bool QObjectProxy::disconnectMethod( const char *sig, PyrSymbol *method) { if( !qObject ) return true; const QMetaObject *mo = qObject->metaObject(); QByteArray signal = QMetaObject::normalizedSignature( sig ); int sigId = mo->indexOfSignal( signal ); if( sigId < 0 ) { qcDebugMsg( 1, QStringLiteral("WARNING: No such signal: '%1'").arg(signal.constData()) ); return false; } for( int i = 0; i < methodSigHandlers.size(); ++i ) { QcMethodSignalHandler *h = methodSigHandlers[i]; if( h->indexOfSignal() == sigId && h->method() == method ) { methodSigHandlers.removeAt(i); delete h; return true; } } return false; } void QObjectProxy::destroy( DestroyAction action ) { switch( action ) { case DestroyObject: delete qObject; return; case DestroyProxy: delete this; return; case DestroyProxyAndObject: delete qObject; delete this; return; } } bool QObjectProxy::destroyEvent( DestroyEvent *e ) { destroy( e->action() ); return true; } QList QObjectProxy::children( PyrSymbol *className ) { QList scChildren; if( !qObject ) return scChildren; const QObjectList &children = qObject->children(); Q_FOREACH( QObject *child, children ) { QObjectProxy *proxy = QObjectProxy::fromObject( child ); if( !proxy ) continue; PyrObject * obj = proxy->_scObject; if( obj ) { if( className && !isKindOf( obj, className->u.classobj ) ) continue; scChildren.append( obj ); } } return scChildren; } PyrObject *QObjectProxy::parent( PyrSymbol *className ) { if( !qObject ) return 0; QObject *parent = qObject->parent(); while( parent ) { // see if this parent has a corresponding proxy QObjectProxy *proxy = QObjectProxy::fromObject( parent ); if( proxy ) { // if parent does not have a corresponding SC object (it is just // being deleted) return no parent; PyrObject *scobj = proxy->_scObject; if( !scobj ) return 0; // if parent SC object is of desired class (or no class specified) // return it, else continue if( !className || isKindOf( scobj, className->u.classobj ) ) { return scobj; } } // if this parent was not appropriate continue to consider the parent's parent parent = parent->parent(); } return 0; } bool QObjectProxy::eventFilter( QObject * watched, QEvent * event ) { int type = event->type(); EventHandlerData *d = _eventHandlers.data(); int n = _eventHandlers.size(); while(n--) { if(d->type == type) break; ++d; } if(n < 0) { qcProxyDebugMsg(3,QStringLiteral("No handler for event (%1), forwarding to the widget") .arg(type)); return false; } QList args; if( !preProcessEvent( watched, event, *d, args ) ) { qcProxyDebugMsg(3,QStringLiteral("Event (%1, %2) not handled, forwarding to the widget") .arg(type) .arg(event->spontaneous() ? "spontaneous" : "inspontaneous") ); return false; } qcProxyDebugMsg(1,QStringLiteral("Will handle event (%1, %2) -> (%3, %4)") .arg(type) .arg(event->spontaneous() ? "spontaneous" : "inspontaneous") .arg(d->method->name) .arg(d->sync == Synchronous ? "sync" : "async") ); bool eventHandled = invokeEventHandler( event, *d, args ); eventHandled = postProcessEvent( watched, event, eventHandled ); return eventHandled; } bool QObjectProxy::invokeEventHandler( QEvent *event, EventHandlerData &eh, QList & args ) { PyrSymbol *method = eh.method; if( eh.sync == Synchronous ) { PyrSlot result; invokeScMethod( method, args, &result ); if( IsTrue( &result ) ) { qcProxyDebugMsg(2,"Event accepted"); event->accept(); return true; } else if( IsFalse( &result ) ) { qcProxyDebugMsg(2,"Event ignored"); event->ignore(); return true; } } else { ScMethodCallEvent *e = new ScMethodCallEvent( method, args ); QApplication::postEvent( this, e ); } qcProxyDebugMsg(2,"Forwarding event to the system"); return false; } bool QObjectProxy::preProcessEvent( QObject *, QEvent *e, EventHandlerData & eh, QList & args ) { return eh.enabled; } inline void QObjectProxy::scMethodCallEvent( ScMethodCallEvent *e ) { invokeScMethod( e->method, e->args, 0, e->locked ); } QObjectProxy * QObjectProxy::fromObject( QObject *object ) { if(!object) return 0; const QObjectList &children = object->children(); Q_FOREACH( QObject *child, children ) { ProxyToken *token = qobject_cast( child ); if( token ) return token->proxy; } return 0; } SuperCollider-Source/QtCollider/QObjectProxy.h000644 000765 000024 00000013423 12756531745 022503 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_QOBJECT_PROXY_H #define QC_QOBJECT_PROXY_H #include "Common.h" #include #include #include #include #include #include #include #include #define qcProxyDebugMsg( LEVEL, MSG ) \ qcDebugMsg( LEVEL, QStringLiteral("[%1]: ").arg(_scClassName) + QString(MSG) ) class QObjectProxy; class QcSignalSpy; class QcMethodSignalHandler; class QcFunctionSignalHandler; namespace QtCollider { struct SetPropertyEvent; class DestroyEvent; struct ScMethodCallEvent; class ProxyToken : public QObject { Q_OBJECT public: ProxyToken( QObjectProxy *p, QObject *parent ) : QObject(parent), proxy(p) { } QObjectProxy *proxy; }; } class QObjectProxy : public QObject { friend class QcMethodSignalHandler; friend class QcFunctionSignalHandler; Q_OBJECT public: enum DestroyAction { DestroyProxy, DestroyObject, DestroyProxyAndObject, }; struct EventHandlerData { EventHandlerData() : type( QEvent::None ) {} int type; PyrSymbol *method; QtCollider::Synchronicity sync; bool enabled; }; QObjectProxy( QObject *qObject, PyrObject *scObject ); virtual ~QObjectProxy(); // Check if this is the right thread. // WARNING: must be called with language locked! bool compareThread(); // WARNING: must be called with language locked! void finalize() { _scObject = 0; } inline QObject *object() const { return qObject; } inline PyrObject *scObject() const { return _scObject; } // Lock for usage of object() outside Qt thread. inline void lock() { mutex.lock(); } inline void unlock() { mutex.unlock(); } QString scClassName() const { return _scClassName; } QList children( PyrSymbol *className ); PyrObject *parent( PyrSymbol *className ); virtual bool setParent( QObjectProxy *parent ); bool setProperty( const char *property, const QVariant & val ); QVariant property( const char *property ); bool connectObject( const char *signal, PyrObject *object, Qt::ConnectionType ); bool connectMethod( const char *signal, PyrSymbol *method, Qt::ConnectionType ); bool disconnectObject( const char *signal, PyrObject *object ); bool disconnectMethod( const char *signal, PyrSymbol *method); bool setEventHandler( int eventType, PyrSymbol *method, QtCollider::Synchronicity, bool enabled = true ); bool setEventHandlerEnabled( int eventType, bool enabled ); // thread-safe if connection == queued bool invokeMethod( const char *method, PyrSlot *ret, PyrSlot *arg, Qt::ConnectionType ); void destroy( DestroyAction ); static QObjectProxy *fromObject( QObject * ); protected: void invokeScMethod ( PyrSymbol *method, const QList & args = QList(), PyrSlot *result = 0, bool locked = false ); virtual bool eventFilter( QObject * watched, QEvent * event ); virtual void customEvent( QEvent * ); virtual bool preProcessEvent( QObject *, QEvent *, EventHandlerData &, QList & args ); virtual bool postProcessEvent( QObject *, QEvent *, bool handled ) { return handled; } bool invokeEventHandler( QEvent *e, EventHandlerData &, QList & args ); const QVector & eventHandlers() { return _eventHandlers; } private Q_SLOTS: void invalidate(); private: void scMethodCallEvent( QtCollider::ScMethodCallEvent * ); bool setPropertyEvent( QtCollider::SetPropertyEvent * ); bool destroyEvent( QtCollider::DestroyEvent * ); QObject *qObject; // NOTE: scObject is protected by the language lock. Should not use it without it! PyrObject *_scObject; // NOTE: for the reason above we extract SC class name at construction QString _scClassName; QVector _eventHandlers; QList methodSigHandlers; QList funcSigHandlers; QMutex mutex; }; namespace QtCollider { struct SetPropertyEvent : public QEvent { SetPropertyEvent() : QEvent( (QEvent::Type) QtCollider::Event_Proxy_SetProperty ) {} PyrSymbol *property; QVariant value; }; class DestroyEvent : public QEvent { public: DestroyEvent( QObjectProxy::DestroyAction act ) : QEvent( (QEvent::Type) QtCollider::Event_Proxy_Destroy ), _action( act ) {} QObjectProxy::DestroyAction action() { return _action; } private: QObjectProxy::DestroyAction _action; }; struct ScMethodCallEvent : public QEvent { ScMethodCallEvent( PyrSymbol *m, const QList &l = QList(), bool b_locked = false ) : QEvent( (QEvent::Type) QtCollider::Event_ScMethodCall ), method( m ), args( l ), locked( b_locked ) {} PyrSymbol *method; QList args; bool locked; }; } // namespace Q_DECLARE_METATYPE( QObjectProxy * ); #endif //QC_QOBJECT_PROXY_H SuperCollider-Source/QtCollider/QtCollider.h000644 000765 000024 00000000253 12321461510 022125 0ustar00crucialstaff000000 000000 #ifndef QT_COLLIDER_H #define QT_COLLIDER_H namespace QtCollider { void initPrimitives (); void init(); int exec(int argc, char** argv); } #endif // QT_COLLIDER_H SuperCollider-Source/QtCollider/QtDownload.cpp000644 000765 000024 00000005273 12524671172 022515 0ustar00crucialstaff000000 000000 /* * QtDownload.cpp * * * Copyright 2013 Scott Wilson. * * This file is part of SuperCollider. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "Common.h" #include "QtDownload.h" #include "QcWidgetFactory.h" #include #include #include #include #include QC_DECLARE_QOBJECT_FACTORY(QtDownload); QtDownload::QtDownload() : QObject(0), started(false) { } QtDownload::~QtDownload() { } void QtDownload::setSource(const QString &t) { m_target = t; } void QtDownload::setDestination(const QString &l) { m_local = l; } void QtDownload::downloadFinished() { if (m_reply->error() == QNetworkReply::NoError) { // only write if no error QFile localFile(this->m_local); if (!localFile.open(QIODevice::WriteOnly)) return; const QByteArray sdata = m_reply->readAll(); localFile.write(sdata); qDebug() << sdata; localFile.close(); // call action Q_EMIT( doFinished() ); } m_reply->deleteLater(); m_manager->deleteLater(); } void QtDownload::download() { if(!started) { started = true; m_manager = new QNetworkAccessManager(this); QUrl url = QUrl::fromEncoded(this->m_target.toLocal8Bit()); QNetworkRequest request; request.setUrl(url); m_reply = m_manager->get(request); QObject::connect(m_reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64))); QObject::connect(m_reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(replyError(QNetworkReply::NetworkError))); bool fin = QObject::connect(m_reply, SIGNAL(finished()),this, SLOT(downloadFinished())); if (!fin) { qWarning("Download could not connect"); } } } void QtDownload::cancel() { if(m_reply) { m_reply->disconnect(); m_reply->abort(); } } void QtDownload::replyError(QNetworkReply::NetworkError errorCode) { qWarning() << m_reply->errorString(); // call action Q_EMIT( doError() ); } void QtDownload::downloadProgress(qint64 received, qint64 total) { qDebug() << received << total; // call action Q_EMIT( doProgress(static_cast(received), static_cast(total)) ); }SuperCollider-Source/QtCollider/QtDownload.h000644 000765 000024 00000003220 12524671172 022150 0ustar00crucialstaff000000 000000 /* * QtDownload.h * * * Copyright 2013 Scott Wilson. * * This file is part of SuperCollider. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include #include #include #include class QtDownload : public QObject { Q_OBJECT Q_PROPERTY( QString source READ source WRITE setSource ); Q_PROPERTY( QString destination READ destination WRITE setDestination ); public: explicit QtDownload(); ~QtDownload(); void setSource(const QString& t); void setDestination(const QString& l); QString source() { return m_target; } QString destination() {return m_local; } Q_INVOKABLE void cancel(); Q_INVOKABLE void download(); Q_SIGNALS: void doFinished(); void doError(); void doProgress(int, int); private: QNetworkAccessManager *m_manager; QString m_target; QString m_local; QNetworkReply* m_reply; bool started; public Q_SLOTS: void downloadFinished(); void downloadProgress(qint64 recieved, qint64 total); void replyError(QNetworkReply::NetworkError errorCode); };SuperCollider-Source/QtCollider/QWidgetProxy.cpp000644 000765 000024 00000032104 12756531745 023050 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QWidgetProxy.h" #include "painting.h" #include "Common.h" #include "hacks/hacks_qt.hpp" #include #include #include #include #include #include #include #include #include #ifdef Q_WS_X11 # include "hacks/hacks_x11.hpp" # include # include // X11 defines the following, clashing with QEvent::Type enum # undef KeyPress # undef KeyRelease #endif #ifdef Q_OS_MAC # include "./hacks/hacks_mac.hpp" #endif using namespace QtCollider; QAtomicInt QWidgetProxy::_globalEventMask = 0; QMimeData * QWidgetProxy::sDragData = 0; QString QWidgetProxy::sDragLabel; QWidgetProxy::QWidgetProxy( QWidget *w, PyrObject *po ): QObjectProxy( w, po ), _keyEventWidget( w ), _mouseEventWidget( w ), _performDrag(false) { } void QWidgetProxy::setKeyEventWidget( QWidget *w ) { if( w == 0 || w == _keyEventWidget ) return; QWidget *me = widget(); if( _keyEventWidget != me ) _keyEventWidget->removeEventFilter( this ); _keyEventWidget = w; if( _keyEventWidget != me ) { _keyEventWidget->installEventFilter( this ); } } void QWidgetProxy::setMouseEventWidget( QWidget *w ) { if( w == 0 || w == _mouseEventWidget ) return; QWidget *me = widget(); if( _mouseEventWidget != me ) _mouseEventWidget->removeEventFilter( this ); _mouseEventWidget = w; if( _mouseEventWidget != me ) { _mouseEventWidget->installEventFilter( this ); } } bool QWidgetProxy::alwaysOnTop() { QWidget *w = widget(); if(!w) return false; Qt::WindowFlags flags = w->windowFlags(); if( flags & Qt::Window && flags & Qt::WindowStaysOnTopHint ) return true; else return false; } void QWidgetProxy::refresh() { QWidget *w = widget(); if( w ) sendRefreshEventRecursive( w ); } void QWidgetProxy::setLayout ( QObjectProxy *layoutProxy ) { QWidget *w = widget(); QLayout *l = qobject_cast( layoutProxy->object() ); if( !w || !l ) return; QLayout *exLayout = w->layout(); if( exLayout != l ) { if( exLayout != 0 ) { qcDebugMsg( 2, QStringLiteral("Deleting old layout.") ); delete exLayout; } qcDebugMsg( 2, QStringLiteral("Setting layout.") ); w->setLayout( l ); l->activate(); } else { qcDebugMsg( 2, QStringLiteral("Layout same as existing. Will do nothing.") ); } } bool QWidgetProxy::setParent( QObjectProxy *parentProxy ) { QObject *parent = parentProxy->object(); if( !parent || !widget() ) return true; if( parent->isWidgetType() ) { QWidget *pw = qobject_cast(parent); bool ok = pw->metaObject()->invokeMethod( pw, "addChild", Q_ARG( QWidget*, widget() ) ); if( !ok ) widget()->setParent( pw ); return true; } return false; } void QWidgetProxy::setDragData( QMimeData * data, const QString & label ) { if (data == 0) return; if (sDragData == 0) { sDragData = data; sDragLabel = label; _performDrag = true; } else { delete data; qcErrorMsg( "QWidgetProxy: attempt at starting a drag while another one is in progress."); } } void QWidgetProxy::customEvent( QEvent *e ) { int type = e->type(); switch( type ) { case QtCollider::Event_Proxy_BringFront: bringFrontEvent(); return; case QtCollider::Event_Proxy_SetFocus: setFocusEvent( static_cast(e) ); return; case QtCollider::Event_Proxy_SetAlwaysOnTop: setAlwaysOnTopEvent( static_cast(e) ); return; default: QObjectProxy::customEvent(e); } } void QWidgetProxy::bringFrontEvent() { QWidget *w = widget(); if( !w ) return; w->setWindowState( w->windowState() & ~Qt::WindowMinimized | Qt::WindowActive ); w->show(); w->raise(); #ifdef Q_WS_X11 raise_window(QX11Info::display(), w); #endif #ifdef Q_OS_MAC QtCollider::Mac::activateApp(); #endif } void QWidgetProxy::setFocusEvent( QtCollider::SetFocusEvent *e ) { if( !widget() ) return; if( e->focus ) widget()->setFocus( Qt::OtherFocusReason ); else widget()->clearFocus(); } void QWidgetProxy::setAlwaysOnTopEvent( QtCollider::SetAlwaysOnTopEvent *e ) { QWidget *w = widget(); if( !w ) return; Qt::WindowFlags flags = w->windowFlags(); if( flags & Qt::Window ) { if( e->alwaysOnTop ) flags |= Qt::WindowStaysOnTopHint; else flags &= ~Qt::WindowStaysOnTopHint; // record the initial state to restore it later QPoint pos = w->pos(); bool visible = w->isVisible(); w->setWindowFlags( flags ); // setting window flags will move the window to (0,0) and hide it, // so restore the initial state w->move(pos); if( visible ) w->show(); } } void QWidgetProxy::performDrag() { Q_ASSERT(sDragData); QFont f; const QString & label = sDragLabel; QFontMetrics fm( f ); QSize size = fm.size( 0, label ) + QSize(8,4); QPixmap pix( size ); QPainter p( &pix ); p.setBrush( QColor(255,255,255) ); QRect r( pix.rect() ); p.drawRect(r.adjusted(0,0,-1,-1)); p.drawText( r, Qt::AlignCenter, label ); p.end(); QDrag *drag = new QDrag( widget() ); drag->setMimeData( sDragData ); drag->setPixmap( pix ); drag->setHotSpot( QPoint( 0, + r.height() + 2 ) ); drag->exec(); sDragData = 0; sDragLabel.clear(); } bool QWidgetProxy::preProcessEvent( QObject *o, QEvent *e, EventHandlerData &eh, QList & args ) { // NOTE We assume that qObject need not be checked here, as we wouldn't get events if // it wasn't existing int acquired_globalEventMask = _globalEventMask.load(); switch( eh.type ) { case QEvent::KeyPress: return ((acquired_globalEventMask & KeyPress) || eh.enabled) && interpretKeyEvent( o, e, args ); case QEvent::KeyRelease: return ((acquired_globalEventMask & KeyRelease) || eh.enabled) && interpretKeyEvent( o, e, args ); case QEvent::MouseButtonPress: case QEvent::MouseMove: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::Enter: case QEvent::Leave: return eh.enabled && interpretMouseEvent( o, e, args ); case QEvent::Wheel: return eh.enabled && interpretMouseWheelEvent( o, e, args ); case QEvent::DragEnter: case QEvent::DragMove: case QEvent::Drop: return eh.enabled && interpretDragEvent( o, e, args ); default: return eh.enabled; } } bool QWidgetProxy::interpretMouseEvent( QObject *o, QEvent *e, QList &args ) { if( o != _mouseEventWidget || !_mouseEventWidget->isEnabled() ) return false; QWidget *w = widget(); QEvent::Type etype = e->type(); if( etype == QEvent::Enter || etype == QEvent::Leave ) return true; QMouseEvent *mouse = static_cast( e ); QPoint pt = ( _mouseEventWidget == w ? mouse->pos() : _mouseEventWidget->mapTo( w, mouse->pos() ) ); args << pt.x(); args << pt.y(); args << (int) mouse->modifiers(); if( etype == QEvent::MouseMove ) { int buttons = mouse->buttons(); if( buttons == 0 ) { // Special treatment of mouse-tracking events. QWidget *win = w->window(); // Only accept if window has a special property enabled. if( !(win && win->property("_qc_win_mouse_tracking").toBool()) ) return false; // Reject the events when mouse pointer leaves the window, // resulting in out-of-bounds coordinates if( win == w ) { if( pt.x() < 0 || pt.x() >= w->width() || pt.y() < 0 || pt.y() >= w->height() ) return false; } } args << (int) mouse->buttons(); } else { // MouseButtonPress, MouseButtonDblClick, MouseButtonRelease int button; switch( mouse->button() ) { case Qt::LeftButton: button = 0; break; case Qt::RightButton: button = 1; break; case Qt::MidButton: button = 2; break; default: button = -1; } args << button; if( etype == QEvent::MouseButtonPress ) args << 1; else if( etype == QEvent::MouseButtonDblClick ) args << 2; } return true; } bool QWidgetProxy::interpretMouseWheelEvent( QObject *o, QEvent *e, QList &args ) { // NOTE: There seems to be a bug in wheel event propagation: // the event is propagated to parent twice! // Therefore we do not let the propagated events through to SC, // (we only let the "spontaneous" ones). if( o != _mouseEventWidget || !e->spontaneous() || !_mouseEventWidget->isEnabled() ) return false; QWheelEvent *we = static_cast(e); QWidget *w = widget(); QPoint pt = _mouseEventWidget == w ? we->pos() : _mouseEventWidget->mapTo( w, we->pos() ); Qt::Orientation ort = we->orientation(); // calculate degrees: delta is in 1/8 of a degree. int deg = we->delta() / 8; args << pt.x(); args << pt.y(); args << (int) we->modifiers(); args << (ort == Qt::Horizontal ? deg : 0); args << (ort == Qt::Vertical ? deg : 0); return true; } bool QWidgetProxy::interpretKeyEvent( QObject *o, QEvent *e, QList &args ) { if( o != _keyEventWidget || !_keyEventWidget->isEnabled() ) return false; QKeyEvent *ke = static_cast( e ); int key = ke->key(); int mods = ke->modifiers(); QChar character; #ifdef Q_OS_MAC bool isLetter = key >= Qt::Key_A && key <= Qt::Key_Z; if (mods & Qt::MetaModifier && isLetter) { character = QChar(key - Qt::Key_A + 1); } else if(mods & Qt::AltModifier && isLetter) { character = (mods & Qt::ShiftModifier) ? QChar(key) : QChar(key - Qt::Key_A + 97 ); } else #endif { QString text( ke->text() ); if (text.count()) character = text[0]; } int unicode = character.unicode(); #ifdef Q_WS_X11 KeySym sym = ke->nativeVirtualKey(); int keycode = XKeysymToKeycode( QX11Info::display(), sym ); #else // FIXME: On Mac OS X, this does not work for modifier keys int keycode = ke->nativeVirtualKey(); #endif args << character; args << mods; args << unicode; args << keycode; args << key; args << ke->spontaneous(); return true; } static QString urlAsString( const QUrl & url ) { if (QURL_IS_LOCAL_FILE(url)) return url.toLocalFile(); else return url.toString(); } static bool interpretMimeData( const QMimeData *data, QList &args ) { if( data->hasUrls() ) { QList urls = data->urls(); if( urls.count() > 1 ) { QVariantList list; Q_FOREACH( QUrl url, urls ) list << urlAsString( url ); args << QVariant(list); } else { args << urlAsString( urls[0] ); } } else if( data->hasText() ) { args << data->text(); } else { return false; } return true; } bool QWidgetProxy::interpretDragEvent( QObject *o, QEvent *e, QList &args ) { if( o != _mouseEventWidget ) return false; QDropEvent *dnd = static_cast(e); const QMimeData *data = dnd->mimeData(); if( dnd->type() == QEvent::DragEnter ) { bool internal = data->hasFormat( "application/supercollider" ); args << internal; if(!internal) interpretMimeData(data, args); } else { QPoint pos = dnd->pos(); args << pos.x() << pos.y(); } return true; } bool QWidgetProxy::postProcessEvent( QObject *object, QEvent *event, bool handled ) { if (_performDrag) { _performDrag = false; performDrag(); return true; } return handled; } void QWidgetProxy::customPaint( QPainter *painter ) { if( QtCollider::paintingAnnounced() ) { qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." ); return; } QtCollider::announcePainting(); QtCollider::lockLang(); if( QtCollider::beginPainting( painter, this ) ) { invokeScMethod( SC_SYM(doDrawFunc), QList(), 0, true ); QtCollider::endPainting(); } QtCollider::unlockLang(); } void QWidgetProxy::sendRefreshEventRecursive( QWidget *w ) { QEvent event( static_cast( QtCollider::Event_Refresh ) ); QApplication::sendEvent( w, &event ); const QObjectList &children = w->children(); Q_FOREACH( QObject *child, children ) { if( child->isWidgetType() ) sendRefreshEventRecursive( static_cast( child ) ); } } SuperCollider-Source/QtCollider/QWidgetProxy.h000644 000765 000024 00000006346 12524671172 022516 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_WIDGET_PROXY_H #define QC_WIDGET_PROXY_H #include "QObjectProxy.h" #include #include #include namespace QtCollider { struct SetFocusEvent; struct SetAlwaysOnTopEvent; struct StartDragEvent; } class QWidgetProxy : public QObjectProxy { Q_OBJECT public: enum GlobalEvent { KeyPress = 0x001, KeyRelease = 0x002 }; public: static void setGlobalEventEnabled ( GlobalEvent ev, bool b ) { int mask = _globalEventMask.load(); if(b) mask |= ev; else mask &= ~ev; _globalEventMask = mask; } public: QWidgetProxy( QWidget *w, PyrObject *po ); void setKeyEventWidget( QWidget * ); void setMouseEventWidget( QWidget * ); bool alwaysOnTop(); void refresh(); void setLayout ( QObjectProxy *layoutProxy ); virtual bool setParent( QObjectProxy *parent ); void setDragData( QMimeData * data, const QString & label ); inline QWidget *widget() { return static_cast( object() ); } protected: virtual void customEvent( QEvent * ); virtual bool preProcessEvent( QObject *, QEvent *, EventHandlerData &, QList & args ); virtual bool postProcessEvent( QObject *, QEvent *, bool handled ); private Q_SLOTS: void customPaint( QPainter * ); private: bool interpretMouseEvent( QObject *, QEvent *, QList &args ); bool interpretMouseWheelEvent( QObject *, QEvent *, QList &args ); bool interpretKeyEvent( QObject *, QEvent *, QList &args ); bool interpretDragEvent( QObject *, QEvent *, QList &args ); void bringFrontEvent(); void setFocusEvent( QtCollider::SetFocusEvent * ); void setAlwaysOnTopEvent( QtCollider::SetAlwaysOnTopEvent * ); void performDrag(); static void sendRefreshEventRecursive( QWidget *w ); QWidget *_keyEventWidget; QWidget *_mouseEventWidget; static QAtomicInt _globalEventMask; static QMimeData *sDragData; static QString sDragLabel; bool _performDrag; }; namespace QtCollider { struct SetFocusEvent : public QEvent { SetFocusEvent( bool b ) : QEvent( (QEvent::Type) QtCollider::Event_Proxy_SetFocus ), focus(b) {} bool focus; }; struct SetAlwaysOnTopEvent : public QEvent { SetAlwaysOnTopEvent( bool b ) : QEvent( (QEvent::Type) QtCollider::Event_Proxy_SetAlwaysOnTop ), alwaysOnTop(b) {} bool alwaysOnTop; }; } #endif //QC_WIDGET_PROXY_H SuperCollider-Source/QtCollider/resources.qrc000644 000765 000024 00000000535 12321461510 022436 0ustar00crucialstaff000000 000000 ../icons/sc_cube_16x16.png ../icons/sc_cube_32x32.png ../icons/sc_cube_48x48.png ../icons/sc_cube_128x128.png SuperCollider-Source/QtCollider/safeptr.hpp000644 000765 000024 00000004516 12524671172 022111 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SAFE_PTR_H #define QC_SAFE_PTR_H #include "Common.h" #include #include #include #include namespace QtCollider { template class SafePtr { public: SafePtr() : d(0) {} SafePtr( const SafePtr & other ) : d ( other.d ) { ref(); } SafePtr( T* ptr ) : d ( new Data( ptr ) ) {} SafePtr & operator= ( const SafePtr & other ) { deref(); d = other.d; ref(); return *this; } ~SafePtr() { deref(); } T * operator-> () const { return d->ptr.load(); } T & operator* () const { return *d->ptr.load(); } operator T* () const { return (d ? d->ptr.load() : 0); } T *ptr() const { return (d ? d->ptr.load() : 0); } void *id() const { return (void*) d; } // useful for checking internal pointer identity void invalidate() { qcDebugMsg(2,"SafePtr: invalidating"); if(d) d->ptr = 0; } private: struct Data { Data ( T * ptr_ ) : ptr(ptr_), refCount(1) {} QAtomicPointer ptr; QAtomicInt refCount; }; void ref() { if( d ) { d->refCount.ref(); qcDebugMsg(2,QString("SafePtr: +refcount = %1").arg(d->refCount.load())); } } void deref() { if( d ) { bool ref = d->refCount.deref(); qcDebugMsg(2,QString("SafePtr: -refcount = %1").arg(d->refCount.load())); if( !ref ) { qcDebugMsg(2,"SafePtr: unreferenced!"); delete d; } } } Data *d; }; } // namespace QtCollider #endif SuperCollider-Source/QtCollider/style/000755 000765 000024 00000000000 13007315613 021056 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/type_codec.cpp000644 000765 000024 00000026663 12321461510 022551 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 - 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "type_codec.hpp" #include "metatype.hpp" #include "QObjectProxy.h" #include "widgets/QcTreeWidget.h" #include "primitives/prim_QPalette.hpp" #include "image.h" #include #include #include #include #include namespace QtCollider { QString TypeCodec::read( PyrSlot *slot ) { if( IsSym(slot) ) { return QString::fromUtf8( slotRawSymbol(slot)->name ); } else if( isKindOfSlot( slot, class_string ) ) { int len = slotRawObject( slot )->size; return QString::fromUtf8( slotRawString(slot)->s, len ); } return QString(); } void TypeCodec::write( PyrSlot *slot, const QString & val ) { PyrString *str = newPyrString( gMainVMGlobals->gc, val.toUtf8().constData(), 0, true ); SetObject( slot, str ); } QPointF TypeCodec::read( PyrSlot *slot ) { PyrSlot *slots = slotRawObject( slot )->slots; float x, y; int err; err = slotFloatVal( slots+0, &x ); if( err ) return QPointF(); err = slotFloatVal( slots+1, &y ); if( err ) return QPointF(); return QPointF( x, y ); } QPointF TypeCodec::safeRead( PyrSlot *slot ) { if ( isKindOfSlot( slot, SC_CLASS(Point) ) ) return read( slot ); else return QPointF(); } void TypeCodec::write( PyrSlot *slot, const QPointF & pt ) { PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Point), 0, true, true ); SetObject( slot, obj ); PyrSlot *slots = obj->slots; SetFloat( slots+0, pt.x() ); SetFloat( slots+1, pt.y() ); } QRectF TypeCodec::read( PyrSlot *slot ) { PyrSlot *slots = slotRawObject( slot )->slots; float bounds[4]; for( int i=0; i<4; ++i ) { int err = slotFloatVal(slots + i, &bounds[i]); if( err ) return QRectF(); } return QRectF( bounds[0], bounds[1], bounds[2], bounds[3] ); } QRectF TypeCodec::safeRead( PyrSlot *slot ) { if ( isKindOfSlot( slot, SC_CLASS(Rect) ) ) return read( slot ); else return QRectF(); } void TypeCodec::write( PyrSlot *slot, const QRectF & r ) { PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Rect), 0, true, true ); SetObject( slot, obj ); PyrSlot *slots = obj->slots; SetFloat( slots+0, r.x() ); SetFloat( slots+1, r.y() ); SetFloat( slots+2, r.width() ); SetFloat( slots+3, r.height() ); } QSizeF TypeCodec::read( PyrSlot *slot ) { PyrSlot *slots = slotRawObject( slot )->slots; float w = 0.f, h = 0.f; slotFloatVal( slots+0, &w ); slotFloatVal( slots+1, &h ); return QSizeF( w, h ); } QSizeF TypeCodec::safeRead( PyrSlot *slot ) { if ( isKindOfSlot( slot, SC_CLASS(Size) ) ) return read( slot ); else return QSizeF(); } void TypeCodec::write( PyrSlot *slot, const QSizeF & sz ) { PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Size), 0, true, true ); SetObject( slot, obj ); PyrSlot *slots = obj->slots; SetFloat( slots+0, sz.width() ); SetFloat( slots+1, sz.height() ); } inline QColor asColor( PyrObject *obj ) { PyrSlot *slots = obj->slots; float r,g,b,a; r = g = b = a = 0.f; slotFloatVal(slots+0, &r); slotFloatVal(slots+1, &g); slotFloatVal(slots+2, &b); slotFloatVal(slots+3, &a); return QColor( r*255, g*255, b*255, a*255 ); } QColor TypeCodec::read( PyrSlot *slot ) { PyrObject *obj = slotRawObject(slot); PyrClass *klass = obj->classptr; if( klass == SC_CLASS(Color) ) return asColor(obj); if( klass == SC_CLASS(Gradient) || klass == SC_CLASS(HiliteGradient) ) { qcWarningMsg("WARNING: Gradient and HiliteGradient are not supported yet." " Using the average gradient color instead."); QColor c1( safeRead(obj->slots+0) ); QColor c2( safeRead(obj->slots+1) ); QColor mix( (c1.red() + c2.red()) / 2, (c1.green() + c2.green()) / 2, (c1.blue() + c2.blue()) / 2 ); return mix; } return QColor(); } void TypeCodec::write( PyrSlot *slot, const QColor & c ) { if(!c.isValid()) { SetNil(slot); return; } PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(Color), 0, true, true ); SetObject( slot, obj ); PyrSlot *slots = obj->slots; SetFloat( slots+0, c.red() / 255.0 ); SetFloat( slots+1, c.green() / 255.0 ); SetFloat( slots+2, c.blue() / 255.0 ); SetFloat( slots+3, c.alpha() / 255.0 ); } QFont TypeCodec::read( PyrSlot *slot ) { PyrSlot *slots = slotRawObject(slot)->slots; QString family = TypeCodec::safeRead( slots+0 ); float fSize = TypeCodec::safeRead( slots+1 ); bool bold = TypeCodec::safeRead( slots+2 ); bool italic = TypeCodec::safeRead( slots+3 ); bool isPtSize = TypeCodec::safeRead( slots+4 ); QFont f; if( !family.isEmpty() ) f.setFamily( family ); if( fSize > 0.f ) { if( isPtSize ) { f.setPointSizeF( fSize ); } else { int pixSize = ( fSize > 1.f ? qRound(fSize) : 1 ); f.setPixelSize( pixSize ); } } f.setBold( bold ); f.setItalic( italic ); return f; } QFont TypeCodec::safeRead( PyrSlot *slot ) { if ( isKindOfSlot( slot, SC_CLASS(Font) ) ) return TypeCodec::read( slot ); else return QFont(); } QPalette TypeCodec::read( PyrSlot *slot ) { QPalette *p = QPALETTE_FROM_OBJECT(slotRawObject(slot)); return *p; } QPalette TypeCodec::safeRead( PyrSlot *slot ) { if ( isKindOfSlot( slot, SC_CLASS(QPalette) ) ) return TypeCodec::read( slot ); else return QPalette(); } void TypeCodec::write( PyrSlot *slot, const QPalette & plt ) { PyrGC *gc = gMainVMGlobals->gc; PyrObject *obj = instantiateObject( gc, SC_CLASS(QPalette), 0, true, true ); SetObject( slot, obj ); QPalette_Init( gMainVMGlobals, obj, plt ); } QObjectProxy * TypeCodec::safeRead( PyrSlot *slot ) { if( !isKindOfSlot( slot, SC_CLASS(QObject) ) ) return 0; return read(slot); } void TypeCodec::write( PyrSlot *slot, QObject * obj ) { QObjectProxy *proxy = QObjectProxy::fromObject(obj); if( proxy && proxy->scObject() ) SetObject( slot, proxy->scObject() ); else SetNil( slot ); } QVariantList TypeCodec::read( PyrSlot *slot ) { if( isKindOfSlot( slot, class_array ) ) { PyrObject *obj = slotRawObject( slot ); PyrSlot *slots = obj->slots; int size = obj->size; QVariantList list; for( int i = 0; i < size; ++i, ++slots ) { list << QtCollider::get(slots); } return list; } else if( isKindOfSlot( slot, class_symbolarray ) ) { PyrSymbolArray *symarray = slotRawSymbolArray( slot ); PyrSymbol **symbols = symarray->symbols; int size = symarray->size; QVariantList list; for( int i = 0; i < size; ++i, ++symbols ) list << QVariant( QString( (*symbols)->name) ); return list; } return QVariantList(); } void TypeCodec::write( PyrSlot *slot, const QVariantList & varList ) { VMGlobals *g = gMainVMGlobals; int count = varList.count(); PyrObject *array = newPyrArray( g->gc, count, 0, true ); SetObject( slot, array ); int i; PyrSlot *s = array->slots; for( i = 0; i < count; ++i, ++s ) { if( !QtCollider::set( s, varList[i] ) ) { qcDebugMsg(1, "WARNING: Could not set one slot of array" ); } array->size++; g->gc->GCWrite( array, s ); } } #define WRONG_OBJECT_FORMAT false template inline static void copy( QVector & dest, PyrSlot *orig, int size ) { ORIG *array = (ORIG*) orig; for( int i = 0; i < size; ++i ) dest << DEST(array[i]); } template static QVector toNumericVector( PyrObject *obj ) { int size = obj->size; PyrSlot *slots = obj->slots; QVector vector; vector.reserve(size); switch (obj->obj_format) { case obj_double: copy( vector, slots, size ); break; case obj_float: copy( vector, slots, size ); break; case obj_int32: copy( vector, slots, size ); break; case obj_int16: copy( vector, slots, size ); break; case obj_int8: copy( vector, slots, size ); break; default: Q_ASSERT( WRONG_OBJECT_FORMAT ); } return vector; } template static void setNumeric( PyrSlot *, numeric_type ); template<> inline void setNumeric( PyrSlot *s, double val ) { SetFloat( s, val ); } template<> inline void setNumeric( PyrSlot *s, int val ) { SetInt( s, val ); } template static void setNumericVector( PyrSlot *slot, const QVector & vec ) { VMGlobals *g = gMainVMGlobals; int count = vec.count(); PyrObject *array = newPyrArray( g->gc, count, 0, true ); SetObject( slot, array ); PyrSlot *s = array->slots; Q_FOREACH( numeric_type val, vec ) { setNumeric( s, val ); ++array->size; ++s; } } QVector TypeCodec< QVector >::read( PyrSlot *slot ) { return toNumericVector(slotRawObject(slot)); } void TypeCodec< QVector >::write( PyrSlot *slot, const QVector & vec ) { setNumericVector( slot, vec ); } QVector TypeCodec< QVector >::read( PyrSlot *slot ) { return toNumericVector(slotRawObject(slot)); } void TypeCodec< QVector >::write( PyrSlot *slot, const QVector & vec ) { setNumericVector( slot, vec ); } QcTreeWidget::ItemPtr TypeCodec::read( PyrSlot *slot ) { PyrSlot *ptrSlot = slotRawObject(slot)->slots+0; if( IsPtr( ptrSlot ) ) { QcTreeWidget::ItemPtr *safePtr = static_cast( slotRawPtr(ptrSlot) ); return *safePtr; } else { return QcTreeWidget::ItemPtr(); } } void TypeCodec::write( PyrSlot *slot, const QcTreeWidget::ItemPtr & item ) { PyrObject *obj = instantiateObject( gMainVMGlobals->gc, SC_CLASS(TreeViewItem), 0, true, true ); QcTreeWidget::Item::initialize( gMainVMGlobals, obj, item ); SetObject( slot, obj ); } SharedImage TypeCodec::read( PyrSlot * slot ) { SharedImage *ptr = reinterpret_cast( slotRawPtr( slotRawObject(slot)->slots+0 ) ); return *ptr; } SharedImage TypeCodec::safeRead( PyrSlot * slot ) { if (!isKindOfSlot(slot, SC_CLASS(Image))) return SharedImage(); else return read(slot); } void TypeCodec::write( PyrSlot *slot, SharedImage image ) { qWarning("WARNING: QtCollider: writing SharedImage to PyrSlot not supported."); } } // namespace QtCollider SuperCollider-Source/QtCollider/type_codec.hpp000644 000765 000024 00000021264 12321461510 022546 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 - 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QT_COLLIDER_TYPE_CODEC_INCLUDED #define QT_COLLIDER_TYPE_CODEC_INCLUDED #include "widgets/QcTreeWidget.h" #include "image.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class QObjectProxy; namespace QtCollider { template struct TypeCodec { }; // Forwarding from QtCollider namespace to TypeCodec template inline T read( PyrSlot *slot ) { return TypeCodec::read(slot); } template inline void write( PyrSlot *slot, const T & val ) { return TypeCodec::write(slot, val); } // Lazy conversion, allows automatic codec deduction struct DecodableSlot { PyrSlot *_slot; DecodableSlot( PyrSlot *slot ): _slot(slot) {} template operator T () { return TypeCodec::safeRead(_slot); } }; inline DecodableSlot get( PyrSlot * slot ) { return DecodableSlot(slot); } template inline T get( PyrSlot * slot ) { return TypeCodec::safeRead(slot); } template inline void set( PyrSlot *slot, const T & val ) { // write is always type-safe TypeCodec::write( slot, val ); } // TypeCodecs template <> struct TypeCodec { static bool read( PyrSlot *slot ) { return IsTrue( slot ); } static bool safeRead( PyrSlot *slot ) { return read(slot); } static void write( PyrSlot *slot, const bool val ) { if(val) SetTrue(slot); else SetFalse(slot); } }; template <> struct TypeCodec { static int read( PyrSlot *slot ) { return slotRawInt(slot); } static int safeRead( PyrSlot *slot ) { int val; if (slotIntVal(slot, &val)) return 0; return val; } static void write( PyrSlot *slot, const int val ) { SetInt(slot, val); } }; template <> struct TypeCodec { static float read( PyrSlot *slot ) { return slotRawFloat(slot); } static float safeRead( PyrSlot *slot ) { float val; if (slotFloatVal(slot, &val)) return 0.f; return val; } static void write( PyrSlot *slot, const float val ) { SetFloat(slot, val); } }; template <> struct TypeCodec { static double read( PyrSlot *slot ) { double d; slotVal(slot, &d); return d; } static double safeRead( PyrSlot *slot ) { double val; if (slotDoubleVal(slot, &val)) return 0.0; return val; } static void write( PyrSlot *slot, const double val ) { // NOTE: the signature actually reads SetFloat(PyrSlot*, double): SetFloat(slot, val); } }; template <> struct TypeCodec { static QChar read( PyrSlot *slot ) { return QChar( slotRawChar(slot) ); } static QChar safeRead( PyrSlot *slot ) { if (GetTag(slot) == tagChar) return QChar( slotRawChar(slot) ); else return QChar(); } static void write( PyrSlot *slot, const QChar & val ) { // FIXME: Should add support for unicode in PyrSlot! SetChar(slot, val.toLatin1()); } }; template <> struct TypeCodec { static QString read( PyrSlot *slot ); static QString safeRead( PyrSlot *slot ) { return read(slot); } static void write( PyrSlot *slot, const QString & val ); }; template <> struct TypeCodec { static QPointF read( PyrSlot *slot ); static QPointF safeRead( PyrSlot *slot ); static void write( PyrSlot *slot, const QPointF & pt ); }; template <> struct TypeCodec { static QPoint read( PyrSlot *slot ) { return TypeCodec::read(slot).toPoint(); } static QPoint safeRead( PyrSlot *slot ) { return TypeCodec::safeRead(slot).toPoint(); } static void write( PyrSlot *slot, const QPoint & pt ) { TypeCodec::write(slot, pt); } }; template <> struct TypeCodec { static QRectF read( PyrSlot *slot ); static QRectF safeRead( PyrSlot *slot ); static void write( PyrSlot *slot, const QRectF & r ); }; template <> struct TypeCodec { static QRect read( PyrSlot *slot ) { return TypeCodec::read(slot).toRect(); } static QRect safeRead( PyrSlot *slot ) { return TypeCodec::safeRead(slot).toRect(); } static void write( PyrSlot *slot, const QRect & rect ) { TypeCodec::write(slot, rect); } }; template <> struct TypeCodec { static QSizeF read( PyrSlot *slot ); static QSizeF safeRead( PyrSlot *slot ); static void write( PyrSlot *slot, const QSizeF & sz ); }; template <> struct TypeCodec { static QSize read( PyrSlot *slot ) { return TypeCodec::read(slot).toSize(); } static QSize safeRead( PyrSlot *slot ) { return TypeCodec::safeRead(slot).toSize(); } static void write( PyrSlot *slot, const QSize & size ) { TypeCodec::write(slot, size); } }; template <> struct TypeCodec { static QColor read( PyrSlot *slot ); static QColor safeRead( PyrSlot *slot ) { if (IsObj(slot)) return read(slot); return QColor(); } static void write( PyrSlot *slot, const QColor & ); }; template <> struct TypeCodec { static QFont read( PyrSlot *slot ); static QFont safeRead( PyrSlot *slot ); static void write( PyrSlot *slot, const QFont & ) { qWarning("WARNING: QtCollider: writing QFont to PyrSlot not supported."); } }; template <> struct TypeCodec { static QPalette read( PyrSlot *slot ); static QPalette safeRead( PyrSlot *slot ); static void write( PyrSlot *slot, const QPalette & ); }; template <> struct TypeCodec { static QObjectProxy* read( PyrSlot *slot ) { PyrSlot *proxySlot = slotRawObject( slot )->slots; if( IsPtr( proxySlot ) ) return (QObjectProxy*) slotRawPtr( proxySlot ); else return 0; } static QObjectProxy* safeRead( PyrSlot *slot ); static void write( PyrSlot *, QObjectProxy * ) { qWarning("WARNING: QtCollider: writing QObjectProxy* to PyrSlot not supported."); } }; template <> struct TypeCodec { static QObject* read( PyrSlot * ) { qWarning("WARNING: QtCollider: reading QObject* from PyrSlot not supported."); return 0; } static void write( PyrSlot *, QObject * ); }; template <> struct TypeCodec { static QWidget* read( PyrSlot * ) { qWarning("WARNING: QtCollider: reading QWidget* from PyrSlot not supported."); return 0; } static void write( PyrSlot *slot, QWidget * widget ) { TypeCodec::write(slot, widget); } }; template <> struct TypeCodec { static PyrObject* read( PyrSlot * ) { qWarning("WARNING: TypeCodec::read(PyrSlot*) = NO-OP"); return 0; } static void write( PyrSlot *slot, PyrObject *object ) { SetObject(slot, object); } }; template <> struct TypeCodec { static QcTreeWidget::ItemPtr read( PyrSlot *slot ); static void write( PyrSlot *slot, const QcTreeWidget::ItemPtr & ); }; template <> struct TypeCodec { static SharedImage read( PyrSlot * slot ); static SharedImage safeRead( PyrSlot * slot ); static void write ( PyrSlot *slot, SharedImage image ); }; template <> struct TypeCodec< QVector > { static QVector read( PyrSlot *slot ); static void write( PyrSlot *slot, const QVector & ); }; template <> struct TypeCodec< QVector > { static QVector read( PyrSlot *slot ); static void write( PyrSlot *slot, const QVector & ); }; template <> struct TypeCodec { static QVariantList read( PyrSlot *slot ); static QVariantList safeRead( PyrSlot *slot ) { return read(slot); } static void write( PyrSlot *slot, const QVariantList & ); }; } // namespace QtCollider #endif // QT_COLLIDER_TYPE_CODEC_INCLUDED SuperCollider-Source/QtCollider/widgets/000755 000765 000024 00000000000 13007315613 021364 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/widgets/BasicWidgets.cpp000644 000765 000024 00000004110 12321461510 024430 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "BasicWidgets.h" #include "../QcWidgetFactory.h" #include #include QC_DECLARE_QWIDGET_FACTORY( QcDefaultWidget ); QC_DECLARE_QWIDGET_FACTORY( QcHLayoutWidget ); QC_DECLARE_QWIDGET_FACTORY( QcVLayoutWidget ); void QcSimpleWidget::setBackground( const QColor &c ) { if(_bkg == c) return; _bkg = c; setAttribute(Qt::WA_OpaquePaintEvent, c.isValid() && c.alpha() == 255); update(); } void QcSimpleWidget::setBackgroundImage( const QtCollider::SharedImage & image, const QRectF & rect, int tileMode, double opacity ) { _bkg_image.setImage( image, rect, tileMode, opacity ); update(); } void QcSimpleWidget::paintEvent( QPaintEvent *e ) { QPainter painter(this); if (_bkg.isValid()) painter.fillRect(e->rect(), _bkg); if (_bkg_image.isValid()) _bkg_image.paint( &painter, rect() ); } class QcCustomPaintedFactory : public QcWidgetFactory { protected: virtual void initialize( QWidgetProxy *p, QcCustomPainted *w ) { QObject::connect( w, SIGNAL(painting(QPainter*)), p, SLOT(customPaint(QPainter*)) ); } }; QC_DECLARE_FACTORY( QcCustomPainted, QcCustomPaintedFactory ); SuperCollider-Source/QtCollider/widgets/BasicWidgets.h000644 000765 000024 00000005346 12321461510 024111 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef _WIDGETS_H #define _WIDGETS_H #include "QcCanvas.h" #include "../layouts/classic_layouts.hpp" #include "image_painter.h" class QcSimpleWidget : public QWidget { Q_OBJECT Q_PROPERTY( QColor background READ background WRITE setBackground ); public: const QColor & background() const { return _bkg; } void setBackground( const QColor &c ); Q_INVOKABLE void setBackgroundImage( const QtCollider::SharedImage & image, const QRectF & rect, int tileMode, double opacity ); Q_INVOKABLE void removeBackgroundImage() { _bkg_image.clear(); update(); } protected: virtual void paintEvent( QPaintEvent * ); private: QColor _bkg; QtCollider::ImagePainter _bkg_image; }; class QcDefaultWidget : public QcSimpleWidget { Q_OBJECT public: QcDefaultWidget(): l(this) {} protected: virtual void resizeEvent( QResizeEvent *e ) { if(!layout()) l.resize(e); } QtCollider::DefaultLayout l; }; class QcHLayoutWidget : public QcSimpleWidget { Q_OBJECT public: QcHLayoutWidget(): l(this) {} protected: virtual void resizeEvent( QResizeEvent *e ) { if(!layout()) l.resize(e); } QtCollider::HLayout l; }; class QcVLayoutWidget : public QcSimpleWidget { Q_OBJECT public: QcVLayoutWidget(): l(this) {} protected: virtual void resizeEvent( QResizeEvent *e ) { if(!layout()) l.resize(e); } QtCollider::VLayout l; }; class QcCustomPainted : public QcCanvas { Q_OBJECT public: QcCustomPainted(): l(this) {} protected: // reimplement event handlers just so events don't propagate virtual void mousePressEvent( QMouseEvent * ) {} virtual void mouseReleaseEvent( QMouseEvent * ) {} virtual void mouseMoveEvent( QMouseEvent * ) {} virtual void resizeEvent( QResizeEvent *e ) { QcCanvas::resizeEvent(e); if(!layout()) l.resize(e); } QtCollider::DefaultLayout l; }; #endif // _WIDGETS_H SuperCollider-Source/QtCollider/widgets/image_painter.h000644 000765 000024 00000015454 12321461510 024346 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2013 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QT_COLLIDER_IMAGE_PAINTER_INCLUDED #define QT_COLLIDER_IMAGE_PAINTER_INCLUDED #include "../image.h" #include "../debug.h" #include namespace QtCollider { struct ImagePainter { enum HorizontalMode { AlignLeft, AlignHCenter, AlignRight, TileHorizontally, StretchHorizontally, }; enum VerticalMode { AlignTop, AlignVCenter, AlignBottom, TileVertically, StretchVertically }; SharedImage image; QRectF sourceRect; HorizontalMode horizontalMode; VerticalMode verticalMode; bool scaleToFit; qreal opacity; ImagePainter(): horizontalMode(AlignLeft), verticalMode(AlignTop), scaleToFit(false), opacity(1.0) {} bool isValid() const { return !image.isNull(); } void setImage( const SharedImage & image, const QRectF & rect = QRectF(), int tileMode = 1, qreal opacity = 1.0 ) { this->image = image; this->sourceRect = rect; this->opacity = opacity; setTileMode(tileMode); } void clear() { image.clear(); } void paint ( QPainter * painter, const QRectF & targetRect ) { if (!image) return; if (image->isPainting()) { qcErrorMsg("Can not draw image while being painted."); return; } const QPixmap & pixmap = image->pixmap(); if (sourceRect.isNull() || targetRect.isNull()) return; painter->save(); painter->setOpacity(opacity); painter->setRenderHint( QPainter::SmoothPixmapTransform, image->transformationMode == Qt::SmoothTransformation ); QRectF rect = sourceRect; if (horizontalMode == StretchHorizontally) { rect.moveLeft(targetRect.left()); rect.setWidth(targetRect.width()); } if (verticalMode == StretchVertically) { rect.moveTop(targetRect.top()); rect.setHeight(targetRect.height()); } if ( horizontalMode != StretchHorizontally && verticalMode != StretchVertically && scaleToFit ) { float aspect_ratio = rect.width() / rect.height(); rect.setHeight( targetRect.height() ); rect.setWidth( rect.height() * aspect_ratio ); if (rect.width() > targetRect.width()) { rect.setWidth( targetRect.width() ); rect.setHeight( rect.width() / aspect_ratio ); } } switch (horizontalMode) { case AlignLeft: case TileHorizontally: rect.moveLeft(targetRect.left()); break; case AlignHCenter: rect.moveLeft(targetRect.left() + targetRect.width() / 2 - rect.width() / 2); break; case AlignRight: rect.moveRight(targetRect.right()); break; default: break; }; switch (verticalMode) { case AlignTop: case TileVertically: rect.moveTop(targetRect.top()); break; case AlignVCenter: rect.moveTop(targetRect.top() + targetRect.height() / 2 - rect.height() / 2); break; case AlignRight: rect.moveBottom(targetRect.bottom()); break; default: break; }; bool tileVertically = verticalMode == TileVertically; bool tileHorizontally = horizontalMode == TileHorizontally; qreal x_origin = rect.left(); qreal y_origin = rect.top(); do { do { painter->drawPixmap( rect, pixmap, sourceRect); if (tileVertically) rect.moveTop( rect.top() + rect.height() ); else break; } while( rect.top() <= targetRect.bottom() ); if (tileHorizontally) { rect.moveTop( y_origin ); rect.moveLeft( rect.left() + rect.width() ); } else break; } while (rect.left() <= targetRect.right()); painter->restore(); } void setTileMode( const int mode ) { /* modes : 1 - fixed to left, fixed to top 2 - horizontally tile, fixed to top 3 - fixed to right, fixed to top 4 - fixed to left, vertically tile 5 - horizontally tile, vertically tile 6 - fixed to right, vertically tile 7 - fixed to left, fixed to bottom 8 - horizontally tile, fixed to bottom 9 - fixed to right, fixed to bottom 10 - fit 11 - center, center (scale) 12 - center , fixed to top 13 - center , fixed to bottom 14 - fixed to left, center 15 - fixed to right, center 16 - center, center (no scale) */ int mode_map_index = mode - 1; if (mode_map_index < 0 || mode_map_index >= 16) return; static int mode_map[16][2] = { { AlignLeft, AlignTop }, { TileHorizontally, AlignTop }, { AlignRight, AlignTop }, { AlignLeft, TileVertically }, { TileHorizontally, TileVertically }, { AlignRight, TileVertically }, { AlignLeft, AlignBottom }, { TileHorizontally, AlignBottom }, { AlignRight, AlignBottom }, { StretchHorizontally, StretchVertically }, { AlignHCenter, AlignVCenter }, { AlignHCenter, AlignTop }, { AlignHCenter, AlignBottom }, { AlignLeft, AlignVCenter }, { AlignRight, AlignVCenter }, { AlignHCenter, AlignVCenter } }; horizontalMode = (HorizontalMode) mode_map[mode_map_index][0]; verticalMode = (VerticalMode) mode_map[mode_map_index][1]; scaleToFit = (mode == 11); } }; } // namespace QtCollider #endif // QT_COLLIDER_IMAGE_PAINTER_INCLUDED SuperCollider-Source/QtCollider/widgets/QcAbstractStepValue.cpp000644 000765 000024 00000002517 12321461510 025751 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include "QcAbstractStepValue.h" bool QcAbstractStepValue::modifyStep( double *pStep ) { Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); if( !mods ) return false; else if( mods & Qt::ShiftModifier ) *pStep = *pStep * _shiftScale; else if( mods & Qt::ControlModifier ) *pStep = *pStep * _ctrlScale; else if( mods & Qt::AltModifier ) *pStep = *pStep * _altScale; else return false; return true; } SuperCollider-Source/QtCollider/widgets/QcAbstractStepValue.h000644 000765 000024 00000003024 12321461510 025410 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_ABSTRACT_STEP_VALUE #define QC_ABSTRACT_STEP_VALUE class QcAbstractStepValue { protected: QcAbstractStepValue() : _shiftScale( 100.f ), _ctrlScale( 10.f ), _altScale( 0.1f ) {} bool modifyStep( double *step ); void setShiftScale( double scale ) { _shiftScale = scale; } void setCtrlScale( double scale ) { _ctrlScale = scale; } void setAltScale( double scale ) { _altScale = scale; } double shiftScale() { return _shiftScale; } double ctrlScale() { return _ctrlScale; } double altScale() { return _altScale; } private: double _shiftScale; double _ctrlScale; double _altScale; }; #endif SuperCollider-Source/QtCollider/widgets/QcButton.cpp000644 000765 000024 00000005745 12756531745 023662 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcButton.h" #include "../QcWidgetFactory.h" QC_DECLARE_QWIDGET_FACTORY(QcButton); QcButton::QcButton(): QtCollider::Style::Client(this), currentState(0) { setAttribute(Qt::WA_AcceptTouchEvents); connect( this, SIGNAL(clicked()), this, SLOT(doAction()) ); } void QcButton::setStates( const QVariantList & statesArg ) { if( !statesArg.count() ) return; states.clear(); Q_FOREACH( const QVariant & var, statesArg ) { QVariantList stateArg = var.toList(); int count = stateArg.size(); State state; if( count >= 1 ) state.text = stateArg[0].toString(); if( count >= 2 ) state.textColor = stateArg[1].value(); if( count >= 3 ) state.buttonColor = stateArg[2].value(); states.append( state ); } setState( 0 ); } void QcButton::setState( int i ) { int c = states.count(); if( !c ) return; currentState = qBound( 0, i, c-1 ); setText( states[currentState].text ); update(); } void QcButton::cycleStates() { if( states.size() < 2 ) return; int i = currentState + 1; if( i >= states.size() ) i = 0; setState( i ); } void QcButton::doAction() { cycleStates(); Q_EMIT( action((int)QApplication::keyboardModifiers()) ); } void QcButton::paintEvent ( QPaintEvent * ) { using namespace QtCollider::Style; using QtCollider::Style::RoundRect; QPainter p(this); p.setRenderHint( QPainter::Antialiasing, true ); State state; if(states.count()) state = states[currentState]; const QPalette &plt = palette(); bool sunken = isDown(); int radius = 2; if(!state.buttonColor.isValid()) state.buttonColor = plt.color(QPalette::Button); if(sunken) state.buttonColor = state.buttonColor.darker(120); QColor focusClr( hasFocus() ? focusColor() : QColor() ); QRect r(rect()); RoundRect frame( r, radius ); if( sunken ) drawSunken( &p, plt, frame, state.buttonColor, focusClr); else drawRaised( &p, plt, frame, state.buttonColor, focusClr ); p.setPen( state.textColor.isValid() ? state.textColor : plt.color(QPalette::ButtonText) ); if(sunken) r.translate(1,1); p.drawText( r, Qt::AlignCenter, text() ); } SuperCollider-Source/QtCollider/widgets/QcButton.h000644 000765 000024 00000003462 12321461510 023275 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "../QcHelper.h" #include "../style/style.hpp" #include class QcButton : public QPushButton, QcHelper, QtCollider::Style::Client { Q_OBJECT Q_PROPERTY( QVariantList states READ dummyVariantList WRITE setStates ); Q_PROPERTY( int value READ getValue WRITE setValue ); Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); public: QcButton(); Q_SIGNALS: void action(int); protected: #ifdef Q_WS_MAC bool hitButton( const QPoint & ) const; #endif virtual void paintEvent ( QPaintEvent * ); private Q_SLOTS: void doAction(); private: struct State { QString text; QColor textColor; QColor buttonColor; }; void setStates( const QVariantList & ); void setValue( int val ) { setState( val ); } int getValue() const { return currentState; } void setState( int ); void cycleStates(); QList states; int currentState; }; SuperCollider-Source/QtCollider/widgets/QcCanvas.cpp000644 000765 000024 00000010426 12321461510 023566 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcCanvas.h" #include "../painting.h" #include "../Common.h" #include #include QcCanvas::QcCanvas( QWidget *parent ) : QWidget( parent ), _paint( false ), _repaintNeeded( true ), _clearOnRefresh( true ), _clearOnce( false ), _resize( false ), _fps( 60.f ), _fpsActual( 0.f ), _timerId( 0 ), _animating( false ), _frameCount( 0 ), _meterPeriod( 1000 ), _meterFrames( 0 ) {} float QcCanvas::frameRate() const { return _fpsActual; } void QcCanvas::setFrameRate( float rate ) { if( rate != _fps ) { _fps = rate; if( _animating && _fps > 0 ) { // restart animation timer with new frame rate killTimer( _timerId ); _timerId = startTimer( 1000.f / _fps ); } } } void QcCanvas::setBackground( const QColor &c ) { if(_bkg == c) return; _bkg = c; setAttribute( Qt::WA_OpaquePaintEvent, c.isValid() && c.alpha() == 255 ); setAttribute( Qt::WA_TranslucentBackground, c.isValid() ); if( !testAttribute(Qt::WA_WState_InPaintEvent) ) update(); } void QcCanvas::setBackgroundImage( const QtCollider::SharedImage & image, const QRectF & rect, int tileMode, double opacity ) { _bkg_image.setImage( image, rect, tileMode, opacity ); if( !testAttribute(Qt::WA_WState_InPaintEvent) ) update(); } void QcCanvas::refresh() { _repaintNeeded = true; update(); } void QcCanvas::clear() { _clearOnce = true; } void QcCanvas::animate( bool on ) { if( on ) { if( !_animating && _fps > 0 ) { _frameCount = 0; _animating = true; _meterTime.start(); _timerId = startTimer( 1000.f / _fps ); _fpsTimer.start( _meterPeriod, this ); } } else if( _animating ) { killTimer( _timerId ); _fpsTimer.stop(); _animating = false; } } void QcCanvas::customEvent( QEvent *e ) { if( e->type() == (QEvent::Type) QtCollider::Event_Refresh ) { e->accept(); refresh(); } } void QcCanvas::changeEvent ( QEvent * e ) { if(e->type() == QEvent::PaletteChange) refresh(); } void QcCanvas::resizeEvent( QResizeEvent * ) { _resize = true; refresh(); } void QcCanvas::paintEvent( QPaintEvent *e ) { if( _paint && _repaintNeeded ) { if( _resize ) { _pixmap = QPixmap( size() ); _resize = false; _clearOnce = true; } if( _clearOnRefresh || _clearOnce ) { _pixmap.fill( QColor(0,0,0,0) ); _clearOnce = false; } bool opaque_before = testAttribute(Qt::WA_OpaquePaintEvent); QPainter pixPainter( &_pixmap ); Q_EMIT( painting(&pixPainter) ); _repaintNeeded = false; bool opaque_after = testAttribute(Qt::WA_OpaquePaintEvent); if( opaque_before && !opaque_after ) { repaint(); return; } } QPainter painter(this); QPalette plt(palette()); if( _bkg.isValid() ) painter.fillRect( e->rect(), _bkg ); if (_bkg_image.isValid()) _bkg_image.paint( &painter, rect() ); if( _paint ) painter.drawPixmap( e->rect(), _pixmap, e->rect() ); } void QcCanvas::timerEvent( QTimerEvent *e ) { if( e->timerId() == _timerId ) { ++_frameCount; ++_meterFrames; _repaintNeeded = true; repaint(); } else if( e->timerId() == _fpsTimer.timerId() ) { // recalc actual fps float dTime = _meterTime.elapsed(); _fpsActual = (dTime > 0) ? (_meterFrames * 1000.f / dTime) : 0.f; // reset fps meter _meterTime.restart(); _meterFrames = 0; } } SuperCollider-Source/QtCollider/widgets/QcCanvas.h000644 000765 000024 00000005575 12321461510 023244 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_CANVAS_H #define QC_CANVAS_H #include "image_painter.h" #include #include #include #include #include class QcCanvas : public QWidget { Q_PROPERTY( bool clearOnRefresh READ clearOnRefresh WRITE setClearOnRefresh ); Q_PROPERTY( bool drawingEnabled READ drawingEnabled WRITE setDrawingEnabled ); Q_PROPERTY( float frameRate READ frameRate WRITE setFrameRate ); Q_PROPERTY( int frameCount READ frameCount ); Q_PROPERTY( QColor background READ background WRITE setBackground ); Q_OBJECT public: QcCanvas( QWidget *parent = 0 ); bool drawingEnabled() const { return _paint; } void setDrawingEnabled( bool b ) { _paint = b; } bool clearOnRefresh() const { return _clearOnRefresh; } void setClearOnRefresh( bool b ) { _clearOnRefresh = b; } float frameRate() const; void setFrameRate( float rate ); int frameCount() const { return _frameCount; } QColor background() const { return _bkg; } void setBackground( const QColor &c ); Q_INVOKABLE void setBackgroundImage( const QtCollider::SharedImage & image, const QRectF & rect, int tileMode, double opacity ); Q_INVOKABLE void removeBackgroundImage() { _bkg_image.clear(); update(); } public Q_SLOTS: void refresh(); void clear(); void animate( bool toggle ); Q_SIGNALS: void painting(QPainter*); protected: virtual void customEvent( QEvent * ); virtual void changeEvent ( QEvent * ); virtual void resizeEvent( QResizeEvent * ); virtual void paintEvent( QPaintEvent * ); virtual void timerEvent( QTimerEvent * ); private: QPixmap _pixmap; bool _paint; bool _repaintNeeded; bool _clearOnRefresh; bool _clearOnce; bool _resize; float _fps; float _fpsActual; int _timerId; bool _animating; int _frameCount; // SC has no idea of unsigned integers QBasicTimer _fpsTimer; int _meterPeriod; // msecs between actual fps recalculation QTime _meterTime; int _meterFrames; QColor _bkg; QtCollider::ImagePainter _bkg_image; }; #endif SuperCollider-Source/QtCollider/widgets/QcCheckBox.h000644 000765 000024 00000002467 12321461510 023514 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "../QcWidgetFactory.h" #include class QcCheckBox : public QCheckBox { Q_OBJECT Q_PROPERTY( bool value READ value WRITE setValue ); public: QcCheckBox() { connect( this, SIGNAL(clicked()), this, SIGNAL(action()) ); } Q_SIGNALS: void action(); private: bool value() { return isChecked(); } void setValue( bool val ) { setChecked(val); } }; QC_DECLARE_QWIDGET_FACTORY( QcCheckBox ); SuperCollider-Source/QtCollider/widgets/QcFileDialog.cpp000644 000765 000024 00000003741 12321461510 024354 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcFileDialog.h" #include "../QcObjectFactory.h" QC_DECLARE_QOBJECT_FACTORY(QcFileDialog); QcFileDialog::QcFileDialog( int fileMode, int acceptMode ) { dialog = new QFileDialog(); dialog->setDirectory( QDir::home() ); switch(fileMode) { case QFileDialog::AnyFile: dialog->setFileMode( QFileDialog::AnyFile ); break; case QFileDialog::ExistingFile: dialog->setFileMode( QFileDialog::ExistingFile ); break; case QFileDialog::Directory: dialog->setFileMode( QFileDialog::Directory ); break; case QFileDialog::ExistingFiles: dialog->setFileMode( QFileDialog::ExistingFiles ); break; default: qcErrorMsg( "File dialog created with invalid file mode!\n"); } switch(acceptMode) { case QFileDialog::AcceptOpen: dialog->setAcceptMode( QFileDialog::AcceptOpen ); break; case QFileDialog::AcceptSave: dialog->setAcceptMode( QFileDialog::AcceptSave ); break; default: qcErrorMsg( "File dialog created with invalid accept mode!\n"); } setParent( dialog ); connect( dialog, SIGNAL(finished(int)), this, SLOT(onFinished(int)) ); } SuperCollider-Source/QtCollider/widgets/QcFileDialog.h000644 000765 000024 00000003530 12524671172 024031 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_FILE_DIALOG_H #define QC_FILE_DIALOG_H #include "../Common.h" #include #include class QcFileDialog : public QObject { Q_OBJECT public: Q_INVOKABLE QcFileDialog( int fileMode = QFileDialog::ExistingFile, int acceptMode = QFileDialog::AcceptOpen ); ~QcFileDialog() { if (dialog) { dialog->deleteLater(); }; } QFileDialog *theDialog() { return dialog; } Q_SIGNALS: void accepted( QVariantList result ); void rejected(); private Q_SLOTS: void show() { dialog->exec(); dialog->deleteLater(); } void onFinished( int res ) { if( res == QDialog::Accepted ) { QStringList files = dialog->selectedFiles(); QVariantList varFiles; Q_FOREACH( QString f, files ) { varFiles << QVariant( f ); } Q_EMIT( accepted( varFiles ) ); } else { Q_EMIT( rejected() ); } } private: QPointer dialog; }; #endif // QC_FILE_DIALOG_H SuperCollider-Source/QtCollider/widgets/QcGraph.cpp000644 000765 000024 00000071173 12756531745 023446 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcGraph.h" #include "../QcWidgetFactory.h" #include "../style/routines.hpp" #include #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcGraph); void QcGraphModel::append( QcGraphElement * e ) { if( _elems.count() ) { QcGraphElement *prev = _elems.last(); prev->_next = e; e->_prev = prev; } _elems.append(e); Q_EMIT( appended(e) ); } void QcGraphModel::removeAt( int i ) { QcGraphElement *e = _elems[i]; int ci = _conns.count(); while( ci-- ) { Connection c = _conns[ci]; if( c.a == e || c.b == e ) _conns.removeAt(ci); } if( e->_prev ) e->_prev->_next = e->_next; if( e->_next ) e->_next->_prev = e->_prev; _elems.removeAt(i); Q_EMIT( removed(e) ); delete e; } QcGraph::QcGraph() : QtCollider::Style::Client(this), _defaultThumbSize( QSize(18,18) ), _style(DotElements), _drawLines( true ), _drawRects( true ), _editable( true ), _step( 0.01 ), _selectionForm( ElasticSelection ), _xOrder( NoOrder ), _gridOn( false ), _geometryDirty( false ), _lastIndex(-1) { QPalette plt( palette() ); setFocusPolicy( Qt::StrongFocus ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); setAttribute(Qt::WA_AcceptTouchEvents); connect( &_model, SIGNAL(removed(QcGraphElement*)), this, SLOT(onElementRemoved(QcGraphElement*)) ); } QVariantList QcGraph::value() const { QVariantList x; QVariantList y; QList elems = _model.elements(); Q_FOREACH( QcGraphElement* e, elems ) { QPointF val = e->value; x.append( val.x() ); y.append( val.y() ); } QVariantList values; values.append( QVariant(x) ); values.append( QVariant(y) ); return values; } QcGraphElement *QcGraph::currentElement() const { return _selection.count() ? _selection.elems.first().elem : 0; } int QcGraph::index() const { QcGraphElement *e = currentElement(); return e ? _model.elements().indexOf(e) : -1; } QVariantList QcGraph::selectionIndexes() const { QVariantList result; int c = _model.elementCount(); for( int i = 0; i < c; ++i ) { QcGraphElement *e = _model.elementAt(i); if(e->selected) result << i; } return result; } float QcGraph::currentX() const { QcGraphElement *e = currentElement(); return e ? e->value.x() : 0.f; } float QcGraph::currentY() const { QcGraphElement *e = currentElement(); return e ? e->value.y() : 0.f; } void QcGraph::setValue( const QVariantList &list ) { if( list.count() != 2 ) return; QVariantList xList = list[0].toList(); QVariantList yList = list[1].toList(); int newc = qMin( xList.count(), yList.count() ); if( !newc ) return; int c = _model.elementCount(); while( c > newc ) { --c; _model.removeAt( c ); } int i; for( i = 0; i < newc; ++i ) { QPointF val( xList[i].toFloat(), yList[i].toFloat() ); if( i < c ) { QcGraphElement *e = _model.elementAt(i); setValue( e, val ); } else { QcGraphElement *e = new QcGraphElement(_defaultThumbSize); setValue( e, val ); _model.append( e ); } } if( newc ) ensureOrder(); _geometryDirty = true; update(); } void QcGraph::setStrings( const QVariantList &list ) { int strc = list.count(); int c = _model.elementCount(); int i; for( i = 0; i < c && i < strc; ++i ) { QcGraphElement *e = _model.elementAt(i); e->text = list[i].toString(); } update(); } void QcGraph::setCurves( const QVariantList & curves ) { for( int i = 0; i < curves.size() && i < _model.elementCount(); ++i ) { const QVariant & data = curves[i]; QcGraphElement::CurveType type; double curvature; if( data.type() == QVariant::Int ) { type = (QcGraphElement::CurveType) data.toInt(); curvature = 0.0; } else { type = QcGraphElement::Curvature; curvature = data.toDouble(); } _model.elementAt(i)->setCurveType( type, curvature ); } update(); } void QcGraph::setCurves( double curvature ) { Q_FOREACH( QcGraphElement* e, _model.elements() ) e->setCurveType( QcGraphElement::Curvature, curvature ); update(); } void QcGraph::setCurves( int typeId ) { QcGraphElement::CurveType type = (QcGraphElement::CurveType)typeId; Q_FOREACH( QcGraphElement* e, _model.elements() ) e->setCurveType( type ); update(); } void QcGraph::setStringAt( int i, const QString & str ) { int c = _model.elementCount(); if( i >= 0 && i < c ) { QcGraphElement *e = _model.elementAt(i); e->text = str; update(); } } void QcGraph::connectElements( int src, QVariantList targets ) { int c = _model.elementCount(); if( src < 0 || src >= c ) return; Q_FOREACH( const QVariant & var, targets ) { int trg = var.toInt(); if( trg < 0 || trg >= c ) continue; _model.connect( src, trg ); } update(); } void QcGraph::setIndex( int i ) { select(i); } void QcGraph::select( int i, bool exclusive ) { if( i >= 0 && i < _model.elementCount() ) { if( exclusive ) setAllDeselected(); setIndexSelected( i, true ); update(); } } void QcGraph::deselect( int i ) { if( i >= 0 && i < _model.elementCount() ) { setIndexSelected( i, false ); update(); } } void QcGraph::deselectAll() { setAllDeselected(); } void QcGraph::setCurrentX( float f ) { QcGraphElement *e = currentElement(); if(!e) return; QPointF val = e->value; val.setX( f ); if( _xOrder != NoOrder ) orderRestrictValue(e,val,true); else restrictValue(val); e->value = val; update(); } void QcGraph::setCurrentY( float f ) { QcGraphElement *e = currentElement(); if(!e) return; QPointF val = e->value; val.setY( f ); if( _xOrder != NoOrder ) orderRestrictValue(e,val,true); else restrictValue(val); e->value = val; update(); } void QcGraph::setThumbSize( int s ) { QSize size(s,s); _defaultThumbSize = size; int c = _model.elementCount(); for( int i=0; isize = size; } _largestThumbSize = size; _geometryDirty = false; update(); } void QcGraph::setThumbWidth( int w ) { _defaultThumbSize.setWidth(w); int c = _model.elementCount(); for( int i=0; isize.setWidth(w); } // For backward compatibility, switch to style that supports // different thumb width and height: _style = RectElements; _largestThumbSize.setWidth(w); update(); } void QcGraph::setThumbHeight( int h ) { _defaultThumbSize.setHeight(h); int c = _model.elementCount(); for( int i=0; isize.setHeight(h); } // For backward compatibility, switch to style that supports // different thumb width and height: _style = RectElements; _largestThumbSize.setHeight(h); update(); } void QcGraph::setThumbSizeAt( int i, int s ) { if( i < 0 || i >= _model.elementCount() ) return; _model.elementAt(i)->size = QSize(s,s); _geometryDirty = true; update(); } void QcGraph::setThumbWidthAt( int i, int w ) { if( i < 0 || i >= _model.elementCount() ) return; _model.elementAt(i)->size.setWidth(w); // For backward compatibility, switch to style that supports // different thumb width and height: _style = RectElements; _geometryDirty = true; update(); } void QcGraph::setThumbHeightAt( int i, int h ) { if( i < 0 || i >= _model.elementCount() ) return; _model.elementAt(i)->size.setHeight(h); // For backward compatibility, switch to style that supports // different thumb width and height: _style = RectElements; _geometryDirty = true; update(); } void QcGraph::setFillColor( const QColor & color ) { int c = _model.elementCount(); for( int i=0; ifillColor = color; } update(); } void QcGraph::setFillColorAt( int i, const QColor & color ) { int c = _model.elementCount(); if( i >= 0 && i < c ) { QcGraphElement *e = _model.elementAt(i); e->fillColor = color; update(); } } void QcGraph::setEditableAt( int i, bool b ) { int c = _model.elementCount(); if( i >= 0 && i < c ) { QcGraphElement *e = _model.elementAt(i); e->editable = b; } } void QcGraph::setStep( double step ) { _step = qMax( 0.0, step ); if( _model.elementCount() ) { ensureOrder(); update(); }; } void QcGraph::setHorizontalOrder( int i ) { _xOrder = (Order) i; if( _xOrder != NoOrder ) { ensureOrder(); update(); } } void QcGraph::onElementRemoved( QcGraphElement *e ) { _selection.elems.removeAll( SelectedElement(e) ); } void QcGraph::setAllDeselected() { int c = _model.elementCount(); for( int i = 0; i < c; ++i ) { QcGraphElement *e = _model.elementAt(i); e->selected = false; } _selection.elems.clear(); } void QcGraph::setIndexSelected( int index, bool select ) { Q_ASSERT( index >= 0 && index < _model.elementCount() ); QcGraphElement *e = _model.elementAt( index ); if( e->selected == select ) return; if( select ) { e->selected = true; int c = _model.elementCount(); int si = 0; int i = 0; while( i < index ) { if( _model.elementAt(i)->selected ) ++si; ++i; } _selection.elems.insert( si, SelectedElement(e) ); _lastIndex = index; } else { e->selected = false; _selection.elems.removeAll( SelectedElement(e) ); } update(); } inline static void qc_graph_round( double &val, double &step, bool &grid ) { if( val < 0.0 ) { val = 0.0; } else if ( grid ) { double ratio = ( val + (step*0.5) > 1.0 ) ? qFloor(1.0/step) : qRound(val/step); val = ratio * step; } else if ( val > 1.0 ) { val = 1.0; } } inline void QcGraph::restrictValue( QPointF & val ) { double x = val.x(); double y = val.y(); bool grid = _step > 0.0; qc_graph_round(x,_step,grid); qc_graph_round(y,_step,grid); val.setX(x); val.setY(y); } void QcGraph::orderRestrictValue( QcGraphElement *e, QPointF & val, bool selected ) { restrictValue(val); double x0 = e->value.x(); double x = val.x(); if( x == x0 ) { return; } else if( x < x0 ) { // new x is smaller, check if not too small; QcGraphElement *prev = e->prev(); if( prev && (selected || !prev->selected) && x < prev->value.x() ) val.setX( prev->value.x() ); } else { // new x is larger, check if not too large; QcGraphElement *next = e->next(); if( next && (selected || !next->selected) && x > next->value.x() ) val.setX( next->value.x() ); } } inline void QcGraph::setValue( QcGraphElement * e, const QPointF& pt ) { QPointF val(pt); restrictValue( val ); e->value = val; } void QcGraph::ensureOrder() { int c = _model.elementCount(); double x_min = 0.0; for( int i = 0; i < c; ++i ) { QcGraphElement *e = _model.elementAt(i); QPointF val = e->value; if( _xOrder != NoOrder && val.x() < x_min ) val.setX(x_min); setValue( e, val ); x_min = e->value.x(); } } void QcGraph::moveFree( QcGraphElement *e, const QPointF & val ) { if( !e->editable ) return; setValue( e, val ); } void QcGraph::moveOrderRestricted( QcGraphElement *e, const QPointF & val ) { if( !e->editable ) return; QPointF v(val); orderRestrictValue( e, v, true ); e->value = v; } void QcGraph::moveSelected( const QPointF & dif, SelectionForm form, bool cached ) { int c = _selection.count(); switch( form ) { case ElasticSelection: { switch( _xOrder ) { case NoOrder: for( int i = 0; i < c; ++i ) { SelectedElement & se = _selection.elems[i]; moveFree( se.elem, (cached ? se.moveOrigin : se.elem->value) + dif ); } break; case RigidOrder: if( dif.x() <= 0 ) { for( int i = 0; i < c; ++i ) { SelectedElement & se = _selection.elems[i]; moveOrderRestricted( se.elem, (cached ? se.moveOrigin : se.elem->value) + dif ); } } else { for( int i = _selection.count() - 1; i >= 0; --i ) { SelectedElement & se = _selection.elems[i]; moveOrderRestricted( se.elem, (cached ? se.moveOrigin : se.elem->value) + dif ); } } break; } break; } case RigidSelection: { // reduce dif until acceptable by all nodes QPointF d(dif); for( int i = 0; i < c; ++i ) { SelectedElement & se = _selection.elems[i]; // if any node in selection is not editable, abort, since // we want to keep the selection form! if( !se.elem->editable ) return; QPointF val0 = (cached ? se.moveOrigin : se.elem->value); QPointF val = val0 + d; if( _xOrder == NoOrder ) { restrictValue( val ); } else { orderRestrictValue( se.elem, val, false ); } d = val - val0; } // if no dif left, do not bother moving if( d.isNull() ) return; // move all with the new dif for( int i = 0; i < c; ++i ) { SelectedElement & se = _selection.elems[i]; if( !se.elem->editable ) continue; se.elem->value = (cached ? se.moveOrigin : se.elem->value) + d; } break; } } } void QcGraph::addCurve( QPainterPath &path, QcGraphElement *e1, QcGraphElement *e2 ) { QcGraphElement::CurveType type = e1->curveType; const QPointF &pt1 = e1->value; const QPointF &pt2 = e2->value; // coefficients for control points of cubic curve // approximating first quarter of sinusoid // technically: y = sin(pi*x/2) over x = [0,1] static const float ax = 1.0/3.0; static const float ay = 0.52359877f; // pi/6 static const float bx = 2.0/3.0; static const float by = 1.0; switch( type ) { case QcGraphElement::Step: path.moveTo( pt1 ); path.lineTo( pt1.x(), pt2.y() ); path.lineTo( pt2 ); break; case QcGraphElement::Hold: path.moveTo( pt1 ); path.lineTo( pt1.y(), pt2.y() ); path.lineTo( pt2 ); break; case QcGraphElement::Linear: path.moveTo( pt1 ); path.lineTo( pt2 ); break; case QcGraphElement::Quadratic: { path.moveTo( pt1 ); const qreal x1 = pt1.x(); const qreal x2 = pt2.x(); const qreal y1 = std::sqrt(pt1.y()); const qreal y2 = std::sqrt(pt2.y()); static const int n = 100; const qreal dx = x2 - x1; const qreal dy = y2 - y1; const qreal k = dx != 0.0 ? dy / dx : 0.0; const qreal a = y1 - x1 * k; const qreal kx = dx / n; for (int i = 1; i < n; ++i) { qreal x = i * kx + x1; qreal y = k * x + a; path.lineTo( x, y*y ); } path.lineTo( pt2 ); break; } case QcGraphElement::Cubic: { path.moveTo( pt1 ); const qreal x1 = pt1.x(); const qreal x2 = pt2.x(); const qreal y1 = std::pow(pt1.y(), qreal(1/3.0)); const qreal y2 = std::pow(pt2.y(), qreal(1/3.0)); static const int n = 100; const qreal dx = x2 - x1; const qreal dy = y2 - y1; const qreal k = dx != 0.0 ? dy / dx : 0.0; const qreal a = y1 - x1 * k; const qreal kx = dx / n; for (int i = 1; i < n; ++i) { qreal x = i * kx + x1; qreal y = k * x + a; path.lineTo( x, y*y*y ); } path.lineTo( pt2 ); break; } case QcGraphElement::Sine: { // half of difference between end points float dx = (pt2.x() - pt1.x()) * 0.5f; float dy = (pt2.y() - pt1.y()) * 0.5f; // middle point QPointF mid = pt1 + QPointF( dx, dy ); path.moveTo( pt1 ); path.cubicTo( pt1 + QPointF( dx*(1-bx), dy*(1-by) ), pt1 + QPointF( dx*(1-ax), dy*(1-ay) ), mid ); path.cubicTo( mid + QPointF( dx*ax, dy*ay ), mid + QPointF( dx*bx, dy*by ), pt2 ); break; } case QcGraphElement::Welch: { // difference between points float dx = (pt2.x() - pt1.x()); float dy = (pt2.y() - pt1.y()); path.moveTo( pt1 ); if( dy > 0 ) path.cubicTo( pt1 + QPointF( dx*ax, dy*ay ), pt1 + QPointF( dx*bx, dy*by ), pt2 ); else path.cubicTo( pt1 + QPointF( dx*(1-bx), dy*(1-by) ), pt1 + QPointF( dx*(1-ax), dy*(1-ay) ), pt2 ); break; } case QcGraphElement::Exponential: { // FIXME: find a Bezier curve approximation path.moveTo( pt1 ); float dx = (pt2.x() - pt1.x()); float dy = (pt2.y() - pt1.y()); // prevent NaN, optimize if( pt1.y() <= 0.f || pt2.y() <= 0.f ) { path.lineTo( dy < 0 ? QPointF(pt1.x(),pt2.y()) : QPointF(pt2.x(), pt1.y()) ); path.lineTo( pt2 ); } else { static const int n = 100; const qreal x1 = pt1.x(); const qreal x2 = pt2.x(); const qreal y1 = pt1.y(); const qreal y2 = pt2.y(); const qreal kx = (x2 - x1) / n; const double ky = y1 != 0.0 ? std::pow(y2 / y1, 1.0 / n) : 1.f; double y = y1; for (int i = 1; i < n; ++i) { qreal x = i * kx + x1; y = y * ky; path.lineTo(x, y); } path.lineTo( pt2 ); } break; } case QcGraphElement::Curvature: // FIXME: find a Bezier curve approximation path.moveTo( pt1 ); // prevent NaN double curve = qBound( -100.0, e1->curvature, 100.0 ); if( std::abs( curve ) < 0.0001 ) { path.lineTo( pt2 ); } else { float dx = (pt2.x() - pt1.x()); float dy = (pt2.y() - pt1.y()); double denom = 1.0 - exp( curve ); const float n = 100.f; for( float ph=1/n; ph<=(1-1/n); ph+=1/n ) { double numer = 1.0 - exp( ph * curve ); qreal y = pt1.y() + dy * (numer / denom); path.lineTo( pt1.x() + (dx * ph), y ); } path.lineTo( pt2 ); } break; } } QSize QcGraph::drawnElementSize( QcGraphElement *e ) { if (_style == DotElements) { int s = qMin(e->size.width(), e->size.height()); return QSize(s,s); } else return e->size; } QRect QcGraph::valueRect() { using namespace QtCollider::Style; if (_geometryDirty) { int w = 0; int h = 0; int c = _model.elementCount(); if (_style == RectElements) { for (int i = 0; i < c; ++i) { QSize s = _model.elementAt(i)->size; w = qMax(w, s.width()); h = qMax(h, s.height()); } } else { for (int i = 0; i < c; ++i) { QSize s = _model.elementAt(i)->size; w = qMax(w, qMin(s.width(), s.height())); } h = w; } _largestThumbSize = QSize(w,h); _geometryDirty = false; } return marginsRect( sunkenContentsRect( rect() ), _largestThumbSize ).adjusted(1,1,-1,-1); } QRectF QcGraph::labelRect( QcGraphElement *e, const QPointF &pt, const QRect &bounds, const QFontMetrics &fm ) { QRectF textRect( fm.boundingRect(e->text) ); QSize sz( drawnElementSize(e) ); qreal hnd_w_2 = sz.width() * 0.5; qreal hnd_h_2 = sz.height() * 0.5; textRect.moveBottomLeft( pt + QPointF(hnd_w_2, -hnd_h_2) ); if( textRect.y() < bounds.y() ) textRect.moveTop( pt.y() + hnd_h_2 ); if( textRect.right() > bounds.right() ) textRect.moveRight( pt.x() - hnd_w_2 ); return textRect; } void QcGraph::paintEvent( QPaintEvent * ) { using namespace QtCollider::Style; using QtCollider::Style::Ellipse; using QtCollider::Style::RoundRect; QPainter p( this ); const QPalette & plt = palette(); p.setRenderHint( QPainter::Antialiasing, true ); RoundRect frame(rect(), 2); drawSunken( &p, plt, frame, background(), hasFocus() ? focusColor() : QColor() ); p.setRenderHint( QPainter::Antialiasing, false ); QRect contentsRect( valueRect() ); //draw grid; p.setPen( gridColor() ); p.setBrush( Qt::NoBrush ); p.drawRect( contentsRect ); if( _gridOn ) { float dx = _gridMetrics.x(); float dy = _gridMetrics.y(); float cl = contentsRect.left(); float cr = contentsRect.right(); float ct = contentsRect.top(); float cb = contentsRect.bottom(); if( contentsRect.width() > 0.f && dx > 0.f && dx < 1.f ) { dx *= contentsRect.width(); int i = 1; float x; while( (x = i * dx + cl) < cr ) { p.drawLine( x, ct, x, cb ); ++i; } } if( contentsRect.height() > 0.f && dy > 0.f && dy < 1.f ) { dy *= contentsRect.height(); int i = 1; float y; while( (y = cb - i * dy) > ct ) { p.drawLine( cl, y, cr, y ); ++i; } } } QList elems = _model.elements(); int c = elems.count(); if( !c ) return; const QColor& strokeClr = strokeColor(); QPen pen; pen.setColor(strokeClr); pen.setWidth(0); p.setPen(pen); // draw lines; if( _drawLines ) { QPainterPath lines; QList conns = _model.connections(); if( conns.count() ) { Q_FOREACH( QcGraphModel::Connection c, conns ) { addCurve( lines, c.a, c.b ); } } else { QcGraphElement *e1 = elems[0]; int i; for( i = 1; i < c; ++i ) { QcGraphElement *e2 = elems[i]; addCurve( lines, e1, e2 ); e1 = e2; } } p.save(); p.setRenderHint( QPainter::Antialiasing, true ); p.setBrush( Qt::NoBrush ); p.translate( contentsRect.x(), contentsRect.y() + contentsRect.height() ); p.scale( contentsRect.width(), -contentsRect.height() ); p.drawPath( lines ); p.restore(); } // draw rects and strings if( _drawRects ) { p.setRenderHint( QPainter::Antialiasing, true ); QFontMetrics fm( font() ); QColor rectColor = plt.color(QPalette::Button).lighter(105); QColor circleColor = rectColor; circleColor.setAlpha(70); QColor dotColor = plt.color(QPalette::Text); const QColor & selectClr = selectionColor(); QRectF rect; QPointF pt; int i; for( i = 0; i < c; ++i ) { QcGraphElement *e = elems[i]; rect.setSize( drawnElementSize(e) ); pt = Style::pos( e->value, contentsRect ); rect.moveCenter( pt.toPoint() ); if( _style == DotElements ) drawDotElement(e, rect, contentsRect, dotColor, circleColor, strokeClr, selectClr, plt, fm, &p); else drawRectElement(e, rect, rectColor, strokeClr, selectClr, plt, &p ); } } } void QcGraph::drawDotElement ( QcGraphElement *e, const QRectF &rect, const QRect & bounds, const QColor & dotColor, const QColor & circleColor, const QColor & textColor, const QColor & selectColor, const QPalette &plt, const QFontMetrics &fm, QPainter *p ) { using namespace QtCollider::Style; using QtCollider::Style::Ellipse; // base Ellipse thumb(rect); drawRaised( p, plt, thumb, circleColor ); // marker QRectF r( thumb._rect ); qreal wdif = r.width() * 0.3; qreal hdif = r.height() * 0.3; p->setPen( Qt::NoPen ); p->setBrush( e->fillColor.isValid() ? e->fillColor : dotColor ); p->drawEllipse( r.adjusted( wdif, hdif, -wdif, -hdif ) ); // selection indicator if( e->selected ) { p->setBrush(Qt::NoBrush); p->setPen( selectColor ); p->drawEllipse( thumb._rect.adjusted(1,1,-1,-1) ); } // label p->setPen( textColor ); QString text = e->text; if( !text.isEmpty() ) { QRectF lblRect( labelRect( e, rect.center(), bounds, fm ) ); p->drawText( lblRect, 0, text ); } } void QcGraph::drawRectElement ( QcGraphElement *e, const QRectF &rect, const QColor & fillColor, const QColor & textColor, const QColor & selectColor, const QPalette &plt, QPainter *p ) { using namespace QtCollider::Style; using QtCollider::Style::RoundRect; // base RoundRect base(rect, 5); drawRaised( p, plt, base, e->fillColor.isValid() ? e->fillColor : fillColor ); // selection indicator if( e->selected ) { p->setBrush(Qt::NoBrush); p->setPen( selectColor ); p->drawRoundedRect( base._rect, 5, 5 ); } // label p->setPen( textColor ); QString text = e->text; if( !text.isEmpty() ) { p->drawText( rect, Qt::AlignCenter, text ); } } void QcGraph::mousePressEvent( QMouseEvent *ev ) { using namespace QtCollider::Style; QList elems = _model.elements(); int c = elems.count(); if( !c ) return; QPointF mpos = ev->pos(); QRectF valueRect( this->valueRect() ); QRectF r; int i; for( i = 0; i < c; ++i ) { QcGraphElement *e = elems[i]; r.setSize( drawnElementSize(e) ); QPointF pt( Style::pos( e->value, valueRect ) ); r.moveCenter( pt ); if( r.contains( mpos ) ) { if( ev->modifiers() & Qt::ShiftModifier ) { setIndexSelected( i, !e->selected ); } else { if( !e->selected ) { setAllDeselected(); setIndexSelected( i, true ); } } _selection.cached = false; if( e->selected ) { // if the element that was hit ended up selected // prepare for moving _selection.shallMove = true; _selection.moveOrigin = Style::value(mpos, valueRect); } else { _selection.shallMove = false; } update(); return; } } _selection.shallMove = false; if( !(ev->modifiers() & Qt::ShiftModifier) ) { setAllDeselected(); } update(); } void QcGraph::mouseMoveEvent( QMouseEvent *ev ) { using namespace QtCollider::Style; if( !ev->buttons() ) return; if( !_editable || !_selection.shallMove || !_selection.size() ) return; if( !_selection.cached ) { int c = _selection.count(); for( int i = 0; i < c; ++i ) { SelectedElement &se = _selection.elems[i]; se.moveOrigin = se.elem->value; } _selection.cached = true; } QRectF valueRect( this->valueRect() ); QPointF dValue( Style::value( ev->pos(), valueRect ) ); dValue = dValue - _selection.moveOrigin; moveSelected( dValue, _selectionForm, true ); update(); doAction( ev->modifiers() ); } void QcGraph::keyPressEvent( QKeyEvent *event ) { int mods = event->modifiers(); if( mods & Qt::AltModifier || mods & Qt::ShiftModifier ) { // selection mode int c = _model.elementCount(); if(!c) return; switch( event->key() ) { case Qt::Key_Right: { // select the index after the last selected one (wrapping) // or extend selection to the right int i = -1; if(_selection.count()) { for (i = c - 1; i >= 0; --i) { if(_model.elementAt(i)->selected) break; } } if( event->modifiers() & Qt::ShiftModifier ) { i = qMin(i + 1, c - 1); setIndexSelected( i, true ); } else { ++i; if (i >= c) i = 0; setAllDeselected(); setIndexSelected( i, true ); } break; } case Qt::Key_Left: { // select the index before the first selected one (wrapping) // or extend selection to the left int i = c; if(_selection.count()) { for(i = 0; i < c; ++i) { if(_model.elementAt(i)->selected) break; } } if( event->modifiers() & Qt::ShiftModifier ) { i = qMax(i - 1, 0); setIndexSelected( i, true ); } else { --i; if (i < 0) i = c - 1; setAllDeselected(); setIndexSelected( i, true ); } break; } default: break; } } else { // editing mode if( !_editable || !_selection.size() ) return; QPointF dValue; switch( event->key() ) { case Qt::Key_Up: dValue.setY( _step ); break; case Qt::Key_Down: dValue.setY( - _step ); break; case Qt::Key_Right: dValue.setX( _step ); break; case Qt::Key_Left: dValue.setX( - _step ); break; default: return; } moveSelected( dValue, _selectionForm, false ); update(); doAction( event->modifiers() ); } } void QcGraph::doAction( Qt::KeyboardModifiers mods ) { Qt::KeyboardModifier ctrlMod = #ifdef Q_OS_MAC Qt::MetaModifier; #else Qt::ControlModifier; #endif if( mods & ctrlMod ) Q_EMIT( metaAction() ); else Q_EMIT( action() ); } SuperCollider-Source/QtCollider/widgets/QcGraph.h000644 000765 000024 00000024765 12321461510 023074 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_GRAPH_H #define QC_GRAPH_H #include "../Common.h" #include "../QcHelper.h" #include "../style/style.hpp" #include struct QcGraphElement { friend class QcGraphModel; enum CurveType { Step = 0, Linear, Sine, Welch, Exponential, Quadratic, Cubic, Curvature, Hold }; QcGraphElement( const QSize & sz ) : size( sz ), curveType( Linear ), curvature( 0.0 ), editable( true ), selected( false ), _prev(0), _next(0) {} void setCurveType( CurveType type, double curve = 0.0 ) { curveType = type; curvature = curve; } QcGraphElement *prev() { return _prev; } QcGraphElement *next() { return _next; } QPointF value; QSize size; QString text; QColor fillColor; CurveType curveType; double curvature; bool editable; bool selected; private: QcGraphElement *_prev; QcGraphElement *_next; }; class QcGraphModel : public QObject { Q_OBJECT public: QcGraphModel( QObject * parent = 0 ) : QObject(parent) {} struct Connection { Connection( QcGraphElement * a_ = 0, QcGraphElement * b_ = 0 ) : a(a_), b(b_) {} QcGraphElement * a; QcGraphElement * b; }; inline QList elements() const { return _elems; } inline QcGraphElement *elementAt( int i ) const { return _elems[i]; } inline int elementCount() const { return _elems.count(); } void append( QcGraphElement * e ); void removeAt( int i ); inline QList connections() const { return _conns; } void connect( int xi, int yi ) { QcGraphElement *x = _elems[xi]; QcGraphElement *y = _elems[yi]; int i; for( i = 0; i < _conns.count(); ++i ) { Connection c = _conns[i]; if( (c.a==x && c.b==y) || (c.a==y && c.b==x) ) return; } _conns.append( Connection(x,y) ); } Q_SIGNALS: void appended( QcGraphElement * ); void removed( QcGraphElement * ); private: QList _conns; QList _elems; }; class QcGraph : public QWidget, QcHelper, QtCollider::Style::Client { Q_OBJECT Q_ENUMS( ElementStyle ) Q_PROPERTY( QVariantList value READ value WRITE setValue ) Q_PROPERTY( QVariantList strings READ dummyVariantList WRITE setStrings ); Q_PROPERTY( int index READ index WRITE setIndex ); Q_PROPERTY( int lastIndex READ lastIndex ); Q_PROPERTY( QVariantList selectionIndexes READ selectionIndexes); Q_PROPERTY( int thumbSize READ dummyInt WRITE setThumbSize ); Q_PROPERTY( int thumbWidth READ dummyInt WRITE setThumbWidth ); Q_PROPERTY( int thumbHeight READ dummyInt WRITE setThumbHeight ); Q_PROPERTY( QColor background READ background WRITE setBackground ); Q_PROPERTY( QColor strokeColor READ strokeColor WRITE setStrokeColor ); Q_PROPERTY( QColor fillColor READ dummyColor WRITE setFillColor ); Q_PROPERTY( QColor gridColor READ gridColor WRITE setGridColor ); Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); Q_PROPERTY( QColor selectionColor READ selectionColor WRITE setSelectionColor ); Q_PROPERTY( bool drawLines READ dummyBool WRITE setDrawLines ); Q_PROPERTY( bool drawRects READ dummyBool WRITE setDrawRects ); Q_PROPERTY( ElementStyle style READ elementStyle WRITE setElementStyle ); Q_PROPERTY( bool editable READ dummyBool WRITE setEditable ); Q_PROPERTY( double step READ step WRITE setStep ); Q_PROPERTY( int selectionForm READ selectionForm WRITE setSelectionForm ); Q_PROPERTY( int horizontalOrder READ horizontalOrder WRITE setHorizontalOrder ); Q_PROPERTY( float x READ currentX WRITE setCurrentX ); Q_PROPERTY( float y READ currentY WRITE setCurrentY ); Q_PROPERTY( QPointF grid READ grid WRITE setGrid ); Q_PROPERTY( bool gridOn READ dummyBool WRITE setGridOn ); public: Q_INVOKABLE void connectElements( int, QVariantList ); Q_INVOKABLE void setStringAt( int, const QString & ); Q_INVOKABLE void setFillColorAt( int, const QColor & ); Q_INVOKABLE void setEditableAt( int, bool ); Q_INVOKABLE void setThumbHeightAt( int, int ); Q_INVOKABLE void setThumbWidthAt( int, int ); Q_INVOKABLE void setThumbSizeAt( int, int ); Q_INVOKABLE void setCurves( double curvature ); Q_INVOKABLE void setCurves( int type ); Q_INVOKABLE void setCurves( const QVariantList & curves ); public Q_SLOTS: Q_INVOKABLE void select( int index, bool exclusive = true ); Q_INVOKABLE void deselect( int index ); Q_INVOKABLE void deselectAll(); Q_SIGNALS: void action(); void metaAction(); public: enum SelectionForm { ElasticSelection, RigidSelection }; enum Order { NoOrder, RigidOrder }; enum ElementStyle { DotElements, RectElements, }; public: QcGraph(); QVariantList value() const; QcGraphElement *currentElement() const; int index() const; int lastIndex() const { return _lastIndex; } QVariantList selectionIndexes() const; float currentX() const; float currentY() const; QPointF grid() const { return _gridMetrics; } void setValue( const QVariantList & ); void setStrings( const QVariantList &list ); void setIndex( int i ); void setCurrentX( float ); void setCurrentY( float ); void setThumbSize( int f ); void setThumbWidth( int f ); void setThumbHeight( int f ); const QColor & background() const { return _bkg.isValid() ? _bkg : palette().color(QPalette::Base); } void setBackground( const QColor &c ) { _bkg = c; update(); } const QColor & selectionColor() const { return _selectColor.isValid() ? _selectColor : palette().color(QPalette::Highlight); } void setSelectionColor( const QColor &c ) { _selectColor = c; update(); } const QColor & strokeColor() const { return _strokeColor.isValid() ? _strokeColor : palette().color(QPalette::Text); } void setStrokeColor( const QColor & c ) { _strokeColor = c; update(); } void setFillColor( const QColor & c ); QColor gridColor() const { if(_gridColor.isValid()) return _gridColor; else { QColor c = palette().color(QPalette::Text); c.setAlpha(40); return c; } } void setGridColor( const QColor & c ) { _gridColor = c; update(); } ElementStyle elementStyle() const { return _style; } void setElementStyle(ElementStyle s) { _style = s; _geometryDirty = true; update(); } void setDrawLines( bool b ) { _drawLines = b; update(); } void setDrawRects( bool b ) { _drawRects = b; update(); } void setEditable( bool b ) { _editable = b; update(); } double step() const { return _step; } void setStep( double ); int selectionForm() const { return (int)_selectionForm; } void setSelectionForm( int i ) { _selectionForm = (SelectionForm) i; } int horizontalOrder() const { return (int)_xOrder; } void setHorizontalOrder( int i ); void setGrid( const QPointF &pt ) { _gridMetrics = pt; update(); } void setGridOn( bool b ) { _gridOn = b; update(); } QSize sizeHint() const { return QSize( 200,200 ); } QSize minimumSizeHint() const { return QSize( 50,50 ); } private Q_SLOTS: void onElementRemoved( QcGraphElement *e ); private: struct SelectedElement { SelectedElement( QcGraphElement *e ) : elem(e) {} bool operator == (const SelectedElement & other) { return elem == other.elem; } QcGraphElement *elem; QPointF moveOrigin; // in data domain }; private: void setAllDeselected(); void setIndexSelected( int index, bool selected ); void restrictValue( QPointF & ); void orderRestrictValue( QcGraphElement *, QPointF &, bool selected ); void setValue( QcGraphElement *, const QPointF & ); void ensureOrder(); void moveFree( QcGraphElement *, const QPointF & ); void moveOrderRestricted( QcGraphElement *, const QPointF & ); void moveSelected( const QPointF & dValue, SelectionForm, bool fromCache ); void addCurve( QPainterPath &, QcGraphElement *e1, QcGraphElement *e2 ); QSize drawnElementSize( QcGraphElement *e ); QRect valueRect(); QRectF labelRect( QcGraphElement *, const QPointF &, const QRect &, const QFontMetrics & ); void drawDotElement( QcGraphElement *, const QRectF &, const QRect & bounds, const QColor & dotColor, const QColor & circleColor, const QColor & textColor, const QColor & selectColor, const QPalette &, const QFontMetrics &, QPainter * ); void drawRectElement( QcGraphElement *, const QRectF &, const QColor & fillColor, const QColor & textColor, const QColor & selectColor, const QPalette &, QPainter * ); void paintEvent( QPaintEvent * ); void mousePressEvent( QMouseEvent * ); void mouseMoveEvent( QMouseEvent * ); void keyPressEvent( QKeyEvent * ); void doAction( Qt::KeyboardModifiers ); QcGraphModel _model; QColor _bkg; QColor _strokeColor; QColor _gridColor; QColor _selectColor; QSize _defaultThumbSize; QPointF _gridMetrics; bool _gridOn; ElementStyle _style; bool _drawLines; bool _drawRects; bool _editable; double _step; SelectionForm _selectionForm; Order _xOrder; bool _geometryDirty; QSize _largestThumbSize; struct Selection { Selection () : cached(false), shallMove(false) {} int size() const { return elems.size(); } int count() const { return elems.count(); } QList elems; bool cached; bool shallMove; QPointF moveOrigin; // in data domain } _selection; int _lastIndex; }; #endif SuperCollider-Source/QtCollider/widgets/QcKnob.cpp000644 000765 000024 00000010302 12756531745 023261 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcKnob.hpp" #include "../QcWidgetFactory.h" #include "../style/routines.hpp" #include #include using namespace QtCollider; QC_DECLARE_QWIDGET_FACTORY(QcKnob); QcKnob::QcKnob() : Style::Client(this), _value(0.f), _mode(0), _step(0.01), _centered(false) { setFocusPolicy( Qt::StrongFocus ); setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); setAttribute(Qt::WA_AcceptTouchEvents); } void QcKnob::setValue( double val ) { _value = qBound( 0.0, val, 1.0 ); update(); } void QcKnob::mousePressEvent( QMouseEvent *e ) { if( _mode == 0 ) { setValue( value( e->pos() ) ); Q_EMIT( action() ); } _prevPos = e->pos(); } void QcKnob::mouseMoveEvent( QMouseEvent *e ) { if( !e->buttons() ) return; if( _mode == 0 ) { double val = value( e->pos() ); if( !(val < 0.0 && _value > 0.5) && !(val > 1.0 && _value < 0.5) ) setValue( value( e->pos() ) ); Q_EMIT( action() ); } else { int dif; dif = _mode == 1 ? e->pos().x() - _prevPos.x() : _prevPos.y() - e->pos().y(); if( dif != 0 ) { double step = _step; modifyStep( &step ); setValue( _value + dif * step ); Q_EMIT( action() ); } } _prevPos = e->pos(); } void QcKnob::paintEvent( QPaintEvent * ) { using namespace QtCollider::Style; using QtCollider::Style::Ellipse; QPainter p(this); p.setRenderHint( QPainter::Antialiasing, true ); const QPalette &plt( palette() ); QColor cGroove = plt.color( QPalette::Window ).lighter( 115 ); QColor cVal = plt.color( QPalette::ButtonText ); QRect bounds( rect() ); int sz = qMin( bounds.width(), bounds.height() ); float sz_2 = sz * 0.5f; QPointF center = QRectF(bounds).center(); p.translate( center ); double rad = sz_2 * 0.75; Ellipse shKnob(QRectF(-rad, -rad, rad*2, rad*2)); drawRaised( &p, plt, shKnob, plt.color( QPalette::Button ).lighter(105), hasFocus() ? focusColor() : QColor() ); p.scale( sz_2, sz_2 ); QPen pen; pen.setWidthF( 0.1 ); p.setBrush( Qt::NoBrush ); QRectF r( -0.95, -0.95, 1.9, 1.9 ); p.save(); // groove & value indicator rotation double range = 300.0; p.rotate( - 90 - range * 0.5 ); double valAng = - _value * range; if( _centered ) { double min = qMin( valAng, -range * 0.5 ); double max = qMax( valAng, -range * 0.5 ); pen.setColor( cGroove ); p.setPen( pen ); p.drawArc( r, -range * 16.f, (min + range) * 16.f ); p.drawArc( r, max * 16.f, -max * 16.f ); pen.setColor( plt.color(QPalette::WindowText) ); p.setPen( pen ); p.drawArc( r, min * 16.f, (max - min) * 16.f ); } else { pen.setColor( cGroove ); p.setPen( pen ); p.drawArc( r, -range * 16.f, (valAng + range) * 16.f ); pen.setColor( plt.color(QPalette::WindowText) ); p.setPen( pen ); p.drawArc( r, valAng * 16.f, -valAng * 16.f ); } p.restore(); // groove & value indicator rotation p.rotate( (360.0 - range) * 0.5 - valAng ); QLineF line( 0, 0.05, 0, 0.55 ); pen.setColor(cVal); pen.setWidthF( 0.15 ); pen.setCapStyle( Qt::RoundCap ); p.setPen( pen ); p.drawLine( line ); } double QcKnob::value( const QPoint &pt ) { double angle = QLineF( rect().center(), pt ).angle(); if( angle > 270.0 ) angle -= 270.0; else angle += 90; return (330 - angle) / 300.0; } SuperCollider-Source/QtCollider/widgets/QcKnob.hpp000644 000765 000024 00000004563 12321461510 023256 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_KNOB_HPP #define QC_KNOB_HPP #include #include "QcAbstractStepValue.h" #include "../style/style.hpp" class QcKnob : public QWidget, QcAbstractStepValue, QtCollider::Style::Client { Q_OBJECT Q_PROPERTY( double shiftScale READ shiftScale WRITE setShiftScale ); Q_PROPERTY( double ctrlScale READ ctrlScale WRITE setCtrlScale ); Q_PROPERTY( double altScale READ altScale WRITE setAltScale ); Q_PROPERTY( double value READ value WRITE setValue ) Q_PROPERTY( int mode READ mode WRITE setMode ) Q_PROPERTY( double step READ step WRITE setStep ) Q_PROPERTY( bool centered READ centered WRITE setCentered ) Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); Q_SIGNALS: void action(); public: QcKnob(); void setValue( double ); double value() const { return _value; } void setMode( int i ) { _mode = i; } int mode() const { return _mode; } void setStep( float step ) { _step = step; } float step() const { return _step; } void setCentered( bool b ) { _centered = b; update(); } bool centered() const { return _centered; } virtual QSize sizeHint() const { return QSize(40,40); } virtual QSize minimumSizeHint() const { return QSize(15,15); } protected: virtual void mousePressEvent( QMouseEvent * ); virtual void mouseMoveEvent( QMouseEvent * ); virtual void paintEvent( QPaintEvent * ); private: double value( const QPoint & ); double _value; double _step; int _mode; QPoint _prevPos; bool _centered; }; #endif // QC_KNOB_HPP SuperCollider-Source/QtCollider/widgets/QcLevelIndicator.cpp000644 000765 000024 00000012520 12756531745 025300 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcLevelIndicator.h" #include "../QcWidgetFactory.h" #include QC_DECLARE_QWIDGET_FACTORY(QcLevelIndicator); QcLevelIndicator::QcLevelIndicator() : QtCollider::Style::Client(this), _value( 0.f ), _warning(0.6), _critical(0.8), _peak( 0.f ), _drawPeak( false ), _ticks(0), _majorTicks(0), _stepWidth(10), _style(LevelIndicatorStyle::Continuous), _clipped(false), _meterColor(0, 255, 0), _warningColor(255, 255, 0), _criticalColor(255,100,0) { _clipTimer = new QTimer( this ); _clipTimer->setSingleShot(true); _clipTimer->setInterval( 1000 ); connect( _clipTimer, SIGNAL(timeout()), this, SLOT(clipTimeout()) ); } const QColor QcLevelIndicator::valueColor(float value) { if(value > _critical) return _criticalColor; else if(value > _warning) return _warningColor; else return _meterColor; } void QcLevelIndicator::clipTimeout() { _clipped = false; update(); } void QcLevelIndicator::paintEvent( QPaintEvent *e ) { QPainter p(this); bool vertical = height() >= width(); float groove = vertical ? width() : height(); float length = vertical ? height() : width(); if (!vertical) { p.scale(-1, 1); p.translate(0, 0); p.rotate(90); } else { p.scale(1, -1); p.translate(0, -height()); } QPalette plt = palette(); if( _ticks || _majorTicks ) groove -= 6; float colorValue = _drawPeak ? _peak : _value; if( colorValue > _critical ) { _clipTimer->stop(); _clipped = true; } else if( _clipped && !_clipTimer->isActive() ) { _clipTimer->start(); } p.fillRect( QRectF(0, 0, groove, length), grooveColor()); QRectF r; r.setWidth( groove ); r.setY(0); p.setRenderHint(QPainter::Antialiasing, true); switch (_style) { case Continuous: { r.setHeight( _value * length ); p.fillRect( r, valueColor(colorValue) ); if( _drawPeak && _peak > 0.f ) { // compensate for border and peak line width float val = _peak * ( length - 4 ) + 2; QPen pen( valueColor(_peak) ); pen.setWidth( 2 ); pen.setCapStyle( Qt::FlatCap ); p.setPen( pen ); p.drawLine( 0.f, val, groove, val ); } break; } case LED: { float ledBaseline = 0; float spaceWidth = _stepWidth <= 3 ? 1 : 2; float cornerWidth = _stepWidth <= 3 ? 0 : 1.2; float stepSpacing = _stepWidth + spaceWidth; float adjustedLength = std::floor(length / stepSpacing) * stepSpacing; r.setHeight(_stepWidth); QPainterPath path; path.addRoundedRect(r, cornerWidth, cornerWidth); while (ledBaseline < adjustedLength * _value) { float normValue = (ledBaseline / adjustedLength); // 0..1 scaled value of the BOTTOM of the rect float nextValue = ((ledBaseline + _stepWidth + spaceWidth) / adjustedLength); QColor c = valueColor(normValue); if (nextValue > _value) { // last cell c = valueColor(_value); c.setAlphaF(c.alphaF() * (0.5 + 0.5 * ((_value - normValue) / (nextValue - normValue)))); } p.fillPath(path, QBrush(c)); ledBaseline += stepSpacing; path.translate(0, stepSpacing); } if( _drawPeak && _peak > 0.f ) { float peak = std::floor(_peak * adjustedLength / stepSpacing) * stepSpacing; peak = std::min(peak, adjustedLength - stepSpacing); // For _peak == 1, don't run off edge of widget QPainterPath peakPath; peakPath.addRoundedRect(r, cornerWidth, cornerWidth); peakPath.translate(0, peak); p.fillPath(peakPath, QBrush(valueColor(_peak))); } break; } default: break; } p.setRenderHint(QPainter::Antialiasing, false); if( _ticks ) { QPen pen( plt.color(QPalette::WindowText) ); pen.setCapStyle( Qt::FlatCap ); p.setPen(pen); float dVal = ( _ticks > 1 ) ? ( length-1) / (float)(_ticks-1) : 0.f; float t = 0; while( t < _ticks ) { float v = t * dVal; p.drawLine( groove, v, width(), v ); t++; } } if( _majorTicks ) { QPen pen ( plt.color(QPalette::WindowText) ); pen.setCapStyle( Qt::FlatCap ); pen.setWidth( 3 ); p.setPen( pen ); float dVal = ( _majorTicks > 1 ) ? (length-3) / (float)(_majorTicks-1) : 0.f; float t = 0; while( t < _majorTicks ) { float v = (int) (t * dVal) + 1; if( vertical ) p.drawLine( groove, v, width(), v ); else p.drawLine( v, groove, v, height() ); t++; } } } SuperCollider-Source/QtCollider/widgets/QcLevelIndicator.h000644 000765 000024 00000006611 12756531745 024751 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_LEVEL_INDICATOR_H #define QC_LEVEL_INDICATOR_H #include "../QcHelper.h" #include "../style/style.hpp" #include #include class QcLevelIndicator : public QWidget, QcHelper, QtCollider::Style::Client { Q_OBJECT Q_PROPERTY( float value READ dummyFloat WRITE setValue ); Q_PROPERTY( float warning READ dummyFloat WRITE setWarning ); Q_PROPERTY( float critical READ dummyFloat WRITE setCritical ); Q_PROPERTY( float peak READ dummyFloat WRITE setPeak ); Q_PROPERTY( bool drawPeak READ dummyBool WRITE setDrawPeak ); Q_PROPERTY( int ticks READ dummyInt WRITE setTicks ); Q_PROPERTY( int majorTicks READ dummyInt WRITE setMajorTicks ); Q_PROPERTY( int stepWidth READ dummyInt WRITE setStepWidth ); Q_PROPERTY( LevelIndicatorStyle style READ style WRITE setStyle ); Q_PROPERTY( QColor grooveColor READ grooveColor WRITE setGrooveColor ); Q_PROPERTY( QColor meterColor READ dummyColor WRITE setMeterColor ); Q_PROPERTY( QColor warningColor READ dummyColor WRITE setWarningColor ); Q_PROPERTY( QColor criticalColor READ dummyColor WRITE setCriticalColor ); public: enum LevelIndicatorStyle { Continuous = 0, LED }; Q_ENUMS(LevelIndicatorStyle); QcLevelIndicator(); void setValue( float f ) { _value = f; update(); } void setWarning( float f ) { _warning = f; update(); } void setCritical( float f ) { _critical = f; update(); } void setPeak( float f ) { _peak = f; update(); } void setDrawPeak( bool b ) { _drawPeak = b; update(); } void setTicks( int i ) { _ticks = qMax(i,0); update(); } void setMajorTicks( int i ) { _majorTicks = qMax(i,0); update(); } void setStepWidth( int i ) { _stepWidth = qMax(i,1); update(); } void setStyle( LevelIndicatorStyle i ) { _style = i; update(); } void setStyle( int i ) { _style = (LevelIndicatorStyle)i; update(); } LevelIndicatorStyle style() { return _style; }; void setMeterColor( const QColor c ) { _meterColor = c; update(); } void setWarningColor( const QColor c ) { _warningColor = c; update(); } void setCriticalColor( const QColor c ) { _criticalColor = c; update(); } virtual QSize sizeHint() const { return QSize( 25, 150 ); } private Q_SLOTS: void clipTimeout(); private: const QColor valueColor(float value); QColor _meterColor, _warningColor, _criticalColor; void paintEvent( QPaintEvent *e ); float _value; float _warning; float _critical; float _peak; bool _drawPeak; int _ticks; int _majorTicks; float _stepWidth; LevelIndicatorStyle _style; bool _clipped; QTimer *_clipTimer; }; #endif SuperCollider-Source/QtCollider/widgets/QcListWidget.cpp000644 000765 000024 00000006233 12321461510 024433 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcListWidget.h" #include "../QcWidgetFactory.h" #include #include class QcListWidgetFactory : public QcWidgetFactory { void initialize( QWidgetProxy *p, QcListWidget *l ) { p->setMouseEventWidget( l->viewport() ); } }; QC_DECLARE_FACTORY( QcListWidget, QcListWidgetFactory ); QcListWidget::QcListWidget() : _emitAction(true) { connect( this, SIGNAL( currentItemChanged( QListWidgetItem*, QListWidgetItem* ) ), this, SLOT( onCurrentItemChanged() ) ); } void QcListWidget::setItems( const QVariantList & items ) { _emitAction = false; clear(); Q_FOREACH( const QVariant & item, items ) addItem( item.toString() ); setCurrentRow( 0 ); _emitAction = true; } void QcListWidget::setColors( const QVariantList & colors ) const { int cc = colors.count(); int ic = count(); for( int i=0; i() ); if( color.isValid() ) it->setBackground( color ); } } void QcListWidget::setCurrentRowWithoutAction( int row ) { bool b = _emitAction; _emitAction = false; setCurrentRow( row ); _emitAction = b; } QVariantList QcListWidget::selection() const { QModelIndexList modelIndexes = QListView::selectedIndexes(); QVariantList indexes; Q_FOREACH( const QModelIndex & index, modelIndexes ) indexes << index.row(); return indexes; } void QcListWidget::setSelection( const QVariantList & list ) { clearSelection(); Q_FOREACH( const QVariant & var, list ) { int row = var.toInt(); QListWidgetItem *item = QListWidget::item(row); if (item) item->setSelected(true); } } void QcListWidget::onCurrentItemChanged() { if( _emitAction ) Q_EMIT( action() ); } void QcListWidget::keyPressEvent( QKeyEvent *e ) { QListWidget::keyPressEvent( e ); switch (e->key()) { case Qt::Key_Return: case Qt::Key_Enter: Q_EMIT( returnPressed() ); e->accept(); break; case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_PageUp: case Qt::Key_PageDown: case Qt::Key_Home: case Qt::Key_End: // Prevent propagating to parent when scroller reaches minimum or maximum: e->accept(); default: break; } } SuperCollider-Source/QtCollider/widgets/QcListWidget.h000644 000765 000024 00000003377 12321461510 024106 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "../QcHelper.h" #include "../Common.h" #include class QcListWidget : public QListWidget, QcHelper { Q_OBJECT Q_PROPERTY( QVariantList items READ dummyVariantList WRITE setItems ); Q_PROPERTY( QVariantList colors READ dummyVariantList WRITE setColors ); Q_PROPERTY( int currentRow READ currentRow WRITE setCurrentRowWithoutAction ) Q_PROPERTY( QVariantList selection READ selection WRITE setSelection ); public: QcListWidget(); void setItems( const QVariantList & ); void setColors( const QVariantList & ) const; void setCurrentRowWithoutAction( int ); QVariantList selection() const; void setSelection( const QVariantList & ); Q_SIGNALS: void action(); void returnPressed(); private Q_SLOTS: void onCurrentItemChanged(); protected: virtual void keyPressEvent( QKeyEvent * ); private: bool _emitAction; }; SuperCollider-Source/QtCollider/widgets/QcMultiSlider.cpp000644 000765 000024 00000024664 12756531745 024645 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcMultiSlider.h" #include "../QcWidgetFactory.h" #include "../style/routines.hpp" #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcMultiSlider); QcMultiSlider::QcMultiSlider() : QtCollider::Style::Client(this), _currentIndex(0), _selectionSize(1), roundStep( 0.f ), editable( true ), ort( Qt::Vertical), elastic( false ), thumbSize( QSizeF( 12.f, 12.f ) ), gap( 1 ), drawRects( true ), drawLines( false ), isFilled( false ), highlight( false ), startIndex( 0 ) { setFocusPolicy( Qt::StrongFocus ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); setAttribute(Qt::WA_AcceptTouchEvents); connect( this, SIGNAL(modified()), this, SLOT(update()) ); connect( this, SIGNAL(interacted()), this, SLOT(doAction()) ); } void QcMultiSlider::setSliderCount( int newSize ) { while( newSize > _values.size() ) _values.append( 0.f ); while( newSize < _values.size() ) _values.removeLast(); update(); } QVector QcMultiSlider::values() const { return QVector::fromList(_values); } void QcMultiSlider::setValues( const QVector & vec ) { _values.clear(); Q_FOREACH( double value, vec ) _values << qBound(0.0, rounded(value), 1.0); update(); } double QcMultiSlider::value() const { if( _currentIndex >= 0 && _currentIndex < _values.count() ) return _values[_currentIndex]; else return 0.0; } void QcMultiSlider::setValue( double val ) { if( _currentIndex >= 0 && _currentIndex < _values.count() ) setValue( _currentIndex, val ); update(); } QVector QcMultiSlider::reference() const { return QVector::fromList(_ref); } void QcMultiSlider::setReference( const QVector & vec ) { _ref.clear(); Q_FOREACH( double value, vec ) _ref << qBound( 0.0, value, 1.0 ); update(); } void QcMultiSlider::setStep( double step ) { if( roundStep == step ) return; roundStep = step; if( step == 0.0 ) return; int c = _values.count(); int i; for( i=0; i= 0 && i < _values.count() ) { _currentIndex = i; _selectionSize = 1; update(); } } void QcMultiSlider::setSelectionSize( int i ) { _selectionSize = qMin(i, _values.count() - _currentIndex); update(); } inline void QcMultiSlider::setValue( int index, double value ) { _values[index] = qBound( 0.0, rounded(value), 1.0 ); } inline double QcMultiSlider::rounded ( double value ) { return roundStep > 0.0 ? qRound( value / roundStep ) * roundStep : value; } QRect QcMultiSlider::contentsRect() { return QtCollider::Style::sunkenContentsRect(rect()).adjusted(2, 2,-2,-2); } QRect QcMultiSlider::valueRect( int count, qreal & spacing ) { QRect r( contentsRect() ); bool horiz = ort == Qt::Horizontal; spacing = elastic ? (qreal) (horiz ? r.height() : r.width()) / count : thumbSize.width() + gap; if( !isFilled ) { int hnd = thumbSize.height(); if( horiz ) { r.setWidth( r.width() - hnd ); r.moveLeft( r.left() + hnd * 0.5 ); } else { r.setHeight( r.height() - hnd ); r.moveTop( r.top() + hnd * 0.5 ); } } return r; } void QcMultiSlider::mousePressEvent( QMouseEvent *e ) { using namespace QtCollider::Style; moveOrigin = e->pos(); int c = _values.count(); if( !c ) return; bool horiz = ort == Qt::Horizontal; qreal spacing; QRect r( valueRect( c - startIndex, spacing ) ); int i; float val; if( horiz ) { i = spacing > 0.f ? floor((float)(moveOrigin.y() - r.y()) / spacing) : 0; val = xValue((qreal)moveOrigin.x(), r); } else { i = spacing > 0.f ? floor((float)(moveOrigin.x() - r.x()) / spacing) : 0; val = yValue((qreal)moveOrigin.y(), r); } i += startIndex; if( i >= startIndex && i < c ) { _currentIndex = i; _selectionSize = 1; if( editable ) setValue( i, val ); if( editable || highlight ) Q_EMIT( modified() ); Q_EMIT( interacted() ); } } void QcMultiSlider::mouseMoveEvent( QMouseEvent *e ) { using namespace QtCollider::Style; if( !e->buttons() ) return; int c = _values.count(); QPoint pos = e->pos(); if( !c ) { moveOrigin = pos; return; } qreal xStep; QRect r( valueRect( c - startIndex, xStep ) ); float xOrig, yOrig, xDest, yDest; int xOffset, xRange; int iOrig, iDest, iMax; if( ort == Qt::Vertical ) { xOffset = r.left(); xRange = r.width(); xOrig = moveOrigin.x(); yOrig = yValue(moveOrigin.y(), r); xDest = pos.x(); yDest = yValue(pos.y(), r); } else { xOffset = r.top(); xRange = r.height(); xOrig = moveOrigin.y(); yOrig = xValue(moveOrigin.x(), r); xDest = pos.y(); yDest = xValue(pos.x(), r); } if( xStep > 0.0 ) { iOrig = floor((xOrig - xOffset) / xStep); iOrig += startIndex; iDest = floor((xDest - xOffset) / xStep); iDest += startIndex; iMax = elastic ? c : qMin( c, int( (float)xRange / xStep) + startIndex + 1); } else { iOrig = iDest = iMax = startIndex; } if( editable && (iOrig != iDest) ) { float k = (yDest - yOrig) / (xDest - xOrig); float n = yOrig - (xOrig - xOffset) * k; int i = iOrig - startIndex; while( iOrig < iDest ) { ++i; if( iOrig >= startIndex && iOrig < iMax ) { float y = (i * xStep) * k + n; setValue( iOrig, y ); } ++iOrig; } while( iOrig > iDest ) { if( iOrig >= startIndex && iOrig < iMax ) { float y = (i * xStep) * k + n; setValue( iOrig, y ); } --iOrig; --i; } } if( iDest >= startIndex && iDest < iMax ) { if( editable ) setValue( iDest, yDest ); _currentIndex = iDest; _selectionSize = 1; } moveOrigin = pos; Q_EMIT( modified() ); Q_EMIT( interacted() ); } void QcMultiSlider::paintEvent( QPaintEvent *e ) { using namespace QtCollider::Style; using QtCollider::Style::Ellipse; using QtCollider::Style::RoundRect; Q_UNUSED(e); QPainter p(this); p.setRenderHint( QPainter::Antialiasing, true ); RoundRect frame(rect(), 2); drawSunken( &p, palette(), frame, background(), hasFocus() ? focusColor() : QColor() ); if( !_values.count() ) return; p.setRenderHint( QPainter::Antialiasing, false ); bool horiz = ort == Qt::Horizontal; QRect bounds( contentsRect() ); p.setClipRect( bounds ); if( horiz ) { p.translate( bounds.topLeft() ); p.rotate(90); p.scale(1.0, -1.0); bounds.setSize( QSize( bounds.height(), bounds.width() ) ); } else { p.translate( bounds.left(), bounds.top() + bounds.height() ); p.scale(1.0, -1.0); } int count = _values.count() - startIndex; qreal spacing, width, yscale; spacing = elastic ? (qreal) bounds.width() / count : thumbSize.width() + gap; width = elastic ? qMin( spacing, (qreal) thumbSize.width() ) : thumbSize.width(); yscale = bounds.height(); if( !isFilled ) yscale -= thumbSize.height(); const QColor & fillClr = fillColor(); // selection if( highlight ) { int i = _currentIndex - startIndex; int c = qMin( count - i, _selectionSize ); if(c) { QRect r; r.setHeight( bounds.height() ); r.setWidth( c * spacing ); r.moveLeft( i * spacing ); QColor hlColor = fillClr; hlColor.setAlpha( 70 ); p.fillRect( r, hlColor ); } } QPen pen; pen.setColor(strokeColor()); pen.setWidth(0); p.setPen(pen); // lines if( drawLines ) { bool fill = isFilled & !drawRects; p.save(); p.setRenderHint( QPainter::Antialiasing, true ); p.translate( spacing * 0.5, isFilled ? 0.0 : thumbSize.height() * 0.5 ); p.scale( 1.0, (qreal) yscale ); if( fill ) p.setBrush( fillClr ); QPainterPath path; // value line path.moveTo( 0, _values[startIndex] ); for( int i = 1; i < count; ++i ) path.lineTo( (qreal) i * spacing, _values[i + startIndex] ); // reference line int refcount = _ref.count() - startIndex; if( refcount > 0 || fill ) { qreal x, y; int i = count - 1; x = i * spacing; y = i < refcount ? _ref[i + startIndex] : 0.f; if( fill ) path.lineTo(x, y); else path.moveTo(x, y); while( --i >= 0 ) { x = i * spacing; y = i < refcount ? _ref[i + startIndex] : 0.f; path.lineTo(x, y); } if( fill ) path.closeSubpath(); } p.drawPath( path ); p.restore(); } // rects if( drawRects ) { p.setRenderHint( QPainter::Antialiasing, false ); p.translate( (spacing - width) * 0.5, 0 ); p.setBrush( fillClr ); QRectF r; r.setWidth( width ); if( isFilled ) { int refcount = _ref.count() - startIndex; for( int i = 0; i < count; ++i ) { int ref = (i < refcount ? _ref[i + startIndex] : 0.f) * yscale; int val = _values[i + startIndex] * yscale; r.moveLeft( i * spacing ); r.moveTop( ref ); r.setHeight( val - ref ); if(horiz) p.drawRect(r.normalized().adjusted(0,0,-1,-1)); else p.drawRect(r.normalized().adjusted(0,1,-1,0)); } } else { r.setHeight( thumbSize.height() ); for( int i = 0; i < count; ++i ) { r.moveLeft( i * spacing ); r.moveTop( _values[i + startIndex] * yscale ); if(horiz) p.drawRect(r.adjusted(0,0,-1,-1)); else p.drawRect(r.adjusted(0,1,-1,0)); } } } } void QcMultiSlider::doAction() { Qt::KeyboardModifier ctrlMod = #ifdef Q_OS_MAC Qt::MetaModifier; #else Qt::ControlModifier; #endif if( QApplication::keyboardModifiers() & ctrlMod ) Q_EMIT( metaAction() ); else Q_EMIT( action() ); } SuperCollider-Source/QtCollider/widgets/QcMultiSlider.h000644 000765 000024 00000013254 12321461510 024257 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_MULTI_SLIDER #define QC_MULTI_SLIDER #include "../QcHelper.h" #include "../style/style.hpp" #include "../Common.h" #include class QcMultiSlider : public QWidget, QcHelper, QtCollider::Style::Client { // TODO setting selection with mouse Q_OBJECT Q_PROPERTY( int sliderCount READ sliderCount WRITE setSliderCount); Q_PROPERTY( QVector values READ values WRITE setValues ); Q_PROPERTY( QVector reference READ reference WRITE setReference ); Q_PROPERTY( double value READ value WRITE setValue ); Q_PROPERTY( double step READ step WRITE setStep ); Q_PROPERTY( int index READ index WRITE setIndex ); Q_PROPERTY( int selectionSize READ selectionSize WRITE setSelectionSize ); Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation ); Q_PROPERTY( bool elastic READ dummyBool WRITE setElastic ); Q_PROPERTY( int indexThumbSize READ dummyFloat WRITE setIndexThumbSize ); Q_PROPERTY( float valueThumbSize READ dummyFloat WRITE setValueThumbSize ); Q_PROPERTY( int gap READ dummyInt WRITE setGap ); Q_PROPERTY( bool drawLines READ dummyBool WRITE setDrawLines ); Q_PROPERTY( bool drawRects READ dummyBool WRITE setDrawRects ); Q_PROPERTY( bool isFilled READ dummyBool WRITE setIsFilled ); Q_PROPERTY( bool highlight READ dummyBool WRITE setHighlight ); Q_PROPERTY( bool editable READ dummyBool WRITE setEditable ); Q_PROPERTY( int startIndex READ dummyInt WRITE setStartIndex ); Q_PROPERTY( QColor background READ background WRITE setBackground ); Q_PROPERTY( QColor fillColor READ fillColor WRITE setFillColor ); Q_PROPERTY( QColor strokeColor READ strokeColor WRITE setStrokeColor ); Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); Q_SIGNALS: void modified(); void interacted(); void action(); void metaAction(); public Q_SLOTS: void doAction(); public: QcMultiSlider(); QVector values() const; void setValues( const QVector & ); double value() const; void setValue( double ); QVector reference() const; void setReference( const QVector & ); double step() const { return roundStep; } void setStep( double ); QSize sizeHint() const { return QSize( 500,300 ); } QSize minimumSizeHint() const { return QSize( 50, 50 ); } const QColor & background() const { return _bkgColor.isValid() ? _bkgColor : palette().color(QPalette::Base); } void setBackground( const QColor & c ) { _bkgColor = c; update(); } const QColor & fillColor() const { return _fillColor.isValid() ? _fillColor : palette().color(QPalette::Text); } void setFillColor( const QColor& c ) { _fillColor = c; update(); } const QColor & strokeColor() const { return _strokeColor.isValid() ? _strokeColor : palette().color(QPalette::Text); } void setStrokeColor( const QColor& c ) { _strokeColor = c; update(); } protected: virtual void mousePressEvent( QMouseEvent * ); virtual void mouseMoveEvent( QMouseEvent * ); virtual void paintEvent( QPaintEvent * ); private: Qt::Orientation orientation() const { return ort; } int index() const { return _currentIndex; } int selectionSize() const { return _selectionSize; } int sliderCount() const { return _values.size(); } void setSliderCount( int size ); void setIndex( int i ); void setSelectionSize( int i ); void setOrientation( Qt::Orientation o ) { ort = o; update(); } void setElastic( bool b ) { elastic = b; update(); } void setIndexThumbSize( float f ) { thumbSize.setWidth(f); update(); } void setValueThumbSize( float f ) { thumbSize.setHeight(f); update(); } void setGap( int i ) { gap = i; update(); } void setDrawLines( bool b ) { drawLines = b; update(); } void setDrawRects( bool b ) { drawRects = b; update(); } void setIsFilled( bool b ) { isFilled = b; update(); } void setHighlight( bool b ) { highlight = b; update(); } void setEditable( bool b ) { editable = b; } void setStartIndex( int i ) { startIndex = qBound(0, i, _values.count()-1); update(); } QRect contentsRect(); QRect valueRect( int count, qreal & spacing ); inline float valueFromPos( float pos, float range ); inline void setValue( int index, double value ); double rounded ( double value ); // values QList _values; QList _ref; int _currentIndex; int _selectionSize; // functional properties double roundStep; bool editable; // visual properties Qt::Orientation ort; bool elastic; QSizeF thumbSize; int gap; bool drawRects; bool drawLines; bool isFilled; bool highlight; int startIndex; QColor _bkgColor; QColor _fillColor; QColor _strokeColor; QColor _focusColor; // temporary QPoint moveOrigin; }; #endif SuperCollider-Source/QtCollider/widgets/QcNumberBox.cpp000644 000765 000024 00000021477 12756531745 024310 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcNumberBox.h" #include "../Common.h" #include "../QcWidgetFactory.h" #include #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcNumberBox); QcNumberBox::QcNumberBox() : scroll( true ), lastPos( 0 ), editedTextColor( QColor( "red" ) ), normalTextColor( palette().color(QPalette::Text) ), _validator( new QDoubleValidator( this ) ), step( 0.1f ), scrollStep( 1.0f ), dragDist( 10.f ), _value( 0. ), _valueType( Number ), _minDec(0), _maxDec(2) { _validator->setDecimals( _maxDec ); setValidator( _validator ); // Do not display thousands separator. It only eats up precious space. QLocale loc( locale() ); loc.setNumberOptions( QLocale::OmitGroupSeparator ); setLocale( loc ); setLocked( true ); setAttribute(Qt::WA_AcceptTouchEvents); connect( this, SIGNAL( editingFinished() ), this, SLOT( onEditingFinished() ) ); connect( this, SIGNAL( valueChanged() ), this, SLOT( updateText() ), Qt::QueuedConnection ); setValue( 0 ); } void QcNumberBox::setLocked( bool locked ) { if( locked ) { setReadOnly( true ); setSelection( 0, 0 ); } else { setReadOnly( false ); } updateTextColor(); } void QcNumberBox::setTextColor( const QColor& c ) { if( c.isValid() ) { normalTextColor = c; updateTextColor(); } } void QcNumberBox::setEditedTextColor( const QColor& c ) { if( c.isValid() ) { editedTextColor = c; updateTextColor(); } } void QcNumberBox::setValue( double val ) { if( val > _validator->top() ) val = _validator->top(); if ( val < _validator->bottom() ) val = _validator->bottom(); val = roundedVal( val ); _value = val; _valueType = Number; Q_EMIT( valueChanged() ); } void QcNumberBox::setInfinite( bool positive ) { _valueType = positive ? Infinite : InfiniteNegative; Q_EMIT( valueChanged() ); } void QcNumberBox::setNaN() { _valueType = NaN; Q_EMIT( valueChanged() ); } void QcNumberBox::setTextValue( const QString &str ) { _valueType = Text; setText( str ); } double QcNumberBox::value () const { return _value; } void QcNumberBox::setMinimum( double min ) { _validator->setBottom(min); if( _valueType == Number ) setValue( _value ); // clip current value } void QcNumberBox::setMaximum( double max ) { _validator->setTop(max); if( _valueType == Number ) setValue( _value ); // clip current value } void QcNumberBox::setDecimals( int d ) { if( d < 0 ) return; _minDec = _maxDec = d; _validator->setDecimals( d ); if( _valueType == Number ) setValue( _value ); // round current value } void QcNumberBox::setMinDecimals( int d ) { if( d < 0 ) return; _minDec = d; if( _minDec > _maxDec ) { _maxDec = d; _validator->setDecimals( d ); } if( _valueType == Number ) setValue( _value ); // round current value } void QcNumberBox::setMaxDecimals( int d ) { if( d < 0 ) return; _maxDec = d; if( _maxDec < _minDec ) _minDec = d; _validator->setDecimals( d ); if( _valueType == Number ) setValue( _value ); // round current value } void QcNumberBox::increment( double factor ) { if( !isReadOnly() || _valueType != Number ) return; setValue( value() + (step * factor) ); Q_EMIT( action() ); } void QcNumberBox::decrement( double factor ) { if( !isReadOnly() || _valueType != Number ) return; setValue( value() - (step * factor) ); Q_EMIT( action() ); } void QcNumberBox::onEditingFinished() { if( isReadOnly() ) return; setValue( locale().toDouble( text() ) ); Q_EMIT( action() ); } void QcNumberBox::updateText() { QString str; switch( _valueType ) { case Number: str = stringForVal( _value ); break; case Text: return; // text was already set case Infinite: str = "+inf"; break; case InfiniteNegative: str = "-inf"; break; case NaN: str = "NaN"; break; } blockSignals(true); setText( str ); // Set cursor to beginning so most significant digits are shown // if widget size too small. setCursorPosition(0); setLocked( true ); blockSignals(false); } void QcNumberBox::stepBy( int steps, double stepSize ) { if( _valueType != Number ) return; modifyStep( &stepSize ); setValue( value() + (steps * stepSize) ); } double QcNumberBox::roundedVal( double val ) { double k = pow( 10, _maxDec ); return qRound( val * k ) / k; } QString QcNumberBox::stringForVal( double val ) { QLocale loc = locale(); QString str = loc.toString( val, 'f', _maxDec ); int i = str.indexOf( loc.decimalPoint() ); if( i > -1 ) { QString dec = str.mid(i+1); while( dec.size() > _minDec && dec.endsWith('0') ) dec.chop(1); if( dec.isEmpty() ) str = str.left(i); else str = str.left(i+1) + dec; } return str; } void QcNumberBox::updateTextColor() { QPalette p( palette() ); p.setColor( QPalette::Text, isReadOnly() ? normalTextColor : editedTextColor ); setPalette( p ); } void QcNumberBox::keyPressEvent ( QKeyEvent * event ) { if( !isReadOnly() ) return QLineEdit::keyPressEvent( event ); int key = event->key(); if( key == Qt::Key_Up ){ stepBy( 1, step ); Q_EMIT( action() ); return; } else if( key == Qt::Key_Down ) { stepBy( -1, step ); Q_EMIT( action() ); return; } else { // unlock typing if valid char is entered QString t = event->text(); int i = 0; if( !t.isEmpty() && ( _validator->validate( t, i ) != QValidator::Invalid ) ) { blockSignals(true); clear(); blockSignals( false ); setLocked( false ); } } QLineEdit::keyPressEvent( event ); } void QcNumberBox::mouseDoubleClickEvent ( QMouseEvent * event ) { Q_UNUSED( event ); setCursorPosition( cursorPositionAt( event->pos() ) ); setLocked( false ); } void QcNumberBox::mousePressEvent ( QMouseEvent * event ) { lastPos = event->globalY(); // If locked, prevent cursor position change. Cursor has to stay at 0 // so most significant digits are shown if widget size too small. if( isReadOnly() ) return; QLineEdit::mousePressEvent( event ); } void QcNumberBox::mouseMoveEvent ( QMouseEvent * event ) { if( scroll && isReadOnly() && _valueType == Number && ( event->buttons() & Qt::LeftButton ) ) { int steps = (event->globalY() - lastPos) / dragDist; if( steps != 0 ) { lastPos = lastPos + (steps * dragDist); stepBy( -steps, scrollStep ); Q_EMIT( action() ); } } else QLineEdit::mouseMoveEvent( event ); } void QcNumberBox::wheelEvent ( QWheelEvent * event ) { if( scroll && isReadOnly() && _valueType == Number && event->orientation() == Qt::Vertical ) { stepBy( event->delta() > 0 ? 1 : -1, scrollStep ); Q_EMIT( action() ); } } #if 0 NumberBoxWidget::NumberBoxWidget() : modifier( 0 ), scrollStep( 1 ) { ScrollLineEdit *scrollLineEdit = new ScrollLineEdit(); scrollLineEdit->setScroll( true ); setLineEdit( scrollLineEdit ); connect( scrollLineEdit, SIGNAL( scrolled(int) ), this, SLOT( scrollBy(int) ) ); connect( this, SIGNAL( editingFinished() ), this, SLOT( onEditingFinished() ) ); } void NumberBoxWidget::setScroll( bool b ) { ScrollLineEdit *edit = qobject_cast( lineEdit() ); edit->setScroll( b ); } void NumberBoxWidget::stepBy( int steps ) { stepBy( steps, singleStep() ); } void NumberBoxWidget::scrollBy( int steps ) { stepBy( steps, scrollStep ); } void NumberBoxWidget::onEditingFinished() { ScrollLineEdit *edit = qobject_cast( lineEdit() ); edit->setLocked( true ); } void NumberBoxWidget::stepBy( int steps, float stepSize ) { modifier->modifyStep( &stepSize ); double val = qMin( maximum(), value() + (steps * stepSize) ); val = qMax( minimum(), val ); setValue( val ); } void NumberBoxWidget::keyPressEvent ( QKeyEvent * event ) { if( event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return ) { interpretText(); Q_EMIT( editingFinished() ); } else QDoubleSpinBox::keyPressEvent( event ); } #endif SuperCollider-Source/QtCollider/widgets/QcNumberBox.h000644 000765 000024 00000011155 12321461510 023721 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_NUMBER_BOX #define QC_NUMBER_BOX #include #include "QcAbstractStepValue.h" #include "../QcHelper.h" #include class QcNumberBox : public QLineEdit, QcHelper, QcAbstractStepValue { Q_OBJECT Q_PROPERTY( double shiftScale READ dummyFloat WRITE setShiftScale ); Q_PROPERTY( double ctrlScale READ dummyFloat WRITE setCtrlScale ); Q_PROPERTY( double altScale READ dummyFloat WRITE setAltScale ); Q_PROPERTY( double minimum READ minimum WRITE setMinimum ); Q_PROPERTY( double maximum READ maximum WRITE setMaximum ); Q_PROPERTY( int decimals READ decimals WRITE setDecimals ); Q_PROPERTY( int maxDecimals READ maxDecimals WRITE setMaxDecimals ); Q_PROPERTY( int minDecimals READ minDecimals WRITE setMinDecimals ); Q_PROPERTY( double value READ value WRITE setValue ); Q_PROPERTY( int valueType READ valueType ); Q_PROPERTY( QString text READ text WRITE setTextValue ); Q_PROPERTY( double step READ dummyFloat WRITE setStep ) Q_PROPERTY( double scrollStep READ dummyFloat WRITE setScrollStep ) Q_PROPERTY( bool scroll READ dummyBool WRITE setScroll ); Q_PROPERTY( QColor normalColor READ dummyColor WRITE setTextColor ); Q_PROPERTY( QColor editingColor READ dummyColor WRITE setEditedTextColor ); public: enum ValueType { Number, Infinite, InfiniteNegative, NaN, Text }; QcNumberBox(); void setStep( double step_ ) { step = step_;} void setScrollStep( double step_ ) { scrollStep = step_; } void setScroll( bool b ) { scroll = b; } void setLocked( bool ); void setTextColor( const QColor& c ); void setEditedTextColor( const QColor& c ); void setValue( double ); Q_INVOKABLE void setInfinite( bool positive = true ); Q_INVOKABLE void setNaN(); void setTextValue( const QString & ); double value() const; int valueType() const { return (int) _valueType; } double minimum() const { return _validator->bottom(); } double maximum() const { return _validator->top(); } void setMinimum( double ); void setMaximum( double ); int decimals() const { return maxDecimals(); } int minDecimals() const { return _minDec; } int maxDecimals() const { return _maxDec; } void setDecimals( int ); void setMinDecimals( int ); void setMaxDecimals( int ); public Q_SLOTS: void increment( double factor ); void decrement( double factor ); Q_SIGNALS: void scrolled( int steps ); void valueChanged(); void action(); private Q_SLOTS: void onEditingFinished(); void updateText(); protected: virtual void keyPressEvent ( QKeyEvent * event ); virtual void mouseDoubleClickEvent ( QMouseEvent * event ); virtual void mousePressEvent ( QMouseEvent * event ); virtual void mouseMoveEvent ( QMouseEvent * event ); virtual void wheelEvent ( QWheelEvent * event ); private: void stepBy( int steps, double stepSize ); double roundedVal( double val ); QString stringForVal( double val ); void updateTextColor(); inline void doAction(); bool scroll; int lastPos; QColor editedTextColor; QColor normalTextColor; QDoubleValidator *_validator; double step; double scrollStep; float dragDist; double _value; ValueType _valueType; int _minDec; int _maxDec; }; #if 0 class NumberBoxWidget : public QDoubleSpinBox { friend class SCNumberBox; Q_OBJECT public: NumberBoxWidget( ); void setScroll( bool b ); private Q_SLOTS: void stepBy( int steps ); void scrollBy( int steps ); void onEditingFinished(); protected: virtual void keyPressEvent ( QKeyEvent * event ); private: void stepBy( int steps, float stepSize ); SCAbstractStepValue *modifier; float scrollStep; }; #endif #endif SuperCollider-Source/QtCollider/widgets/QcPenPrinter.cpp000644 000765 000024 00000002026 12321461510 024436 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jonatan Liljedahl * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcPenPrinter.h" #include "../QcObjectFactory.h" QC_DECLARE_QOBJECT_FACTORY(QcPenPrinter); SuperCollider-Source/QtCollider/widgets/QcPenPrinter.h000644 000765 000024 00000004726 12756531745 024140 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jonatan Liljedahl * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_PEN_PRINTER_H #define QC_PEN_PRINTER_H #include "../painting.h" #include "../debug.h" #include #include #include class QcPenPrinter : public QObject { Q_OBJECT Q_PROPERTY( QRect pageRect READ pageRect ); Q_PROPERTY( QRect paperRect READ paperRect ); Q_PROPERTY( int fromPage READ fromPage ); Q_PROPERTY( int toPage READ toPage ); public: QcPenPrinter(): dialog(0) {} ~QcPenPrinter() { delete dialog; } QRect pageRect() const { return printer.pageRect(); } QRect paperRect() const { return printer.paperRect(); } int fromPage() const { return printer.fromPage(); } int toPage() const { return printer.toPage(); } Q_SIGNALS: void dialogDone(int); void printFunc(); private Q_SLOTS: void show() { if( !dialog ) { dialog = new QPrintDialog(&printer); dialog->setWindowTitle( QStringLiteral("Print Document") ); dialog->setOptions ( QAbstractPrintDialog::PrintToFile | QAbstractPrintDialog::PrintPageRange | QAbstractPrintDialog::PrintShowPageSize ); connect( dialog, SIGNAL(finished(int)), this, SIGNAL(dialogDone(int)) ); } if( dialog->isVisible() ) qcWarningMsg("WARNING: Print dialog already open."); else dialog->exec(); } void print() { QPainter painter; painter.begin(&printer); QtCollider::beginPainting(&painter); Q_EMIT ( printFunc() ); painter.end(); QtCollider::endPainting(); } void newPage() { printer.newPage(); } private: QPrinter printer; QPrintDialog *dialog; }; #endif // QC_PEN_PRINTER_H SuperCollider-Source/QtCollider/widgets/QcPopUpMenu.cpp000644 000765 000024 00000003075 12321461510 024245 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcPopUpMenu.h" #include "../QcWidgetFactory.h" QC_DECLARE_QWIDGET_FACTORY(QcPopUpMenu); QcPopUpMenu::QcPopUpMenu() : _changed(false), _reactivation(false) { connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(setChanged()) ); connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(clearChanged()), Qt::QueuedConnection ); connect( this, SIGNAL(activated(int)), this, SLOT(doAction(int)) ); } void QcPopUpMenu::setItems( const QVariantList & items ) { clear(); Q_FOREACH( const QVariant & item, items ) addItem( item.toString() ); } void QcPopUpMenu::doAction( int choice ) { if( _changed || _reactivation ) Q_EMIT( action() ); } SuperCollider-Source/QtCollider/widgets/QcPopUpMenu.h000644 000765 000024 00000003062 12321461510 023706 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "../QcHelper.h" #include class QcPopUpMenu : public QComboBox, QcHelper { Q_OBJECT Q_PROPERTY( QVariantList items READ dummyVariantList WRITE setItems ); Q_PROPERTY( bool reactivationEnabled READ reactivationEnabled WRITE setReactivationEnabled ) public: QcPopUpMenu(); bool reactivationEnabled() const { return _reactivation; } void setReactivationEnabled( bool b ) { _reactivation = b; } Q_SIGNALS: void action(); private Q_SLOTS: void doAction(int); void setChanged() { _changed = true; } void clearChanged() { _changed = false; } private: void setItems( const QVariantList & ); bool _changed; bool _reactivation; }; SuperCollider-Source/QtCollider/widgets/QcQuartzComposerView.h000644 000765 000024 00000004661 12321461510 025655 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2013 Scott Wilson * * This file is part of SuperCollider Qt GUI. Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_QUARTZCOMPOSER #define QC_QUARTZCOMPOSER #include #include #import class QcQuartzComposerContainerView : public QMacCocoaViewContainer { Q_OBJECT public: QcQuartzComposerContainerView( QWidget *parent = 0 ); ~QcQuartzComposerContainerView(); QSize sizeHint() const { return QSize(150,150); } QSize minimumSizeHint() const { return QSize(30,30); } }; class QcQuartzComposerView : public QWidget { Q_OBJECT public: QcQuartzComposerView(QWidget *parent = 0); ~QcQuartzComposerView(); QSize sizeHint() const; virtual void resizeEvent( QResizeEvent* ); QcQuartzComposerContainerView *containerView; QVariantList inputKeys() const; QVariantList outputKeys() const; bool hasInputKey(NSString *key); bool hasOutputKey(NSString *key); void setInputPort(NSString *key, id val); id getInputPort(NSString *key); id getOutputPort(NSString *key); NSString* getTypeForKey(NSString *key); Q_INVOKABLE void startRendering(); Q_INVOKABLE void stopRendering(); Q_INVOKABLE void loadCompositionFromFile( const QString & path ); Q_INVOKABLE void setMaxRenderingFrameRate( double rate ); Q_PROPERTY( QVariantList inputKeys READ inputKeys ); Q_PROPERTY( QVariantList outputKeys READ outputKeys ); private: QVariantList variantForNSObject( id nsObject, NSString * type ) const; id nsObjectForQVariant( const QVariantList & data ); QCView *mQCView; }; #endif SuperCollider-Source/QtCollider/widgets/QcQuartzComposerView.mm000644 000765 000024 00000010227 12321461510 026032 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2013 Scott Wilson * * This file is part of SuperCollider Qt GUI. Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcQuartzComposerView.h" #include "../QcWidgetFactory.h" #include QC_DECLARE_QWIDGET_FACTORY(QcQuartzComposerView); QcQuartzComposerContainerView::QcQuartzComposerContainerView( QWidget *parent ) : QMacCocoaViewContainer(0, parent) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; QCView *qcView = [[QCView alloc] init]; [qcView setAutostartsRendering: YES]; [qcView setEventForwardingMask: NSAnyEventMask]; setCocoaView(qcView); [qcView release]; [pool release]; } QcQuartzComposerContainerView::~QcQuartzComposerContainerView() { } // QMacCocoaViewContainer *must* be wrapped in a parent view // so we make a wrapper here which does most of the work QcQuartzComposerView::QcQuartzComposerView(QWidget *parent) :QWidget(parent) { containerView = new QcQuartzComposerContainerView(this); mQCView = [(QCView*)containerView->cocoaView() retain]; } QcQuartzComposerView::~QcQuartzComposerView() { [mQCView release]; } QSize QcQuartzComposerView::sizeHint() const { return containerView->sizeHint(); } void QcQuartzComposerView::resizeEvent(QResizeEvent * e) { containerView->resize(e->size()); QWidget::resizeEvent(e); } void QcQuartzComposerView::startRendering() { [mQCView startRendering]; } void QcQuartzComposerView::stopRendering() { [mQCView stopRendering]; } void QcQuartzComposerView::loadCompositionFromFile( const QString& path ) { QByteArray byteArray = path.toUtf8(); const char* cString = byteArray.constData(); NSString *nsString = [[NSString alloc] initWithUTF8String:cString]; [mQCView loadCompositionFromFile: nsString]; [nsString release]; } void QcQuartzComposerView::setMaxRenderingFrameRate(double rate) { [mQCView setMaxRenderingFrameRate: rate]; } QVariantList QcQuartzComposerView::inputKeys() const { NSArray* inputKeys = [mQCView inputKeys]; int size = [inputKeys count]; QVariantList keylist; for( int i = 0; i < size; ++i ) { NSString *name = [inputKeys objectAtIndex: i]; QString key = QString::fromUtf8([name UTF8String]); keylist << QVariant( key ); } return keylist; } QVariantList QcQuartzComposerView::outputKeys() const { NSArray* outputKeys = [mQCView outputKeys]; int size = [outputKeys count]; QVariantList keylist; for( int i = 0; i < size; ++i ) { NSString *name = [outputKeys objectAtIndex: i]; QString key = QString::fromUtf8([name UTF8String]); keylist << QVariant( key ); } return keylist; } bool QcQuartzComposerView::hasInputKey(NSString *key) { return [[mQCView inputKeys] containsObject: key]; } bool QcQuartzComposerView::hasOutputKey(NSString *key) { return [[mQCView outputKeys] containsObject: key]; } void QcQuartzComposerView::setInputPort(NSString *key, id val) { [mQCView setValue:val forInputKey:key]; } id QcQuartzComposerView::getInputPort(NSString *key) { return [mQCView valueForInputKey: key]; } id QcQuartzComposerView::getOutputPort(NSString *key) { return [mQCView valueForOutputKey: key]; } NSString* QcQuartzComposerView::getTypeForKey(NSString *key) { NSDictionary *attributes = [[mQCView attributes] objectForKey: key]; NSString *type = [attributes objectForKey:QCPortAttributeTypeKey]; return type; } SuperCollider-Source/QtCollider/widgets/QcRangeSlider.cpp000644 000765 000024 00000023165 12756531745 024602 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcRangeSlider.h" #include "../QcWidgetFactory.h" #include "../style/routines.hpp" #include #include #include #include #define HND 10 QC_DECLARE_QWIDGET_FACTORY(QcRangeSlider); QcRangeSlider::QcRangeSlider() : QtCollider::Style::Client(this), _lo( 0.0 ), _hi( 1.0 ), _step( 0.01f ), mouseMode( None ) { setFocusPolicy( Qt::StrongFocus ); setOrientation( Qt::Vertical ); setAttribute(Qt::WA_AcceptTouchEvents); } void QcRangeSlider::setOrientation( Qt::Orientation o ) { _ort = o; if( _ort == Qt::Horizontal ) { setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed ); } else { setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding ); } updateGeometry(); update(); } void QcRangeSlider::setLoValue( double val ) { val = qMax( 0.0, qMin( 1.0, val ) ); if( val <= _hi ) { _lo = val; } else { _lo = _hi; _hi = val; } update(); } void QcRangeSlider::setHiValue( double val ) { val = qMax( 0.0, qMin( 1.0, val ) ); if( val >= _lo ) { _hi = val; } else { _hi = _lo; _lo = val; } update(); } void QcRangeSlider::setRange( double val, double range ) { range = qBound( 0.0, range, 1.0 ); _lo = qBound( 0.0, val, 1.0 - range); _hi = _lo + range; update(); } QSize QcRangeSlider::sizeHint() const { return ( _ort == Qt::Horizontal ? QSize( 150, 20 ) : QSize( 20, 150 ) ); } QSize QcRangeSlider::minimumSizeHint() const { return ( _ort == Qt::Horizontal ? QSize( 30, 20 ) : QSize( 20, 30 ) ); } void QcRangeSlider::increment( double factor ) { moveBy( factor * _step ); } void QcRangeSlider::decrement( double factor ) { moveBy( -factor * _step ); } void QcRangeSlider::increment() { double step = _step; modifyStep( &step ); moveBy( step ); } void QcRangeSlider::decrement() { double step = _step; modifyStep( &step ); moveBy( -step ); } QRect QcRangeSlider::thumbRect() { using namespace QtCollider::Style; QRect contRect( sunkenContentsRect(rect()) ); int hnd2 = HND * 2; if( _ort == Qt::Horizontal ) { double valRange = contRect.width() - hnd2; double left = _lo * valRange; double right = _hi * valRange; right += hnd2; return QRect( left + contRect.x(), contRect.y(), right - left, contRect.height() ); } else { double valRange = contRect.height() - hnd2; int up = (1.0 - _hi) * valRange; int down = (1.0 - _lo) * valRange; down += hnd2; return QRect( contRect.x(), contRect.y() + up, contRect.width(), down - up ); } } double QcRangeSlider::valueFromPos( const QPoint& pos ) { using namespace QtCollider::Style; bool horiz = _ort == Qt::Horizontal; QSize margins = horiz ? QSize(HND*2, 0) : QSize(0, HND*2); QRect valBounds = marginsRect( sunkenContentsRect(rect()), margins ); return horiz ? xValue( pos.x(), valBounds ) : yValue( pos.y(), valBounds ); } void QcRangeSlider::moveBy( double dif ) { if( _lo + dif < 0.0 ) { _hi += 0.0 - _lo; _lo = 0.0; } else if( _hi + dif > 1.0 ) { _lo += 1.0 - _hi; _hi = 1.0; } else { _lo += dif; _hi += dif; } update(); } void QcRangeSlider::mouseMoveEvent ( QMouseEvent * e ) { using namespace QtCollider::Style; if( !e->buttons() ) return; if( mouseMode == SetHi || mouseMode == SetLo ) { double val = valueFromPos( e->pos() ); if( mouseMode == SetLo ) { if( val > _hi ) mouseMode = SetHi; setLoValue( val ); } else if( mouseMode == SetHi ) { if( val < _lo ) mouseMode = SetLo; setHiValue( val ); } } else if( mouseMode != None ) { QPoint pt = e->pos() - dragOrigin; QRect contRect( sunkenContentsRect(rect()) ); double dif; if( _ort == Qt::Horizontal ) { double range = contRect.width() - HND*2; dif = range > 0 ? pt.x() / range : 0.0; } else { double range = contRect.height() - HND*2; dif = range > 0 ? - pt.y() / range : 0.0; } if( dif != 0.0 ) { switch( mouseMode ) { case Move: setRange( dragVal + dif, dragRange ); break; case MoveHi: setHiValue( qMax(dragVal + dif, (double)_lo) ); break; case MoveLo: setLoValue( qMin(dragVal + dif, (double)_hi) ); break; default:; } } } Q_EMIT( action() ); } void QcRangeSlider::mousePressEvent ( QMouseEvent * e ) { using namespace QtCollider::Style; if( e->modifiers() & Qt::ShiftModifier ) { double center = (_hi + _lo) * 0.5; double val = valueFromPos( e->pos() ); if( val < center ) { mouseMode = SetLo; setLoValue( val ); } else { mouseMode = SetHi; setHiValue( val ); } Q_EMIT( action() ); } else { QRect thumb( thumbRect() ); int len, pos; if( _ort == Qt::Horizontal ) { len = thumb.width(); pos = e->pos().x() - thumb.left(); } else { len = thumb.height(); pos = thumb.top() + len - e->pos().y(); } if( pos < 0 || pos > len ) return; dragOrigin = e->pos(); if( pos < HND ) { mouseMode = MoveLo; dragVal = _lo; } else if( pos >= len - HND ) { mouseMode = MoveHi; dragVal = _hi; } else { mouseMode = Move; dragVal = _lo; dragRange = _hi - _lo; } } update(); } void QcRangeSlider::mouseReleaseEvent ( QMouseEvent * e ) { Q_UNUSED(e); mouseMode = None; } void QcRangeSlider::keyPressEvent ( QKeyEvent *e ) { switch( e->key() ) { case Qt::Key_Up: case Qt::Key_Right: increment(); break; case Qt::Key_Down: case Qt::Key_Left: decrement(); break; case Qt::Key_A: _lo = 0.0; _hi = 1.0; update(); break; case Qt::Key_N: _lo = 0.0; _hi = 0.0; update(); break; case Qt::Key_X: _lo = 1.0; _hi = 1.0; update(); break; case Qt::Key_C: _lo = 0.5; _hi = 0.5; update(); break; default: return QWidget::keyPressEvent( e ); } Q_EMIT( action() ); } inline void drawMarker( QPainter *p, const QColor &color, Qt::Orientation ort, bool first, const QPoint & pt, int len ) { p->save(); p->setRenderHint( QPainter::Antialiasing, false ); QPen pen(color); bool vert = ort == Qt::Vertical; if(vert) { pen.setWidth(1); p->setPen(pen); p->drawPoint( QPoint( pt.x() + len * 0.5, first ? pt.y() - 5 : pt.y() + 5 ) ); pen.setWidth(2); p->setPen(pen); QLine line( pt.x() + 1, pt.y(), pt.x() + len - 1, pt.y() ); p->drawLine(line); } else { pen.setWidth(1); p->setPen(pen); p->drawPoint( QPoint( first ? pt.x() - 5 : pt.x() + 5, pt.y() + len * 0.5 ) ); pen.setWidth(2); p->setPen(pen); QLine line( pt.x(), pt.y() + 1, pt.x(), pt.y() + len - 1 ); p->drawLine(line); } p->restore(); } void QcRangeSlider::paintEvent ( QPaintEvent *e ) { using namespace QtCollider::Style; using QtCollider::Style::RoundRect; Q_UNUSED(e); QPainter p(this); p.setRenderHint( QPainter::Antialiasing, true ); const QPalette & plt = palette(); const QColor & knobClr = knobColor(); RoundRect frame(rect(), 2); drawSunken( &p, plt, frame, grooveColor(), hasFocus() ? focusColor() : QColor() ); QRect contRect( sunkenContentsRect(rect()) ); QRect hndRect; QRect valRect; int HND2 = HND * 2; bool horiz = _ort == Qt::Horizontal; if( horiz ) { double valRange = contRect.width() - HND2; int lo = _lo * valRange; int hi = _hi * valRange; valRect = QRect( lo + HND + contRect.x(), contRect.y(), hi - lo, contRect.height() ); hndRect = valRect.adjusted( -HND, 0, HND, 0 ); } else { double valRange = contRect.height() - HND2; int hi = _hi * valRange; int lo = _lo * valRange; valRect = QRect( contRect.x(), contRect.y() + contRect.height() - hi - HND, contRect.width(), hi - lo ); hndRect = valRect.adjusted( 0, -HND, 0, HND ); } // handle RoundRect handle(hndRect, 2); drawRaised( &p, plt, handle, plt.color(QPalette::Button).lighter(105) ); // markers if( horiz ) { int mark_len = hndRect.height() - 4; QPoint pt( hndRect.left() + HND, hndRect.top() + 2 ); drawMarker( &p, knobClr, _ort, true, pt, mark_len ); pt.setX( hndRect.right() - HND + 1 ); drawMarker( &p, knobClr, _ort, false, pt, mark_len ); } else { int mark_len = hndRect.width() - 4; QPoint pt( hndRect.left() + 2, hndRect.top() + HND ); drawMarker( &p, knobClr, _ort, true, pt, mark_len ); pt.setY( hndRect.bottom() - HND + 1 ); drawMarker( &p, knobClr, _ort, false, pt, mark_len ); } // value region if( horiz ? valRect.width() > 2 : valRect.height() > 2 ) { p.setRenderHint( QPainter::Antialiasing, false ); QColor c( knobClr ); c.setAlpha(50); p.setPen(Qt::NoPen); p.setBrush(c); if( horiz ) p.drawRect(valRect.adjusted( 1, 2, -1, -2 )); else p.drawRect(valRect.adjusted( 2, 1, -2, -1 )); } } SuperCollider-Source/QtCollider/widgets/QcRangeSlider.h000644 000765 000024 00000006350 12321461510 024220 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_RANGE_SLIDER #define QC_RANGE_SLIDER #include "QcAbstractStepValue.h" #include "../QcHelper.h" #include "../style/style.hpp" #include class QcRangeSlider : public QWidget, QcHelper, QcAbstractStepValue, QtCollider::Style::Client { Q_OBJECT Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation ); Q_PROPERTY( double loValue READ loValue WRITE setLoValue ) Q_PROPERTY( double hiValue READ hiValue WRITE setHiValue ) Q_PROPERTY( double shiftScale READ dummyFloat WRITE setShiftScale ); Q_PROPERTY( double ctrlScale READ dummyFloat WRITE setCtrlScale ); Q_PROPERTY( double altScale READ dummyFloat WRITE setAltScale ); Q_PROPERTY( double step READ dummyFloat WRITE setStep ) Q_PROPERTY( QColor grooveColor READ grooveColor WRITE setGrooveColor ); Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); Q_PROPERTY( QColor knobColor READ knobColor WRITE setKnobColor ); public: enum MouseMode { None = 0, Move, MoveHi, MoveLo, SetLo, SetHi }; QcRangeSlider(); Qt::Orientation orientation() const { return _ort; } void setOrientation( Qt::Orientation o ); double loValue() const { return _lo; } void setLoValue( double ); double hiValue() const { return _hi; } void setHiValue( double ); void setRange( double val, double range ); void setStep( double f ) { _step = f; } QSize sizeHint() const; QSize minimumSizeHint() const; const QColor & knobColor() const { return _knobColor.isValid() ? _knobColor : palette().color(QPalette::ButtonText); } void setKnobColor(const QColor &c) { _knobColor = c; update(); } public Q_SLOTS: void increment( double factor ); void decrement( double factor ); Q_SIGNALS: void action(); private: QRect thumbRect(); QRect valueRect(); double valueFromPos( const QPoint& pos ); void moveBy( double ); void increment(); void decrement(); void mouseMoveEvent ( QMouseEvent * ); void mousePressEvent ( QMouseEvent * ); void mouseReleaseEvent ( QMouseEvent * ); void keyPressEvent ( QKeyEvent * ); void paintEvent ( QPaintEvent * ); Qt::Orientation _ort; double _lo; double _hi; double _step; QPoint dragOrigin; double dragVal, dragRange; MouseMode mouseMode; QColor _knobColor; }; #endif SuperCollider-Source/QtCollider/widgets/QcScope.cpp000644 000765 000024 00000011211 12524671172 023431 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcScope.h" #include "../QcWidgetFactory.h" #include #include QC_DECLARE_QWIDGET_FACTORY(QcScope); QcScope::QcScope() : bufNum( 0 ), xOffset( 0.f ), yOffset( 0.f ), xZoom( 1.f ), yZoom( 1.f ), style( 0 ), _bkg( QColor(0,0,0) ) { memset( &buffer, 0, sizeof(SndBuf) ); timer = new QTimer( this ); timer->setInterval( 15 ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); connect( timer, SIGNAL( timeout() ), this, SLOT( updateScope() ) ); } QcScope::~QcScope() { free( buffer.data ); } void QcScope::setBufferNumber( int n ) { bufNum = n; timer->start(); } void QcScope::setWaveColors( const QVariantList & newColors ) { colors.clear(); Q_FOREACH( const QVariant & var, newColors ) { QColor color = var.value(); if( !color.isValid() ) colors.append( QColor( 0,0,0 ) ); else colors.append( color ); } } int QcScope::updateInterval() const { return timer->interval(); } void QcScope::setUpdateInterval( int interval ) { timer->setInterval( qMax(0, interval) ); } int getScopeBuf( uint32 index, SndBuf *buf, bool& changed ); void QcScope::updateScope() { #ifndef NO_INTERNAL_SERVER //printf("update\n"); bool changed; getScopeBuf( bufNum, &buffer, changed ); if( changed ) { //printf("channels: %i\n", buffer.channels); update(); } #endif } inline void QcScope::setPoint( QPointF& pt, float x, float y, float xRatio, float yRatio, int xStart, int yStart ) { pt.setX( ((x + xOffset) * xRatio) + xStart ); pt.setY( yStart - ((y + yOffset) * yRatio) ); } void QcScope::paint1D( bool overlapped, QPainter & p ) { QRect area = rect(); float xRatio = xZoom * area.width() / (float )buffer.frames; float yRatio = yZoom * area.height() * 0.5; if( !overlapped ) yRatio /= buffer.channels; int c, f, s; QPointF pt1; QPointF pt2; QPen pen; pen.setWidth(0); // width==0 means width 1 regardless of transformations for( c = 0; c < buffer.channels; c++ ) { pen.setColor(c < colors.count() ? colors[c] : QColor(255,255,255)); p.setPen(pen); float yCenter = area.height() * 0.5; if( !overlapped ) { yCenter *= ( c * 2 + 1); yCenter /= buffer.channels; } yCenter += area.y(); setPoint( pt1, 0, buffer.data[c], xRatio, yRatio, area.x(), yCenter ); for( f = 1, s = c + buffer.channels; f < buffer.frames; f++, s += buffer.channels ) { setPoint( pt2, f, buffer.data[s], xRatio, yRatio, area.x(), yCenter ); p.drawLine( pt1, pt2 ); pt1 = pt2; } } } void QcScope::paint2D( QPainter & p ) { QPen pen; pen.setWidth(0); // width==0 means width 1 regardless of transformations pen.setColor(colors.count() ? colors[0] : QColor(255,255,255)); QRect area = rect(); int minSize = qMin( area.width(), area.height() ); float xRatio = xZoom * minSize * 0.5; float yRatio = yZoom * minSize * 0.5; QPoint center = area.center(); int centerY = center.y(); int centerX = center.x(); QPointF pt1; QPointF pt2; float *data = buffer.data; float y = buffer.channels > 1 ? data[1] : 0.f; setPoint( pt1, data[0], y, xRatio, yRatio, centerX, centerY ); data += buffer.channels; int f; for( f = 1; f < buffer.frames; f++, data += buffer.channels ) { if( buffer.channels > 1 ) y = data[1]; setPoint( pt2, data[0], y, xRatio, yRatio, centerX, centerY ); p.drawLine( pt1, pt2 ); pt1 = pt2; } } void QcScope::paintEvent ( QPaintEvent * event ) { Q_UNUSED( event ); QPainter p( this ); QRect area = rect(); p.fillRect( area, _bkg ); if( buffer.frames == 0 ) return; if( style == 0 ) paint1D( false, p ); else if( style == 1 ) paint1D( true, p ); else if( style == 2 ) paint2D( p ); } SuperCollider-Source/QtCollider/widgets/QcScope.h000644 000765 000024 00000005460 12321461510 023073 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SCOPE_H #define QC_SCOPE_H #include "../QcHelper.h" #include #include #include class QcScope : public QWidget, QcHelper { Q_OBJECT Q_PROPERTY( int bufferNumber READ dummyInt WRITE setBufferNumber ); Q_PROPERTY( float xOffset READ dummyFloat WRITE setXOffset ); Q_PROPERTY( float yOffset READ dummyFloat WRITE setYOffset ); Q_PROPERTY( float xZoom READ dummyFloat WRITE setXZoom ); Q_PROPERTY( float yZoom READ dummyFloat WRITE setYZoom ); Q_PROPERTY( int style READ dummyInt WRITE setStyle ); Q_PROPERTY( QVariantList waveColors READ dummyVariantList WRITE setWaveColors ); Q_PROPERTY( QColor background READ background WRITE setBackground ); Q_PROPERTY( int updateInterval READ updateInterval WRITE setUpdateInterval ); public: QcScope(); ~QcScope(); void setBufferNumber( int ); void setXOffset( float f ) { xOffset = f; } void setYOffset( float f ) { yOffset = f; } void setXZoom( float f ) { xZoom = f; } void setYZoom( float f ) { yZoom = f; } void setStyle( int i ) { style = i; } void setWaveColors( const QVariantList & colors ); QColor background() const { return _bkg; } void setBackground( const QColor &c ) { _bkg = c; update(); } int updateInterval() const; void setUpdateInterval( int i ); QSize sizeHint() const { return QSize( 500, 300 ); } QSize minimumSizeHint() const { return QSize( 50, 50 ); } private Q_SLOTS: void updateScope(); private: void paintEvent ( QPaintEvent * event ); void setPoint( QPointF& pt, float frame, float data, float xRatio, float yRatio, int xStart, int yStart ); void paint1D( bool overlapped, QPainter & ); void paint2D( QPainter & ); int bufNum; SndBuf buffer; QTimer *timer; float xOffset; float yOffset; float xZoom; float yZoom; int style; QList colors; QColor _bkg; }; #endif SuperCollider-Source/QtCollider/widgets/QcScopeShm.cpp000644 000765 000024 00000021510 12756531745 024114 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of Qt GUI for SuperCollider. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcScopeShm.h" #include "scope_shm_interface.hpp" #include "../QcWidgetFactory.h" #include "../debug.h" #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcScopeShm); QcScopeShm::QcScopeShm() : _srvPort(-1), _scopeIndex(-1), _shm(new ScopeShm(this)), _running(false), _data(0), _availableFrames(0), xOffset( 0.f ), yOffset( 0.f ), xZoom( 1.f ), yZoom( 1.f ), _style( 0 ), _bkg( QColor(0,0,0) ), _fill( true ) { setAttribute( Qt::WA_OpaquePaintEvent, true ); setAutoFillBackground(false); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); timer = new QTimer( this ); timer->setInterval( 50 ); connect( timer, SIGNAL( timeout() ), this, SLOT( updateScope() ) ); } QcScopeShm::~QcScopeShm() { stop(); } void QcScopeShm::setServerPort( int port ) { if( _running ) { qcWarningMsg( "QScope: Can not change server port while running!" ); return; } _srvPort = port; } void QcScopeShm::setBufferNumber( int n ) { if( _running ) { // TODO: release used reader? initScopeReader( _shm, n ); } _scopeIndex = n; } void QcScopeShm::setWaveColors( const QVariantList & newColors ) { colors.clear(); Q_FOREACH( const QVariant & var, newColors ) { QColor color = var.value(); if( !color.isValid() ) colors.append( QColor( 0,0,0 ) ); else colors.append( color ); } } int QcScopeShm::updateInterval() const { return timer->interval(); } void QcScopeShm::setUpdateInterval( int interval ) { timer->setInterval( qMax(0, interval) ); } void QcScopeShm::start() { if( _running ) return; if( _srvPort < 0 || _scopeIndex < 0 ) return; connectSharedMemory( _srvPort ); if( !_shm->client ) { stop(); return; } initScopeReader( _shm, _scopeIndex ); timer->start(); _running = true; } void QcScopeShm::stop() { // TODO: release used reader? delete _shm->client; _shm->client = 0; timer->stop(); _running = false; } void QcScopeShm::updateScope() { bool valid = _shm->reader.valid(); //qcDebugMsg(1, tr("valid = %1").arg(valid)); if(!valid) return; bool ok = _shm->reader.pull( _availableFrames ); //qcDebugMsg(1, tr("Got %1 frames").arg(_availableFrames) ); if(ok) { _data = _shm->reader.data(); update(); } } void QcScopeShm::resizeEvent ( QResizeEvent * ev ) { _pixmap = QPixmap(ev->size()); } void QcScopeShm::paintEvent ( QPaintEvent * event ) { Q_UNUSED( event ); QPainter p; _pixmap.fill( _bkg ); if( _running && _availableFrames ) { int chanCount = _shm->reader.channels(); int maxFrames = _shm->reader.max_frames(); QRect area (_pixmap.rect()); p.begin(&_pixmap); switch (_style) { case 0: paint1D( false, chanCount, maxFrames, _availableFrames, area, p ); break; case 1: paint1D( true, chanCount, maxFrames, _availableFrames, area, p ); break; case 2: paint2D( chanCount, maxFrames, _availableFrames, area, p ); break; } p.end(); } p.begin(this); p.drawPixmap(0, 0, _pixmap); } void QcScopeShm::paint1D( bool overlapped, int chanCount, int maxFrames, int frameCount, const QRect &area, QPainter & painter ) { //qcDebugMsg( 0, tr("Drawing: data %1 / channels %2 / max-size %3").arg(_data!=0).arg(chanCount).arg(maxFrames) ); if( frameCount < 2 || area.width() < 1 || area.height() < 1 ) return; float yRatio = - yZoom * area.height() * 0.5; if( !overlapped ) yRatio /= chanCount; float yHeight = area.height(); if( !overlapped ) yHeight /= chanCount; QPen pen; pen.setWidth(0); // width==0 means width 1 regardless of transformations pen.setCapStyle( Qt::FlatCap ); if( frameCount < area.width() ) { float xRatio = xZoom * area.width() / (frameCount-1); for( int ch = 0; ch < chanCount; ch++ ) { float *frameData = _data + (ch * maxFrames); //frame vector float yOrigin = yHeight * (overlapped ? 0.5 : ch + 0.5); QColor strokeColor = ch < colors.count() ? colors[ch] : QColor(255,255,255); QColor fillColor(strokeColor); fillColor.setAlpha(0.65 * 255); pen.setColor( strokeColor ); painter.save(); painter.translate( area.x(), area.y() + yOrigin ); painter.scale( xRatio, yRatio ); painter.setPen(pen); QPainterPath path; path.moveTo( xOffset, frameData[0] ); for( int f = 1; f < frameCount; ++f ) path.lineTo( xOffset + f, frameData[f] ); if (_fill) { path.lineTo(xOffset + frameCount, 0); path.lineTo(0, 0); path.lineTo(xOffset, frameData[0]); painter.fillPath(path, QBrush(fillColor)); } painter.drawPath(path); painter.restore(); } } else { int w = area.width(); float fpp = frameCount / (float) w; // frames per x pixel float ypix = yRatio != 0.f ? -1/yRatio : 0.f; // value per y pixel; for( int ch = 0; ch < chanCount; ch++ ) { float *frameData = _data + (ch * maxFrames); //frame vector float yOrigin = yHeight * (overlapped ? 0.5 : ch + 0.5); QColor strokeColor = ch < colors.count() ? colors[ch] : QColor(255,255,255); QColor fillColor(strokeColor); fillColor.setAlpha(0.65 * 255); painter.save(); painter.translate( area.x(), area.y() + yOrigin ); painter.setPen(pen); QPainterPath pathLine; QPainterPath pathFill; int p=0, f=1; // pixel, frame float min, max; min = max = frameData[0]; while( p++ < w ) { int f_max = fpp * p; for(; f < f_max; ++f) { float d = frameData[f]; if( d < min ) min = d; if( d > max ) max = d; } qreal x = p-1; float y = max * yRatio; pathLine.moveTo( x, y ); y = qMax( min * yRatio, y+1 ); pathLine.lineTo( x, y ); if (_fill) { pathFill.moveTo( x, y ); pathFill.lineTo( x, 0 ); } // flip min/max to ensure continuity float val = min; min = max; max = val; } pen.setColor(strokeColor); painter.strokePath(pathLine, pen); if (_fill) { pen.setColor(fillColor); painter.strokePath(pathFill, pen); } painter.restore(); } } } void QcScopeShm::paint2D( int chanCount, int maxFrames, int frameCount, const QRect &area, QPainter & painter ) { int minSize = qMin( area.width(), area.height() ); // NOTE: use yZoom for both axis, since both represent value, as opposed to index float xRatio = yZoom * minSize * 0.5; float yRatio = -yZoom * minSize * 0.5; QPoint center = area.center(); QPen pen; pen.setWidth(0); // width==0 means width 1 regardless of transformations pen.setCapStyle( Qt::FlatCap ); pen.setColor(colors.count() ? colors[0] : QColor(255,255,255)); painter.setPen(pen); painter.translate( center.x(), center.y() ); painter.scale( xRatio, yRatio ); QPainterPath path; if( chanCount >= 2 ) { float *data1 = _data; float *data2 = _data + maxFrames; path.moveTo( data1[0], data2[0] ); for( int f = 1; f < frameCount; ++f ) path.lineTo( data1[f], data2[f] ); } else { float *data1 = _data; path.moveTo( data1[0], 0.f ); for( int f = 1; f < frameCount; ++f ) path.lineTo( data1[f], 0.f ); } painter.drawPath(path); } void QcScopeShm::connectSharedMemory( int port ) { try { server_shared_memory_client * client = new server_shared_memory_client(port); _shm->client = client; qcDebugMsg(1,"Shared memory connected"); } catch (std::exception & e) { _shm->client = 0; qcErrorMsg(QStringLiteral("Cannot connect to shared memory: %1").arg(e.what()) ); } } void QcScopeShm::initScopeReader( ScopeShm *shm, int index ) { shm->reader = shm->client->get_scope_buffer_reader( index ); qcDebugMsg(1,QStringLiteral("Initialized scope buffer reader for index %1.").arg(index)); } SuperCollider-Source/QtCollider/widgets/QcScopeShm.h000644 000765 000024 00000007555 12524671172 023566 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of Qt GUI for SuperCollider. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SCOPE_H #define QC_SCOPE_H #include "../QcHelper.h" #include #include // FIXME: Due to Qt bug #22829, moc can not process headers that include // boost/type_traits/detail/has_binary_operator.hp from boost 1.48, so // we have to wrap the shm interface into a separate class. namespace QtCollider { class ScopeShm; } using QtCollider::ScopeShm; class QcScopeShm : public QWidget, QcHelper { Q_OBJECT Q_PROPERTY( int serverPort READ serverPort WRITE setServerPort ); Q_PROPERTY( int bufferNumber READ dummyInt WRITE setBufferNumber ); Q_PROPERTY( float xOffset READ dummyFloat WRITE setXOffset ); Q_PROPERTY( float yOffset READ dummyFloat WRITE setYOffset ); Q_PROPERTY( float xZoom READ dummyFloat WRITE setXZoom ); Q_PROPERTY( float yZoom READ dummyFloat WRITE setYZoom ); Q_PROPERTY( int style READ style WRITE setStyle ); Q_PROPERTY( QVariantList waveColors READ dummyVariantList WRITE setWaveColors ); Q_PROPERTY( QColor background READ background WRITE setBackground ); Q_PROPERTY( bool fill READ fill WRITE setFill ); Q_PROPERTY( int updateInterval READ updateInterval WRITE setUpdateInterval ); Q_PROPERTY( bool running READ running ); public: QcScopeShm(); ~QcScopeShm(); int serverPort() const { return _srvPort; } void setServerPort( int ); void setBufferNumber( int ); void setXOffset( float f ) { xOffset = f; } void setYOffset( float f ) { yOffset = f; } void setXZoom( float f ) { xZoom = f; } void setYZoom( float f ) { yZoom = f; } int style() const { return _style; } void setStyle( int i ) { _style = i; } void setWaveColors( const QVariantList & colors ); QColor background() const { return _bkg; } void setBackground( const QColor &c ) { _bkg = c; update(); } bool fill() { return _fill; }; void setFill(bool b) { _fill = b; }; int updateInterval() const; void setUpdateInterval( int i ); bool running() const { return _running; } QSize sizeHint() const { return QSize( 500, 300 ); } QSize minimumSizeHint() const { return QSize( 50, 50 ); } public Q_SLOTS: void start(); void stop(); protected: void resizeEvent ( QResizeEvent * ); void paintEvent ( QPaintEvent * ); private Q_SLOTS: void updateScope(); private: void connectSharedMemory( int port ); void initScopeReader( ScopeShm *, int index ); void paint1D( bool overlapped, int channels, int maxFrames, int frames, const QRect &area, QPainter & ); void paint2D( int channels, int maxFrames, int frames, const QRect &area, QPainter & ); int _srvPort; int _scopeIndex; ScopeShm *_shm; bool _running; float *_data; uint _availableFrames; QTimer *timer; float xOffset; float yOffset; float xZoom; float yZoom; int _style; QList colors; QColor _bkg; bool _fill; QPixmap _pixmap; }; #endif SuperCollider-Source/QtCollider/widgets/QcScrollArea.cpp000644 000765 000024 00000007544 12756531745 024435 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcScrollArea.h" #include "../QcWidgetFactory.h" #include #include #include #include #include class QcScrollWidgetFactory : public QcWidgetFactory { protected: virtual void initialize( QWidgetProxy *p, QcScrollWidget *w ) { QObject::connect( w, SIGNAL(painting(QPainter*)), p, SLOT(customPaint(QPainter*)) ); } }; QC_DECLARE_FACTORY( QcScrollWidget, QcScrollWidgetFactory ); QcScrollWidget::QcScrollWidget( QWidget *parent ) : QcCanvas( parent ) { setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ); setAttribute(Qt::WA_AcceptTouchEvents); } QSize QcScrollWidget::sizeHint() const { QRect r = childrenRect(); QSize sz( r.x() + r.width(), r.y() + r.height() ); return sz; } bool QcScrollWidget::event ( QEvent * e ) { int t = e->type(); if( t == QEvent::ChildAdded ) { QChildEvent *ce = static_cast(e); ce->child()->installEventFilter( this ); } else if( t == QEvent::ChildRemoved ) { updateGeometry(); } return QWidget::event( e ); } bool QcScrollWidget::eventFilter ( QObject * watched, QEvent * event ) { Q_UNUSED( watched ); switch( event->type() ) { case QEvent::Resize: case QEvent::Move: case QEvent::Show: case QEvent::Hide: updateGeometry(); break; default: return false; } return false; } QC_DECLARE_QWIDGET_FACTORY(QcScrollArea); QcScrollArea::QcScrollArea() { connect( horizontalScrollBar(), SIGNAL(actionTriggered(int)), this, SIGNAL(scrolled()) ); connect( verticalScrollBar(), SIGNAL(actionTriggered(int)), this, SIGNAL(scrolled()) ); } void QcScrollArea::setWidget( QObjectProxy *proxy ) { QWidget *w = qobject_cast( proxy->object() ); if( !w ) { qcErrorMsg( "QcScrollArea::setCanvas: given proxy does not contain a valid widget." ); return; } QScrollArea::setWidget( w ); setWidgetResizable( true ); } void QcScrollArea::addChild( QWidget* w ) { if( widget() ) w->setParent( widget() ); } QRectF QcScrollArea::innerBounds() const { QSize vs = viewport()->size(); if( !widget() ) return QRectF(0,0,vs.width(),vs.height()); QSize cs = widget()->size(); return QRectF(0, 0, qMax( vs.width(), cs.width() ), qMax( vs.height(), cs.height() ) ); } void QcScrollArea::setHasBorder( bool b ) { if( b ) QFrame::setFrameShape( QFrame::StyledPanel ); else QFrame::setFrameShape( QFrame::NoFrame ); } QPointF QcScrollArea::visibleOrigin() const { QWidget *w = widget(); return ( w != 0 ? widget()->mapFromParent( QPoint(0,0) ) : QPoint(0,0) ); } void QcScrollArea::setVisibleOrigin( const QPointF &pt ) { if (horizontalScrollBar()->maximum() < pt.x()) horizontalScrollBar()->setMaximum(pt.x()); if (verticalScrollBar()->maximum() < pt.y()) verticalScrollBar()->setMaximum(pt.y()); horizontalScrollBar()->setValue( pt.x() ); verticalScrollBar()->setValue( pt.y() ); } SuperCollider-Source/QtCollider/widgets/QcScrollArea.h000644 000765 000024 00000003703 12321461510 024047 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SCROLL_AREA_H #define QC_SCROLL_AREA_H #include "QcCanvas.h" #include "../QcHelper.h" #include class QObjectProxy; class QcScrollWidget : public QcCanvas { Q_OBJECT public: QcScrollWidget( QWidget *parent = 0 ); QSize sizeHint() const; protected: virtual bool event ( QEvent * ); virtual bool eventFilter ( QObject *, QEvent * ); }; class QcScrollArea : public QScrollArea, public QcHelper { Q_OBJECT Q_PROPERTY( bool hasBorder READ dummyBool WRITE setHasBorder ); Q_PROPERTY( QRectF innerBounds READ innerBounds ); Q_PROPERTY( QPointF visibleOrigin READ visibleOrigin WRITE setVisibleOrigin ); Q_SIGNALS: void scrolled(); public: QcScrollArea(); Q_INVOKABLE void setWidget( QObjectProxy * ); Q_INVOKABLE void addChild( QWidget* w ); void setHasBorder( bool b ); QRectF innerBounds() const; QPointF visibleOrigin() const; void setVisibleOrigin( const QPointF & ); QSize sizeHint() const { return QSize( 300,200 ); } QSize minimumSizeHint() const { return QSize( 50, 50 ); } }; #endif //QC_SCROLL_AREA_H SuperCollider-Source/QtCollider/widgets/QcSlider.cpp000644 000765 000024 00000011742 12756531745 023623 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcSlider.h" #include "../QcWidgetFactory.h" #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcSlider); QcSlider::QcSlider() : QtCollider::Style::Client(this), _value(0.0), _step(0.0), _hndLen(20) { setFocusPolicy( Qt::StrongFocus ); setOrientation( Qt::Vertical ); setAttribute(Qt::WA_AcceptTouchEvents); } double QcSlider::pixelStep() { using namespace QtCollider::Style; QRect contRect( sunkenContentsRect(rect()) ); int range = (_ort == Qt::Horizontal) ? contRect.width() : contRect.height(); range -= _hndLen; if(range > 0) return 1.0 / range; else return 0.0; } void QcSlider::setValue( double val ) { double step = _step; modifyStep(&step); if (step) val = qRound(val / step) * step; _value = qBound(0.0, val, 1.0); update(); } void QcSlider::increment( double factor ) { double step = qMax(_step, pixelStep()); setValue( step * factor + _value ); update(); } void QcSlider::decrement( double factor ) { double step = qMax(_step, pixelStep()); setValue( - step * factor + _value ); update(); } void QcSlider::setOrientation( int i ) { _ort = (Qt::Orientation) i; if(_ort == Qt::Horizontal) setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); else setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Expanding ); updateGeometry(); update(); } QSize QcSlider::sizeHint() const { if( orientation() == Qt::Horizontal ) return QSize(qMax(_hndLen + 10, 150), 20); else return QSize(20, qMax(_hndLen + 10, 150)); } QSize QcSlider::minimumSizeHint() const { if( orientation() == Qt::Horizontal ) return QSize(_hndLen + 10, 20); else return QSize(20, _hndLen + 10); } void QcSlider::mousePressEvent ( QMouseEvent *e ) { setValue( valueAt(e->pos()) ); update(); Q_EMIT( action() ); } void QcSlider::mouseMoveEvent ( QMouseEvent *e ) { if( !e->buttons() ) return; setValue( valueAt(e->pos()) ); update(); Q_EMIT( action() ); } void QcSlider::wheelEvent ( QWheelEvent *e ) { double step = qMax(_step, pixelStep()); modifyStep(&step); double dval = e->delta() / 120.0 * step; setValue( _value + dval ); Q_EMIT( action() ); } void QcSlider::paintEvent( QPaintEvent *e ) { using namespace QtCollider::Style; using QtCollider::Style::RoundRect; QPainter p(this); const QPalette &plt = palette(); p.save(); p.setRenderHint( QPainter::Antialiasing, true ); QRect rGroove = rect(); // draw groove RoundRect shGroove( rGroove, 2 ); drawSunken( &p, plt, shGroove, grooveColor(), hasFocus() ? focusColor() : QColor() ); // geometry QRect rHandle( thumbRect() ); // draw handle RoundRect shHandle( rHandle, 2 ); drawRaised( &p, plt, shHandle, plt.color(QPalette::Button).lighter(105) ); p.restore(); // draw marker QPen pen(knobColor()); pen.setWidth(2); p.setPen(pen); if(_ort == Qt::Horizontal) { qreal center = rHandle.center().x() + 1; QLine line( center, rHandle.top() + 3, center, rHandle.bottom() - 2 ); p.drawLine(line); pen.setColor(plt.color(QPalette::Light)); } else { qreal center = rHandle.center().y() + 1; QLine line( rHandle.left() + 3, center, rHandle.right() - 2, center ); p.drawLine(line); pen.setColor(plt.color(QPalette::Light)); } } QRect QcSlider::thumbRect () { using namespace QtCollider::Style; QRect contRect( sunkenContentsRect(rect()) ); QRect r; if( _ort == Qt::Horizontal ) { int pos = _value * (contRect.width() - _hndLen); r.setX( pos + contRect.left() ); r.setY( contRect.top() ); r.setSize( QSize( _hndLen, contRect.height() ) ); } else { int pos = _value * (contRect.height() - _hndLen); r.setX( contRect.left() ); r.setY( contRect.bottom() - pos - _hndLen + 1 ); r.setSize( QSize( contRect.width(), _hndLen ) ); } return r; } double QcSlider::valueAt( const QPoint &pos ) { using namespace QtCollider::Style; QRect contRect( sunkenContentsRect(rect()) ); if (_ort == Qt::Horizontal) return xValue( pos.x(), contRect, QSize(_hndLen, 0) ); else return yValue( pos.y(), contRect, QSize(0, _hndLen) ); } SuperCollider-Source/QtCollider/widgets/QcSlider.h000644 000765 000024 00000006065 12321461510 023246 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SLIDER #define QC_SLIDER #include "QcAbstractStepValue.h" #include "../QcHelper.h" #include "../style/style.hpp" #include class QcSlider : public QWidget, QcHelper, QcAbstractStepValue, QtCollider::Style::Client { Q_OBJECT Q_PROPERTY( double shiftScale READ dummyFloat WRITE setShiftScale ); Q_PROPERTY( double ctrlScale READ dummyFloat WRITE setCtrlScale ); Q_PROPERTY( double altScale READ dummyFloat WRITE setAltScale ); Q_PROPERTY( double step READ step WRITE setStep ) Q_PROPERTY( double pixelStep READ pixelStep ) Q_PROPERTY( double value READ value WRITE setValue ); Q_PROPERTY( int orientation READ orientation WRITE setOrientation ); Q_PROPERTY( int handleLength READ handleLength WRITE setHandleLength ); Q_PROPERTY( QColor grooveColor READ grooveColor WRITE setGrooveColor ); Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); Q_PROPERTY( QColor knobColor READ knobColor WRITE setKnobColor ); public Q_SLOTS: void increment( double factor ); void decrement( double factor ); Q_SIGNALS: void action(); void preAction( double ); public: QcSlider(); double value() { return _value; } void setValue( double val ); double step() { return _step; } void setStep( double d ) { _step = d; } double pixelStep(); Qt::Orientation orientation() const { return _ort; } void setOrientation( int ); int handleLength() const { return _hndLen; } void setHandleLength( int i ) { _hndLen = i; updateGeometry(); update(); } const QColor & knobColor() const { return _knobColor.isValid() ? _knobColor : palette().color(QPalette::ButtonText); } void setKnobColor(const QColor &c) { _knobColor = c; update(); } virtual QSize sizeHint() const; virtual QSize minimumSizeHint() const; protected: virtual void mousePressEvent ( QMouseEvent * ); virtual void mouseMoveEvent ( QMouseEvent * ); virtual void wheelEvent ( QWheelEvent * ); virtual void paintEvent ( QPaintEvent * ); private: QRect thumbRect (); double valueAt( const QPoint &pos ); Qt::Orientation _ort; double _value; double _step; int _hndLen; QColor _knobColor; }; #endif SuperCollider-Source/QtCollider/widgets/QcSlider2D.cpp000644 000765 000024 00000010217 12756531745 024005 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcSlider2D.h" #include "../QcWidgetFactory.h" #include "../style/routines.hpp" #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcSlider2D); QcSlider2D::QcSlider2D() : QtCollider::Style::Client(this), _x( 0.0 ), _y( 0.0 ), _thumbSize( QSize( 20, 20 ) ), _step( 0.01 ) { setFocusPolicy( Qt::StrongFocus ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); setAttribute(Qt::WA_AcceptTouchEvents); } void QcSlider2D::incrementX( double factor ) { setValue( QPointF( _step * factor + _x, _y ) ); } void QcSlider2D::decrementX( double factor ) { setValue( QPointF( -_step * factor + _x, _y ) ); } void QcSlider2D::incrementY( double factor ) { setValue( QPointF( _x, _step * factor + _y ) ); } void QcSlider2D::decrementY( double factor ) { setValue( QPointF( _x, -_step * factor + _y ) ); } QRect QcSlider2D::thumbRect() { using namespace QtCollider::Style; return QtCollider::Style::rect( QPointF(_x,_y), sunkenContentsRect(rect()), _thumbSize ); } void QcSlider2D::setValue( const QPointF val, bool doAction ) { double x = qMax( 0.0, qMin( 1.0, (double)val.x() ) ); double y= qMax( 0.0, qMin( 1.0, (double)val.y() ) ); if( x != _x || y != _y ) { _x = x; _y = y; update(); if( doAction ) Q_EMIT( action() ); } } void QcSlider2D::mouseMoveEvent ( QMouseEvent * ev ) { using namespace QtCollider::Style; if( !ev->buttons() ) return; QPointF val = QtCollider::Style::value( QPointF(ev->pos()), sunkenContentsRect(rect()), _thumbSize ); setValue(val); } void QcSlider2D::mousePressEvent ( QMouseEvent * ev ) { using namespace QtCollider::Style; QPointF val = QtCollider::Style::value( QPointF(ev->pos()), sunkenContentsRect(rect()), _thumbSize ); setValue(val); } void QcSlider2D::keyPressEvent ( QKeyEvent *e ) { double step = _step; switch( e->key() ) { case Qt::Key_Up: modifyStep( &step ); setValue( QPointF( _x, _y + step ) ); break; case Qt::Key_Down: modifyStep( &step ); setValue( QPointF( _x, _y - step ) ); break; case Qt::Key_Right: modifyStep( &step ); setValue( QPointF( _x + step, _y ) ); break; case Qt::Key_Left: modifyStep( &step ); setValue( QPointF( _x - step, _y ) ); break; case Qt::Key_N: setValue( QPointF( 0.0, 0.0 ) ); break; case Qt::Key_X: setValue( QPointF( 1.0, 1.0 ) ); break; case Qt::Key_C: setValue( QPointF( 0.5, 0.5 ) ); break; case Qt::Key_R: Q_EMIT( randomize() ); break; default: QWidget::keyPressEvent( e ); } } void QcSlider2D::paintEvent ( QPaintEvent *e ) { using namespace QtCollider::Style; using QtCollider::Style::Ellipse; using QtCollider::Style::RoundRect; Q_UNUSED(e); QPainter p(this); p.setRenderHint( QPainter::Antialiasing, true ); QPalette plt = palette(); RoundRect frame(rect(), 2); drawSunken( &p, plt, frame, grooveColor(), hasFocus() ? focusColor() : QColor() ); Ellipse thumb(thumbRect()); drawRaised( &p, plt, thumb, plt.color(QPalette::Button).lighter(105) ); QRectF r( thumb._rect ); qreal wdif = r.width() * 0.3; qreal hdif = r.height() * 0.3; p.setPen( Qt::NoPen ); p.setBrush( knobColor() ); p.drawEllipse( r.adjusted( wdif, hdif, -wdif, -hdif ) ); } SuperCollider-Source/QtCollider/widgets/QcSlider2D.h000644 000765 000024 00000005625 12321461510 023435 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SLIDER_2D #define QC_SLIDER_2D #include "QcAbstractStepValue.h" #include "../QcHelper.h" #include "../style/style.hpp" #include class QcSlider2D : public QWidget, QcHelper, QcAbstractStepValue, QtCollider::Style::Client { Q_OBJECT Q_PROPERTY( double xValue READ xValue WRITE setXValue ) Q_PROPERTY( double yValue READ yValue WRITE setYValue ) Q_PROPERTY( double shiftScale READ dummyFloat WRITE setShiftScale ); Q_PROPERTY( double ctrlScale READ dummyFloat WRITE setCtrlScale ); Q_PROPERTY( double altScale READ dummyFloat WRITE setAltScale ); Q_PROPERTY( double step READ dummyFloat WRITE setStep ) Q_PROPERTY( QColor grooveColor READ grooveColor WRITE setGrooveColor ); Q_PROPERTY( QColor focusColor READ focusColor WRITE setFocusColor ); Q_PROPERTY( QColor knobColor READ knobColor WRITE setKnobColor ); public: QcSlider2D(); double xValue() const { return _x; } double yValue() const { return _y; } void setXValue( double x ) { setValue( QPointF( x, _y ), false ); } void setYValue( double y ) { setValue( QPointF( _x, y ), false ); } void setStep( double f ) { _step = f;} const QColor & knobColor() const { return _knobColor.isValid() ? _knobColor : palette().color(QPalette::ButtonText); } void setKnobColor(const QColor &c) { _knobColor = c; update(); } QSize sizeHint() const { return QSize(150,150); } QSize minimumSizeHint() const { return QSize(30,30); } public Q_SLOTS: void incrementX( double factor = 1.f ); void decrementX( double factor = 1.f ); void incrementY( double factor = 1.f ); void decrementY( double factor = 1.f ); Q_SIGNALS: void action(); void randomize(); private: QRect thumbRect(); void setValue( const QPointF val, bool doAction = true ); void mouseMoveEvent ( QMouseEvent * ); void mousePressEvent ( QMouseEvent * ); void keyPressEvent ( QKeyEvent * ); void paintEvent ( QPaintEvent * ); double _x; double _y; QSize _thumbSize; double _step; QColor _knobColor; }; #endif SuperCollider-Source/QtCollider/widgets/QcTextEdit.cpp000644 000765 000024 00000013401 12756531745 024125 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcTextEdit.h" #include "../QcWidgetFactory.h" #include "../hacks/hacks_qt.hpp" #include #include #include #include #include class QcTextEditFactory : public QcWidgetFactory { void initialize( QWidgetProxy *p, QcTextEdit *w ) { p->setMouseEventWidget( w->viewport() ); } }; QC_DECLARE_FACTORY( QcTextEdit, QcTextEditFactory ); QcTextEdit::QcTextEdit() : _interpretSelection(true) { setAttribute(Qt::WA_AcceptTouchEvents); connect( this, SIGNAL(interpret(QString)), qApp, SLOT(interpret(QString)), Qt::QueuedConnection ); } QString QcTextEdit::documentFilename() const { return _document; } void QcTextEdit::setDocument( const QString &filename ) { QFile file( filename ); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return; QByteArray data = file.readAll(); setText( data ); _document = filename; } int QcTextEdit::selectionStart() const { return textCursor().selectionStart(); } int QcTextEdit::selectionSize() const { QTextCursor cursor = textCursor(); return cursor.selectionEnd() - cursor.selectionStart(); } void QcTextEdit::select( int start, int size ) { if( start < 0 ) start = 0; QTextCursor cursor( document() ); cursor.movePosition( QTextCursor::Right, QTextCursor::MoveAnchor, start ); cursor.movePosition( size > 0 ? QTextCursor::Right : QTextCursor::Left, QTextCursor::KeepAnchor, qAbs(size) ); setTextCursor( cursor ); } QString QcTextEdit::selectedString() const { QString selection( textCursor().selectedText() ); return prepareText(selection); } void QcTextEdit::replaceSelectedText( const QString &string ) { QTextCursor cursor( textCursor() ); if( cursor.hasSelection() ) { cursor.removeSelectedText(); cursor.insertText( string ); } } QString QcTextEdit::currentLine() const { return textCursor().block().text(); } void QcTextEdit::setTextFont( const QFont &f ) { QTextCharFormat format; format.setFont( f ); QTextCursor cursor( document() ); cursor.select( QTextCursor::Document ); cursor.mergeCharFormat( format ); QTextEdit::setFont(f); } void QcTextEdit::setTextColor( const QColor &color ) { QTextCharFormat format; format.setForeground( color ); QTextCursor cursor( document() ); cursor.select( QTextCursor::Document ); cursor.mergeCharFormat( format ); } void QcTextEdit::setRangeColor( const QVariantList &list ) { if( list.count() < 3 ) return; QColor c = list[0].value(); int start = list[1].toInt(); int size = list[2].toInt(); QTextCharFormat format; format.setForeground( c ); QTextCursor cursor( document() ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, start ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor, size ); cursor.mergeCharFormat( format ); } void QcTextEdit::setRangeFont( const QVariantList & list ) { if( list.count() < 3 ) return; QFont f = list[0].value(); int start = list[1].toInt(); int size = list[2].toInt(); QTextCharFormat format; format.setFont( f ); QTextCursor cursor( document() ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, start ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor, size ); cursor.mergeCharFormat( format ); } void QcTextEdit::setRangeText( const QVariantList & list ) { if( list.count() < 3 ) return; QString text = list[0].value(); int start = list[1].toInt(); int size = list[2].toInt(); QTextCursor cursor( document() ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::MoveAnchor, start ); cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor, size ); cursor.insertText( text ); } void QcTextEdit::keyPressEvent( QKeyEvent *e ) { if( _interpretSelection && e->modifiers() & (Qt::ControlModifier|Qt::ShiftModifier) && ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) ) { QTextCursor c(textCursor()); QString code; if ( c.hasSelection() ) { code = c.selectedText(); } { code = c.block().text(); } Q_EMIT( interpret( prepareText(code) ) ); return; } QTextEdit::keyPressEvent( e ); } void QcTextEdit::insertFromMimeData ( const QMimeData * data ) { if(data->hasUrls()) { QTextCursor c( textCursor() ); QList urls = data->urls(); int n = urls.count(); for(int i = 0; i < n; ++i) { QUrl &url = urls[i]; QString text = QURL_IS_LOCAL_FILE(url) ? url.toLocalFile() : url.toString(); c.insertText(text); if(n > 1) c.insertText("\n"); } } else QTextEdit::insertFromMimeData(data); } QString & QcTextEdit::prepareText( QString & text ) const { // NOTE: QTextDocument contains unicode paragraph separators U+2029 // instead of newline \n characters return text.replace( QChar( 0x2029 ), QChar( '\n' ) ); } SuperCollider-Source/QtCollider/widgets/QcTextEdit.h000644 000765 000024 00000005527 12321461510 023560 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_TEXT_EDIT #define QC_TEXT_EDIT #include "../QcHelper.h" #include class QcTextEdit : public QTextEdit, QcHelper { Q_OBJECT Q_PROPERTY( QString document READ documentFilename WRITE setDocument ); Q_PROPERTY( int selectionStart READ selectionStart ); Q_PROPERTY( int selectionSize READ selectionSize ); Q_PROPERTY( QString selectedString READ selectedString WRITE replaceSelectedText ); Q_PROPERTY( QString currentLine READ currentLine ); Q_PROPERTY( QFont textFont READ dummyFont WRITE setTextFont ); Q_PROPERTY( QColor textColor READ dummyColor WRITE setTextColor ); Q_PROPERTY( QVariantList rangeColor READ dummyVariantList WRITE setRangeColor ); Q_PROPERTY( QVariantList rangeFont READ dummyVariantList WRITE setRangeFont ); Q_PROPERTY( QVariantList rangeText READ dummyVariantList WRITE setRangeText ); Q_PROPERTY( bool enterInterpretsSelection READ interpretSelection WRITE setInterpretSelection ); public: QcTextEdit(); QString documentFilename() const; void setDocument( const QString & ); int selectionStart() const; int selectionSize() const; Q_INVOKABLE void select( int start, int size ); QString selectedString() const; void replaceSelectedText( const QString & ); QString currentLine() const; bool interpretSelection() const { return _interpretSelection; } void setInterpretSelection( bool b ) { _interpretSelection = b; } void setTextFont( const QFont & ); void setTextColor( const QColor & ); void setRangeColor( const QVariantList & ); void setRangeFont( const QVariantList & ); void setRangeText( const QVariantList & ); Q_SIGNALS: void interpret( const QString & code ); protected: virtual void keyPressEvent( QKeyEvent * ); virtual void insertFromMimeData ( const QMimeData * ); private: QString & prepareText( QString & str ) const; QString _document; bool _interpretSelection; }; #endif SuperCollider-Source/QtCollider/widgets/QcTextField.h000644 000765 000024 00000002664 12321461510 023715 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "../QcWidgetFactory.h" #include #include class QcTextField : public QLineEdit { Q_OBJECT public: QcTextField() {} protected: virtual void keyPressEvent( QKeyEvent *e ) { // NOTE: We could use the returnPressed() signal, but that would still // propagate the event to parent, which we want to avoid. if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) Q_EMIT(action()); else QLineEdit::keyPressEvent(e); } Q_SIGNALS: void action(); }; QC_DECLARE_QWIDGET_FACTORY( QcTextField ); SuperCollider-Source/QtCollider/widgets/QcTreeWidget.cpp000644 000765 000024 00000016265 12756531745 024451 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcTreeWidget.h" #include "../QcWidgetFactory.h" #include #include class QcTreeWidgetFactory : public QcWidgetFactory { void initialize( QWidgetProxy *p, QcTreeWidget *w ) { p->setMouseEventWidget( w->viewport() ); } }; QC_DECLARE_FACTORY( QcTreeWidget, QcTreeWidgetFactory ); QcTreeWidget::QcTreeWidget() { setAttribute(Qt::WA_AcceptTouchEvents); // Forward signals to argument-less versions connectable from SC. connect( this, SIGNAL( itemActivated(QTreeWidgetItem*, int) ), this, SIGNAL( action() ) ); connect( this, SIGNAL( itemPressed(QTreeWidgetItem*, int) ), this, SIGNAL( itemPressedAction() ) ); connect( this, SIGNAL( currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*) ), this, SIGNAL( currentItemChanged() ) ); } QVariantList QcTreeWidget::columns() const { QVariantList varList; QTreeWidgetItem *header = headerItem(); if( header ) { for( int i = 0; i < header->columnCount(); ++i ) { varList << header->text(i); } } return varList; } void QcTreeWidget::setColumns( const QVariantList & varList ) { int count = varList.size(); setColumnCount( count ); QStringList labels; Q_FOREACH( const QVariant & var, varList ) labels << var.toString(); setHeaderLabels( labels ); } QcTreeWidget::ItemPtr QcTreeWidget::currentItem() const { QTreeWidgetItem *item = QTreeWidget::currentItem(); return QcTreeWidget::Item::safePtr( item ); } void QcTreeWidget::setCurrentItem( const ItemPtr &item ) { _emitAction = false; QTreeWidget::setCurrentItem( item ); _emitAction = true; } QcTreeWidget::ItemPtr QcTreeWidget::item( const QcTreeWidget::ItemPtr & parent, int index ) { QTreeWidgetItem *item = parent ? parent->child(index) : QTreeWidget::topLevelItem(index); return QcTreeWidget::Item::safePtr( item ); } QcTreeWidget::ItemPtr QcTreeWidget::parentItem( const QcTreeWidget::ItemPtr & item ) { if( !item ) return QcTreeWidget::ItemPtr(); return QcTreeWidget::Item::safePtr( item->parent() ); } int QcTreeWidget::indexOfItem( const QcTreeWidget::ItemPtr & item ) { if( !item ) return -1; QTreeWidgetItem *parent = item->parent(); if( parent ) return parent->indexOfChild( item ); else return indexOfTopLevelItem( item ); } QcTreeWidget::ItemPtr QcTreeWidget::addItem ( const QcTreeWidget::ItemPtr & parent, const QVariantList & varList ) { QStringList strings; for( int i = 0; i < varList.count(); ++i ) strings << varList[i].toString(); Item *item = new Item( strings ); if( !parent ) addTopLevelItem( item ); else parent->addChild( item ); return item->safePtr(); } QcTreeWidget::ItemPtr QcTreeWidget::insertItem ( const QcTreeWidget::ItemPtr & parent, int index, const QVariantList & varList ) { int itemCount = topLevelItemCount(); if( index < 0 || index > itemCount ) return ItemPtr(); QStringList strings; for( int i = 0; i < varList.count(); ++i ) strings << varList[i].toString(); Item *item = new Item( strings ); if( !parent ) insertTopLevelItem( index, item ); else parent->insertChild( index, item ); if( !item->treeWidget() ) { delete item; return ItemPtr(); } return item->safePtr(); } void QcTreeWidget::removeItem( const QcTreeWidget::ItemPtr & item ) { delete item.ptr(); } QVariantList QcTreeWidget::strings( const QcTreeWidget::ItemPtr & item ) { QVariantList varList; if( !item ) return varList; for( int i = 0; i < item->columnCount(); ++i ) { varList << item->text(i); } return varList; } void QcTreeWidget::setText( const QcTreeWidget::ItemPtr &item, int column, const QString & text ) { if( item ) item->setText( column, text ); } void QcTreeWidget::setColor( const QcTreeWidget::ItemPtr &item, int column, const QColor & color ) { if( item ) item->setBackground( column, color ); } void QcTreeWidget::setTextColor( const QcTreeWidget::ItemPtr & item, int column, const QColor & color ) { if( item ) item->setData( column, Qt::ForegroundRole, color ); } QWidget * QcTreeWidget::itemWidget( const QcTreeWidget::ItemPtr &item, int column ) { return item ? QTreeWidget::itemWidget( item, column ) : 0; } void QcTreeWidget::setItemWidget( const QcTreeWidget::ItemPtr &item, int column, QObjectProxy *o ) { if( !item ) return; QWidget *w = qobject_cast(o->object()); if( !w ) return; QTreeWidget::setItemWidget( item, column, w ); } void QcTreeWidget::removeItemWidget( const QcTreeWidget::ItemPtr &item, int column ) { if( item ) QTreeWidget::removeItemWidget( item, column ); } void QcTreeWidget::sort( int column, bool descending ) { sortItems( column, descending ? Qt::DescendingOrder : Qt::AscendingOrder ); } void QcTreeWidget::keyPressEvent( QKeyEvent *e ) { QTreeWidget::keyPressEvent( e ); switch (e->key()) { case Qt::Key_Up: case Qt::Key_Down: case Qt::Key_Left: case Qt::Key_Right: case Qt::Key_PageUp: case Qt::Key_PageDown: case Qt::Key_Home: case Qt::Key_End: // Prevent propagating to parent when scroller reaches minimum or maximum: e->accept(); default: break; } } //////////////////////////////// Item ////////////////////////////////////// QcTreeWidget::ItemPtr QcTreeWidget::Item::safePtr( QTreeWidgetItem * item ) { if( item && item->type() == Item::Type ) return static_cast(item)->safePtr(); else return ItemPtr(); } void QcTreeWidget::Item::initialize ( VMGlobals *g, PyrObject *obj, const QcTreeWidget::ItemPtr &ptr ) { Q_ASSERT( isKindOf( obj, SC_CLASS(TreeViewItem) ) ); if( ptr.id() ) { // store the SafePtr QcTreeWidget::ItemPtr *newPtr = new QcTreeWidget::ItemPtr( ptr ); SetPtr( obj->slots+0, newPtr ); // store the id for equality comparison SetPtr( obj->slots+1, ptr.id() ); // install finalizer } else { SetNil( obj->slots+0 ); SetNil( obj->slots+1 ); } InstallFinalizer( g, obj, 2, &QcTreeWidget::Item::finalize ); } int QcTreeWidget::Item::finalize( VMGlobals *g, PyrObject *obj ) { qcDebugMsg(1,"finalizing QTreeViewItem!"); if( IsPtr( obj->slots+0 ) ) { QcTreeWidget::ItemPtr *ptr = static_cast( slotRawPtr(obj->slots+0) ); delete ptr; } return errNone; } bool QcTreeWidget::Item::operator< (const QTreeWidgetItem &other) const { int column = treeWidget()->sortColumn(); return text(column).toLower() < other.text(column).toLower(); } SuperCollider-Source/QtCollider/widgets/QcTreeWidget.h000644 000765 000024 00000007240 12321461510 024063 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_TREE_WIDGET_H #define QC_TREE_WIDGET_H #include "../Common.h" #include "../QObjectProxy.h" #include "../safeptr.hpp" #include #include #include #include #include using namespace QtCollider; class QcTreeWidget : public QTreeWidget { public: class Item : public QTreeWidgetItem { public: enum { Type = QTreeWidgetItem::UserType }; Item() : QTreeWidgetItem( Item::Type ), _safePtr(this) {} Item( const QStringList & strings ) : QTreeWidgetItem( strings, Item::Type ), _safePtr(this) {} ~Item() { _safePtr.invalidate(); } SafePtr safePtr() const { return _safePtr; } static SafePtr safePtr( QTreeWidgetItem* ); static void initialize( VMGlobals *, PyrObject *, const SafePtr & ); static int finalize( VMGlobals *, PyrObject * ); bool operator< ( const QTreeWidgetItem & other ) const; private: SafePtr _safePtr; }; typedef SafePtr ItemPtr; Q_OBJECT Q_PROPERTY( QVariantList columns READ columns WRITE setColumns ) Q_PROPERTY( QcTreeWidget::ItemPtr currentItem READ currentItem WRITE setCurrentItem ); public: Q_INVOKABLE QcTreeWidget::ItemPtr item( const QcTreeWidget::ItemPtr & parent, int index ); Q_INVOKABLE QcTreeWidget::ItemPtr parentItem( const QcTreeWidget::ItemPtr & ); Q_INVOKABLE int indexOfItem( const QcTreeWidget::ItemPtr & ); Q_INVOKABLE QcTreeWidget::ItemPtr addItem ( const QcTreeWidget::ItemPtr & parent, const QVariantList & data ); Q_INVOKABLE QcTreeWidget::ItemPtr insertItem ( const QcTreeWidget::ItemPtr & parent, int index, const QVariantList & data ); Q_INVOKABLE void removeItem( const QcTreeWidget::ItemPtr & ); Q_INVOKABLE QVariantList strings( const QcTreeWidget::ItemPtr & ); Q_INVOKABLE void setText( const QcTreeWidget::ItemPtr &, int column, const QString & ); Q_INVOKABLE void setColor( const QcTreeWidget::ItemPtr &, int column, const QColor & ); Q_INVOKABLE void setTextColor( const QcTreeWidget::ItemPtr &, int column, const QColor & ); Q_INVOKABLE QWidget * itemWidget( const QcTreeWidget::ItemPtr &, int column ); Q_INVOKABLE void setItemWidget( const QcTreeWidget::ItemPtr &, int column, QObjectProxy * ); Q_INVOKABLE void removeItemWidget( const QcTreeWidget::ItemPtr &, int column ); Q_INVOKABLE void sort( int column, bool descending ); Q_SIGNALS: void action(); void itemPressedAction(); void currentItemChanged(); public: QcTreeWidget(); ItemPtr currentItem() const; void setCurrentItem( const ItemPtr & ); QVariantList columns() const; void setColumns( const QVariantList & ); protected: virtual void keyPressEvent( QKeyEvent * ); private: QTreeWidgetItem * _itemOnPress; bool _emitAction; }; Q_DECLARE_METATYPE( QcTreeWidget::ItemPtr ); #endif SuperCollider-Source/QtCollider/widgets/QcWebView.cpp000644 000765 000024 00000012430 12756531745 023744 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcWebView.h" #include "web_page.hpp" #include "../QcWidgetFactory.h" #include #include #include #include #include #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(WebView); namespace QtCollider { WebView::WebView( QWidget *parent ) : QWebView( parent ), _interpretSelection(false), _editable(false) { QtCollider::WebPage *page = new WebPage(this); page->setDelegateReload(true); setPage( page ); // Set the style's standard palette to avoid system's palette incoherencies // get in the way of rendering web pages setPalette( style()->standardPalette() ); setAttribute(Qt::WA_AcceptTouchEvents); page->action( QWebPage::Copy )->setShortcut( QKeySequence::Copy ); page->action( QWebPage::Paste )->setShortcut( QKeySequence::Paste ); connect( this, SIGNAL(linkClicked(QUrl)), this, SLOT(onLinkClicked(QUrl)) ); connect( page->action(QWebPage::Reload), SIGNAL(triggered(bool)), this, SLOT(onPageReload()) ); connect( this, SIGNAL(interpret(QString)), qApp, SLOT(interpret(QString)), Qt::QueuedConnection ); connect( page, SIGNAL(jsConsoleMsg(const QString&, int, const QString&)), this, SIGNAL(jsConsoleMsg(const QString&, int, const QString&)) ); connect( this, SIGNAL(loadFinished(bool)), this, SLOT(updateEditable(bool)) ); } QString WebView::url() const { return QWebView::url().toString(); } void WebView::setUrl( const QString & str ) { load( urlFromString(str) ); } QString WebView::html () const { return page()->mainFrame()->toHtml(); } void WebView::setHtml ( const QString &html, const QString &baseUrl ) { QUrl url( baseUrl.isEmpty() ? QUrl() : urlFromString(baseUrl) ); QWebView::setHtml( html, url ); } QString WebView::plainText () const { return page()->mainFrame()->toPlainText(); } QWebPage::LinkDelegationPolicy WebView::linkDelegationPolicy () const { return page()->linkDelegationPolicy(); } void WebView::setLinkDelegationPolicy ( QWebPage::LinkDelegationPolicy p ) { page()->setLinkDelegationPolicy( p ); } bool WebView::delegateReload() const { WebPage *p = qobject_cast(page()); Q_ASSERT(p); return p->delegateReload(); } void WebView::setDelegateReload( bool flag ) { WebPage *p = qobject_cast(page()); Q_ASSERT(p); p->setDelegateReload( flag ); } void WebView::setFontFamily( int generic, const QString & specific ) { settings()->setFontFamily( (QWebSettings::FontFamily) generic, specific ); } void WebView::evaluateJavaScript ( const QString &script ) { if( script.isEmpty() ) return; QWebFrame *frame = page()->currentFrame(); if( frame ) frame->evaluateJavaScript( script ); } void WebView::findText( const QString &searchText, bool reversed ) { QWebPage::FindFlags flags( QWebPage::FindWrapsAroundDocument ); if( reversed ) flags |= QWebPage::FindBackward; QWebView::findText( searchText, flags ); } void WebView::onLinkClicked( const QUrl &url ) { Q_EMIT( linkActivated( url.toString() ) ); } void WebView::onPageReload() { Q_EMIT( reloadTriggered( url() ) ); } void WebView::contextMenuEvent ( QContextMenuEvent * event ) { QMenu menu; QPoint pos = event->pos(); QWebHitTestResult hitTest = page()->mainFrame()->hitTestContent( pos ); if (!hitTest.linkElement().isNull()) { menu.addAction( pageAction(QWebPage::CopyLinkToClipboard) ); menu.addSeparator(); } if (hitTest.isContentEditable() || hitTest.isContentSelected()) { menu.addAction( pageAction(QWebPage::Copy) ); if (hitTest.isContentEditable()) menu.addAction( pageAction(QWebPage::Paste) ); menu.addSeparator(); } menu.addAction( pageAction(QWebPage::Back) ); menu.addAction( pageAction(QWebPage::Forward) ); menu.addAction( pageAction(QWebPage::Reload) ); menu.exec( event->globalPos() ); } void WebView::keyPressEvent( QKeyEvent *e ) { int key = e->key(); int mods = e->modifiers(); if( _interpretSelection && ( key == Qt::Key_Enter || ( key == Qt::Key_Return && mods & (Qt::ControlModifier|Qt::ShiftModifier) ) ) ) { QString selection = selectedText(); if( !selection.isEmpty() ) { Q_EMIT( interpret( selection ) ); return; } } QWebView::keyPressEvent( e ); } } // namespace QtCollider SuperCollider-Source/QtCollider/widgets/QcWebView.h000644 000765 000024 00000006300 12321461510 023364 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_WEB_VIEW_H #define QC_WEB_VIEW_H #include #include #include namespace QtCollider { class WebPage; class WebView : public QWebView { Q_OBJECT Q_PROPERTY( QString url READ url WRITE setUrl ); Q_PROPERTY( QString html READ html ) Q_PROPERTY( QString plainText READ plainText ) Q_PROPERTY( QWebPage::LinkDelegationPolicy linkDelegationPolicy READ linkDelegationPolicy WRITE setLinkDelegationPolicy ) Q_PROPERTY( bool delegateReload READ delegateReload WRITE setDelegateReload ); Q_PROPERTY( bool enterInterpretsSelection READ interpretSelection WRITE setInterpretSelection ); Q_PROPERTY( bool editable READ editable WRITE setEditable ); public: Q_INVOKABLE void setHtml ( const QString &html, const QString &baseUrl = QString() ); Q_INVOKABLE void evaluateJavaScript ( const QString &script ); Q_INVOKABLE void setFontFamily( int genericFontFamily, const QString & fontFamily ); public Q_SLOTS: void findText( const QString &searchText, bool reversed = false ); Q_SIGNALS: void linkActivated( const QString & ); void reloadTriggered( const QString & ); void interpret( const QString & code ); void jsConsoleMsg( const QString &, int, const QString & ); public: WebView( QWidget *parent = 0 ); QString url() const; void setUrl( const QString & ); QString html () const; QString plainText () const; QWebPage::LinkDelegationPolicy linkDelegationPolicy () const; void setLinkDelegationPolicy ( QWebPage::LinkDelegationPolicy ); bool delegateReload() const; void setDelegateReload( bool ); bool interpretSelection() const { return _interpretSelection; } void setInterpretSelection( bool b ) { _interpretSelection = b; } bool editable() const { return _editable; } void setEditable( bool b ) { _editable = b; page()->setContentEditable(b); } inline static QUrl urlFromString( const QString & str ) { return QUrl::fromUserInput(str); } protected: virtual void keyPressEvent( QKeyEvent * ); virtual void contextMenuEvent ( QContextMenuEvent * ); private Q_SLOTS: void onLinkClicked( const QUrl & ); void onPageReload(); void updateEditable(bool ok) { if(ok) page()->setContentEditable(_editable); } private: bool _interpretSelection; bool _editable; }; } // namespace QtCollider #endif // QC_WEB_VIEW_H SuperCollider-Source/QtCollider/widgets/QcWindow.cpp000644 000765 000024 00000006015 12321461510 023621 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "QcWindow.h" #include "../QcWidgetFactory.h" #include "../QWidgetProxy.h" #include #include #include class QcWindowFactory : public QcObjectFactory { // NOTE: use basic object contruction, but return widget proxy public: virtual QObjectProxy *proxy( QcWindow *obj, PyrObject *sc_obj ) { QObjectProxy *proxy = new QWidgetProxy( obj, sc_obj ); QObject::connect( obj, SIGNAL(painting(QPainter*)), proxy, SLOT(customPaint(QPainter*)) ); return proxy; } }; class QcScrollWindowFactory : public QcObjectFactory { // NOTE: use basic object contruction, but return widget proxy // NOTE: painting will be performed by QcScrollWidget and its factory public: virtual QObjectProxy *proxy( QcScrollWindow *obj, PyrObject *sc_obj ) { return new QWidgetProxy( obj, sc_obj ); } }; QC_DECLARE_FACTORY( QcWindow, QcWindowFactory ); QC_DECLARE_FACTORY( QcScrollWindow, QcScrollWindowFactory ); static void qcInitWindow ( QWidget *window, const QString &title, const QRectF & geom_, bool resizable, bool frame ) { // window title window->setWindowTitle( title ); // size, resizability QRect geom(geom_.toRect()); if( geom.isEmpty() ) { geom = QApplication::desktop()->availableGeometry(); geom.setSize( window->sizeHint() ); } if( resizable ) { window->setGeometry( geom ); } else { window->move( geom.topLeft() ); window->setFixedSize( geom.size() ); } // frameless? if( !frame ) window->setWindowFlags( window->windowFlags() | Qt::FramelessWindowHint ); // Ctrl+W shortcut: close the window QShortcut *closeShortcut = new QShortcut( QKeySequence( Qt::CTRL | Qt::Key_W ), window ); QObject::connect( closeShortcut, SIGNAL(activated()), window, SLOT(close()) ); } QcWindow::QcWindow( const QString &title, const QRectF & geom, bool resizable, bool frame ) { qcInitWindow( this, title, geom, resizable, frame ); } QcScrollWindow::QcScrollWindow( const QString &title, const QRectF & geom, bool resizable, bool frame ) { qcInitWindow( this, title, geom, resizable, frame ); } SuperCollider-Source/QtCollider/widgets/QcWindow.h000644 000765 000024 00000002521 12321461510 023264 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_WINDOW_H #define QC_WINDOW_H #include "BasicWidgets.h" #include "QcScrollArea.h" class QcWindow : public QcCustomPainted { Q_OBJECT public: QcWindow() {} Q_INVOKABLE QcWindow( const QString &title, const QRectF & geom, bool resizable, bool frame ); }; class QcScrollWindow : public QcScrollArea { Q_OBJECT public: QcScrollWindow() {} Q_INVOKABLE QcScrollWindow( const QString &title, const QRectF & geom, bool resizable, bool frame ); }; #endif SuperCollider-Source/QtCollider/widgets/scope_shm_interface.hpp000644 000765 000024 00000002415 12321461510 026073 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of Qt GUI for SuperCollider. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SCOPE_SHM_INTERFACE_HPP #define QC_SCOPE_SHM_INTERFACE_HPP #include "../../common/server_shm.hpp" #include namespace QtCollider { class ScopeShm : public QObject { public: ScopeShm(QObject *parent) : QObject(parent), client(0) {} server_shared_memory_client *client; scope_buffer_reader reader; }; } // namespace QtCollider #endif // QC_SCOPE_SHM_INTERFACE_HPP SuperCollider-Source/QtCollider/widgets/soundfileview/000755 000765 000024 00000000000 13007315613 024247 5ustar00crucialstaff000000 000000 SuperCollider-Source/QtCollider/widgets/web_page.cpp000644 000765 000024 00000003020 12321461510 023630 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "web_page.hpp" #include #include namespace QtCollider { void WebPage::triggerAction ( WebAction action, bool checked ) { switch ( action ) { case QWebPage::Reload: if( _delegateReload ) return; break; case QWebPage::Copy: // ignore text formatting, copy only plain text: QApplication::clipboard()->setText( selectedText() ); return; default: break; } QWebPage::triggerAction( action, checked ); } void WebPage::javaScriptConsoleMessage ( const QString & msg, int line, const QString & src ) { Q_EMIT( jsConsoleMsg(msg,line,src) ); } } // namespace QtCollider SuperCollider-Source/QtCollider/widgets/web_page.hpp000644 000765 000024 00000003071 12321461510 023643 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_WEB_PAGE_HPP_INCLUDED #define QC_WEB_PAGE_HPP_INCLUDED #include namespace QtCollider { class WebPage : public QWebPage { Q_OBJECT public: WebPage( QObject *parent ) : QWebPage( parent ), _delegateReload(false) {} virtual void triggerAction ( WebAction action, bool checked = false ); virtual void javaScriptConsoleMessage ( const QString &, int, const QString & ); bool delegateReload() const { return _delegateReload; } void setDelegateReload( bool flag ) { _delegateReload = flag; } Q_SIGNALS: void jsConsoleMsg( const QString &, int, const QString & ); private: bool _delegateReload; }; } // namespace QtCollider #endif // QC_WEB_PAGE_HPP_INCLUDED SuperCollider-Source/QtCollider/widgets/soundfileview/cachestream.cpp000644 000765 000024 00000022251 12756531745 027254 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "view.hpp" #include SoundCacheStream::SoundCacheStream() : SoundStream ( 0, 0.0, 0.0 ), _caches(0), _fpu(0.0), _dataOffset(0), _dataSize(0), _ready(false), _loading(false), _loadProgress(0) { _loader = new SoundCacheLoader( this ); connect( _loader, SIGNAL(loadProgress(int)), this, SLOT(onLoadProgress(int)), Qt::QueuedConnection ); connect( _loader, SIGNAL(loadingDone()), this, SLOT(onLoadingDone()), Qt::QueuedConnection ); } SoundCacheStream::~SoundCacheStream() { if( _loader->isRunning() ) { _loader->terminate(); _loader->wait(); } delete [] _caches; } void SoundCacheStream::load( const QVector & data, int nf, int offset, int ch ) { if( _loader->isRunning() ) { _loader->terminate(); _loader->wait(); } _ready = false; _loading = true; _loadProgress = 0; delete [] _caches; _ch = ch; _beg = _dataOffset = 0; _dur = _dataSize = nf; _fpu = 1.0; _caches = new SoundCache [ch]; for( int c = 0; c < ch; ++c ) { short *min = _caches[c].min = new short [nf]; short *max = _caches[c].max = new short [nf]; float *sum = _caches[c].sum = new float [nf]; float *sum2 = _caches[c].sum2 = new float [nf]; int s = c + (offset * ch); for( int f = 0; f < nf; ++f, s += ch ) { double val = std::max(-1.0, std::min(1.0, data[s])) * SHRT_MAX; min[f] = val; sum[f] = val; sum2[f] = val * val; } memcpy( max, min, nf * sizeof(short) ); } _loadProgress = 100; _loading = false; _ready = true; Q_EMIT( loadingDone() ); } void SoundCacheStream::load( SNDFILE *sf, const SF_INFO &info, sf_count_t beg, sf_count_t dur, int maxFramesPerUnit, int maxRawFrames ) { Q_ASSERT( maxRawFrames > 0 && maxFramesPerUnit > 0 ); _ready = false; _loadProgress = 0; if( _loader->isRunning() ) { _loader->terminate(); _loader->wait(); } delete [] _caches; _ch = info.channels; _beg = _dataOffset = beg; _dur = dur; // adjust data size for data amount limit if( _dur <= maxRawFrames ) { // ok, not crossing the limit _dataSize = _dur; _fpu = 1.0; } else { _dataSize = maxRawFrames; _fpu = (double) _dur / _dataSize; // re-adjust for data resolution limit if( _fpu > maxFramesPerUnit ) { _dataSize = (double) _dur / maxFramesPerUnit; _fpu = (double) _dur / _dataSize; } } _caches = new SoundCache [info.channels]; int ch; for( ch = 0; ch < info.channels; ++ch ) { _caches[ch].min = new short [_dataSize]; _caches[ch].max = new short [_dataSize]; _caches[ch].sum = new float [_dataSize]; _caches[ch].sum2 = new float [_dataSize]; } _loading = true; _loader->load( sf, info ); } void SoundCacheStream::allocate ( int nf, int ch ) { Q_ASSERT( nf > 0 && ch > 0 ); if( _loader->isRunning() ) { _loader->terminate(); _loader->wait(); } delete [] _caches; _ch = ch; _beg = _dataOffset = 0; _dur = _dataSize = nf; _fpu = 1.0; _caches = new SoundCache [ch]; for( int c = 0; c < ch; ++c ) { short *min = _caches[c].min = new short [nf]; short *max = _caches[c].max = new short [nf]; float *sum = _caches[c].sum = new float [nf]; float *sum2 = _caches[c].sum2 = new float [nf]; size_t bytes = nf * sizeof(short); memset( min, 0, bytes ); memset( max, 0, bytes ); bytes = nf * sizeof(float); memset( sum, 0, bytes ); memset( sum2, 0, bytes ); } _loadProgress = 100; _loading = false; _ready = true; } void SoundCacheStream::write( const QVector & data, int offset, int count ) { Q_ASSERT( _ready && _fpu == 1.0 ); Q_ASSERT( count == (float) data.size() / _ch ); int end = offset + count; // make sure range is ok Q_ASSERT( offset >= 0 && end <= _dataSize ); for( int c = 0; c < _ch; ++c ) { short *min = _caches[c].min; short *max = _caches[c].max; float *sum = _caches[c].sum; float *sum2 = _caches[c].sum2; int s = c; for( int f = offset; f < end; ++f, s += _ch ) { double val = std::max(-1.0, std::min(1.0, data[s])) * SHRT_MAX; min[f] = val; sum[f] = val; sum2[f] = val * val; } memcpy( max + offset, min + offset, count * sizeof(short) ); } } bool SoundCacheStream::displayData ( int ch, double f_beg, double f_dur, short *minBuffer, short *maxBuffer, short *minRMS, short *maxRMS, int bufferSize ) { bool ok = _ready && ch < channels() && ( f_beg >= beginning() ) && ( f_beg + f_dur <= beginning() + duration() ) && bufferSize <= f_dur * _fpu; if( !ok ) return false; double ratio = f_dur / _fpu / bufferSize; double cache_pos = (f_beg - _dataOffset) / _fpu ; short min = SHRT_MAX; short max = SHRT_MIN; double D_SHRT_MAX = (double) SHRT_MAX; double D_SHRT_MIN = (double) SHRT_MIN; int i; for( i = 0; i < bufferSize; ++i ) { int f = floor(cache_pos); // first frame bool no_overlap = f == ceil(cache_pos); float frac0 = f + 1.f - cache_pos; cache_pos += ratio; // Due to possibility of floating point operation failures. if( cache_pos > _dataSize ) cache_pos = _dataSize; int frame_count = ceil(cache_pos) - f ; float frac1 = cache_pos + 1.f - ceil(cache_pos); //short min = SHRT_MAX; //short max = SHRT_MIN; double sum = 0.0; double sum2 = 0.0; short *p_min = _caches[ch].min; short *p_max = _caches[ch].max; float *p_sum = _caches[ch].sum; float *p_sum2 = _caches[ch].sum2; int countdown = frame_count; while( countdown-- ) { // NOTE for min-max, behave as if first frame was ceil(cache_pos) instead of floor(), // to not smudge too much at large scale if( countdown < frame_count - 1 || no_overlap ) { if( p_min[f] < min ) min = p_min[f]; if( p_max[f] > max ) max = p_max[f]; } float frac; if( countdown == frame_count - 1 ) frac = frac0; else if( countdown == 0 ) frac = frac1; else frac = 1.0; sum += p_sum[f] * frac; sum2 += p_sum2[f] * frac; ++f; } double n = f_dur / bufferSize; double avg = sum / n; double stdDev = std::sqrt( std::abs((sum2 - (sum*avg) ) / n) ); minBuffer[i] = min; maxBuffer[i] = max; minRMS[i] = std::max(D_SHRT_MIN, std::min(D_SHRT_MAX, avg - stdDev )); maxRMS[i] = std::max(D_SHRT_MIN, std::min(D_SHRT_MAX, avg + stdDev )); // assure continuity from pixel to pixel min = maxBuffer[i]; max = minBuffer[i]; } return true; } short *SoundCacheStream::rawFrames( int ch, sf_count_t b, sf_count_t d, bool *interleaved ) { if( !_ready || _fpu != 1.0 || ch > channels() || b < _dataOffset || b + d > _dataOffset + _dataSize ) return 0; *interleaved = false; return _caches[ch].min + b - _dataOffset; } /*SoundCacheLoader::SoundCacheLoader( SNDFILE *sf, const SF_INFO &info, int maxFPU, int maxRawFrames ) : _sf( sf ), _sfInfo( info ), _maxFPU( maxFPU ), maxRawFrames( maxRawFrames ) {}*/ void SoundCacheStream::onLoadProgress( int progress ) { _loadProgress = progress; Q_EMIT( loadProgress(progress) ); } void SoundCacheStream::onLoadingDone() { // FIXME what if the signal is received just after starting another load? _ready = true; _loading = false; Q_EMIT( loadingDone() ); } void SoundCacheLoader::load( SNDFILE *sf, const SF_INFO &info ) { Q_ASSERT( !isRunning() ); _sf = sf; _info = info; start(); } void SoundCacheLoader::run() { Q_ASSERT( _sf ); int channels = _cache->channels(); double fpu = _cache->_fpu; int size = _cache->_dataSize; double offset = _cache->_dataOffset; SoundCache *chanCaches = _cache->_caches; int i = 0; while( i < size ) { int chunkSize = qMin( 1000, size - i ); double beg = i * fpu + offset; double dur = chunkSize * fpu; sf_count_t i_beg = floor(beg); sf_count_t i_dur = ceil(beg+dur) - i_beg; SoundFileStream sfStream( _sf, _info, i_beg, i_dur ); int ch; for( ch = 0; ch < channels; ++ch ) { sfStream.integrate( ch, beg, dur, chanCaches[ch].min + i, chanCaches[ch].max + i, chanCaches[ch].sum + i, chanCaches[ch].sum2 + i, chunkSize ); } i += chunkSize; Q_EMIT( loadProgress( i * 100 / size ) ); } Q_EMIT( loadingDone() ); } SuperCollider-Source/QtCollider/widgets/soundfileview/filestream.cpp000644 000765 000024 00000014210 12756531745 027124 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "view.hpp" #include SoundFileStream::SoundFileStream() : _data(0), _dataSize(0), _dataOffset(0) {} SoundFileStream::SoundFileStream( SNDFILE *sf, const SF_INFO &info, sf_count_t b, sf_count_t d ) : _data(0) { load( sf, info, b, d ); } SoundFileStream::~SoundFileStream() { delete[] _data; } void SoundFileStream::load( SNDFILE *sf, const SF_INFO &info, sf_count_t beg, sf_count_t dur ) { delete[] _data; _dataOffset = beg; _dataSize = dur; _data = new short [_dataSize * info.channels]; sf_seek( sf, _dataOffset, SEEK_SET); if (info.format & SF_FORMAT_FLOAT || info.format & SF_FORMAT_DOUBLE) { // libsndfile reading float into short is broken for non-power-of-two channel counts int sampleCount = _dataSize * info.channels; float *tmp = new float [sampleCount]; _dataSize = sf_readf_float( sf, tmp, _dataSize ); for (int i = 0; i < sampleCount; ++i) _data[i] = std::max( -1.f, std::min( 1.f, tmp[i] ) ) * std::numeric_limits::max(); delete[] tmp; } else { _dataSize = sf_readf_short( sf, _data, _dataSize ); } _ch = info.channels; _beg = _dataOffset; _dur = _dataSize; } bool SoundFileStream::integrate ( int ch, double f_beg, double f_dur, short *minBuffer, short *maxBuffer, float *sumBuf, float *sum2Buf, int bufferSize ) { bool ok = _data != 0 && ch < channels() && ( f_beg >= beginning() ) && ( f_beg + f_dur <= beginning() + duration() ); if( !ok ) return false; double fpu = f_dur / bufferSize; double f_pos = f_beg - _dataOffset; double f_pos_max = _dataSize; int i; for( i = 0; i < bufferSize; ++i ) { int data_pos = floor(f_pos); // increment position // slower, but error-proof: // f_pos = (double)(i+1) / width() * f_dur + f_beg; // the following is a faster variant, but floating point operations are fallible, // so we need to make sure we stay within the constraints of f_dur; double f_pos1 = f_pos + fpu; if( f_pos1 > f_pos_max ) f_pos1 = f_pos_max; int frame_count = ceil(f_pos1) - data_pos; float frac0 = data_pos + 1.f - f_pos; float frac1 = f_pos1 + 1.f - ceil(f_pos1); // get min, max and sum short *samples = _data + (data_pos * channels()) + ch; short min = SHRT_MAX; short max = SHRT_MIN; float sum = 0.f; float sum2 = 0.f; int f; // frame for( f = 0; f < frame_count; ++f, samples += channels() ){ // TODO should we overlap min-max or not here? float sample = *samples; float frac; if( f == 0 ) frac = frac0; else if( f == frame_count - 1 ) frac = frac1; else frac = 1.0; if( sample < min ) min = sample; if( sample > max ) max = sample; sum += sample * frac; sum2 += sample * sample * frac; } minBuffer[i] = min; maxBuffer[i] = max; sumBuf[i] = sum; sum2Buf[i] = sum2; f_pos = f_pos1; } return true; } bool SoundFileStream::displayData ( int ch, double f_beg, double f_dur, short *minBuffer, short *maxBuffer, short *minRMS, short *maxRMS, int bufferSize ) { bool ok = _data != 0 && ch < channels() && ( f_beg >= beginning() ) && ( f_beg + f_dur <= beginning() + duration() ); if( !ok ) return false; double fpu = f_dur / bufferSize; double f_pos = f_beg - _dataOffset; double f_pos_max = _dataSize; short min = SHRT_MAX; short max = SHRT_MIN; double D_SHRT_MAX = (double) SHRT_MAX; double D_SHRT_MIN = (double) SHRT_MIN; int i; for( i = 0; i < bufferSize; ++i ) { int data_pos = floor(f_pos); // increment position // slower, but error-proof: // f_pos = (double)(i+1) / width() * f_dur + f_beg; // the following is a faster variant, but floating point operations are fallible, // so we need to make sure we stay within the constraints of f_dur; double f_pos1 = f_pos + fpu; if( f_pos1 > f_pos_max ) f_pos1 = f_pos_max; int frame_count = ceil(f_pos1) - data_pos; float frac0 = data_pos + 1.f - f_pos; float frac1 = f_pos1 + 1.f - ceil(f_pos1); // get min, max and sum short *samples = _data + (data_pos * channels()) + ch; float sum = 0.f; float sum2 = 0.f; int f; // frame for( f = 0; f < frame_count; ++f, samples += channels() ){ // TODO should we overlap min-max or not here? float sample = *samples; float frac; if( f == 0 ) frac = frac0; else if( f == frame_count - 1 ) frac = frac1; else frac = 1.0; if( sample < min ) min = sample; if( sample > max ) max = sample; sum += sample * frac; sum2 += sample * sample * frac; } double n = fpu; double avg = sum / n; double stdDev = std::sqrt( std::abs((sum2 - (sum*avg) ) / n) ); minBuffer[i] = min; maxBuffer[i] = max; minRMS[i] = std::max(D_SHRT_MIN, std::min(D_SHRT_MAX, avg - stdDev )); maxRMS[i] = std::max(D_SHRT_MIN, std::min(D_SHRT_MAX, avg + stdDev )); f_pos = f_pos1; min = maxBuffer[i]; max = minBuffer[i]; } return true; } short *SoundFileStream::rawFrames( int ch, sf_count_t b, sf_count_t d, bool *interleaved ) { if( ch > channels() || b < _dataOffset || b + d > _dataOffset + _dataSize ) return 0; *interleaved = true; sf_count_t offset = (b - _dataOffset) * channels() + ch; return ( _data + offset ); } SuperCollider-Source/QtCollider/widgets/soundfileview/view.cpp000644 000765 000024 00000047423 12756531745 025757 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "view.hpp" #include "../../QcWidgetFactory.h" #include #include #include #include #include #include #include #include QC_DECLARE_QWIDGET_FACTORY(QcWaveform); const int kMaxRawFrames = 300000; const int kMaxFramesPerCacheUnit = 128; QcWaveform::QcWaveform( QWidget * parent ) : QWidget( parent ), sf(0), _rangeBeg(0), _rangeDur(0), _rangeEnd(0), _cache(0), _curSel(0), _showCursor(false), _cursorEditable(true), _cursorPos(0), _showGrid(true), _gridResolution(1.0), _gridOffset(0.0), _beg(0.0), _dur(0.0), _yZoom(1.f), pixmap(0), _bkgColor( QColor(0,0,0) ), _cursorColor( QColor(255,0,0) ), _gridColor( QColor(100,100,200) ), _peakColor( QColor(242,178,0) ), _rmsColor( QColor(255,255,0) ), dirty(false), _drawWaveform(true) { memset( &sfInfo, 0, sizeof(SF_INFO) ); setFocusPolicy( Qt::StrongFocus ); setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ); setAttribute( Qt::WA_OpaquePaintEvent, true ); } QcWaveform::~QcWaveform() { delete _cache; delete pixmap; if( sf ) sf_close( sf ); } void QcWaveform::load( const QString& filename ) { qcDebugMsg( 1, "QcWaveform::load( filename )" ); SF_INFO new_info; memset( &new_info, 0, sizeof(SF_INFO) ); SNDFILE *new_sf = sf_open( filename.toStdString().c_str(), SFM_READ, &new_info ); if( !new_sf ) { qcErrorMsg(QStringLiteral("Could not open soundfile: ") + filename); return; } doLoad( new_sf, new_info, 0, new_info.frames ); } void QcWaveform::load( const QString& filename, int beg, int dur ) { qcDebugMsg( 1, "QcWaveform::load( filename, beg, dur )" ); SF_INFO new_info; memset( &new_info, 0, sizeof(SF_INFO) ); SNDFILE *new_sf = sf_open( filename.toStdString().c_str(), SFM_READ, &new_info ); if( !new_sf ) { qcErrorMsg(QStringLiteral("Could not open soundfile: ") + filename); return; } doLoad( new_sf, new_info, beg, dur ); } void QcWaveform::load( const QVector & data, int offset, int ch, int sr ) { qcDebugMsg( 1, "QcWaveform::load( data, offset, channels )" ); if( ch < 1 ) { qcWarningMsg( "QSoundFileView: invalid number of channels!" ); return; } int ns = data.count(); int nf = ns / ch; if( nf * ch != ns ) { qcWarningMsg( "QSoundFileView: size of data not a multiple of channel count!" ); return; } if( offset < 0 || nf - offset < 1 ) { qcWarningMsg( "QSoundFileView: invalid range of data!" ); return; } delete _cache; if( sf ) sf_close( sf ); sf = 0; SF_INFO new_info; memset( &new_info, 0, sizeof(SF_INFO) ); new_info.channels = ch; new_info.samplerate = sr; sfInfo = new_info; _beg = _rangeBeg = 0; _dur = _rangeDur = _rangeEnd = nf - offset; updateFPP(); _cache = new SoundCacheStream(); connect( _cache, SIGNAL(loadingDone()), this, SIGNAL(loadingDone()) ); connect( _cache, SIGNAL(loadingDone()), this, SLOT(redraw()) ); _cache->load( data, _rangeDur, offset, ch ); } void QcWaveform::allocate ( int frames, int ch, int sr ) { if( ch < 1 ) { qcWarningMsg( "QSoundFileView: invalid number of channels!" ); return; } delete _cache; if( sf ) sf_close( sf ); sf = 0; SF_INFO new_info; memset( &new_info, 0, sizeof(SF_INFO) ); new_info.channels = ch; new_info.samplerate = sr; sfInfo = new_info; _beg = _rangeBeg = 0; _dur = _rangeDur = _rangeEnd = frames; updateFPP(); _cache = new SoundCacheStream(); _cache->allocate( frames, ch ); redraw(); } void QcWaveform::write( const QVector & data, int offset ) { if( sf ) { qcWarningMsg( "QSoundFileView: can not write data while displaying a sound file!" ); return; } if( !_cache || !_cache->ready() ) { qcWarningMsg( "QSoundFileView: can not write data; memory has not been allocated yet!" ); return; } int ch = sfInfo.channels; int ns = data.size(); int nf = ns / ch; if( nf * ch != ns ) { qcWarningMsg( "QSoundFileView: can not write data; size not a multiple of channels!" ); return; } if( offset < 0 || offset + nf > _rangeEnd ) { qcWarningMsg( "QSoundFileView: can not write data; either offset is wrong or data size is too large." ); return; } _cache->write( data, offset, nf ); redraw(); } void QcWaveform::doLoad( SNDFILE *new_sf, const SF_INFO &new_info, sf_count_t beg, sf_count_t dur ) { // set up soundfile to scale data in range [-1,1] to int range // when reading floating point data as int sf_command( new_sf, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE ); // check beginning and duration validity if( beg < 0 || dur < 1 || beg + dur > new_info.frames ) { qcErrorMsg("Invalid beginning and/or duration."); sf_close( new_sf ); return; } // cleanup previous state // NOTE we have to delete SoundCacheStream before closing the soundfile, as it might be still // loading it // TODO: should SoundCacheStream open the soundfile on its own? delete _cache; if( sf ) sf_close( sf ); sf = new_sf; sfInfo = new_info; _beg = _rangeBeg = beg; _dur = _rangeDur = dur; _rangeEnd = _rangeBeg + _rangeDur; updateFPP(); _cache = new SoundCacheStream(); connect( _cache, SIGNAL(loadProgress(int)), this, SIGNAL(loadProgress(int)) ); connect( _cache, SIGNAL(loadProgress(int)), this, SLOT(update()) ); connect( _cache, SIGNAL(loadingDone()), this, SIGNAL(loadingDone()) ); connect( _cache, SIGNAL(loadingDone()), this, SLOT(redraw()) ); _cache->load( sf, sfInfo, beg, dur, kMaxFramesPerCacheUnit, kMaxRawFrames ); redraw(); } float QcWaveform::loadProgress() { return _cache ? _cache->loadProgress() : 1.f; } float QcWaveform::zoom() { // NOTE We have limited _rangeDur to 1 minimum. return _dur / _rangeDur; } float QcWaveform::xZoom() { return ( sfInfo.samplerate ? _dur / sfInfo.samplerate : 0 ); } float QcWaveform::yZoom() { return _yZoom; } QVariantList QcWaveform::selections() const { QVariantList slist; for( int i = 0; i < 64; ++i ) { slist << QVariant( selection(i) ); } return slist; } void QcWaveform::setCurrentSelection( int i ) { if( i < 0 || i > 63 ) return; _curSel = i; update(); } QVariantList QcWaveform::selection( int i ) const { QVariantList list; if( i < 0 || i > 63 ) return list; const Selection &s = _selections[i]; list << QVariant(static_cast(s.start - _rangeBeg)); list << QVariant(static_cast(s.size)); return list; } void QcWaveform::setSelection( int i, sf_count_t a, sf_count_t b ) { if( i < 0 || i > 63 ) return; Selection& s = _selections[i]; s.start = qMin( a, b ); s.size = qMax( a, b ) - s.start; update(); } void QcWaveform::setSelection( int i, QVariantList list ) { if( list.count() < 2 ) return; sf_count_t start = list[0].toInt() + _rangeBeg; sf_count_t end = start + list[1].toInt(); setSelection( i, start, end ); } void QcWaveform::setSelectionStart( int i, sf_count_t frame ) { if( i < 0 || i > 63 ) return; Selection& s = _selections[i]; sf_count_t frame2 = s.start + s.size; s.start = qMin( frame, frame2 ); s.size = qMax( frame, frame2 ) - s.start; update(); } void QcWaveform::setSelectionEnd( int i, sf_count_t frame ) { if( i < 0 || i > 63 ) return; Selection& s = _selections[i]; sf_count_t frame2 = s.start; s.start = qMin( frame, frame2 ); s.size = qMax( frame, frame2 ) - s.start; update(); } void QcWaveform::setSelectionEditable( int i, bool editable ) { if( i < 0 || i > 63 ) return; _selections[i].editable = editable; update(); } void QcWaveform::setSelectionColor( int i, const QColor &c ) { if( i < 0 || i > 63 ) return; _selections[i].color = c; update(); } QVariantList QcWaveform::waveColors() const { QVariantList clist; Q_FOREACH( QColor clr, _waveColors ) clist << QVariant(clr); return clist; } void QcWaveform::setWaveColors( const QVariantList &list ) { _waveColors.clear(); Q_FOREACH( const QVariant & var, list ) _waveColors << var.value(); redraw(); } void QcWaveform::zoomTo( double z ) { z = qMax( 0.0, qMin( 1.0, z ) ); _dur = qMax( _rangeDur * z, 1.0 ); //printf("dur: %Li view: %Li\n", sfInfo.frames, _dur); if( _beg + _dur > _rangeEnd ) _beg = _rangeEnd - _dur; updateFPP(); redraw(); } void QcWaveform::zoomBy( double factor ) { zoomTo( zoom() * factor ); } void QcWaveform::zoomAllOut() { _beg = _rangeBeg; _dur = _rangeDur; updateFPP(); redraw(); } void QcWaveform::scrollTo( double startFrame ) { _beg = qBound( (double)_rangeBeg, startFrame, _rangeEnd - _dur ); redraw(); } void QcWaveform::scrollBy( double f ) { scrollTo( _beg + f ); } float QcWaveform::scrollPos() { double scrollRange = _rangeDur - _dur; return scrollRange > 0.0 ? (_beg - _rangeBeg) / scrollRange : 0.f; } void QcWaveform::setScrollPos( double fraction ) { scrollTo( fraction * (_rangeDur - _dur) + _rangeBeg ); } void QcWaveform::scrollToStart() { scrollTo( _rangeBeg ); } void QcWaveform::scrollToEnd() { scrollTo( _rangeEnd - _dur ); } void QcWaveform::setXZoom( double seconds ) { // NOTE We have limited _rangeDur to 1 minimum. double frac = seconds * sfInfo.samplerate / _rangeDur; zoomTo( frac ); } void QcWaveform::setYZoom( double factor ) { _yZoom = factor; redraw(); } void QcWaveform::zoomSelection( int i ) { if( i < 0 || i > 63 ) return; Selection &s = _selections[i]; if( s.start >= _rangeEnd || s.size < 1 || s.start + s.size <= _rangeBeg ) return; _beg = qMax( s.start, _rangeBeg ); double end = qMin( s.start + s.size, _rangeEnd ); _dur = end - _beg; // clear the selection s.size = 0; updateFPP(); redraw(); } void QcWaveform::resizeEvent( QResizeEvent * ) { delete pixmap; pixmap = new QPixmap( size() ); updateFPP(); redraw(); } void QcWaveform::paintEvent( QPaintEvent *ev ) { Q_ASSERT( pixmap != 0 ); QPainter p( this ); // if loading draw progress if( _cache && _cache->loading() ) { QRect r( rect() ); p.fillRect( r, QColor(100,100,100) ); r.setRight( r.right() * _cache->loadProgress() / 100 ); p.fillRect( r, QColor( 0, 0, 0 ) ); p.setPen( QColor(255,255,255) ); QTextOption opt; opt.setAlignment( Qt::AlignCenter ); p.drawText( rect(), "loading...", opt ); return; } p.fillRect( rect(), _bkgColor ); // draw waveform on pixmap if( _drawWaveform && dirty ) { draw( pixmap, 0, width(), _beg, _dur ); dirty = false; } // draw selections p.save(); p.scale( (double) width() / _dur, 1.0 ); p.translate( _beg * -1.0, 0.0 ); p.setPen( Qt::NoPen ); int i; for( i = 0; i < 64; ++i ) { const Selection &s = _selections[i]; if( s.size > 0 ) { QRectF r ( s.start, 0, s.size, height() ); p.setBrush( s.color ); p.drawRect( r ); } } p.restore(); // draw time grid if( _showGrid && sfInfo.samplerate > 0 && _gridResolution > 0.f ) { p.save(); double durSecs = (double) _dur / sfInfo.samplerate; double begSecs = (double) _beg / sfInfo.samplerate; p.scale( width() / durSecs, 1.0 ); p.setPen( _gridColor ); double offset = _gridOffset - begSecs; offset -= ( floor( offset / _gridResolution ) * _gridResolution ); while( offset < durSecs ) { p.drawLine( QLineF( offset, 0.0, offset, height() ) ); offset += _gridResolution; } p.restore(); } // paste the waveform pixmap on screen if( _drawWaveform ) p.drawPixmap( ev->rect(), *pixmap, ev->rect() ); // draw cursor if( _showCursor && _cursorPos >= _beg && _cursorPos < _beg + _dur ) { double cursorX = (_cursorPos - _beg) / _fpp; p.setPen( _cursorColor ); p.drawLine( QLineF( cursorX, 0, cursorX, height() ) ); } } void QcWaveform::keyPressEvent( QKeyEvent *ev ) { if( ev->key() == Qt::Key_Shift && _dragAction == Navigate ) { _dragPoint = mapFromGlobal(QCursor::pos()); _dragData2 = zoom(); } else ev->ignore(); } void QcWaveform::mousePressEvent( QMouseEvent *ev ) { _dragAction = NoDragAction; _dragPoint = ev->pos(); _dragFrame = ev->pos().x() * _fpp + _beg; Qt::KeyboardModifiers mods = ev->modifiers(); Qt::MouseButton btn = ev->button(); #ifdef Q_OS_MAC Qt::KeyboardModifier CTRL = Qt::MetaModifier; #else Qt::KeyboardModifier CTRL = Qt::ControlModifier; #endif if( btn == Qt::LeftButton ) { if( (mods & Qt::ShiftModifier) && ( mods & CTRL ) ) { _dragFrame = _selections[_curSel].start; _dragAction = MoveSelection; } else if( mods & Qt::ShiftModifier ) { _dragAction = Select; const Selection &s = _selections[_curSel]; if( _dragFrame < s.start + (s.size*0.5) ) { setSelectionStart( _curSel, _dragFrame ); _dragFrame = s.start + s.size; } else { setSelectionEnd( _curSel, _dragFrame ); _dragFrame = s.start; } Q_EMIT( action() ); } else { if( !(mods & CTRL) ) { _dragAction = Select; _selections[_curSel].start = _dragFrame; _selections[_curSel].size = 0; update(); Q_EMIT( action() ); } if( _cursorEditable ) { _cursorPos = _dragFrame; if( mods & CTRL ) _dragAction = MoveCursor; update(); Q_EMIT( metaAction() ); } } } else if( btn == Qt::RightButton ) { _dragAction = Navigate; _dragData = ev->pos().x() * _fpp + _beg; _dragData2 = zoom(); } } void QcWaveform::mouseDoubleClickEvent ( QMouseEvent * ) { setSelection( _curSel, _rangeBeg, _rangeEnd ); Q_EMIT( action() ); } void QcWaveform::mouseMoveEvent( QMouseEvent *ev ) { if( !ev->buttons() ) return; if( _dragAction == Navigate ) { Qt::KeyboardModifiers mods = ev->modifiers(); if( mods & Qt::ShiftModifier ) { double factor = pow( 2, (ev->pos().y() - _dragPoint.y()) * 0.008 ); // zoom to the initial zoom times the factor based on distance from initial position zoomTo( _dragData2 * factor ); } // scroll to the clicked frame minus the current mouse position in frames // _fpp has been adjusted by zooming scrollTo( _dragData - (ev->pos().x() * _fpp) ); } else if( _dragAction == Select ) { sf_count_t frame = qBound( 0, ev->pos().x(), width() ) * _fpp + _beg; setSelection( _curSel, _dragFrame, frame ); update(); Q_EMIT( action() ); } else if( _dragAction == MoveSelection ) { double dpos = ev->pos().x() - _dragPoint.x(); Selection &s = _selections[_curSel]; s.start = _dragFrame + (dpos * _fpp); s.start = qBound( _rangeBeg, s.start, _rangeEnd - s.size ); update(); Q_EMIT( action() ); } else if( _dragAction == MoveCursor ) { _cursorPos = qBound( 0, ev->pos().x(), width() ) * _fpp + _beg; update(); Q_EMIT( metaAction() ); } } void QcWaveform::rebuildCache ( int maxFPU, int maxRawFrames ) { } void QcWaveform::draw( QPixmap *pix, int x, int width, double f_beg, double f_dur ) { // FIXME anomaly: when _fpp reaching 1.0 rms can go outside min-max! pix->fill( QColor( 0, 0, 0, 0 ) ); QPainter p( pix ); if( !_cache || !_cache->ready() ) return; // check for sane situation: if( f_beg < _rangeBeg || f_beg + f_dur > _rangeEnd ) return; // data indexes sf_count_t i_beg = floor(f_beg); // data beginning; sf_count_t i_count = ceil( f_beg + f_dur ) - i_beg; // data count; bool haveOneMore; if( i_beg + i_count < _rangeEnd ) { ++i_count; haveOneMore = true; } else { haveOneMore = false; } // data source - choose according to horiz. zoom (data-display resolution) bool canUseCache = _fpp < 1.0 ? _cache->fpu() == 1.0 : _fpp >= _cache->fpu(); SoundStream *soundStream; SoundFileStream sfStream; if( canUseCache ) { qcDebugMsg( 2, QStringLiteral("using cache") ); soundStream = _cache; } else if( sf ) { qcDebugMsg( 2, QStringLiteral("using file") ); soundStream = &sfStream; sfStream.load( sf, sfInfo, i_beg, i_count ); } else { qcWarningMsg( "QSoundFileView: can't paint waveform: view resolution exceeds data cache resolution," " and soundfile is not given." ); return; } // geometry float spacing = pix->height() * 0.15f / (sfInfo.channels + 1); float chHeight = pix->height() * 0.85f / (float) sfInfo.channels; float yScale = -chHeight / 65535.f * _yZoom; //spacing /= yscale; // initial painter setup QPen minMaxPen; QPen rmsPen; float halfChH = chHeight * 0.5; p.translate( 0.f, halfChH + spacing ); int waveColorN = _waveColors.count(); int ch; for( ch = 0; ch < soundStream->channels(); ++ch ) { if( ch < waveColorN && _waveColors[ch].isValid() ) { QColor clr( _waveColors[ch] ); rmsPen.setColor( clr ); minMaxPen.setColor( clr.darker( 140 ) ); } else { rmsPen.setColor( _rmsColor ); minMaxPen.setColor( _peakColor ); } // draw center line p.setPen( QColor(90,90,90) ); p.drawLine( x, 0, x + width, 0 ); // draw bounding lines p.setPen( QColor(100,100,100) ); p.drawLine( x, halfChH, x+width, halfChH ); p.drawLine( x, -halfChH, x+width, -halfChH ); p.save(); p.setClipping(true); p.setClipRect( x, -halfChH, x+width, chHeight ); p.scale( 1.f, yScale ); if( _fpp > 1.0 ) { // draw min-max regions and RMS short * minBuffer = (short*)alloca(width * sizeof(short)); short * maxBuffer = (short*)alloca(width * sizeof(short));; short * minRMS = (short*)alloca(width * sizeof(short));; short * maxRMS = (short*)alloca(width * sizeof(short));; bool ok = soundStream->displayData( ch, f_beg, f_dur, minBuffer, maxBuffer, minRMS, maxRMS, width ); // printf("integration ok: %i\n", ok); Q_ASSERT( ok ); int i; for( i = 0; i < width; ++i ) { short min = minBuffer[i]; short max = maxBuffer[i]; if( max != min ) { p.setPen( minMaxPen ); p.drawLine( x + i, min, x + i, max ); } else { p.setPen( minMaxPen ); p.drawPoint( x + i, min ); } p.setPen( rmsPen ); p.drawLine( x + i, minRMS[i], x + i, maxRMS[i] ); } } else { // draw lines between actual values qreal ppf = 1.0 / _fpp; qreal dx = (i_beg - f_beg) * ppf; bool interleaved = false; short *data = soundStream->rawFrames( ch, i_beg, i_count, &interleaved ); //printf("got raw frames ok: %i\n", data != 0 ); Q_ASSERT( data != 0 ); int step = interleaved ? soundStream->channels() : 1; QPainterPath path; if( i_count ) { QPointF pt( dx, (qreal) *data ); path.moveTo( pt ); } int f; // frame for( f = 1; f < i_count; ++f ) { data += step; QPointF pt( f * ppf + dx, (qreal) *data ); path.lineTo( pt ); } if( i_count && !haveOneMore ) { path.lineTo( QPointF( f * ppf + dx, (qreal)*data ) ); } p.setPen( rmsPen ); p.drawPath( path ); } p.restore(); p.translate( 0.f, chHeight + spacing ); } } SuperCollider-Source/QtCollider/widgets/soundfileview/view.hpp000644 000765 000024 00000030212 12321461510 025724 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_SOUND_FILE_VIEW_H #define QC_SOUND_FILE_VIEW_H #include "../../Common.h" #include "../../QcHelper.h" #include #include #include #include #include #include class QcWaveform; class SoundCacheStream; struct SoundCache { SoundCache() : min(0), max(0), sum(0), sum2(0) {}; ~SoundCache() { delete [] min; delete [] max; delete [] sum; delete [] sum2; } short *min; short *max; float *sum; float *sum2; }; class QcWaveform : public QWidget, public QcHelper { Q_OBJECT Q_PROPERTY( float readProgress READ loadProgress ); Q_PROPERTY( int startFrame READ startFrame ); Q_PROPERTY( int frames READ frames ); Q_PROPERTY( double viewFrames READ viewFrames ); Q_PROPERTY( double viewStartFrame READ viewStartFrame WRITE scrollTo ); Q_PROPERTY( float scrollPos READ scrollPos WRITE setScrollPos ); Q_PROPERTY( int currentSelection READ currentSelection WRITE setCurrentSelection ); Q_PROPERTY( QVariantList selections READ selections ); Q_PROPERTY( float yZoom READ yZoom WRITE setYZoom ); Q_PROPERTY( float xZoom READ xZoom WRITE setXZoom ); Q_PROPERTY( bool cursorVisible READ cursorVisible WRITE setCursorVisible ); Q_PROPERTY( bool cursorEditable READ cursorEditable WRITE setCursorEditable ); Q_PROPERTY( int cursorPosition READ cursorPosition WRITE setCursorPosition ); Q_PROPERTY( bool gridVisible READ gridVisible WRITE setGridVisible ); Q_PROPERTY( float gridOffset READ gridOffset WRITE setGridOffset ); Q_PROPERTY( float gridResolution READ gridResolution WRITE setGridResolution ); Q_PROPERTY( bool drawsWaveform READ drawsWaveform WRITE setDrawsWaveform ); Q_PROPERTY( QColor background READ background WRITE setBackground ); Q_PROPERTY( QColor peakColor READ peakColor WRITE setPeakColor ); Q_PROPERTY( QColor rmsColor READ rmsColor WRITE setRmsColor ); Q_PROPERTY( QColor cursorColor READ cursorColor WRITE setCursorColor ); Q_PROPERTY( QColor gridColor READ gridColor WRITE setGridColor ); public: Q_INVOKABLE void load( const QString& filename ); // NOTE: Using int instead of sf_count_t for accessibility from SC language. Q_INVOKABLE void load( const QString& filename, int beginning, int duration ); Q_INVOKABLE void load( const QVector & data, int offset = 0, int channels = 1, int samplerate = 44100 ); Q_INVOKABLE void allocate ( int frames, int channels = 1, int samplerate = 44100 ); Q_INVOKABLE void write( const QVector & data, int offset ); public: struct Selection { Selection() : start(0), size(0), editable(true), color(QColor(0,0,150)) {} sf_count_t start; sf_count_t size; bool editable; QColor color; }; QcWaveform( QWidget * parent = 0 ); ~QcWaveform(); float loadProgress(); sf_count_t startFrame() { return _rangeBeg; } sf_count_t frames() { return _rangeDur; } double viewStartFrame() { return _beg; } double viewFrames() { return _dur; } float scrollPos(); // as fraction of scrolling range float zoom(); //visible fraction float xZoom(); //visible seconds float yZoom(); //factor QVariantList selections() const; int currentSelection() const { return _curSel; } void setCurrentSelection( int i ); // for SC: selection start relative to first loaded frame Q_INVOKABLE QVariantList selection( int index ) const; // for SC: selection start relative to first loaded frame Q_INVOKABLE void setSelection( int index, QVariantList data ); void setSelection( int i, sf_count_t a, sf_count_t b ); Q_INVOKABLE void setSelectionStart( int i, sf_count_t frame ); Q_INVOKABLE void setSelectionEnd( int i, sf_count_t frame ); Q_INVOKABLE void setSelectionEditable( int index, bool editable ); Q_INVOKABLE void setSelectionColor( int index, const QColor &clr ); Q_PROPERTY( QVariantList waveColors READ waveColors WRITE setWaveColors ); bool cursorVisible() const { return _showCursor; } void setCursorVisible( bool b ) { _showCursor = b; update(); } int cursorPosition() const { return _cursorPos; } void setCursorPosition( int pos ) { _cursorPos = pos; update(); } bool cursorEditable() const { return _cursorEditable; } void setCursorEditable( bool b ) { _cursorEditable = b; } bool gridVisible() const { return _showGrid; } void setGridVisible( bool b ) { _showGrid = b; update(); } float gridOffset() const { return _gridOffset; } void setGridOffset( float f ) { _gridOffset = f; update(); } float gridResolution() const { return _gridResolution; } void setGridResolution( float f ) { _gridResolution = f; update(); } bool drawsWaveform() const { return _drawWaveform; } void setDrawsWaveform( bool b ) { _drawWaveform = b; update(); } QVariantList waveColors() const; void setWaveColors( const QVariantList & ); const QColor & background() const { return _bkgColor; } void setBackground( const QColor &c ) { if(_bkgColor == c) return; _bkgColor = c; setAttribute(Qt::WA_OpaquePaintEvent, c.isValid() && c.alpha() == 255); update(); } const QColor & peakColor() const { return _peakColor; } void setPeakColor( const QColor &clr ) { _peakColor = clr; redraw(); } const QColor & rmsColor() const { return _rmsColor; } void setRmsColor( const QColor &clr ) { _rmsColor = clr; redraw(); } const QColor & cursorColor() const { return _cursorColor; } void setCursorColor( const QColor &c ) { _cursorColor = c; update(); } const QColor & gridColor() const { return _gridColor; } void setGridColor( const QColor &c ) { _gridColor = c; update(); } QSize sizeHint() const { return QSize( 400, 200 ); } QSize minimumSizeHint() const { return QSize( 100, 20 ); } public Q_SLOTS: void zoomTo( double fraction ); //void zoomTo( float fraction, quint64 frame ); void zoomBy( double factor ); void zoomAllOut(); void zoomSelection( int selectionIndex ); void scrollTo( double frame ); void scrollBy( double frames ); void setScrollPos( double fraction ); // as fraction of scrolling range void scrollToStart(); void scrollToEnd(); void setYZoom( double factor ); void setXZoom( double seconds ); Q_SIGNALS: void loadProgress( int ); void loadingDone(); void action(); void metaAction(); public Q_SLOTS: void redraw() { dirty = true; update(); } protected: virtual void resizeEvent( QResizeEvent * ); virtual void paintEvent( QPaintEvent * ); virtual void keyPressEvent( QKeyEvent * ); virtual void mousePressEvent( QMouseEvent * ); virtual void mouseDoubleClickEvent ( QMouseEvent * ); virtual void mouseMoveEvent( QMouseEvent * ); private: void doLoad( SNDFILE *new_sf, const SF_INFO &new_info, sf_count_t beginning, sf_count_t duration ); inline void updateFPP() { _fpp = width() ? (double) _dur / width() : 0.0; } void rebuildCache ( int maxFramesPerCache, int maxRawFrames ); void draw ( QPixmap *, int x, int width, double beginning, double duration ); // data SNDFILE *sf; SF_INFO sfInfo; sf_count_t _rangeBeg; sf_count_t _rangeDur; sf_count_t _rangeEnd; SoundCacheStream *_cache; // selections Selection _selections[64]; int _curSel; // cursor bool _showCursor; sf_count_t _cursorPos; bool _cursorEditable; //grid bool _showGrid; float _gridResolution; float _gridOffset; // view double _beg; double _dur; double _fpp; float _yZoom; // painting QPixmap *pixmap; QColor _bkgColor; QColor _peakColor; QColor _rmsColor; QColor _cursorColor; QColor _gridColor; bool dirty; bool _drawWaveform; QList _waveColors; // interaction enum DragAction { NoDragAction, Navigate, Select, MoveSelection, MoveCursor }; DragAction _dragAction; QPointF _dragPoint; sf_count_t _dragFrame; double _dragData; double _dragData2; }; class SoundStream { public: inline int channels() { return _ch; } inline sf_count_t beginning() { return _beg; } inline sf_count_t duration() { return _dur; } virtual bool displayData( int channel, double offset, double duration, short *minBuffer, short *maxBuffer, short *minRMS, short *maxRMS, int bufferSize ) = 0; virtual short *rawFrames( int channel, sf_count_t beginning, sf_count_t duration, bool *interleaved ) = 0; protected: SoundStream() : _ch( 0 ), _beg( 0 ), _dur( 0 ) {} SoundStream( int channels, sf_count_t beginning, sf_count_t duration ) : _ch( channels ), _beg( beginning ), _dur( duration ) {} int _ch; sf_count_t _beg; sf_count_t _dur; }; class SoundFileStream : public SoundStream { public: SoundFileStream(); SoundFileStream( SNDFILE *sf, const SF_INFO &sf_info, sf_count_t beginning, sf_count_t duration ); ~SoundFileStream(); void load( SNDFILE *sf, const SF_INFO &sf_info, sf_count_t beginning, sf_count_t duration ); bool integrate( int channel, double offset, double duration, short *minBuffer, short *maxBuffer, float *sumBuffer, float *sum2Buffer, int bufferSize ); bool displayData( int channel, double offset, double duration, short *minBuffer, short *maxBuffer, short *minRMS, short *maxRMS, int bufferSize ); short *rawFrames( int channel, sf_count_t beginning, sf_count_t duration, bool *interleaved ); private: short *_data; sf_count_t _dataSize; sf_count_t _dataOffset; }; class SoundCacheLoader; class SoundCacheStream : public QObject, public SoundStream { friend class SoundCacheLoader; Q_OBJECT public: SoundCacheStream(); ~SoundCacheStream(); void load( const QVector & data, int frames, int offset, int channels ); void load( SNDFILE *sf, const SF_INFO &info, sf_count_t beg, sf_count_t dur, int maxFramesPerUnit, int maxRawFrames ); void allocate ( int frames, int channels ); void write( const QVector & data, int offset, int count ); inline double fpu() { return _fpu; } inline bool ready() { return _ready; } inline bool loading() { return _loading; } inline int loadProgress() { return _loadProgress; } bool displayData( int channel, double offset, double duration, short *minBuffer, short *maxBuffer, short *minRMS, short *maxRMS, int bufferSize ); short *rawFrames( int channel, sf_count_t beginning, sf_count_t duration, bool *interleaved ); Q_SIGNALS: void loadProgress( int ); void loadingDone(); private Q_SLOTS: void onLoadProgress( int ); void onLoadingDone(); private: SoundCache *_caches; double _fpu; // soundfile frames per cache unit sf_count_t _dataOffset; // offset into soundfile of first frame cached (in frames) sf_count_t _dataSize; // amount of cache units bool _ready; bool _loading; SoundCacheLoader *_loader; int _loadProgress; }; class SoundCacheLoader : public QThread { Q_OBJECT public: SoundCacheLoader( SoundCacheStream *cache ) : QThread( cache ), _cache( cache ), _sf(0) {} void load( SNDFILE *sf, const SF_INFO &info ); Q_SIGNALS: void loadProgress( int ); void loadingDone(); private: void run(); SoundCacheStream *_cache; SNDFILE *_sf; SF_INFO _info; }; #endif SuperCollider-Source/QtCollider/style/ProxyStyle.cpp000644 000765 000024 00000004157 12756531745 023753 0ustar00crucialstaff000000 000000 #include "ProxyStyle.hpp" #include "../QcApplication.h" #include #include #include #include #ifdef Q_OS_MAC #include "../hacks/hacks_mac.hpp" #endif using namespace QtCollider; static bool AlwaysShowScrollbars() { #if defined(Q_OS_MAC) return QtCollider::Mac::AlwaysShowScrollbars(); #elif defined(Q_OS_X11) return !QcApplication::SystemHasMouseWheel(); #elif defined(Q_OS_WIN) return !QcApplication::SystemHasMouseWheel(); #else return !QcApplication::SystemHasMouseWheel(); #endif }; void ProxyStyle::drawComplexControl ( ComplexControl ctrl, const QStyleOptionComplex *opt, QPainter *p, const QWidget * w) const { // FIXME: this is a workaround for the WebKit bug #104116 (or a variation on it). if( ctrl == QStyle::CC_ScrollBar && qobject_cast(w) != 0 && opt->type == QStyleOption::SO_Slider ) { // WebKit tries to hide scrollbars, but mistakenly hides QWebView - NULL-ify styleObject to prevent. const QStyleOptionSlider *optSlider = static_cast(opt); QStyleOptionSlider opt2( *optSlider ); opt2.styleObject = NULL; QProxyStyle::drawComplexControl( ctrl, &opt2, p, w ); return; } if (ctrl == QStyle::CC_ScrollBar && AlwaysShowScrollbars()) { const QStyleOptionSlider *optSlider = static_cast(opt); QStyleOptionSlider opt2( *optSlider ); opt2.state = State_On; QProxyStyle::drawComplexControl( ctrl, static_cast(&opt2), p, w ); return; } QProxyStyle::drawComplexControl( ctrl, opt, p, w ); } int ProxyStyle::styleHint ( StyleHint hint, const QStyleOption * option, const QWidget * widget, QStyleHintReturn * returnData ) const { switch( hint ) { case QStyle::SH_Slider_AbsoluteSetButtons: return Qt::LeftButton; case QStyle::SH_Slider_PageSetButtons: return Qt::NoButton; case QStyle::SH_ScrollBar_Transient: return 1; default: return QProxyStyle::styleHint( hint, option, widget, returnData ); } } SuperCollider-Source/QtCollider/style/ProxyStyle.hpp000644 000765 000024 00000001061 12756531745 023747 0ustar00crucialstaff000000 000000 #ifndef QC_PROXY_STYLE_H #define QC_PROXY_STYLE_H #include namespace QtCollider { class ProxyStyle : public QProxyStyle { public: ProxyStyle ( QStyle *style = 0 ) : QProxyStyle(style) { } virtual void drawComplexControl ( ComplexControl, const QStyleOptionComplex *, QPainter *, const QWidget * w = 0 ) const; virtual int styleHint ( StyleHint, const QStyleOption * = 0, const QWidget * = 0, QStyleHintReturn * = 0 ) const; }; } // namespace QtCollider #endif // QC_PROXY_STYLE_H SuperCollider-Source/QtCollider/style/routines.hpp000644 000765 000024 00000014531 12321461510 023437 0ustar00crucialstaff000000 000000 #ifndef QC_STYLE_ROUTINES_H #define QC_STYLE_ROUTINES_H #include #include namespace QtCollider { namespace Style { #if 0 namespace ReliefType { struct Hover; struct Raised; struct Flat; struct Sunken; }; using namespace ReliefType; namespace ShapeType { struct Rect; struct RoundRect; struct LeftRoundRect; struct RightRoundRect; struct TopRoundRect; struct BottomRoundRect; struct Ellipse; }; using namespace ShapeType; // drawShape // template void drawShape( QPainter *, const QRect & ); template void drawShape( QPainter *, const QRect &, qreal param1 ); template<> void drawShape ( QPainter *p, const QRect &r ) { p->drawRect(r); } template<> void drawShape ( QPainter *p, const QRect &r ) { p->drawEllipse(r); } template<> void drawShape ( QPainter *p, const QRect &r, qreal radius ) { p->drawRoundedRect( r, radius, radius, Qt::RelativeSize ); } // drawReliefShape // template struct Shape { template void draw(); }; #endif struct Rect { Rect( QRectF rect ) : _rect(rect) {} template inline void draw( QPainter * p, const RectT &r ) const { p->drawRect(r); } QRectF _rect; }; struct RoundRect { RoundRect( QRectF rect, qreal radius ) : _rect(rect), _radius(radius) {} template inline void draw( QPainter * p, const RectT &r ) const { p->drawRoundedRect(r, _radius, _radius, Qt::AbsoluteSize ); } QRectF _rect; qreal _radius; }; struct Ellipse { Ellipse( QRectF rect ) : _rect(rect) {} template inline void draw( QPainter * p, const RectT &r ) const { p->drawEllipse(r); } QRectF _rect; }; template void drawRaised (QPainter *p, const QPalette &plt, const ShapeT &shape, const QColor &color, const QColor &focusColor = QColor()) { p->save(); bool focus = focusColor.isValid(); QRectF r( shape._rect ); p->setBrush(Qt::NoBrush); // focus indication QPen pen; pen.setWidth(2); if( focus ) { pen.setColor(focusColor); p->setPen(pen); shape.draw( p, r.adjusted(1,1,-1,-1) ); r.adjust(2,2,-2,-2); } else { r.adjust(1,1,-1,-1); } // edge QColor edgeClr( focus ? plt.color(QPalette::Light) : plt.color(QPalette::Dark) ); if(focus) edgeClr.setAlpha(100); else edgeClr.setAlpha( color.alpha() ); pen.setColor(edgeClr); p->setPen(pen); shape.draw( p, r ); // center double pos = shape._rect.height(); pos = (pos - 3) / pos; QLinearGradient lgrad( shape._rect.topLeft(), shape._rect.bottomLeft() ); lgrad.setColorAt( 0, color.lighter(110) ); lgrad.setColorAt( pos, color.darker(105) ); lgrad.setColorAt( 1, color.darker(115) ); p->setPen(Qt::NoPen); p->setBrush( QBrush(lgrad) ); shape.draw( p, r ); p->restore(); } template void drawSunken (QPainter *p, const QPalette &plt, const ShapeT &shape, const QColor &color, const QColor &focusColor = QColor()) { p->save(); QPen pen; pen.setWidth(2); // outer border QColor c = focusColor.isValid() ? focusColor : QColor(255,255,255,20); pen.setColor(c); p->setPen(pen); p->setBrush(Qt::NoBrush); shape.draw( p, shape._rect.adjusted(1,1,-1,-1) ); // inner border QColor c1( plt.color(QPalette::Shadow) ); c1.setAlpha( 180 ); pen.setColor(c1); p->setPen(pen); p->setBrush(Qt::NoBrush); shape.draw( p, shape._rect.adjusted(2,2,-2,-2) ); // shadow QColor c2=color; c2.setAlpha(150); p->setPen(Qt::NoPen); p->setBrush(c2); shape.draw( p, shape._rect.adjusted(2,2,-2,-2) ); // background p->setBrush(color); shape.draw( p, shape._rect.adjusted(2,3,-2,-2) ); p->restore(); } template RectT sunkenContentsRect ( const RectT & r ) { return r.adjusted(1, 1,-1,-1 ); } template qreal xValue ( qreal x, const RectT & bounds ) { return (x - bounds.x()) / bounds.width(); } template qreal yValue ( qreal y, const RectT & bounds ) { return (bounds.y() + bounds.height() - y) / bounds.height(); } template qreal xValue ( qreal x, const RectT & bounds, const SizeT & margin ) { return margin.width() < bounds.width() ? (x - bounds.x() - (margin.width() * 0.5)) / (bounds.width() - margin.width()) : 0.0; } template qreal yValue ( qreal y, const RectT & bounds, const SizeT & margin ) { return margin.height() < bounds.height() ? (bounds.y() + bounds.height() - y - (margin.height() * 0.5)) / (bounds.height() - margin.height()) : 0.0; } template QPointF value ( const PointT & pos, const RectT & bounds ) { return QPointF( xValue(pos.x(), bounds), yValue(pos.y(), bounds) ); } template QPointF value ( const PointT & pos, const RectT & bounds, const SizeT & margin ) { return QPointF( xValue(pos.x(), bounds, margin), yValue(pos.y(), bounds, margin) ); } template RectT marginsRect ( const RectT & bounds, const SizeT & margin ) { RectT r; r.setSize( SizeT( qMax((qreal)bounds.width() - margin.width(), qreal(0.0)), qMax((qreal)bounds.height() - margin.height(), qreal(0.0)) ) ); r.moveCenter( bounds.center() ); return r; } template RectT rect ( const QPointF & value, const RectT & bounds, const SizeT & size ) { qreal x = value.x() * (bounds.width() - size.width()) + bounds.left(); qreal y = bounds.top() + bounds.height() - size.height() - value.y() * (bounds.height() - size.height()); return RectT( x, y, size.width(), size.height() ); } template QPointF pos ( const QPointF & value, const RectT & bounds, const SizeT & margin ) { qreal x = value.x() * (bounds.width() - margin.width()) + bounds.left() + margin.x() * 0.5; qreal y = - value.y() * (bounds.height() - margin.height()) + bounds.top() + bounds.height() - margin.y() * 0.5; return QPointF(x,y); } template QPointF pos ( const QPointF & value, const RectT & bounds ) { qreal x = value.x() * bounds.width() + bounds.left(); qreal y = - value.y() * bounds.height() + bounds.top() + bounds.height(); return QPointF(x,y); } } // namespace QtCollider } // namespace Style #endif SuperCollider-Source/QtCollider/style/slider_style.cpp000644 000765 000024 00000004452 12321461510 024265 0ustar00crucialstaff000000 000000 #include "style.hpp" #include "routines.hpp" #include "../widgets/QcSlider.h" #include namespace QtCollider { namespace Style { QRect Slider::sc_groove ( const QStyleOption *opt, const QcSlider * ) { return sunkenContentsRect(opt->rect); } QRect Slider::sc_handle ( const QStyleOptionSlider *opt, const QcSlider *s ) { QRect contRect( sunkenContentsRect(opt->rect) ); double valRange = opt->maximum - opt->minimum; double val = valRange > 0.0 ? (opt->sliderPosition - opt->minimum) / valRange : 0.0; int len = s->handleLength(); QRect r; if( opt->orientation == Qt::Horizontal ) { int pos = val * (contRect.width() - len); r.setX( pos + contRect.left() ); r.setY( contRect.top() ); r.setSize( QSize( len, contRect.height() ) ); } else { int pos = val * (contRect.height() - len); r.setX( contRect.left() ); r.setY( contRect.bottom() - pos - len + 1 ); r.setSize( QSize( contRect.width(), len ) ); } return r; } void Slider::cc_draw ( const QStyleOptionSlider *opt, QPainter *p, const QcSlider *slider ) { using QtCollider::Style::Ellipse; using QtCollider::Style::RoundRect; const QPalette &plt = opt->palette; p->save(); p->setRenderHint( QPainter::Antialiasing, true ); QRect rGroove = opt->rect; // draw groove RoundRect shGroove( rGroove, 2 ); QColor baseColor( slider->grooveColor() ); QColor focusColor; if( opt->state & QStyle::State_HasFocus ) focusColor = slider->focusColor(); drawSunken( p, plt, shGroove, baseColor, focusColor ); // geometry QRect rHandle( sc_handle( opt, slider ) ); // draw handle RoundRect shHandle( rHandle, 2 ); drawRaised( p, plt, shHandle, plt.color(QPalette::Button).lighter(105) ); p->restore(); // draw marker QPen pen(plt.color(QPalette::ButtonText)); pen.setWidth(2); p->setPen(pen); if(opt->orientation == Qt::Horizontal) { qreal center = rHandle.center().x() + 1; QLine line( center, rHandle.top() + 3, center, rHandle.bottom() - 2 ); p->drawLine(line); pen.setColor(plt.color(QPalette::Light)); } else { qreal center = rHandle.center().y() + 1; QLine line( rHandle.left() + 3, center, rHandle.right() - 2, center ); p->drawLine(line); pen.setColor(plt.color(QPalette::Light)); } } } // namespace Style } // namespace QtCollider SuperCollider-Source/QtCollider/style/style.cpp000644 000765 000024 00000000353 12321461510 022717 0ustar00crucialstaff000000 000000 #include "style.hpp" #include "routines.hpp" using namespace QtCollider::Style; void StyleImpl::polish ( QPalette & p ) { _colors[Focus] = p.color(QPalette::Highlight); _colors[Groove] = p.color(QPalette::Window).darker(120); } SuperCollider-Source/QtCollider/style/style.hpp000644 000765 000024 00000002575 12321461510 022734 0ustar00crucialstaff000000 000000 #ifndef QC_STYLE_H #define QC_STYLE_H #include "ProxyStyle.hpp" #include "routines.hpp" #include class QcSlider; namespace QtCollider { namespace Style { enum ColorRole { Focus = 0, Groove, ColorRoleCount }; class StyleImpl : public ProxyStyle { Q_OBJECT public: StyleImpl( QStyle *s = 0 ) : ProxyStyle( s ) {} virtual void polish ( QPalette & ); QColor color( ColorRole role ) { Q_ASSERT(role < ColorRoleCount); return _colors[role]; } private: QColor _colors[ColorRoleCount]; }; struct Client { Client( QWidget *w ) : _widget(w) {} QColor focusColor() const { return color(Focus); } void setFocusColor( const QColor & c ) { setColor(Focus, c); } QColor grooveColor() const { return color(Groove); } void setGrooveColor( const QColor & c ) { setColor(Groove, c); } QColor color ( ColorRole role ) const { Q_ASSERT(role < ColorRoleCount); QColor c( _colors[role] ); if( c.isValid() ) return c; else { StyleImpl *style = qobject_cast(_widget->style()); return style ? style->color(role) : QColor(); } } void setColor( ColorRole role, const QColor & color ) { Q_ASSERT( role < ColorRoleCount ); _colors[role] = color; _widget->update(); } private: QColor _colors[ColorRoleCount]; QWidget *_widget; }; } // namespace QtCollider } // namespace Style #endif SuperCollider-Source/QtCollider/primitives/image_primitive_helper_funcs.h000644 000765 000024 00000006065 12321461510 030174 0ustar00crucialstaff000000 000000 /************************************************************************ * * This file is part of SuperCollider Qt GUI. * * Copyright 2013 Jakob Leben (jakob.leben@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ // these functions are useful for the creation of QImage SC objects #ifndef SuperCollider_image_primitive_helper_funcs_h #define SuperCollider_image_primitive_helper_funcs_h #include #include "../image.h" #include "../type_codec.hpp" namespace QC = QtCollider; namespace QtCollider { inline QC::Image * to_image( struct PyrObject * obj ) { SharedImage *shared_image_ptr = reinterpret_cast( slotRawPtr(obj->slots) ); return shared_image_ptr->data(); } inline QC::Image * to_image( PyrSlot * slot ) { SharedImage *shared_image_ptr = reinterpret_cast( slotRawPtr( slotRawObject(slot)->slots ) ); return shared_image_ptr->data(); } inline QRgb color_to_pixel( const QColor & color ) { int r, g, b, a; color.getRgb( &r, &g, &b, &a ); qreal k = a / 255.f; r *= k; g *= k; b *= k; QRgb pixel = (a << 24) | (r << 16) | (g << 8) | b; return pixel; } inline QColor pixel_to_color( QRgb pixel ) { int r, g, b, a; int mask = 0xFF; a = pixel >> 24 & mask; r = pixel >> 16 & mask; g = pixel << 8 & mask; b = pixel & mask; if ( a > 0 ) { qreal k = a > 0 ? 255.f / a : 0.f; r *= k; g *= k; b *= k; return QColor(r,g,b,a); } else return QColor(0,0,0,0); } inline int finalize_image_object( struct VMGlobals *g, struct PyrObject *obj ) { SharedImage *shared_image_ptr = reinterpret_cast( slotRawPtr(obj->slots) ); delete shared_image_ptr; SetNil( obj->slots+0 ); return errNone; } inline void initialize_image_object( struct VMGlobals *g, struct PyrObject *obj, Image *image ) { assert( IsNil( obj->slots ) && IsNil( obj->slots+1 ) ); SharedImage *shared_image_ptr = new SharedImage(image); SetPtr( obj->slots, shared_image_ptr ); // dataptr InstallFinalizer( g, obj, 1, finalize_image_object ); // finalizer } } // namespace QtCollider #endif SuperCollider-Source/QtCollider/primitives/prim_misc.cpp000644 000765 000024 00000020366 12756531745 024626 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "primitives.h" #include "../Common.h" #include "../type_codec.hpp" #include "../QcApplication.h" #include "../QObjectProxy.h" #include "../style/style.hpp" #include "QtCollider.h" #ifdef Q_OS_MAC # include "../hacks/hacks_mac.hpp" #endif #include #include #include #include #include #include #include #include namespace QtCollider { QC_LANG_PRIMITIVE( QtGUI_SetDebugLevel, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QtCollider::setDebugLevel( QtCollider::get(a) ); return errNone; } QC_LANG_PRIMITIVE( QtGUI_DebugLevel, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { SetInt( r, QtCollider::debugLevel() ); return errNone; } QC_LANG_PRIMITIVE( QWindow_ScreenBounds, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QRect screenGeometry = QApplication::desktop()->screenGeometry(); QtCollider::set( r, screenGeometry ); return errNone; } QC_LANG_PRIMITIVE( QWindow_AvailableGeometry, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QRect rect = QApplication::desktop()->availableGeometry(); QtCollider::set( r, rect ); return errNone; } QC_LANG_PRIMITIVE( Qt_StringBounds, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QString str = QtCollider::get( a ); QFont f = QtCollider::get( a+1 ); QFontMetrics fm( f ); QRect bounds = fm.boundingRect( str ); // we keep the font height even on empty string; if( str.isEmpty() ) bounds.setHeight( fm.height() ); QtCollider::set( r, bounds ); return errNone; } QC_LANG_PRIMITIVE( Qt_AvailableFonts, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QFontDatabase database; QVariantList list; Q_FOREACH( QString family, database.families() ) list << family; QtCollider::set( r, list ); return errNone; } QC_LANG_PRIMITIVE( QFont_SetDefaultFont, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if ( !isKindOfSlot( a+0, SC_CLASS(Font) ) ) return errWrongType; QFont font( QtCollider::read(a+0) ); const char *className = IsSym(a+1) ? slotRawSymbol(a+1)->name : 0; QApplication::setFont( font, className ); return errNone; } QC_LANG_PRIMITIVE( QFont_DefaultFamilyForStyle, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { // NOTE: // On X11 systems we rely on default fontconfig mappings of font familiy names, // as style hints are not necessarily supported. // On other systems, style hints should work. if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if ( !IsInt(a) ) return errWrongType; QFont::StyleHint styleHint; QString family; switch (slotRawInt(a)) { case 0: styleHint = QFont::SansSerif; family = "sans-serif"; break; case 1: styleHint = QFont::Serif; family = "serif"; break; case 2: styleHint = QFont::Monospace; family = "monospace"; break; default: styleHint = QFont::AnyStyle; } QFont font(family); font.setStyleHint(styleHint, QFont::PreferMatch); QtCollider::set( r, font.defaultFamily() ); return errNone; } QC_LANG_PRIMITIVE( Qt_GlobalPalette, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QPalette p( QApplication::palette() ); QtCollider::set( r, p ); return errNone; } QC_LANG_PRIMITIVE( Qt_SetGlobalPalette, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); // The line below is a workaround. The non-win term causes Error C2440 in VS // https://msdn.microsoft.com/en-us/library/sy5tsf8z.aspx #if defined(_MSC_VER) QPalette p = (QPalette&&) QtCollider::get(a); #else QPalette p = QtCollider::get( a ); #endif QApplication::setPalette( p ); return errNone; } QC_LANG_PRIMITIVE( Qt_FocusWidget, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QWidget *w = QApplication::focusWidget(); #ifdef Q_OS_MAC // On Mac we need to make additional checks, as Qt does not monitor // focus changes to native Cocoa windows in the same application. if( w && !QtCollider::Mac::isKeyWindow( w ) ) w = 0; #endif if( w ) { QObjectProxy *proxy = QObjectProxy::fromObject(w); if( proxy && proxy->scObject() ) { SetObject( r, proxy->scObject() ); return errNone; } } SetNil(r); return errNone; } QC_LANG_PRIMITIVE( Qt_SetStyle, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QString str = QtCollider::get( a ); if( str.isEmpty() ) return errFailed; QStyle *style = QStyleFactory::create( str ); if( !style ) return errFailed; QApplication::setStyle( new QtCollider::Style::StyleImpl( style ) ); return errNone; } QC_LANG_PRIMITIVE( Qt_AvailableStyles, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QVariantList list; Q_FOREACH( QString key, QStyleFactory::keys() ) list << key; QtCollider::set( r, list ); return errNone; } QC_LANG_PRIMITIVE( QWebView_ClearMemoryCaches, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QWebSettings::clearMemoryCaches(); return errNone; } QC_LANG_PRIMITIVE( Qt_IsMethodOverridden, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if(NotObj(a) || NotSym(a+1)) return errWrongType; PyrObject *self = slotRawObject(r); PyrObjectHdr *superclass = slotRawObject(a); PyrSymbol *method = slotRawSymbol(a+1); for(PyrClass *klass = self->classptr; klass != superclass && klass != class_object; klass = slotRawSymbol(&klass->superclass)->u.classobj) { PyrSlot *methodSlot = &klass->methods; if(!IsObj(methodSlot)) continue; PyrObject *methodArray = slotRawObject(methodSlot); PyrSlot *methods = methodArray->slots; for(int i = 0; i < methodArray->size; ++i) { PyrMethod *m = slotRawMethod(methods+i); if(slotRawSymbol(&m->name) == method){ SetTrue(r); return errNone; } } } SetFalse(r); return errNone; } QC_LANG_PRIMITIVE( Qt_CursorPosition, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QtCollider::set(r, QCursor::pos()); return errNone; } void defineMiscPrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/prim_QImage.cpp000644 000765 000024 00000036674 12756531745 025047 0ustar00crucialstaff000000 000000 /************************************************************************ * * This file is part of SuperCollider Qt GUI. * * Copyright 2013 Jakob Leben (jakob.leben@gmail.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "primitives.h" #include "image_primitive_helper_funcs.h" #include "../image.h" #include "../QcApplication.h" #include "../Common.h" #include "../type_codec.hpp" #include "../painting.h" #include "../hacks/hacks_qt.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include namespace QC = QtCollider; namespace QtCollider { QPainter *imgPainter = 0; QC_LANG_PRIMITIVE( QImage_NewPath, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QString path( QtCollider::get(a) ); QPixmap pixmap(path); if (pixmap.isNull()) return errFailed; Image *image = new Image(); image->setPixmap(pixmap); initialize_image_object(g, slotRawObject(r), image); return errNone; } QC_LANG_PRIMITIVE( QImage_NewURL, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { // FIXME: // We can not run an event loop while waiting to receive data, because that // would allow GUI to try and call into the language, resulting in a deadlock. qcErrorMsg("QImage: loading from URL not yet implemented."); return errFailed; #if 0 QString url_str = QtCollider::get(a); QUrl url(url_str); if( !url.isValid() || url.isEmpty() ) { qcErrorMsg( QStringLiteral("QImage: invalid or empty URL: ") + url_str ); return errFailed; } if( QURL_IS_LOCAL_FILE(url) ) { if( QImage_InitPath( g, slotRawObject(r), url.toLocalFile() ) ) { return errNone; } else { qcErrorMsg( QStringLiteral("QImage: file doesn't exist or can't be opened: ") + url_str ); return errFailed; } } if( !IsFloat(a+1) && !IsInt(a+1) ) return errWrongType; // Take a safe read to allow Integers: float timeout = QtCollider::get(a+1); QNetworkAccessManager manager; QScopedPointer reply( manager.get( QNetworkRequest(url) ) ); QEventLoop loop; QcApplication::connect( &manager, SIGNAL(finished(QNetworkReply*)), &loop, SLOT(quit()) ); QcApplication::connect( reply.data(), SIGNAL(error(QNetworkReply::NetworkError)), &loop, SLOT(quit()) ); QTimer::singleShot( 100 * timeout, &loop, SLOT(quit()) ); loop.exec(); // blocks if( reply->error() != QNetworkReply::NoError ) { qcErrorMsg( QStringLiteral("QImage: error trying to download: ") + url_str ); return errFailed; } else if( !reply->isFinished() ) { qcErrorMsg( QStringLiteral("QImage: timeout while trying to download: ") + url_str ); reply->abort(); return errFailed; } QByteArray byteArray = reply->readAll(); if( byteArray.isEmpty() ) { qcErrorMsg( QStringLiteral("QImage: no data received: ") + url_str ); return errFailed; } if( QImage_InitFromData( g, slotRawObject(r), byteArray ) ) { return errNone; } else { qcErrorMsg( QStringLiteral("QImage: failed trying to open downloaded data: ") + url_str ); return errFailed; } #endif } QC_LANG_PRIMITIVE( QImage_NewEmpty, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotInt(a) || NotInt(a+1) ) return errWrongType; int width = QtCollider::read(a); int height = QtCollider::read(a+1); QImage qimage(width, height, QImage::Format_ARGB32_Premultiplied); qimage.fill( QColor(Qt::transparent).rgba() ); Image *image = new Image; image->setImage(qimage); initialize_image_object(g, slotRawObject(r), image); return errNone; } QC_LANG_PRIMITIVE( QImage_NewFromWindow, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QObjectProxy *proxy = QtCollider::get(a); if( !proxy ) return errWrongType; QWidget *widget = qobject_cast( proxy->object() ); if( !widget ) return errWrongType; QRect rect; if( IsObj(a+1) && slotRawObject(a+1)->classptr == SC_CLASS(Rect) ) rect = QtCollider::read(a+1); else if (NotNil(a+1)) return errWrongType; QPixmap pixmap = QPixmap::grabWidget( widget, rect ); if (pixmap.isNull()) return errFailed; Image *image = new Image; image->setPixmap(pixmap); initialize_image_object(g, slotRawObject(r), image); return errNone; } QC_LANG_PRIMITIVE( QImage_Free, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); Image *image = to_image(r); if (image->isPainting()) { qcErrorMsg("QImage: can not free while being painted."); return errFailed; } image->clear(); return errNone; } QC_LANG_PRIMITIVE( QImage_HasSmoothTransformation, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); Image *image = to_image(r); QC::write( r, image->transformationMode == Qt::SmoothTransformation ); return errNone; } QC_LANG_PRIMITIVE( QImage_SetSmoothTransformation, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); bool smooth = QC::get(a); Image *image = to_image(r); image->transformationMode = smooth ? Qt::SmoothTransformation : Qt::FastTransformation; return errNone; } QC_LANG_PRIMITIVE( QImage_Width, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); Image *image = to_image(r); SetInt( r, image->width() ); return errNone; } QC_LANG_PRIMITIVE( QImage_Height, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); Image *image = to_image(r); SetInt( r, image->height() ); return errNone; } QC_LANG_PRIMITIVE( QImage_SetSize, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotInt(a) || NotInt(a+1) || NotInt(a+2) ) return errWrongType; QSize new_size( QtCollider::read(a), QtCollider::read(a+1) ); int resize_mode = QtCollider::read(a+2); Image *image = to_image(r); if (image->isPainting()) { qcErrorMsg("QImage: can not resize while being painted."); return errFailed; } image->resize( new_size, resize_mode ); return errNone; } QC_LANG_PRIMITIVE( QImage_Write, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QString path = QC::get(a); QString format = QC::get(a+1); if(NotInt(a+2)) return errWrongType; int quality = QC::read(a+2); QImage & image = to_image(r)->image(); if( image.save(path, format.toUpper().toStdString().c_str(), quality) ) return errNone; qcErrorMsg( QStringLiteral("QImage: Failed to write to file: ") + path ); return errFailed; } QC_LANG_PRIMITIVE( QImage_SetPainter, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( QtCollider::paintingAnnounced() ) { qcDebugMsg(1, "WARNING: Custom painting already in progress. Will not paint." ); return errFailed; } Image *image = to_image(r); assert( !image->isPainting() ); assert( imgPainter == 0 ); imgPainter = new QPainter( &image->image() ); QtCollider::announcePainting(); QtCollider::beginPainting( imgPainter ); image->setPainting(true); return errNone; } QC_LANG_PRIMITIVE( QImage_UnsetPainter, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); Image *image = to_image(r); assert( image->isPainting() ); image->setPainting(false); assert( imgPainter != 0 ); QtCollider::endPainting(); delete imgPainter; imgPainter = 0; return errNone; } QC_LANG_PRIMITIVE( QImage_GetPixel, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotInt(a) || NotInt(a+1)) return errWrongType; int x = QC::read(a); int y = QC::read(a+1); QImage & image = to_image(r)->image(); if( x >= image.width() || y >= image.height() ) return errIndexOutOfRange; int *line = reinterpret_cast( image.scanLine(y) ); SetInt( r, line[x] ); return errNone; } QC_LANG_PRIMITIVE( QImage_GetColor, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotInt(a) || NotInt(a+1)) return errWrongType; int x = QC::read(a); int y = QC::read(a+1); QImage & image = to_image(r)->image(); if( x >= image.width() || y >= image.height() ) return errIndexOutOfRange; QRgb *line = reinterpret_cast( image.scanLine(y) ); QC::set(r, pixel_to_color(line[x]) ); return errNone; } QC_LANG_PRIMITIVE( QImage_SetPixel, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotInt(a) || NotInt(a+1) || NotInt(a+2) ) return errWrongType; int pixel = QC::read(a); int x = QC::read(a+1); int y = QC::read(a+2); QImage & image = to_image(r)->image(); if( x >= image.width() || y >= image.height() ) return errIndexOutOfRange; int *line = reinterpret_cast( image.scanLine(y) ); line[x] = pixel; return errNone; } QC_LANG_PRIMITIVE( QImage_SetColor, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if ( NotObj(a) || slotRawObject(a)->classptr != SC_CLASS(Color) || NotInt(a+1) || NotInt(a+2) ) return errWrongType; QColor color( QC::read(a) ); int x = QC::read(a+1); int y = QC::read(a+2); QImage & image = to_image(r)->image(); if( x >= image.width() || y >= image.height() ) return errIndexOutOfRange; QRgb *line = reinterpret_cast( image.scanLine(y) ); line[x] = color_to_pixel(color); return errNone; } QC_LANG_PRIMITIVE( QImage_TransferPixels, 4, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if (!isKindOfSlot(a, class_int32array)) { qcErrorMsg("QImage: array argument is not a Int32Array"); return errWrongType; } if( NotInt(a+2) ) return errWrongType; int start = QC::read(a+2); if( !(IsTrue(a+3) || IsFalse(a+3)) ) return errWrongType; bool store = IsTrue(a+3); // t/f g/s QImage &image = to_image(r)->image(); QRect rect; if( IsNil(a+1) ) { rect = image.rect(); } else { if (!isKindOfSlot(a+1, SC_CLASS(Rect))) return errWrongType; rect = QC::read(a+1); if (rect.isEmpty()) return errNone; if( !image.rect().contains(rect) ) { qcErrorMsg("QImage: source rectangle out of image bounds"); return errFailed; } } PyrInt32Array* array = reinterpret_cast( slotRawObject(a) ); QRgb *pixelData = reinterpret_cast( array->i ) + start; int width = rect.width(); int height = rect.height(); int size = width * height; int x = rect.x(); int y = rect.y(); int max_x = width + x; int max_y = height + y; if( array->size - start < size ) return errIndexOutOfRange; if(store) { for( int iy = y; iy < max_y; ++iy ) { QRgb *line = reinterpret_cast( image.scanLine(iy) ); for( int ix = x; ix < max_x; ++ix ) { line[ix] = *pixelData; ++pixelData; } } } else { for( int iy = y; iy < max_y; ++iy ) { QRgb *line = reinterpret_cast( image.scanLine(iy) ); for( int ix = x; ix < max_x; ++ix ) { *pixelData = line[ix]; ++pixelData; } } } return errNone; } QC_LANG_PRIMITIVE( QImage_Fill, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotObj(a) || slotRawObject(a)->classptr != SC_CLASS(Color) ) return errWrongType; QColor color = QC::read(a); QImage &image = to_image(r)->image(); image.fill( color_to_pixel(color) ); return errNone; } QC_LANG_PRIMITIVE( QImage_Formats, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); if( NotInt(a) ) return errWrongType; int rw = QC::read(a); QList formats = rw ? QImageWriter::supportedImageFormats() : QImageReader::supportedImageFormats(); PyrObject *array = newPyrArray( g->gc, formats.size(), 0, true ); SetObject(r, array); for( int i = 0; i < formats.size(); ++i ) { PyrString *str = newPyrString( g->gc, formats[i].constData(), obj_immutable, false ); SetObject(array->slots+i, str); ++array->size; g->gc->GCWriteNew( array, str ); // we know str is white so we can use GCWriteNew } return errNone; } QC_LANG_PRIMITIVE( QImage_PixelToColor, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotInt(a) ) return errWrongType; QRgb pixel = static_cast( QC::read(a) ); QC::set( r, pixel_to_color(pixel) ); return errNone; } QC_LANG_PRIMITIVE( QImage_ColorToPixel, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if ( NotObj(a) || slotRawObject(a)->classptr != SC_CLASS(Color) ) return errWrongType; QColor color = QC::read(a); int pixel = static_cast( color_to_pixel(color) ); QC::set( r, pixel ); return errNone; } void defineQImagePrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/prim_QObject.cpp000644 000765 000024 00000043743 12756531745 025226 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "primitives.h" #include "../QObjectProxy.h" #include "../QcObjectFactory.h" #include "../QcApplication.h" #include "../Common.h" #include "../type_codec.hpp" #include "../metatype.hpp" #include "../painting.h" #include #include #include #include #include #include #include #ifdef _WIN32 # include "SC_Win32Utils.h" #else # include #endif #define IS_OBJECT_NIL( a ) \ IsNil( slotRawObject(a)->slots ) #define QOBJECT_FROM_SLOT( s ) \ ((QObjectProxy*) slotRawPtr( slotRawObject( s )->slots )) #define CLASS_NAME( slot ) \ slotRawSymbol( &slotRawObject( slot )->classptr->name )->name namespace QtCollider { int QObject_Finalize( struct VMGlobals *, struct PyrObject * ); QC_LANG_PRIMITIVE( QObject_New, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if(NotSym(a+0)) return errWrongType; PyrObject *scObject = slotRawObject( r ); QString qtClassName = QString(slotRawSymbol(a+0)->name); qcSCObjectDebugMsg( 1, scObject, QStringLiteral("CREATE: %2").arg(qtClassName) ); if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); QcAbstractFactory *f = QtCollider::factories().value( qtClassName ); if( !f ) { qcErrorMsg( QStringLiteral("Factory for class '%1' not found!").arg(qtClassName) ); return errFailed; } QObjectProxy *proxy = 0; MetaValue args[10]; PyrSlot *argSlot = a+1; int argc; if( isKindOfSlot( argSlot, class_array ) ) { PyrObject *array = slotRawObject( argSlot ); argSlot = array->slots; argc = array->size; } else { argc = 1; } for( int i = 0; isize() ); Q_ASSERT(mem); args[i].read( mem, type, slot ); } } proxy = f->newInstance( scObject, args ); if( !proxy ) return errFailed; SetPtr( scObject->slots, proxy ); InstallFinalizer( g, scObject, 1, QObject_Finalize ); return errNone; } QC_LANG_PRIMITIVE( QObject_Destroy, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { qcSCObjectDebugMsg( 1, slotRawObject(r), "DESTROY" ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); // Post the destruction event asynchronously; DestroyEvent *e = new DestroyEvent( QObjectProxy::DestroyObject ); QApplication::postEvent( proxy, e ); return errNone; } int QObject_Finalize( struct VMGlobals *, struct PyrObject *obj ) { qcSCObjectDebugMsg( 1, obj, "FINALIZE" ); QObjectProxy *proxy = (QObjectProxy*) slotRawPtr( obj->slots ); // Invalidate proxy's SC object pointer directly. // Note that it is protected by language mutex; proxy->finalize(); // Post the destruction event asynchronously; DestroyEvent *e = new DestroyEvent( QObjectProxy::DestroyProxyAndObject ); QApplication::postEvent( proxy, e ); return errNone; } QC_LANG_PRIMITIVE( QObject_SetParent, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); QObjectProxy *parent = QtCollider::get( a ); if( !parent ) return errWrongType; qcSCObjectDebugMsg( 1, slotRawObject(r), "SET PARENT" ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->setParent( parent ); return ok ? errNone : errFailed; } static void qcGetProperties( const QMetaObject *mo, PyrSlot *r, VMGlobals *g ) { int count = mo->propertyCount(); PyrObject *array = newPyrArray( g->gc, count, 0, true ); SetObject( r, array ); PyrSlot *s = array->slots; for( int i = 0; i < count; ++i, ++s ) { SetSymbol( s, getsym( mo->property(i).name() ) ); array->size++; } } static void qcGetMethods ( const QMetaObject *mo, bool getPlain, bool getSignals, bool getSlots, PyrSlot *r, VMGlobals *g ) { int count = mo->methodCount(); PyrObject *array = newPyrArray( g->gc, count, 0, true ); SetObject( r, array ); PyrSlot *s = array->slots; for( int i = 0; i < count; ++i ) { QMetaMethod method = mo->method(i); switch( method.methodType() ) { case QMetaMethod::Method: if( !getPlain || (method.access() != QMetaMethod::Public) ) continue; break; case QMetaMethod::Signal: if( !getSignals ) continue; break; case QMetaMethod::Slot: if( !getSlots || (method.access() != QMetaMethod::Public) ) continue; break; default: continue; } QtCollider::set( s, QString::fromLatin1( method.methodSignature() ) ); array->size++; g->gc->GCWrite( array, s ); ++s; } } QC_LANG_PRIMITIVE( QMetaObject_Properties, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); PyrSlot *sClassName = slotRawObject(r)->slots+0; if(NotSym(sClassName)) return errWrongType; QString className( slotRawSymbol(sClassName)->name ); QcAbstractFactory *f = QtCollider::factories().value( className ); if( !f ) { qcErrorMsg( QStringLiteral("Factory for class '%1' not found!").arg(className) ); return errFailed; } const QMetaObject *mo = f->metaObject(); qcGetProperties( mo, r, g ); return errNone; } QC_LANG_PRIMITIVE( QMetaObject_Methods, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !QcApplication::compareThread() ) return QtCollider::wrongThreadError(); PyrSlot *sClassName = slotRawObject(r)->slots+0; if(NotSym(sClassName)) return errWrongType; QString className( slotRawSymbol(sClassName)->name ); QcAbstractFactory *f = QtCollider::factories().value( className ); if( !f ) { qcErrorMsg( QStringLiteral("Factory for class '%1' not found!").arg(className) ); return errFailed; } bool getPlain = IsTrue(a+0); bool getSignals = IsTrue(a+1); bool getSlots = IsTrue(a+2); const QMetaObject *mo = f->metaObject(); qcGetMethods( mo, getPlain, getSignals, getSlots, r, g ); return errNone; } QC_LANG_PRIMITIVE( QObject_GetProperties, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QObject *obj = proxy->object(); if( !obj ) { SetNil(r); return errNone; } const QMetaObject *mo = obj->metaObject(); qcGetProperties( mo, r, g ); return errNone; } QC_LANG_PRIMITIVE( QObject_GetMethods, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QObject *obj = proxy->object(); if( !obj ) { SetNil(r); return errNone; } bool getPlain = IsTrue(a+0); bool getSignals = IsTrue(a+1); bool getSlots = IsTrue(a+2); const QMetaObject *mo = obj->metaObject(); qcGetMethods( mo, getPlain, getSignals, getSlots, r, g ); return errNone; } QC_LANG_PRIMITIVE( QObject_SetProperty, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( NotSym( a ) ) return errWrongType; PyrSymbol *property = slotRawSymbol( a ); bool sync = IsTrue( a+2 ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("SET: %1").arg(property->name) ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QVariant val = QtCollider::get( a+1 ); if( sync && !QtCollider::isPaintingObject(proxy) ) { proxy->setProperty( property->name, val ); } else { SetPropertyEvent *e = new SetPropertyEvent(); e->property = property; e->value = val; QApplication::postEvent( proxy, e ); } return errNone; } QC_LANG_PRIMITIVE( QObject_GetProperty, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( NotSym(a) ) return errWrongType; PyrSymbol *symProp = slotRawSymbol( a ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("GET: %1").arg(symProp->name) ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QVariant val = proxy->property( symProp->name ); if( !val.isValid() ) { qcDebugMsg(1, QStringLiteral("WARNING: Invalid property '%1'").arg(symProp->name)); SetNil(r); return errNone; } if( QtCollider::set(r, val) ) return errNone; else return errFailed; } QC_LANG_PRIMITIVE( QObject_SetEventHandler, 4, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( NotInt( a+0 ) || NotSym( a+1 ) ) return errWrongType; int eventType = QtCollider::get( a+0 ); PyrSymbol *method = 0; slotSymbolVal( a+1, &method ); Synchronicity sync = IsTrue( a+2 ) ? Synchronous : Asynchronous; bool enabled = IsTrue( a+3 ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("SET EVENT HANDLER: type %1 -> %2 [%3, %4]") .arg(eventType).arg(method->name) .arg(sync == Synchronous ? "SYNC" : "ASYNC") .arg(enabled ? "on" : "off") ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->setEventHandler( eventType, method, sync, enabled ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_SetEventHandlerEnabled, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotInt( a+0 ) ) return errWrongType; bool enabled = IsTrue( a+1 ); if( !enabled && !IsFalse( a+1 ) ) return errWrongType; int type = QtCollider::get( a+0 ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("SET EVENT HANDLER STATE: type %1 = %2") .arg(type).arg(enabled ? "on" : "off") ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->setEventHandlerEnabled( type, enabled ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_ConnectMethod, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym(a+0) || NotSym( a+1 ) ) return errWrongType; PyrSymbol *signal = slotRawSymbol(a+0); PyrSymbol *handler = slotRawSymbol(a+1); Qt::ConnectionType ctype = IsTrue( a+2 ) ? Qt::DirectConnection : Qt::QueuedConnection; qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("CONNECT METHOD: %1 -> %2 [%3]").arg(signal->name).arg(handler->name) .arg( IsTrue(a+2) ? "SYNC" : "ASYNC") ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->connectMethod( signal->name, handler, ctype ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_DisconnectMethod, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym(a+0) || NotSym( a+1 ) ) return errWrongType; PyrSymbol *signal = slotRawSymbol(a+0); PyrSymbol *handler = slotRawSymbol(a+1); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("DISCONNECT METHOD: %1 -> %2").arg(signal->name).arg(handler->name) ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->disconnectMethod( signal->name, handler ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_ConnectObject, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym(a+0) || NotObj( a+1 ) ) return errWrongType; PyrSymbol *signal = slotRawSymbol(a+0); PyrObject *handlerObj = slotRawObject( a+1 ); Qt::ConnectionType ctype = IsTrue( a+2 ) ? Qt::DirectConnection : Qt::QueuedConnection; qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("CONNECT OBJECT: %1 -> %2 [%3]") .arg( signal->name ) .arg( slotRawSymbol( &handlerObj->classptr->name )->name ) .arg( IsTrue(a+2) ? "SYNC" : "ASYNC") ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->connectObject( signal->name, handlerObj, ctype ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_DisconnectObject, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym(a+0) || NotObj( a+1 ) ) return errWrongType; PyrSymbol *signal = slotRawSymbol(a+0); PyrObject *handlerObj = slotRawObject( a+1 ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("DISCONNECT OBJECT: %1").arg(signal->name) ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); bool ok = proxy->disconnectObject( signal->name, handlerObj ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_ConnectSlot, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { // Args: signal, receiver, slot if( !isKindOfSlot( a+1, SC_CLASS(QObject) ) || NotSym( a+0 ) || NotSym( a+2 ) ) return errWrongType; PyrSymbol *symSig = slotRawSymbol( a+0 ); PyrSymbol *symSlot = slotRawSymbol( a+2 ); QObjectProxy *sndProxy = QOBJECT_FROM_SLOT( r ); QObjectProxy *rcvProxy = QOBJECT_FROM_SLOT( a+1 ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("CONNECT TO SLOT: %1 -> %2").arg(symSig->name).arg(symSlot->name) ); QString strSig = QStringLiteral("2") + symSig->name; QString strSlot = QStringLiteral("1") + symSlot->name; sndProxy->lock(); rcvProxy->lock(); bool ok; if( !sndProxy->object() || !rcvProxy->object() ) { ok = true; } else { ok = QObject::connect( sndProxy->object(), strSig.toStdString().c_str(), rcvProxy->object(), strSlot.toStdString().c_str() ); } sndProxy->unlock(); rcvProxy->unlock(); if (!ok) { qcErrorMsg( QStringLiteral("Failed to connect %1::%2 to %3::%4!\n") .arg(sndProxy->scClassName()).arg(symSig->name) .arg(rcvProxy->scClassName()).arg(symSlot->name) ); return errFailed; } return errNone; } QC_LANG_PRIMITIVE( QObject_InvokeMethod, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym( a+0 ) ) return errWrongType; PyrSymbol *method = slotRawSymbol( a+0 ); PyrSlot *methodArgs = a+1; bool sync = !IsFalse( a+2 ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("INVOKE: '%1' [%2]").arg(method->name).arg(sync ? "SYNC" : "ASYNC") ); QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); PyrSlot *retSlot; Qt::ConnectionType cType; if( sync ) { if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); retSlot = r; cType = Qt::DirectConnection; } else { retSlot = 0; cType = Qt::QueuedConnection; } bool ok = proxy->invokeMethod( method->name, retSlot, methodArgs, cType ); return ok ? errNone : errFailed; } QC_LANG_PRIMITIVE( QObject_IsValid, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); bool needLock = !proxy->compareThread(); if (needLock) proxy->lock(); bool hasObject = proxy->object() != 0; if (needLock) proxy->unlock(); SetBool( r, hasObject ); return errNone; } QC_LANG_PRIMITIVE( QObject_GetChildren, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym(a) && NotNil(a) ) return errWrongType; QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); PyrSymbol *className = IsSym( a ) ? slotRawSymbol( a ) : 0; qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("GET CHILDREN: of class '%1'") .arg( className ? className->name : "QObject" ) ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QList children = proxy->children( className ); int count = children.count(); PyrObject *array = newPyrArray( g->gc, count, 0, true ); SetObject( r, array ); PyrSlot *s = array->slots; Q_FOREACH( PyrObject *obj, children ) { SetObject( s, obj ); ++array->size; g->gc->GCWrite( array, s ); ++s; } return errNone; } QC_LANG_PRIMITIVE( QObject_GetParent, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotSym(a) && NotNil(a) ) return errWrongType; QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); PyrSymbol *className = IsSym( a ) ? slotRawSymbol( a ) : 0; qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("GET PARENT") ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); PyrObject *parent = proxy->parent( className ); if( parent ) SetObject( r, parent ); else SetNil( r ); return errNone; } void defineQObjectPrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/prim_QPalette.cpp000644 000765 000024 00000007306 12321461510 025365 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "prim_QPalette.hpp" #include "primitives.h" #include "../Common.h" #include "../type_codec.hpp" #include #include #include namespace QtCollider { int QPalette_Finalize( struct VMGlobals *g, struct PyrObject *obj ) { delete QPALETTE_FROM_OBJECT(obj); return errNone; } void QPalette_Init( struct VMGlobals *g, struct PyrObject *obj, const QPalette & palette ) { assert( obj->classptr == SC_CLASS(QPalette) ); assert( IsNil(obj->slots) && IsNil(obj->slots+1) ); QPalette *p = new QPalette(palette); SetPtr( obj->slots, p ); InstallFinalizer( g, obj, 1, QPalette_Finalize ); } QC_LANG_PRIMITIVE( QPalette_New, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPalette_Init( g, slotRawObject(r) ); return errNone; } QC_LANG_PRIMITIVE( QPalette_Auto, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QColor button = QtCollider::get(a); QColor window = QtCollider::get(a+1); QPalette_Init( g, slotRawObject(r), QPalette(button, window) ); return errNone; } QC_LANG_PRIMITIVE( QPalette_System, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPalette_Init( g, slotRawObject(r), QtCollider::systemPalette() ); return errNone; } QC_LANG_PRIMITIVE( QPalette_Color, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPalette *p = QPALETTE_FROM_OBJECT(slotRawObject(r)); if(NotInt(a)) return errWrongType; QPalette::ColorRole role = (QPalette::ColorRole)(slotRawInt(a)); if( IsInt(a+1) ) { QPalette::ColorGroup group = (QPalette::ColorGroup)(slotRawInt(a+1)); QtCollider::set( r, p->color( group, role ) ); } else { QtCollider::set( r, p->color( role ) ); } return errNone; } QC_LANG_PRIMITIVE( QPalette_SetColor, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPalette *p = QPALETTE_FROM_OBJECT(slotRawObject(r)); QColor color = QtCollider::get(a); if(NotInt(a+1)) return errWrongType; QPalette::ColorRole role = (QPalette::ColorRole)(slotRawInt(a+1)); if( IsInt(a+2) ) { QPalette::ColorGroup group = (QPalette::ColorGroup)(slotRawInt(a+2)); p->setColor( group, role, color ); } else { p->setColor( role, color ); } return errNone; } QC_LANG_PRIMITIVE( QPalette_HasColor, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPalette *p = QPALETTE_FROM_OBJECT(slotRawObject(r)); if(NotInt(a)) return errWrongType; QPalette::ColorRole role = (QPalette::ColorRole)(slotRawInt(a)); QPalette::ColorGroup group; group = IsInt(a+1) ? (QPalette::ColorGroup)(slotRawInt(a+1)) : QPalette::Normal; SetBool( r, p->isBrushSet( group, role ) ); return errNone; } void defineQPalettePrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/prim_QPalette.hpp000644 000765 000024 00000002326 12321461510 025367 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_PRIM_QPALETTE_HPP #define QC_PRIM_QPALETTE_HPP #include struct PyrObject; struct VMGlobals; #define QPALETTE_FROM_OBJECT( OBJ ) reinterpret_cast( slotRawPtr(OBJ->slots) ); namespace QtCollider { void QPalette_Init( struct VMGlobals *g, struct PyrObject *obj, const QPalette & palette = QPalette() ); } #endif SuperCollider-Source/QtCollider/primitives/prim_QPen.cpp000644 000765 000024 00000052053 12756531745 024534 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2013 Jakob Leben (jakob.leben@gmail.com) * Copyright 2010 Ivan Leben (ivan.leben@gmail.com) (QPen_ArcTo) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "primitives.h" #include "../painting.h" #include "../image.h" #include "../type_codec.hpp" #include "PyrKernel.h" #include #include #include #include static bool announced = false; static QObject *paintingObject = NULL; static QPainter *painter = 0; static QPainterPath path; namespace QtCollider { void announcePainting() { announced = true; } bool paintingAnnounced() { return announced; } bool isPaintingObject(QObject* obj) { return obj == paintingObject; } bool beginPainting( QPainter *p, QObject* obj ) { if( painter ) { qcErrorMsg( QStringLiteral("Painting already in progress!") ); return false; } painter = p; paintingObject = obj; painter->setRenderHint( QPainter::Antialiasing, true ); QColor black( 0,0,0 ); QPen pen( black ); pen.setCapStyle( Qt::FlatCap ); painter->setPen( pen ); painter->setBrush( black ); path = QPainterPath(); return true; } void endPainting() { painter = 0; announced = false; paintingObject = NULL; } QPainter *globalPainter() { return painter; } } typedef QVector2D vec2; typedef QVector3D vec3; static const double PI = 3.14159265358979323846264338327950288419717; inline static qreal globalAngle( const vec2 &v ) { //assuming v is normalized qreal cosa = v.x(); qreal sina = -v.y(); return sina >= 0.0 ? acosf(cosa) : 2.0*PI - acosf(cosa); } inline static qreal vectorAngle( const vec2 &v1, const vec2 &v2 ) { //assuming v1,v2 are normalized return acosf( vec2::dotProduct( v1, v2 ) ); } inline static qreal signedAngle( const vec2 &v1, const vec2 &v2 ) { //assuming v1,v2 are normalized qreal a = vectorAngle( v1, v2 ); vec3 c = vec3::crossProduct( vec3(v1), vec3(v2) ); return c.z() > 0.0 ? a : -a; } inline static qreal radToDeg( qreal rad ) { return rad * 180.0 / PI; } inline static bool isPenValid() { if( !painter ) { qcErrorMsg( QStringLiteral("Usage of QPen is not allowed at this point!") ); return false; } return true; } #define QC_QPEN_PRIMITIVE( NAME, ARGC, RECEIVER, ARGS, GLOBAL ) \ struct NAME {}; \ template<> struct LangPrimitive { \ static int implementation ( RECEIVER, ARGS, GLOBAL ); \ static int mediate( VMGlobals *g, int i ) { \ if(!isPenValid()) return errFailed; \ PyrSlot *stack = g->sp - i + 1; \ return implementation( stack, i > 1 ? stack+1 : 0, g ); \ } \ static void define( int base, int index ) { \ definePrimitive( base, index, "_" #NAME, &mediate, ARGC + 1, 0 ); \ } \ }; \ int LangPrimitive::implementation( RECEIVER, ARGS, GLOBAL ) namespace QtCollider { QC_QPEN_PRIMITIVE( QPen_Save, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { painter->save(); return errNone; } QC_QPEN_PRIMITIVE( QPen_Restore, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { painter->restore(); return errNone; } QC_QPEN_PRIMITIVE( QPen_Clear, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { path = QPainterPath(); return errNone; } QC_QPEN_PRIMITIVE( QPen_FillColor, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QColor color = QtCollider::get( a ); painter->setBrush( color ); return errNone; } QC_QPEN_PRIMITIVE( QPen_StrokeColor, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QColor color = QtCollider::get( a ); QPen pen = painter->pen(); pen.setColor( color ); painter->setPen( pen ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Width, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float width; if( slotFloatVal( a, &width ) ) return errWrongType; QPen pen = painter->pen(); pen.setWidthF( width ); painter->setPen( pen ); return errNone; } QC_QPEN_PRIMITIVE( QPen_SetJoinStyle, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { int style = QtCollider::get(a); QPen pen = painter->pen(); switch( style ) { case 0: pen.setJoinStyle( Qt::MiterJoin ); break; case 1: pen.setJoinStyle( Qt::RoundJoin ); break; case 2: pen.setJoinStyle( Qt::BevelJoin ); break; default: return errFailed; } painter->setPen( pen ); return errNone; } QC_QPEN_PRIMITIVE( QPen_SetCapStyle, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { int style = QtCollider::get(a); QPen pen = painter->pen(); switch( style ) { case 0: pen.setCapStyle( Qt::FlatCap ); break; case 1: pen.setCapStyle( Qt::RoundCap ); break; case 2: pen.setCapStyle( Qt::SquareCap ); break; default: return errFailed; } painter->setPen( pen ); return errNone; } QC_QPEN_PRIMITIVE( QPen_SetDashPattern, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !IsObj( a ) ) return errWrongType; PyrObject *obj = slotRawObject( a ); if( obj->classptr != class_floatarray ) return errWrongType; PyrFloatArray *farray = reinterpret_cast(obj); int s = farray->size; float *f = farray->f; QVector pattern; int i = 1; while( ipen(); pen.setDashPattern( pattern ); painter->setPen( pen ); } return errNone; } QC_QPEN_PRIMITIVE( QPen_SetOpacity, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float opacity = QtCollider::get(a); painter->setOpacity( opacity ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Clip, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { painter->setClipPath( path ); path = QPainterPath(); return errNone; } QC_QPEN_PRIMITIVE( QPen_AntiAliasing, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { bool b = IsTrue( a ); if( !b && !IsFalse( a ) ) return errWrongType; painter->setRenderHint( QPainter::Antialiasing, b ); return errNone; } QC_QPEN_PRIMITIVE( QPen_SetFont, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { painter->setFont( QtCollider::get( a ) ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Translate, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float x, y; if( slotFloatVal( a, &x ) ) return errWrongType; if( slotFloatVal( a+1, &y ) ) return errWrongType; painter->translate( x, y ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Scale, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float x, y; if( slotFloatVal( a, &x ) ) return errWrongType; if( slotFloatVal( a+1, &y ) ) return errWrongType; painter->scale( x, y ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Shear, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float x, y; if( slotFloatVal( a, &x ) ) return errWrongType; if( slotFloatVal( a+1, &y ) ) return errWrongType; painter->shear( x, y ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Rotate, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float angle, x, y; if( slotFloatVal( a, &angle ) ) return errWrongType; if( slotFloatVal( a+1, &x ) ) return errWrongType; if( slotFloatVal( a+2, &y ) ) return errWrongType; painter->translate( x, y ); painter->rotate( angle ); painter->translate( -x, -y ); return errNone; } QC_QPEN_PRIMITIVE( QPen_SetTransform, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QVariantList list = QtCollider::get( a ); if( list.count() < 6 ) return errWrongType; float f[6]; int i = 6; while( i ) { --i; const QVariant & var = list[i]; if( !var.canConvert( QVariant::Double ) ) return errWrongType; f[i] = var.value(); } QTransform transform( f[0], f[1], f[2], f[3], f[4], f[5] ); painter->setWorldTransform( transform, true ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Transform, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { const QTransform & transform = painter->worldTransform(); PyrDoubleArray *doubleArray = newPyrDoubleArray( g->gc, 6, 0, true ); SetObject( r, doubleArray ); double *val = doubleArray->d; val[0] = transform.m11(); val[1] = transform.m12(); val[2] = transform.m21(); val[3] = transform.m22(); val[4] = transform.dx(); val[5] = transform.dy(); doubleArray->size = 6; return errNone; } QC_QPEN_PRIMITIVE( QPen_MoveTo, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF point = QtCollider::get( a ); path.moveTo( point ); return errNone; } QC_QPEN_PRIMITIVE( QPen_LineTo, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF point = QtCollider::get( a ); path.lineTo( point ); return errNone; } QC_QPEN_PRIMITIVE( QPen_CubicTo, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF endPoint = QtCollider::get( a ); QPointF cPoint1 = QtCollider::get( a+1 ); QPointF cPoint2 = QtCollider::get( a+2 ); path.cubicTo( cPoint1, cPoint2, endPoint ); return errNone; } QC_QPEN_PRIMITIVE( QPen_QuadTo, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF endPoint = QtCollider::get( a ); QPointF cPoint = QtCollider::get( a+1 ); path.quadTo( cPoint, endPoint ); return errNone; } QC_QPEN_PRIMITIVE( QPen_ArcTo, 3, PyrSlot *r, PyrSlot *arg, VMGlobals *g ) { QPointF pt1 = QtCollider::get( arg ); QPointF pt2 = QtCollider::get( arg+1 ); float radius; if( slotFloatVal( arg+2, &radius ) ) return errWrongType; radius = qMax( 0.f, radius ); vec2 a( path.currentPosition() ); vec2 b( pt1 ); vec2 c( pt2 ); vec2 va = (a - b).normalized(); vec2 vc = (c - b).normalized(); vec2 m = (va + vc).normalized(); qreal lineAngle = vectorAngle( va, vc ); qreal dm = radius / sinf( lineAngle * 0.5f ); qreal dv = radius / tanf( lineAngle * 0.5f ); vec2 center = b + dm * m; vec2 start = b + dv * va; vec2 end = b + dv * vc; vec2 vs = (start - center).normalized(); vec2 ve = (end - center).normalized(); qreal arcAngle = signedAngle( ve, vs ); qreal arcStart = globalAngle( vs ); path.lineTo( start.x(), start.y() ); path.arcTo( center.x() - radius, center.y() - radius, 2*radius, 2*radius, radToDeg( arcStart ), radToDeg( arcAngle ) ); // The current SC API does not want to pull the line to the last point. // Personally, I think it would be better: // path.lineTo( pt2 ); return errNone; } QC_QPEN_PRIMITIVE( QPen_AddRect, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QRectF rect = QtCollider::get( a ); path.addRect( rect ); return errNone; } QC_QPEN_PRIMITIVE( QPen_AddRoundedRect, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { float radiusX, radiusY; QRectF rect; rect = QtCollider::get( a ); if( slotFloatVal( a+1, &radiusX ) ) return errWrongType; if( slotFloatVal( a+2, &radiusY ) ) return errWrongType; path.addRoundedRect( rect, radiusX, radiusY ); return errNone; } QC_QPEN_PRIMITIVE( QPen_AddEllipse, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QRectF rect = QtCollider::get( a ); path.addEllipse( rect ); return errNone; } QC_QPEN_PRIMITIVE( QPen_AddArc, 4, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF center = QtCollider::get( a ); float radius, startAngle, arcAngle; if( slotFloatVal( a+1, &radius ) ) return errWrongType; if( slotFloatVal( a+2, &startAngle ) ) return errWrongType; if( slotFloatVal( a+3, &arcAngle ) ) return errWrongType; // have to swap angle direction for sinf() QPointF start( radius * cosf( startAngle ), -radius * sinf( startAngle ) ); start += center; QRectF rect; rect.setSize( QSizeF( 2*radius, 2*radius ) ); rect.moveCenter( center ); path.moveTo( start ); path.arcTo( rect, radToDeg( startAngle ), radToDeg( arcAngle ) ); return errNone; } QC_QPEN_PRIMITIVE( QPen_AddWedge, 4, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF center = QtCollider::get( a ); float radius, startAngle, sweepLength; if( slotFloatVal( a+1, &radius ) ) return errWrongType; if( slotFloatVal( a+2, &startAngle ) ) return errWrongType; if( slotFloatVal( a+3, &sweepLength ) ) return errWrongType; path.moveTo( center ); QRectF rect; rect.setSize( QSizeF( 2*radius, 2*radius ) ); rect.moveCenter( center ); path.arcTo( rect, startAngle, sweepLength ); path.closeSubpath(); return errNone; } QC_QPEN_PRIMITIVE( QPen_AddAnnularWedge, 5, PyrSlot *, PyrSlot *a, VMGlobals *g ) { QPointF c = QtCollider::get( a ); float innerRadius, outerRadius, startAngle, arcAngle; if( slotFloatVal( a+1, &innerRadius ) ) return errWrongType; if( slotFloatVal( a+2, &outerRadius ) ) return errWrongType; if( slotFloatVal( a+3, &startAngle ) ) return errWrongType; if( slotFloatVal( a+4, &arcAngle ) ) return errWrongType; float saDeg = radToDeg( startAngle ); float aaDeg = radToDeg( arcAngle ); QPointF start( outerRadius * cosf( startAngle ), -outerRadius * sinf( startAngle ) ); start += c; path.moveTo( start ); QPointF pt( innerRadius, innerRadius ); path.arcTo( QRectF( c - pt, c + pt ), saDeg, aaDeg ); pt = QPointF( outerRadius, outerRadius ); path.arcTo( QRectF( c - pt, c + pt ), saDeg + aaDeg, -aaDeg ); return errNone; } QC_QPEN_PRIMITIVE( QPen_Draw, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( path.isEmpty() ) return errNone; int style = QtCollider::get( a ); QPen pen = painter->pen(); QBrush brush = painter->brush(); switch ( style ) { case 0: case 1: painter->setPen( Qt::NoPen ); break; case 2: painter->setBrush( Qt::NoBrush ); break; case 3: case 4: default: ; } if ( style == 1 || style == 4 ) { path.setFillRule( Qt::OddEvenFill ); } else { path.setFillRule( Qt::WindingFill ); } painter->drawPath( path ); path = QPainterPath(); painter->setPen( pen ); painter->setBrush( brush ); return errNone; } QC_QPEN_PRIMITIVE( QPen_FillAxialGradient, 4, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF pt1 = QtCollider::get(a+0); QPointF pt2 = QtCollider::get(a+1); QColor c1 = QtCollider::get(a+2); QColor c2 = QtCollider::get(a+3); QLinearGradient grad( pt1, pt2 ); grad.setColorAt( 0, c1 ); grad.setColorAt( 1, c2 ); QPen pen = painter->pen(); QBrush brush = painter->brush(); painter->setPen( Qt::NoPen ); painter->setBrush( grad ); painter->drawPath( path ); painter->setPen( pen ); painter->setBrush( brush ); path = QPainterPath(); return errNone; } QC_QPEN_PRIMITIVE( QPen_FillRadialGradient, 6, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QPointF pt1 = QtCollider::get(a+0); QPointF pt2 = QtCollider::get(a+1); float r1 = QtCollider::get(a+2); float r2 = QtCollider::get(a+3); QColor c1 = QtCollider::get(a+4); QColor c2 = QtCollider::get(a+5); QRadialGradient grad( pt2, r2, pt1 ); grad.setColorAt( (r2 > 0 ? r1 / r2 : 0), c1 ); grad.setColorAt( 1, c2 ); QPen pen = painter->pen(); QBrush brush = painter->brush(); painter->setPen( Qt::NoPen ); painter->setBrush( grad ); painter->drawPath( path ); painter->setPen( pen ); painter->setBrush( brush ); path = QPainterPath(); return errNone; } QC_QPEN_PRIMITIVE( QPen_StringAtPoint, 4, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QString str = QtCollider::get( a ); if( str.isEmpty() ) return errNone; QPointF pt = QtCollider::get( a+1 ); painter->save(); if( NotNil( a+2 ) ) painter->setFont( QtCollider::get( a+2 ) ); QPen pen( painter->pen() ); pen.setColor( NotNil( a+3 ) ? QtCollider::get( a+3 ) : painter->brush().color() ); painter->setPen( pen ); QFont f( painter->font() ); QFontMetrics fm( f ); QRect rect = fm.boundingRect( str ); painter->drawText( pt - rect.topLeft(), str ); painter->restore(); return errNone; } QC_QPEN_PRIMITIVE( QPen_StringInRect, 5, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QString str = QtCollider::get( a ); if( str.isEmpty() ) return errNone; QRectF rect = QtCollider::get( a+1 ); painter->save(); if( NotNil( a+2 ) ) painter->setFont( QtCollider::get( a+2 ) ); QPen pen( painter->pen() ); pen.setColor( NotNil( a+3 ) ? QtCollider::get( a+3 ) : painter->brush().color() ); painter->setPen( pen ); Qt::Alignment align; if( NotNil(a+4) ) align = static_cast( QtCollider::get( a+4 ) ); else align = Qt::AlignTop | Qt::AlignLeft; painter->drawText( rect, align, str ); painter->restore(); return errNone; } QC_QPEN_PRIMITIVE( QPen_DrawImage, 5, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QtCollider::SharedImage image = QtCollider::get(a+1); if (!image) return errWrongType; if (image->isPainting()) { qcErrorMsg("QImage: can not draw while being painted."); return errFailed; } QPixmap & pixmap = image->pixmap(); QRectF source; if (IsNil(a+2)) source = QRectF( pixmap.rect() ); else if (isKindOfSlot(a+2, SC_CLASS(Rect))) source = QtCollider::read(a+2); else return errWrongType; QRectF target; if (isKindOfSlot(a+0, SC_CLASS(Point))) { QPointF point = QtCollider::read(a+0); target = QRectF(point.x(), point.y(), source.width(), source.height()); } else if (isKindOfSlot(a+0, SC_CLASS(Rect))) { target = QtCollider::read(a+0); } else return errWrongType; int composition = QtCollider::get(a+3); float opacity = QtCollider::get(a+4); painter->save(); painter->setCompositionMode((QPainter::CompositionMode)composition); painter->setRenderHint( QPainter::SmoothPixmapTransform, image->transformationMode == Qt::SmoothTransformation ); painter->setOpacity(opacity); painter->drawPixmap(target, pixmap, source); painter->restore(); return errNone; } QC_QPEN_PRIMITIVE( QPen_TileImage, 5, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QtCollider::SharedImage image = QtCollider::get(a+1); if (!image) return errWrongType; if (image->isPainting()) { qcErrorMsg("QImage: can not draw while being painted."); return errFailed; } QPixmap & pixmap = image->pixmap(); QRectF source; if (IsNil(a+2)) source = QRectF( pixmap.rect() ); else if (isKindOfSlot(a+2, SC_CLASS(Rect))) source = QtCollider::read(a+2); else return errWrongType; QRectF target; if (isKindOfSlot(a+0, SC_CLASS(Rect))) target = QtCollider::read(a+0); else return errWrongType; if (target.isEmpty() || source.isEmpty()) return errNone; int composition = QtCollider::get(a+3); float opacity = QtCollider::get(a+4); painter->save(); painter->setCompositionMode((QPainter::CompositionMode)composition); painter->setRenderHint( QPainter::SmoothPixmapTransform, image->transformationMode == Qt::SmoothTransformation ); painter->setOpacity(opacity); painter->setClipRect( target ); QRectF area = source; area.moveTo( target.topLeft() ); float max_x = target.right(); float max_y = target.bottom(); int iter_x, iter_y; for( iter_y = 0; ; ++iter_y ) { area.moveTop(iter_y * source.height() + target.top() ); if (area.top() > max_y) break; for ( iter_x = 0; ; ++iter_x ) { area.moveLeft( iter_x * source.width() + target.left() ); if (area.left() > max_x) break; painter->drawPixmap(area, pixmap, source); } } painter->restore(); return errNone; } void defineQPenPrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/prim_QQuartzComposer.mm000644 000765 000024 00000031671 12756531745 026642 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2013 Scott Wilson (i@scottwilson.ca) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #import #include "primitives.h" #include "image_primitive_helper_funcs.h" #include "../QObjectProxy.h" #include "../QcObjectFactory.h" #include "../QcApplication.h" #include "../Common.h" #include "../type_codec.hpp" #include "../metatype.hpp" #include "../widgets/QcQuartzComposerView.h" #include #include #include #include #include #define QOBJECT_FROM_SLOT( s ) \ ((QObjectProxy*) slotRawPtr( slotRawObject( s )->slots )) extern PyrSymbol *s_proto, *s_parent; extern int ivxIdentDict_array, ivxIdentDict_size, ivxIdentDict_parent, ivxIdentDict_proto, ivxIdentDict_know; int identDictPut(struct VMGlobals *g, PyrObject *dict, PyrSlot *key, PyrSlot *value); extern PyrClass *class_identdict; namespace QtCollider { // conversion functions static int getNSObjectForSCObject(PyrSlot *scobject, id *returnID, VMGlobals *g) { int err = errNone; id returnObject; // find the value type and set appropriately if(IsFloat(scobject)) { // it's a float float val; err = slotFloatVal(scobject, &val); if (err) { *returnID = NULL; return err; } returnObject = [NSNumber numberWithFloat: val]; } else if(IsInt(scobject)) { // it's an int int val; err = slotIntVal(scobject, &val); if (err) { *returnID = NULL; return err; } returnObject = [NSNumber numberWithInt: val]; } else if(IsTrue(scobject)) { // it's bool true returnObject = [NSNumber numberWithBool: YES]; } else if(IsFalse(scobject)) { // it's bool false returnObject = [NSNumber numberWithBool: NO]; } else if(isKindOfSlot(scobject, s_string->u.classobj)) { // it's a string PyrString *string = slotRawString(scobject); if(string->size == 0) { *returnID = NULL; return errFailed; } char cstring[string->size + 1]; slotStrVal(scobject, cstring, string->size + 1); returnObject = [NSString stringWithCString:cstring encoding:NSUTF8StringEncoding]; } else if(isKindOfSlot(scobject, s_color->u.classobj)) { // it's a color PyrSlot *slots = slotRawObject(scobject)->slots; float red, green, blue, alpha; err = slotFloatVal(slots+0, &red); if (!err) err = slotFloatVal(slots+1, &green); if (!err) err = slotFloatVal(slots+2, &blue); if (!err) err = slotFloatVal(slots+3, &alpha); if (err) { *returnID = NULL; return err; } returnObject = [NSColor colorWithCalibratedRed: red green: green blue: blue alpha: alpha]; } else if(isKindOfSlot(scobject, s_identitydictionary->u.classobj)) { // it's a structure (dict) PyrObject *array; array = slotRawObject(&(slotRawObject(scobject)->slots[ivxIdentDict_array])); if (!isKindOf((PyrObject*)array, class_array)) { *returnID = NULL; return errFailed; } NSMutableDictionary *structure = [NSMutableDictionary dictionary]; int len = array->size; for(int i=0; islots+i; if(!IsNil(element)) { PyrSymbol *keysymbol; err = slotSymbolVal(element, &keysymbol); if (err) { *returnID = NULL; return err; } NSString *key = [NSString stringWithCString: keysymbol->name encoding: NSUTF8StringEncoding]; id innerSCObject; int innerErr = getNSObjectForSCObject(element + 1, &innerSCObject, g); if(!innerSCObject) { *returnID = NULL; return innerErr;} [structure setObject: innerSCObject forKey: key]; } } returnObject = structure; } else if(isKindOfSlot(scobject, class_array)) { // it's a structure (array) PyrSlot *array = scobject; int len = slotRawObject(array)->size; NSMutableArray *structure = [NSMutableArray arrayWithCapacity: (unsigned)len]; for(int i =0; islots+i; id innerSCObject; int innerErr = getNSObjectForSCObject(element, &innerSCObject, g); if(!innerSCObject) { *returnID = NULL; return innerErr; } [structure addObject: innerSCObject]; } returnObject = structure; } else if(isKindOfSlot(scobject, SC_CLASS(Image))) { // it's an image SharedImage *img = reinterpret_cast( slotRawPtr( slotRawObject(scobject)->slots+0 ) ); if((*img)->isPainting()) { *returnID = NULL; return errFailed; } QPixmap pixmap = (*img)->pixmap(); CGImageRef cgImage = QtMac::toCGImageRef(pixmap); returnObject = [[NSImage alloc] initWithCGImage:cgImage size:NSZeroSize]; CGImageRelease(cgImage); } else { // it's something else... *returnID = NULL; return errWrongType; } if(!returnObject) { *returnID = NULL; err = errFailed; } else { *returnID = returnObject; } return err; } static int getSCObjectForNSObject(PyrSlot *slot, id nsObject, NSString *type, VMGlobals *g) { if([type isEqualToString:QCPortTypeBoolean]) { SetBool(slot, [nsObject boolValue]); return errNone; } else if([type isEqualToString:QCPortTypeIndex]) { SetInt(slot, [nsObject intValue]); return errNone; } else if([type isEqualToString:QCPortTypeNumber]) { SetFloat(slot, [nsObject floatValue]); return errNone; } else if([type isEqualToString:QCPortTypeString]) { const char * cstr = [nsObject UTF8String]; PyrString *string = newPyrString(g->gc, cstr, 0, true); SetObject(slot, string); return errNone; } else if([type isEqualToString:QCPortTypeColor]) { PyrObject* colorObj = instantiateObject(g->gc, s_color->u.classobj, 0, false, true); PyrSlot *slots = colorObj->slots; SetFloat( slots+0, [nsObject redComponent] ); SetFloat( slots+1, [nsObject greenComponent] ); SetFloat( slots+2, [nsObject blueComponent] ); SetFloat( slots+3, [nsObject alphaComponent] ); SetObject(slot, colorObj); return errNone; } else if([type isEqualToString:QCPortTypeStructure]) { // for the moment QC seems to deal with all internal structures as NSCFDictionary // but check here to be safe if([nsObject isKindOfClass: [NSDictionary class]]){ PyrObject *dict, *array; dict = instantiateObject(g->gc, class_identdict, 5, true, false); array = newPyrArray(g->gc, 4, 0, false); array->size = 4; nilSlots(array->slots, array->size); SetObject(dict->slots + ivxIdentDict_array, array); // we know that dict is white so don't need GCWrite SetObject(slot, dict); NSEnumerator *enumerator = [nsObject keyEnumerator]; id key; while ((key = [enumerator nextObject])) { id innerNSObject = [nsObject objectForKey: key]; PyrSlot innerSlot; NSString *innerType; if([innerNSObject isKindOfClass: [NSNumber class]]){ if(!strcmp([innerNSObject objCType], @encode(BOOL))) { innerType = QCPortTypeBoolean; } else if(!strcmp([innerNSObject objCType], @encode(int))) { innerType = QCPortTypeIndex; } else innerType = QCPortTypeNumber; } else if([innerNSObject isKindOfClass: [NSColor class]]){ innerType = QCPortTypeColor; } else if([innerNSObject isKindOfClass: [NSString class]]){ innerType = QCPortTypeString; } else if([innerNSObject isKindOfClass: [NSArray class]] || [innerNSObject isKindOfClass: [NSDictionary class]]){ innerType = QCPortTypeStructure; } else return errWrongType; // it's something else int err = getSCObjectForNSObject(&innerSlot, innerNSObject, innerType, g); if(err) return err; PyrSlot outKey; // key could be an NSNumber, so convert if([key isKindOfClass: [NSNumber class]]){ key = [key stringValue]; } SetSymbol(&outKey, getsym([key UTF8String])); err = identDictPut(g, dict, &outKey, &innerSlot); if(err) return err; } return errNone; } } else if([type isEqualToString:QCPortTypeImage]) { // QImage NSImage *nsimage = (NSImage*)nsObject; CGImageRef cgImage = [nsimage CGImageForProposedRect:NULL context:NULL hints:NULL]; QPixmap pixmap = QtMac::fromCGImageRef(cgImage); PyrObject* imageObj = instantiateObject(g->gc, SC_CLASS(Image), 0, false, true); Image *image = new Image; image->setPixmap(pixmap); initialize_image_object(g, imageObj, image); SetObject(slot, imageObj); return errNone; } return errWrongType; // it's something else } // primitives QC_LANG_PRIMITIVE( QQuartzComposer_SetInputPort, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QcQuartzComposerView* view = static_cast(proxy->object()); if( NotSym( a ) ) return errWrongType; PyrSymbol *keysymbol = slotRawSymbol( a ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("SET: %1").arg(keysymbol->name) ); NSString *key = [NSString stringWithCString:keysymbol->name encoding: NSUTF8StringEncoding]; if(!(view->hasInputKey(key))) { post("There is no port with key \"%s\".\n\n", [key UTF8String]); return errFailed; } id val; int err = getNSObjectForSCObject(a+1, &val, g); if(err) return err; view->setInputPort(key, val); return errNone; } QC_LANG_PRIMITIVE( QQuartzComposer_GetInputPort, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QcQuartzComposerView* view = static_cast(proxy->object()); if( NotSym(a) ) return errWrongType; PyrSymbol *keysymbol = slotRawSymbol( a ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("GET: %1").arg(keysymbol->name) ); NSString *key = [NSString stringWithCString: keysymbol->name encoding: NSUTF8StringEncoding]; if(!(view->hasInputKey(key))) { post("There is no port with key \"%s\".\n\n", [key UTF8String]); return errFailed; } NSString *type = view->getTypeForKey(key); id nsObject = view->getInputPort(key); int err = getSCObjectForNSObject(r, nsObject, type, g); if (err) return err; return errNone; } QC_LANG_PRIMITIVE( QQuartzComposer_GetOutputPort, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QObjectProxy *proxy = QOBJECT_FROM_SLOT( r ); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QcQuartzComposerView* view = static_cast(proxy->object()); if( NotSym(a) ) return errWrongType; PyrSymbol *keysymbol = slotRawSymbol( a ); qcSCObjectDebugMsg( 1, slotRawObject(r), QStringLiteral("GET: %1").arg(keysymbol->name) ); NSString *key = [NSString stringWithCString: keysymbol->name encoding: NSUTF8StringEncoding]; if(!(view->hasOutputKey(key))) { post("There is no port with key \"%s\".\n\n", [key UTF8String]); return errFailed; } NSString *type = view->getTypeForKey(key); id nsObject = view->getOutputPort(key); int err = getSCObjectForNSObject(r, nsObject, type, g); if (err) return err; return errNone; } void defineQcQuartzComposerPrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/prim_QWidget.cpp000644 000765 000024 00000014100 12321461510 025200 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "primitives.h" #include "../type_codec.hpp" #include "../QWidgetProxy.h" #include "../Common.h" #include #include #include #include #include #include #include // WARNING these primitives have to always execute asynchronously, or Cocoa language client will // hang. #define QWIDGET_PROXY_RECEIVER(slot) \ qobject_cast( QtCollider::read(slot) ) namespace QtCollider { QC_LANG_PRIMITIVE( QWidget_SetFocus, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *proxy = QWIDGET_PROXY_RECEIVER(r); QApplication::postEvent( proxy, new SetFocusEvent( IsTrue(a) ) ); return errNone; } QC_LANG_PRIMITIVE( QWidget_BringFront, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *proxy = QWIDGET_PROXY_RECEIVER(r); QApplication::postEvent( proxy, new QEvent( (QEvent::Type) QtCollider::Event_Proxy_BringFront ) ); return errNone; } QC_LANG_PRIMITIVE( QWidget_Refresh, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *proxy = QWIDGET_PROXY_RECEIVER(r); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); proxy->refresh(); return errNone; } QC_LANG_PRIMITIVE( QWidget_MapToGlobal, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *proxy = QWIDGET_PROXY_RECEIVER(r); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QWidget *w = proxy->widget(); if( !w ) return errNone; QPoint pt( QtCollider::get( a ) ); pt = w->mapToGlobal( pt ); QtCollider::set( r, pt ); return errNone; } QC_LANG_PRIMITIVE( QWidget_SetLayout, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( !isKindOfSlot( a, SC_CLASS(Layout) ) ) return errWrongType; QWidgetProxy *wProxy = QWIDGET_PROXY_RECEIVER(r); if( !wProxy->compareThread() ) return QtCollider::wrongThreadError(); QObjectProxy *lProxy = QtCollider::get( a ); wProxy->setLayout( lProxy ); return errNone; } QC_LANG_PRIMITIVE( QWidget_GetAlwaysOnTop, 0, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *wProxy = QWIDGET_PROXY_RECEIVER(r); if( QThread::currentThread() != wProxy->thread() ) return errFailed; SetBool( r, wProxy->alwaysOnTop() ); return errNone; } QC_LANG_PRIMITIVE( QWidget_SetAlwaysOnTop, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *wProxy = QWIDGET_PROXY_RECEIVER(r); QApplication::postEvent( wProxy, new SetAlwaysOnTopEvent( IsTrue(a) ) ); return errNone; } struct MimeData : public QMimeData { virtual ~MimeData() { qcDebugMsg(1,"Drag data object destroyed, clearing QView.currentDrag."); QtCollider::lockLang(); PyrClass *classView = getsym("View")->u.classobj; PyrSymbol *symClearDrag = getsym("prClearCurrentDrag"); if( !classView || !symClearDrag ) return; QtCollider::runLang( classView, symClearDrag ); QtCollider::unlockLang(); } }; QC_LANG_PRIMITIVE( QWidget_StartDrag, 3, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { qcDebugMsg(1, "Starting drag..."); QWidgetProxy *wProxy = QWIDGET_PROXY_RECEIVER(r); if( !wProxy->compareThread() ) return QtCollider::wrongThreadError(); PyrSlot *data = a+1; QString str = QtCollider::get(a+2); QString label = QtCollider::get(a); QMimeData *mime = new QtCollider::MimeData; mime->setData( "application/supercollider", QByteArray() ); QColor color = QtCollider::get(data); if( color.isValid() ) mime->setColorData( QVariant(color) ); if( !str.isEmpty() ) mime->setText( str ); wProxy->setDragData( mime, label ); return errNone; } QC_LANG_PRIMITIVE( QWidget_SetGlobalEventEnabled, 2, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { if( NotInt( a+0 ) ) return errWrongType; int event = QtCollider::get(a+0); bool enabled = IsTrue(a+1); if( !enabled && !IsFalse(a+1) ) return errWrongType; QWidgetProxy::setGlobalEventEnabled( (QWidgetProxy::GlobalEvent) event, enabled ); return errNone; } QC_LANG_PRIMITIVE( QWidget_SetAcceptsMouse, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *proxy = QWIDGET_PROXY_RECEIVER(r); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QWidget *w = proxy->widget(); if( !w ) return errNone; bool accept = IsTrue(a); w->setAttribute( Qt::WA_TransparentForMouseEvents, !accept ); return errNone; } QC_LANG_PRIMITIVE( QWidget_AcceptsMouse, 1, PyrSlot *r, PyrSlot *a, VMGlobals *g ) { QWidgetProxy *proxy = QWIDGET_PROXY_RECEIVER(r); if( !proxy->compareThread() ) return QtCollider::wrongThreadError(); QWidget *w = proxy->widget(); if( !w ) return errNone; bool accept = !w->testAttribute( Qt::WA_TransparentForMouseEvents ); SetBool(r, accept); return errNone; } void defineQWidgetPrimitives() { LangPrimitiveDefiner definer; definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); definer.define(); } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/primitives.cpp000644 000765 000024 00000003416 12756531745 025034 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "primitives.h" #include "../Common.h" #include "QtCollider.h" #include namespace QtCollider { #define QC_DO_SYMBOL(SYM) PyrSymbol * sym_##SYM QC_DO_SYMBOLS #undef QC_DO_SYMBOL void defineQObjectPrimitives(); void defineQPenPrimitives(); void defineMiscPrimitives(); void defineQWidgetPrimitives(); void defineQPalettePrimitives(); void defineQImagePrimitives(); #ifdef __APPLE__ void defineQcQuartzComposerPrimitives(); #endif void initPrimitives () { QtCollider::init(); qcDebugMsg(1,"initializing QtGUI primitives"); defineQObjectPrimitives(); defineQWidgetPrimitives(); defineQPenPrimitives(); defineMiscPrimitives(); defineQPalettePrimitives(); defineQImagePrimitives(); #ifdef __APPLE__ defineQcQuartzComposerPrimitives(); #endif #define QC_DO_SYMBOL(SYM) sym_##SYM = getsym(#SYM); QC_DO_SYMBOLS #undef QC_DO_SYMBOL } } // namespace QtCollider SuperCollider-Source/QtCollider/primitives/primitives.h000644 000765 000024 00000004156 12321461510 024457 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include #include #include #include namespace QtCollider { template struct LangPrimitive { }; class LangPrimitiveDefiner { public: LangPrimitiveDefiner() : _base( nextPrimitiveIndex() ), _index(0) {} template void define() { LangPrimitive::define( _base, _index++ ); } private: int _base; int _index; }; } // namespace #define QC_LANG_PRIMITIVE( NAME, ARGC, RECEIVER, ARGS, GLOBAL ) \ struct NAME {}; \ template<> struct LangPrimitive { \ static int implementation ( RECEIVER, ARGS, GLOBAL ); \ static int mediate( VMGlobals *g, int i ) { \ PyrSlot *stack = g->sp - i + 1; \ return implementation( stack, i > 1 ? stack+1 : 0, g ); \ } \ static void define( int base, int index ) { \ definePrimitive( base, index, "_" #NAME, &mediate, ARGC + 1, 0 ); \ } \ }; \ int LangPrimitive::implementation( RECEIVER, ARGS, GLOBAL ) #if 0 #define QC_LANG_PRIMITIVE( name, argc, receiver, args, global ) \ int name ( receiver, args, global ); \ static QtCollider::LangPrimitive<&name> p_##name( "_" #name, argc ); \ int name ( receiver, args, global ) #endifSuperCollider-Source/QtCollider/layouts/classic_layouts.hpp000644 000765 000024 00000011663 12321461510 025333 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_CLASSIC_LAYOUTS_H #define QC_CLASSIC_LAYOUTS_H #include #include #include "../Common.h" namespace QtCollider { enum HSizePolicy { StickLeft = 1, HStretch, StickRight }; enum VSizePolicy { StickTop = 1, VStretch, StickBottom }; static VSizePolicy vSizePolicy( QWidget *w ) { QVariant var = w->property( "_qc_vSizePolicy" ); if( !var.isValid() ) return StickTop; return (VSizePolicy) var.toInt(); } static HSizePolicy hSizePolicy( QWidget *w ) { QVariant var = w->property( "_qc_hSizePolicy" ); if( !var.isValid() ) return StickLeft; return (HSizePolicy) var.toInt(); } class DefaultLayout { public: DefaultLayout( QWidget * w ): parent(w), initialized(false) {} void resize( QResizeEvent *e ) { QRect r; r.setSize(e->size()); if( !initialized ) { initialized = true; geom = r; return; } QPoint dPos = r.topLeft() - geom.topLeft(); QSize dSize = r.size() - geom.size(); const QObjectList &children = parent->children(); Q_FOREACH( QObject *o, children ) { if(!o->isWidgetType()) continue; QWidget *child = static_cast(o); QRect g = child->geometry(); int x = g.x(); int y = g.y(); int w = g.width(); int h = g.height(); if( !dPos.isNull() ) { x += dPos.x(); y += dPos.y(); } if( !dSize.isNull() ) { if( hSizePolicy(child) == QtCollider::StickRight ) x += dSize.width(); if( vSizePolicy(child) == QtCollider::StickBottom ) y += dSize.height(); if( hSizePolicy(child) == QtCollider::HStretch ) w += dSize.width(); if( vSizePolicy(child) == QtCollider::VStretch ) h += dSize.height(); } child->setGeometry( QRect(x, y, w, h) ); } geom = r; } private: QWidget *parent; bool initialized; QRect geom; }; class HLayout { public: HLayout( QWidget * w ): parent(w) {} void resize( QResizeEvent *e ) { QRect geom; geom.setSize(e->size()); const QObjectList &children = parent->children(); int varWidth = geom.width(); int i = 0; Q_FOREACH( QObject *o, children ) { if(!o->isWidgetType()) continue; QWidget *w = static_cast(o); if( hSizePolicy(w) == QtCollider::HStretch ) { ++i; } else { QRect r = w->geometry(); varWidth -= r.width(); if( varWidth < 0 ) break; } } int partWidth = i > 0 && varWidth > 0 ? varWidth / i : 0; int x = 0; Q_FOREACH( QObject *o, children ) { if(!o->isWidgetType()) continue; QWidget *w = static_cast(o); QRect r = w->geometry(); r.setHeight( geom.height() ); r.moveTo( x, geom.top() ); if( hSizePolicy(w) == QtCollider::HStretch ) r.setWidth( partWidth ); x += r.width(); w->setGeometry( r ); } } private: QWidget *parent; }; class VLayout { public: VLayout( QWidget * w ): parent(w) {} void resize( QResizeEvent *e ) { QRect geom; geom.setSize(e->size()); const QObjectList &children = parent->children(); int varHeight = geom.height(); int i = 0; Q_FOREACH( QObject *o, children ) { if(!o->isWidgetType()) continue; QWidget *w = static_cast(o); if( vSizePolicy(w) == QtCollider::VStretch ) { ++i; } else { QRect r = w->geometry(); varHeight -= r.height(); if( varHeight < 0 ) break; } } int partHeight = i > 0 && varHeight > 0 ? varHeight / i : 0; int y = 0; Q_FOREACH( QObject *o, children ) { if(!o->isWidgetType()) continue; QWidget *w = static_cast(o); QRect r = w->geometry(); r.setWidth( geom.width() ); r.moveTo( geom.left(), y ); if( vSizePolicy(w) == QtCollider::VStretch ) r.setHeight( partHeight ); y += r.height(); w->setGeometry( r ); } } private: QWidget *parent; }; } // namespace QtCollider #endif // QC_CLASSIC_LAYOUTS_H SuperCollider-Source/QtCollider/layouts/layouts.cpp000644 000765 000024 00000003351 12321461510 023620 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "layouts.hpp" QC_DECLARE_QOBJECT_FACTORY(QcHBoxLayout); QC_DECLARE_QOBJECT_FACTORY(QcVBoxLayout); QC_DECLARE_QOBJECT_FACTORY(QcGridLayout); QC_DECLARE_QOBJECT_FACTORY(QcStackLayout); void QcGridLayout::addItem( const QVariantList &data ) { if( data.count() < 6 ) return; int row = data[1].toInt(); int column = data[2].toInt(); int rSpan = data[3].toInt(); int cSpan = data[4].toInt(); Qt::Alignment alignment = (Qt::Alignment) data[5].toInt(); QVariant varObject = data[0]; QObjectProxy *p = varObject.value(); if( !p || !p->object() ) return; QWidget *w = qobject_cast( p->object() ); if( w ) { addWidget( w, row, column, rSpan, cSpan, alignment ); return; } QLayout *l = qobject_cast( p->object() ); if(l) { addLayout( l, row, column, rSpan, cSpan, alignment ); return; } } SuperCollider-Source/QtCollider/layouts/layouts.hpp000644 000765 000024 00000020565 12321461510 023633 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2010 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_LAYOUTS_H #define QC_LAYOUTS_H #include "stack_layout.hpp" #include "../Common.h" #include "../QcObjectFactory.h" #include "../QObjectProxy.h" #include #include #include #include template struct QcLayout : public LAYOUT { public: QVariantList margins() const { return QVariantList(); } void setMargins( const QVariantList &list ) { if( list.size() < 4 ) return; int m[4]; for( int i=0; i<4; ++i ) m[i] = list[i].toInt(); LAYOUT::setContentsMargins( m[0], m[1], m[2], m[3] ); } }; template class QcBoxLayout : public QcLayout { public: QcBoxLayout() {} QcBoxLayout( const QVariantList & items ) { Q_FOREACH( const QVariant &var, items ) { QVariantList item = var.toList(); addItem( item ); } } void addItem( const QVariantList & item ) { if( item.size() < 3 ) return; int stretch = item[1].toInt(); Qt::Alignment alignment = (Qt::Alignment) item[2].toInt(); const QVariant & varObject = item[0]; if( !varObject.isValid() ) { BOXLAYOUT::addStretch( stretch ); return; } if( varObject.canConvert() ) { int size = varObject.toInt(); BOXLAYOUT::addSpacing( size ); return; } QObjectProxy *p = varObject.value(); if( !p || !p->object() ) return; QWidget *w = qobject_cast( p->object() ); if( w ) { BOXLAYOUT::addWidget( w, stretch, alignment ); return; } QLayout *l2 = qobject_cast( p->object() ); if(l2) { if (l2->parent()) { // FIXME: inserting layout that already has parent is broken in Qt. // See Qt bug 30758. qcErrorMsg("Can not insert a layout that already has a parent into another layout!"); return; } BOXLAYOUT::addLayout( l2, stretch ); return; } } void insertItem( const QVariantList & item ) { if( item.size() < 4 ) return; int index = item[1].toInt(); int stretch = item[2].toInt(); Qt::Alignment alignment = (Qt::Alignment) item[3].toInt(); const QVariant & varObject = item[0]; if( !varObject.isValid() ) { BOXLAYOUT::insertStretch( index, stretch ); return; } if( varObject.canConvert() ) { int size = varObject.toInt(); BOXLAYOUT::insertSpacing( index, size ); return; } QObjectProxy *p = varObject.value(); if( !p || !p->object() ) return; QWidget *w = qobject_cast( p->object() ); if( w ) { BOXLAYOUT::insertWidget( index, w, stretch, alignment ); return; } QLayout *l2 = qobject_cast( p->object() ); if(l2) { BOXLAYOUT::insertLayout( index, l2, stretch ); return; } } void setStretch( QObjectProxy *p, int stretch ) { QWidget *w = qobject_cast( p->object() ); if( w ) { BOXLAYOUT::setStretchFactor( w, stretch ); return; } QLayout *l = qobject_cast( p->object() ); if(l) { BOXLAYOUT::setStretchFactor( l, stretch ); return; } } void setAlignment( QObjectProxy *p, Qt::Alignment alignment ) { QWidget *w = qobject_cast( p->object() ); if( w ) { BOXLAYOUT::setAlignment( w, alignment ); return; } QLayout *l = qobject_cast( p->object() ); if(l) { BOXLAYOUT::setAlignment( l, alignment ); return; } } }; class QcHBoxLayout : public QcBoxLayout { Q_OBJECT Q_PROPERTY( QVariantList margins READ margins WRITE setMargins ) public: QcHBoxLayout() {} Q_INVOKABLE QcHBoxLayout( const QVariantList &items ): QcBoxLayout(items) {} Q_INVOKABLE void addItem( const QVariantList &data ) { QcBoxLayout::addItem(data); } Q_INVOKABLE void insertItem( const QVariantList &data ) { QcBoxLayout::insertItem(data); } Q_INVOKABLE void setStretch( int index, int stretch ) { QBoxLayout::setStretch( index, stretch ); } Q_INVOKABLE void setStretch( QObjectProxy *p, int stretch ) { QcBoxLayout::setStretch( p, stretch ); } Q_INVOKABLE void setAlignment( int i, int a ) { itemAt(i)->setAlignment( (Qt::Alignment) a ); update(); } Q_INVOKABLE void setAlignment( QObjectProxy *p, int a ) { QcBoxLayout::setAlignment( p, (Qt::Alignment) a ); } }; class QcVBoxLayout : public QcBoxLayout { Q_OBJECT Q_PROPERTY( QVariantList margins READ margins WRITE setMargins ) public: QcVBoxLayout() {} Q_INVOKABLE QcVBoxLayout( const QVariantList &items ): QcBoxLayout(items) {} Q_INVOKABLE void addItem( const QVariantList &data ) { QcBoxLayout::addItem(data); } Q_INVOKABLE void insertItem( const QVariantList &data ) { QcBoxLayout::insertItem(data); } Q_INVOKABLE void setStretch( int index, int stretch ) { QBoxLayout::setStretch( index, stretch ); } Q_INVOKABLE void setStretch( QObjectProxy *p, int stretch ) { QcBoxLayout::setStretch( p, stretch ); } Q_INVOKABLE void setAlignment( int i, int a ) { itemAt(i)->setAlignment( (Qt::Alignment) a ); update(); } Q_INVOKABLE void setAlignment( QObjectProxy *p, int a ) { QcBoxLayout::setAlignment( p, (Qt::Alignment) a ); } }; class QcGridLayout : public QcLayout { Q_OBJECT Q_PROPERTY( QVariantList margins READ margins WRITE setMargins ) Q_PROPERTY( int verticalSpacing READ verticalSpacing WRITE setVerticalSpacing ) Q_PROPERTY( int horizontalSpacing READ horizontalSpacing WRITE setHorizontalSpacing ) public: Q_INVOKABLE void addItem( const QVariantList &dataList ); Q_INVOKABLE void setRowStretch( int row, int factor ) { QcLayout::setRowStretch( row, factor ); } Q_INVOKABLE void setColumnStretch( int column, int factor ) { QcLayout::setColumnStretch( column, factor ); } Q_INVOKABLE void setAlignment( int r, int c, int a ) { QLayoutItem *item = itemAtPosition(r,c); if(item) { item->setAlignment( (Qt::Alignment) a ); update(); } } Q_INVOKABLE void setAlignment( QObjectProxy *p, int a ) { QWidget *w = qobject_cast( p->object() ); if( w ) { QLayout::setAlignment( w, (Qt::Alignment) a ); return; } QLayout *l = qobject_cast( p->object() ); if(l) { QLayout::setAlignment( l, (Qt::Alignment) a ); return; } } Q_INVOKABLE int minRowHeight( int row ) { return ( row >= 0 && row < rowCount() ) ? rowMinimumHeight( row ) : 0; } Q_INVOKABLE int minColumnWidth( int col ) { return ( col >= 0 && col < columnCount() ) ? columnMinimumWidth( col ) : 0; } Q_INVOKABLE void setMinRowHeight( int row, int h ) { setRowMinimumHeight( row, h ); } Q_INVOKABLE void setMinColumnWidth( int col, int w ) { setColumnMinimumWidth( col, w ); } }; class QcStackLayout : public QcLayout { Q_OBJECT Q_PROPERTY( QVariantList margins READ margins WRITE setMargins ) public: QcStackLayout() {} Q_INVOKABLE QcStackLayout( const QVariantList &items ) { Q_FOREACH(const QVariant & var, items) { QObjectProxy *p = var.value(); if(!p) return; QWidget *w = qobject_cast( p->object() ); if(w) addWidget(w); } } Q_INVOKABLE void insertWidget( int index, QObjectProxy *proxy ) { if (QWidget *w = qobject_cast( proxy->object() )) QtCollider::StackLayout::insertWidget(index, w); } }; #endif SuperCollider-Source/QtCollider/layouts/stack_layout.cpp000644 000765 000024 00000025462 12321461510 024631 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (qt-info@nokia.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "stack_layout.hpp" #include namespace QtCollider { StackLayout::StackLayout() : _index(-1), _mode(StackOne), _gotParent(false) {} StackLayout::~StackLayout() { qDeleteAll(_list); } int StackLayout::addWidget(QWidget *widget) { return insertWidget(_list.count(), widget); } int StackLayout::insertWidget(int index, QWidget *widget) { addChildWidget(widget); index = qMin(index, _list.count()); if (index < 0) index = _list.count(); QWidgetItem *wi = new QWidgetItem( widget ); _list.insert(index, wi); invalidate(); if (_index < 0) { setCurrentIndex(index); } else { if (index <= _index) ++_index; if (_mode == StackOne) widget->hide(); widget->lower(); } return index; } QLayoutItem *StackLayout::itemAt(int index) const { return _list.value(index); } QLayoutItem *StackLayout::takeAt(int index) { if (index < 0 || index >= _list.size()) return 0; QLayoutItem *item = _list.takeAt(index); if (index == _index) { _index = -1; if ( _list.count() > 0 ) { int newIndex = (index == _list.count()) ? index-1 : index; setCurrentIndex(newIndex); } } else if (index < _index) { --_index; } // NOTE: Here, the Qt implementation hides item->widget() if it exists and is not being // deleted. We can't reproduce this, because we can't access private info on whether the // widget is being deleted. return item; } void StackLayout::setCurrentIndex(int index) { QWidget *prev = currentWidget(); QWidget *next = widget(index); if (!next || next == prev) return; _index = index; if(!parent()) return; bool reenableUpdates = false; QWidget *parent = parentWidget(); if (parent && parent->updatesEnabled()) { reenableUpdates = true; parent->setUpdatesEnabled(false); } QWidget *fw = parent ? parent->window()->focusWidget() : 0; if (prev) { prev->clearFocus(); if (_mode == StackOne) prev->hide(); } next->raise(); next->show(); // try to move focus onto the incoming widget if focus // was somewhere on the outgoing widget. if (parent) { if (fw && (prev && prev->isAncestorOf(fw))) { // focus was on old page // look for the best focus widget we can find if (QWidget *nfw = next->focusWidget()) nfw->setFocus(); else { // second best: first child widget in the focus chain QWidget *i = fw; while ((i = i->nextInFocusChain()) != fw) { if (((i->focusPolicy() & Qt::TabFocus) == Qt::TabFocus) && !i->focusProxy() && i->isVisibleTo(next) && i->isEnabled() && next->isAncestorOf(i)) { i->setFocus(); break; } } // third best: incoming widget if (i == fw ) next->setFocus(); } } } if (reenableUpdates) parent->setUpdatesEnabled(true); if (_mode == StackOne) // expandingDirections() might have changed, so invalidate(): invalidate(); } int StackLayout::currentIndex() const { return _index; } void StackLayout::setCurrentWidget(QWidget *widget) { int index = indexOf(widget); if (index == -1) { qWarning("StackLayout::setCurrentWidget: Widget %p not contained in stack", widget); return; } setCurrentIndex(index); } QWidget *StackLayout::currentWidget() const { return _index >= 0 ? _list.at(_index)->widget() : 0; } QWidget *StackLayout::widget(int index) const { if (index < 0 || index >= _list.size()) return 0; return _list.at(index)->widget(); } int StackLayout::count() const { return _list.size(); } void StackLayout::addItem(QLayoutItem *item) { QWidget *widget = item->widget(); if (widget) { addWidget(widget); delete item; } else { qWarning("StackLayout::addItem: Only widgets can be added"); } } QSize StackLayout::sizeHint() const { QSize s(0, 0); switch (_mode) { case StackOne: if (_index >= 0) if (QWidget *w = _list.at(_index)->widget()) { if (w->sizePolicy().horizontalPolicy() != QSizePolicy::Ignored) s.setWidth(w->sizeHint().width()); if (w->sizePolicy().verticalPolicy() != QSizePolicy::Ignored) s.setHeight(w->sizeHint().height()); } break; case StackAll: { int n = _list.count(); for (int i = 0; i < n; ++i) if (QWidget *w = _list.at(i)->widget()) { QSize ws(w->sizeHint()); if (w->sizePolicy().horizontalPolicy() == QSizePolicy::Ignored) ws.setWidth(0); if (w->sizePolicy().verticalPolicy() == QSizePolicy::Ignored) ws.setHeight(0); s = s.expandedTo(ws); } break; } } return s; } static QSize smartMinSize(const QSize &sizeHint, const QSize &minSizeHint, const QSize &minSize, const QSize &maxSize, const QSizePolicy &sizePolicy) { QSize s(0, 0); if (sizePolicy.horizontalPolicy() != QSizePolicy::Ignored) { if (sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag) s.setWidth(minSizeHint.width()); else s.setWidth(qMax(sizeHint.width(), minSizeHint.width())); } if (sizePolicy.verticalPolicy() != QSizePolicy::Ignored) { if (sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag) { s.setHeight(minSizeHint.height()); } else { s.setHeight(qMax(sizeHint.height(), minSizeHint.height())); } } s = s.boundedTo(maxSize); if (minSize.width() > 0) s.setWidth(minSize.width()); if (minSize.height() > 0) s.setHeight(minSize.height()); return s.expandedTo(QSize(0,0)); } QSize StackLayout::minimumSize() const { QSize s(0, 0); switch (_mode) { case StackOne: if (_index >= 0) if (QWidget *w = _list.at(_index)->widget()) s = smartMinSize(w->sizeHint(), w->minimumSizeHint(), w->minimumSize(), w->maximumSize(), w->sizePolicy()); break; case StackAll: { int n = _list.count(); for (int i = 0; i < n; ++i) if (QWidget *w = _list.at(i)->widget()) s = s.expandedTo( smartMinSize(w->sizeHint(), w->minimumSizeHint(), w->minimumSize(), w->maximumSize(), w->sizePolicy())); break; } } return s; } Qt::Orientations StackLayout::expandingDirections () const { Qt::Orientations directions; switch (_mode) { case StackOne: directions = _index >= 0 ? _list.at(_index)->expandingDirections() : (Qt::Orientations) 0; break; case StackAll: { Qt::Orientations directions = 0; int n = _list.count(); for (int i = 0; i < n; ++i) directions |= _list.at(i)->expandingDirections(); break; } } return directions; } void StackLayout::setGeometry(const QRect &rect) { switch (_mode) { case StackOne: if (QWidget *widget = currentWidget()) widget->setGeometry(rect); break; case StackAll: if (const int n = _list.count()) for (int i = 0; i < n; ++i) if (QWidget *widget = _list.at(i)->widget()) widget->setGeometry(rect); break; } } StackLayout::StackingMode StackLayout::stackingMode() const { return _mode; } void StackLayout::setStackingMode(StackingMode stackingMode) { if (_mode == stackingMode) return; _mode = stackingMode; if( !parent() ) return; const int n = _list.count(); if (n == 0) return; switch (_mode) { case StackOne: { const int idx = currentIndex(); if ( idx >= 0 ) for (int i = 0; i < n; ++i) if (QWidget *widget = _list.at(i)->widget()) widget->setVisible(i == idx); break; } case StackAll: { // Turn overlay on: Make sure all widgets are the same size QRect geometry; if (const QWidget *widget = currentWidget()) geometry = widget->geometry(); for (int i = 0; i < n; ++i) if (QWidget *widget = _list.at(i)->widget()) { if (!geometry.isNull()) widget->setGeometry(geometry); widget->setVisible(true); } } break; } invalidate(); } void StackLayout::invalidate() { QWidget *pw = parentWidget(); if(pw && !_gotParent) { _gotParent = true; const int n = _list.count(); if (n == 0) return; QWidget *cw = currentWidget(); switch (_mode) { case StackOne: { if(cw) for (int i = 0; i < n; ++i) if (QWidget *widget = _list.at(i)->widget()) widget->setVisible(widget == cw); break; } case StackAll: { for (int i = 0; i < n; ++i) if (QWidget *widget = _list.at(i)->widget()) widget->setVisible(true); break; } } // NOTE: re-order the widgets after setting visibility, since the latter // may affect the order itself (at least on Mac OS X) if(cw) { for (int i = 0; i < n; ++i) { QWidget * w = _list.at(i)->widget(); if( w && w != cw ) w->lower(); } } } QLayout::invalidate(); } } // namespace QtCollider SuperCollider-Source/QtCollider/layouts/stack_layout.hpp000644 000765 000024 00000004720 12321461510 024630 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * Contact: Nokia Corporation (qt-info@nokia.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QT_COLLIDER_STACK_LAYOUT_HPP_INCLUDED #define QT_COLLIDER_STACK_LAYOUT_HPP_INCLUDED #include #include namespace QtCollider { class StackLayout : public QLayout { Q_OBJECT Q_ENUMS(StackingMode) Q_PROPERTY( int currentIndex READ currentIndex WRITE setCurrentIndex ) Q_PROPERTY( StackingMode stackingMode READ stackingMode WRITE setStackingMode ) Q_PROPERTY( int count READ count ) public: enum StackingMode { StackOne, StackAll }; StackLayout(); ~StackLayout(); int addWidget(QWidget *w); int insertWidget(int index, QWidget *w); QWidget *currentWidget() const; void setCurrentWidget(QWidget *widget); int currentIndex() const; void setCurrentIndex(int index); inline QWidget *widget() { return QLayout::widget(); } QWidget *widget(int) const; int count() const; StackingMode stackingMode() const; void setStackingMode(StackingMode stackingMode); // abstract virtual functions: void addItem(QLayoutItem *item); QLayoutItem *itemAt(int) const; QLayoutItem *takeAt(int); QSize sizeHint() const; QSize minimumSize() const; Qt::Orientations expandingDirections () const; void setGeometry(const QRect &rect); virtual void invalidate(); private: QList _list; int _index; StackingMode _mode; bool _gotParent; }; } // namespace QtCollider #endif // QT_COLLIDER_STACK_LAYOUT_HPP_INCLUDED SuperCollider-Source/QtCollider/hacks/hacks_mac.hpp000644 000765 000024 00000002302 12756531745 023446 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_MAC_HACKS_H #define QC_MAC_HACKS_H #include namespace QtCollider { namespace Mac { bool IsCmdPeriodKeyUp(void * event); bool IsCmdPeriodKeyDown(void * event); bool isKeyWindow ( QWidget *w ); bool AlwaysShowScrollbars(); void activateApp (); } // namespace Mac } // namespace QtCollider #endif SuperCollider-Source/QtCollider/hacks/hacks_mac.mm000644 000765 000024 00000004040 12756531745 023271 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011-2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "hacks_mac.hpp" #import namespace QtCollider { namespace Mac { bool isKeyWindow ( QWidget *w ) { return [[reinterpret_cast(w->winId()) window] isKeyWindow]; } bool IsCmdPeriodKeyDown(void * event) { NSEvent * nsevent = reinterpret_cast(event); if ([nsevent type] == NSKeyDown) { if ([nsevent modifierFlags] & NSCommandKeyMask) { NSString * chars = [nsevent charactersIgnoringModifiers]; return [chars characterAtIndex:0] == 0x2E; // Unicode encoding for period } } return false; } bool IsCmdPeriodKeyUp(void * event) { NSEvent * nsevent = reinterpret_cast(event); if ([nsevent type] == NSKeyUp) { if ([nsevent modifierFlags] & NSCommandKeyMask) { NSString * chars = [nsevent charactersIgnoringModifiers]; return [chars characterAtIndex:0] == 0x2E; } } return false; } bool AlwaysShowScrollbars() { return ([NSScroller preferredScrollerStyle] == NSScrollerStyleLegacy); } void activateApp() { [NSApp activateIgnoringOtherApps:YES]; } } // namespace Mac } // namespace QtCollider SuperCollider-Source/QtCollider/hacks/hacks_qt.hpp000644 000765 000024 00000002050 12321461510 023306 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #if QT_VERSION >= 0x040800 #define QURL_IS_LOCAL_FILE(url) url.isLocalFile() #else #define QURL_IS_LOCAL_FILE(url) url.scheme() == QString("file") #endif SuperCollider-Source/QtCollider/hacks/hacks_x11.cpp000644 000765 000024 00000011612 12321461510 023272 0ustar00crucialstaff000000 000000 /************************************************************************ * * adapted from: * wmctrl * A command line tool to interact with an EWMH/NetWM compatible X Window Manager. * * Copyright 2003 Tomas Styblo * Copyright 2011 Tim Blechmann (tim@klingt.org) * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "hacks_x11.hpp" #ifdef Q_WS_X11 #include #include #include #include #define MAX_PROPERTY_VALUE_LEN 4096 static inline void p_verbose(...) {} #define gchar char #define gboolean bool #define g_malloc (char*)malloc #define g_free free static gchar *get_property (Display *disp, Window win, Atom xa_prop_type, const gchar *prop_name, unsigned long *size) { Atom xa_prop_name; Atom xa_ret_type; int ret_format; unsigned long ret_nitems; unsigned long ret_bytes_after; unsigned long tmp_size; unsigned char *ret_prop; gchar *ret; xa_prop_name = XInternAtom(disp, prop_name, False); /* MAX_PROPERTY_VALUE_LEN / 4 explanation (XGetWindowProperty manpage): * * long_length = Specifies the length in 32-bit multiples of the * data to be retrieved. */ if (XGetWindowProperty(disp, win, xa_prop_name, 0, MAX_PROPERTY_VALUE_LEN / 4, False, xa_prop_type, &xa_ret_type, &ret_format, &ret_nitems, &ret_bytes_after, &ret_prop) != Success) { p_verbose("Cannot get %s property.\n", prop_name); return NULL; } if (xa_ret_type != xa_prop_type) { p_verbose("Invalid type of %s property.\n", prop_name); XFree(ret_prop); return NULL; } /* null terminate the result to make string handling easier */ tmp_size = (ret_format / 8) * ret_nitems; ret = g_malloc(tmp_size + 1); memcpy(ret, ret_prop, tmp_size); ret[tmp_size] = '\0'; if (size) { *size = tmp_size; } XFree(ret_prop); return ret; }/*}}}*/ static int client_msg(Display *disp, Window win, const char *msg, /* {{{ */ unsigned long data0, unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4) { XEvent event; long mask = SubstructureRedirectMask | SubstructureNotifyMask; event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.message_type = XInternAtom(disp, msg, False); event.xclient.window = win; event.xclient.format = 32; event.xclient.data.l[0] = data0; event.xclient.data.l[1] = data1; event.xclient.data.l[2] = data2; event.xclient.data.l[3] = data3; event.xclient.data.l[4] = data4; if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) { return EXIT_SUCCESS; } else { fprintf(stderr, "Cannot send %s event.\n", msg); return EXIT_FAILURE; } }/*}}}*/ static int activate_window (Display *disp, Window win, /* {{{ */ gboolean switch_desktop) { unsigned long *desktop; /* desktop ID */ if ((desktop = (unsigned long *)get_property(disp, win, XA_CARDINAL, "_NET_WM_DESKTOP", NULL)) == NULL) { if ((desktop = (unsigned long *)get_property(disp, win, XA_CARDINAL, "_WIN_WORKSPACE", NULL)) == NULL) { p_verbose("Cannot find desktop ID of the window.\n"); } } if (switch_desktop && desktop) { if (client_msg(disp, DefaultRootWindow(disp), "_NET_CURRENT_DESKTOP", *desktop, 0, 0, 0, 0) != EXIT_SUCCESS) { p_verbose("Cannot switch desktop.\n"); } } if (desktop) g_free(desktop); client_msg(disp, win, "_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); XMapRaised(disp, win); return EXIT_SUCCESS; }/*}}}*/ #undef p_verbose #undef gchar #undef gboolean #undef g_malloc #undef g_free bool raise_window(Display * display, QWidget * win) { Window window = win->winId(); int raised_via_xlib_error = XRaiseWindow(display, window); if (raised_via_xlib_error == 0) return true; int raised_via_ewmh_error = activate_window(display, window, true); return raised_via_ewmh_error == 0; } #endif SuperCollider-Source/QtCollider/hacks/hacks_x11.hpp000644 000765 000024 00000002176 12321461510 023304 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2011 Tim Blechmann (tim@klingt.org) * Copyright 2011 Jakob Leben (jakob.leben@gmail.com) * * This file is part of SuperCollider Qt GUI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #ifndef QC_HACKS_HACKS_X11_HPP #define QC_HACKS_HACKS_X11_HPP #include #ifdef Q_WS_X11 #include #include bool raise_window(Display * display, QWidget * window); #endif #endif SuperCollider-Source/platform/CMakeLists.txt000644 000765 000024 00000000301 12665004746 022245 0ustar00crucialstaff000000 000000 if(WIN32) add_subdirectory(windows) endif() # NB bsd currently OK to ride on linux for this subdir. eventually may need separating. if(UNIX AND NOT APPLE) add_subdirectory(linux) endif() SuperCollider-Source/platform/disable_startup_files/000755 000765 000024 00000000000 13007315613 024047 5ustar00crucialstaff000000 000000 SuperCollider-Source/platform/linux/000755 000765 000024 00000000000 13007315613 020637 5ustar00crucialstaff000000 000000 SuperCollider-Source/platform/renderAllHelp.scd000644 000765 000024 00000000160 12321461511 022706 0ustar00crucialstaff000000 000000 SCDoc.helpSourceDir = thisProcess.argv[0]; SCDoc.helpTargetDir = thisProcess.argv[1]; SCDoc.renderAll; 0.exit; SuperCollider-Source/platform/linux/CMakeLists.txt000644 000765 000024 00000000560 12321461511 023375 0ustar00crucialstaff000000 000000 install(DIRECTORY examples DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/SuperCollider ) install(FILES icons/supercollider.png icons/supercollider.xpm DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps ) install(FILES ../../icons/sc_ide.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps ) install(FILES supercollider.xml DESTINATION share/mime/packages ) SuperCollider-Source/platform/linux/examples/000755 000765 000024 00000000000 13007315613 022455 5ustar00crucialstaff000000 000000 SuperCollider-Source/platform/linux/icons/000755 000765 000024 00000000000 13007315613 021752 5ustar00crucialstaff000000 000000 SuperCollider-Source/platform/linux/supercollider.xml000644 000765 000024 00000000725 12321461511 024236 0ustar00crucialstaff000000 000000 SuperCollider source code SuperCollider-Source/platform/linux/icons/supercollider.png000644 000765 000024 00000010254 12321461511 025333 0ustar00crucialstaff000000 000000 PNG  IHDR00WbKGD pHYs  LIDAThZKlWv=U]H6M%Kd3ֻ +/b l*0Hfxm!mJTl]]]߮,EQ jv{9Wqe%(Z q<N A'B' e,0 qeIEdY(BP,;(&!!$_l6x<>/(3A.)RNR$H8#|wh4p]/^ĥKJ"Mk7~jE]M&8Oz y~3Je 2lFFBՂi<uy& q eOs7 !ޟ coUu4bZ\\H$!NNNnv1dYF:F>GP}Gh4p8ܹB4M{IZ$ 7޸ "AqFhZX\\ĥKP*dqݻv ˲0:,  T*$ (" C|g}63Z_WQV_BQh2cMӐH$˲T*assBX__1>&AQ18( HH&Pq4Mm|gwqRD_A8b dY~h cR)D"\.AihZd2j(JX]]E*Bp8D0dASi(pN4!2 *VVV|>M !!!$ ~׮]2`6Q,177t:`?d;;;(JpQ.V]בd<\ׅaGDӁeY$ bXZZbJ$EݶmxEQ(PV (X[[eYGZERA*ppp=T*<ӨT*Hp^FL&u\.\@ZE\F.(yv۷qu|'xꫯ""<8qDQ!߳n#c~~iݻXYY,,NNNpttNw6F˲q* ױJ9<ϒxxxo_}ܹ}q018h8 ,cnn5nt:l6~/ϟGVC.C>GF݆i$ BW\&VWWqsfF]u]X4a6ӶmI!ZA0LNÜ4M4MPׯ_ǧ~+WCXD>GR3s3V@Eض AaJ@^G݆m ƍ܄8<mq}믿6yx,HRDV:* t]G"aPUFfd((j @4._ 󰷷F0 Ad2yo# BAV(J]בL&q(BEE8yeq3Q% EQПyh6ۗ뺈i^CER)$ R)$ID"l6 MD)4&u@5@)1p۶!2s48Cǐ$}" C6pYi"QVK#!c9J!q?`օfBp]e^Cuj5q A{4K4MxW*yz̝>LO<MӘ )y&N< ^2 !iRvY YV88ü~4,ضx=LU$IbY.tVs2٦#,wO͇.CA, DO.EQd.D+@ۙΎ 0WeɄ}S L&Q,1m,˂eYPUuY:uBdYfJ;=ݳl63mD"_|V p]$D"~d2l6L&NkV6ң4@)DR4r$4MC2D:f${vbJa u_u]O&yppԷ~,--akk GGG(rm-)8KtH(JG\f_ttvoGbYdzβ, MӆsssfsP ,B^"2TUeNt(ՊiX^^ƹs簺Ba`mloocggfiqc. öm}MӾUUun/7MX,R0 ܽ{Z KKKE!YK/!bqq5(0F&x 0شJE>K} `M۶7ljvOUՍv-e2dYz=|x";Z?݉UUų>˚]^.Fǁa8>>F@DcMMUU>L%lHcZ-۶5MFѢiPU~!lZBlh4m۰m^tN9Ȳlj{}5;::2$E8nq܀x<AqLMMӟ&4'<"5[V !UU${7DZH)D yA!0  pgNO8^L̈Oj֧Y#t]/!~}}g`&4`s;Cj@+(ؘY@С?Cgj4'?*Pjc<( fx|*?*V@tk{s|?pjoIENDB`SuperCollider-Source/platform/linux/icons/supercollider.xpm000644 000765 000024 00000013372 12321461511 025357 0ustar00crucialstaff000000 000000 /* XPM */ static char *sc_cube_bw[] = { /* columns rows colors chars-per-pixel */ "32 32 231 2", " c black", ". c #010101", "X c gray1", "o c gray2", "O c gray3", "+ c #090909", "@ c gray4", "# c #0B0B0B", "$ c #0C0C0C", "% c gray5", "& c #0E0E0E", "* c gray6", "= c #101010", "- c #111111", "; c gray7", ": c #131313", "> c gray8", ", c #151515", "< c #161616", "1 c gray9", "2 c #181818", "3 c #191919", "4 c gray10", "5 c #1B1B1B", "6 c gray11", "7 c #1D1D1D", "8 c #1E1E1E", "9 c gray12", "0 c #202020", "q c gray13", "w c #222222", "e c #232323", "r c gray14", "t c #252525", "y c gray15", "u c #272727", "i c #282828", "p c gray16", "a c #2A2A2A", "s c gray17", "d c #2C2C2C", "f c #2D2D2D", "g c gray18", "h c #2F2F2F", "j c gray19", "k c #323232", "l c gray20", "z c #343434", "x c #353535", "c c #373737", "v c gray22", "b c #393939", "n c #3A3A3A", "m c gray23", "M c #3C3C3C", "N c gray24", "B c #3E3E3E", "V c #3F3F3F", "C c gray25", "Z c #414141", "A c gray26", "S c #434343", "D c #444444", "F c gray27", "G c #464646", "H c gray28", "J c #484848", "K c #494949", "L c gray29", "P c #4B4B4B", "I c #4C4C4C", "U c gray30", "Y c #4E4E4E", "T c gray31", "R c #505050", "E c #515151", "W c gray32", "Q c #535353", "! c gray33", "~ c #555555", "^ c #565656", "/ c gray34", "( c #585858", ") c gray35", "_ c #5A5A5A", "` c #5B5B5B", "' c gray36", "] c #5D5D5D", "[ c gray37", "{ c #5F5F5F", "} c #606060", "| c gray38", " . c #626262", ".. c gray39", "X. c #646464", "o. c #656565", "O. c gray40", "+. c #676767", "@. c #686868", "#. c DimGray", "$. c #6A6A6A", "%. c gray42", "&. c #6C6C6C", "*. c #6D6D6D", "=. c gray43", "-. c #6F6F6F", ";. c gray44", ":. c #717171", ">. c #727272", ",. c gray45", "<. c #747474", "1. c gray46", "2. c #767676", "3. c #777777", "4. c gray47", "5. c gray48", "6. c #7B7B7B", "7. c #7C7C7C", "8. c gray49", "9. c #7E7E7E", "0. c #7F7F7F", "q. c #808080", "w. c #818181", "e. c gray51", "r. c #838383", "t. c #848484", "y. c gray52", "u. c #868686", "i. c gray53", "p. c #888888", "a. c #898989", "s. c gray54", "d. c #8B8B8B", "f. c gray55", "g. c #8D8D8D", "h. c #8E8E8E", "j. c gray56", "k. c #909090", "l. c gray57", "z. c #929292", "x. c #939393", "c. c gray59", "v. c #979797", "b. c #989898", "n. c gray60", "m. c #9A9A9A", "M. c #9B9B9B", "N. c gray61", "B. c #9D9D9D", "V. c gray62", "C. c #9F9F9F", "Z. c #A0A0A0", "A. c gray63", "S. c #A2A2A2", "D. c gray64", "F. c #A4A4A4", "G. c #A5A5A5", "H. c gray65", "J. c #A7A7A7", "K. c gray66", "L. c #A9A9A9", "P. c #AAAAAA", "I. c gray67", "U. c #ACACAC", "Y. c gray68", "T. c #AEAEAE", "R. c gray69", "E. c #B1B1B1", "W. c #B2B2B2", "Q. c gray70", "!. c #B4B4B4", "~. c gray71", "^. c #B6B6B6", "/. c #B7B7B7", "(. c gray72", "). c #B9B9B9", "_. c gray73", "`. c #BBBBBB", "'. c #BCBCBC", "]. c gray", "[. c gray75", "{. c #C0C0C0", "}. c #C1C1C1", "|. c gray76", " X c #C3C3C3", ".X c gray77", "XX c #C5C5C5", "oX c #C6C6C6", "OX c gray78", "+X c #C8C8C8", "@X c gray79", "#X c #CACACA", "$X c #CBCBCB", "%X c gray80", "&X c #CECECE", "*X c gray81", "=X c #D0D0D0", "-X c gray82", ";X c #D2D2D2", ":X c LightGray", ">X c gray83", ",X c gray84", ".7.f.p.<.y.R.-X-X^.m.g.k.B.^.+X%X}.D.w.4.a.K.>XaXhXjXlX", "lX<.q.3 f ! { 1.f.i.>.4.B.%X5X$X;X2X{.M.r.8.g.~.4XuXgXhX6XXXpXlX", "lX*.9.q 7 < i A U =.f.y.-.%.d.E.z.2.1.b.}.7XsXgX8X!.w.F 8 ( qXlX", "lXO.8.i r s i 2 w j m +.f.t.%.6.K.=XiXdXwX+XF.7.[ H l i w ! 8 k.tX.] e K ( Q R F m o.H 2 { }.H.W | m.l.3.9.p.<.} k.^.#.h $.lX", "lX7 ;.X.0 b ! R Q P c .Y 1 ^ `.Y.) _ x.v.q.e.k.8.` i.`.>.a ' lX", "lX> =.$.9 i p v C m l { ! < Y Q.!.} ! f.B.v.b.h.>.^ 9.{.7.t T lX", "lX$ *.6...M z j i j h ] ` , F U.`.@.Y t.Z.x.w.*._ Y 2.oXy.q Z lX", "lXo L 4.<.5.+.U H v i _ | > N G.|.-.J <.0.X.Y G ! ;.A.#Xh.6 z lX", "lXlX% > H X.#.4.&.[ ) X.@.: z V.#X2.Z G L ( *.s.A./.@X>Xn.1 t lX", "lXlXlX% $ ; m T [ 3.>.;.=.; d v.=X9.B I X.a.U.OX3X;XT.8.M > 2 lX", "lXlXlXlX. # # * g n ! 2.2.- r k.X'.V.<.R b e : + $ lX", "lXlXlXlXlXlX # $ % 9 y J * 5 a.6X2X-X{.L.k.-.G u & + $ # lXlXlX", "lXlXlXlXlXlXlXlX. $ # @ ; $ : e.0X=XV.@.c = + @ # $ o lXlXlX", "lXlXlXlXlXlXlXlXlXlX. % $ O $ B S - + # # # X lXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlX. % * $ # @ . lXlXlXlXlXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlX lXlXlXlXlXlXlXlXlXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; SuperCollider-Source/platform/linux/examples/onetwoonetwo.sc000644 000765 000024 00000001154 12321461511 025551 0ustar00crucialstaff000000 000000 s = Server.local; "SC_JACK_DEFAULT_OUTPUTS".setenv("system:playback_1,system:playback_2"); s.waitForBoot({ SynthDef("onetwoonetwo", { var freqs, cycle, freq, rez, cut, sig; freqs = #[30, 40, 42, 38, 60, 40, 68, 50]; cycle = 0.5 * freqs.size; freq = Select.kr(LFSaw.kr(0.6,0,cycle,cycle),freqs); rez = SinOsc.kr(0.1,0,0.8,1); cut = SinOsc.kr(0.1,0.5,400,800); sig = Mix(CombN.ar(RLPF.ar(Saw.ar([freq.midicps, (freq+7.001).midicps],mul:0.5),cut,rez),1.2,1.2,3)); sig = Pan2.ar(sig, SinOsc.kr(0.6,mul:0.2)); Out.ar(0, sig); }).send(s, ["/s_new", "onetwoonetwo", -1, 1, s.asTarget.nodeID]); }); // EOFSuperCollider-Source/platform/disable_startup_files/extPlatform.sc000644 000765 000024 00000000051 12756531745 026717 0ustar00crucialstaff000000 000000 + Platform { loadStartupFiles {^this} } SuperCollider-Source/package/background.png000644 000765 000024 00000030052 12321461511 022071 0ustar00crucialstaff000000 000000 PNG  IHDRX)tEXtSoftwareAdobe ImageReadyqe</IDATx}{UUEy5@@!wA0J!EPk8EB$~`GAC &$ Q iYqDnj "i3~ks͵|\7oT5j|@W9_)0Ҥ-Y|OB9gP?_f +gX_ K쨅`B=߭&nu1Bj~2_HQfm 2qu>Djh%}02`im]lZGE  Rʊ00Ro+ވ0gB)3B1+Gn ],:WByXgUh?4m!AAd#Bc0"ܤD$p*qpH;M$ΊgRxWL`tB"@g5H3<_ݰknj28]n,$PmƊ.0P"/5b̪+2Sc-h  TâXtJXhn mvA:BLN1V;5jO߿Pp{n|cle>DU.64ZZ>Sf )͔>'3"4V\9ڟqᳶ]If). AFe qOBqmb8-;5^|bKwWqK*wP.[Z̔Z o F=ɆEpDBY&CL4ǞrtԘrKf*M%]MtCeYƀ"JiVa3ay 5JAtHǾm-֢пߞh@ʶZ~W6-vjLDM%bքYuL}6/qk]奍fgDצ6G\Vh,q,?vnX0s91B "ը,9>;{盅Dr^+[T#O轂D7n&; ,\_l/mDA凃nbDHA0"5N3"jk1aKD&ڐx'ʟ,/BJP",9g-[8nJ-CtzG[\z&ee:9-_0EC\X6ݎł8)1Lf̺,7ٙ(32"ed3 NQ ky琐Sq4 fʞR-d "`ר؂+2V{#8v CըeK{hF<"̈́4fzrl8@vD%C'jYF΋)˔3v;Ocu܏Һ‰P϶M)A,kaq;cEZ;gyvRsb TrF͸E]$ةu҆Ju_|l⍰.2ADbxV1'ipxGK)NQ{w:aA* ;,\-nBxGW'43Y&ڱH' M,yAӅ :}iX5'P/,'.cui%u#¢73c-ja,(i|Iq Ajk4Γ2Fr85jbUq[ӎpʷ+ )_԰r*+**U:kunMG5?|(0p.oG n(F TM-qc߁%ĭ:0[%[uŚe)!  tG>aKLy13fcר%Rޒ(1(&XϑKJAF|a(]E\],ٌe[JYJ\Ͷ?d-&]ءY. ;}2f1нÜp H5Ju wAaQ2'=xq{%|gK:z6=Gw%v2aP۰Z򲧲jrB-5vZڼ׍uؼb0R>MF)j^ m#U'˘)֘t8Σ'QΘW&x#¸BΈԣݍc-6:"rz:B "yΩ%6# Vpk[303+1dXY3i`ݎcv z]62;lyC_)s8%K®Q "pxA*η ι7<9{>Ma⩾FWV " 2iXG\?ם(Ĕr򶍵5L۪ nrd,⻱G[O܁ijFIF{>XFy3.sD -!c{;C$nlHiרCضbSF-d7Lw}Q1ݎhŮQHd0AN6>aY9H/]_h.zQ]*Ykq¾%ӯ Ruj%B:)!/QyƢDAlQ(qk(*=`^{vs,oS)9‰}'˸ZD"BgiK6y5^QeYN #633ckv|Ci$eAs4ÈPDHbdOg1LFGJJ/ KنA}4!A{Al;1DxA |2-2D{8=F0O˶D1x/V6ɶKA8IT CDWϒ!IڒMOcڜo2^-7V &OHB$1 )9Q!+K2(6c%:CDhgw+b۱.HBS-HFM(!wPV ?{(-MN+NN4ae a,XR)%0M=9ceٿI]/oj'j06oxѭȽCdn&l&eGnD)_Gh$;}NcfM tG&9®Q7p}Q: _oCxM OQJA:"H>J pnJvh* [މMm>5jui1!HQDd'26kq)Gl` U{DHsOAXMv&st,⺟DדJdbL ~ tGN:cZ`?c̗TArA B2 2,1 ŝ "BmJ F$A$Bx@~.I <gړdXK5R׬AIN$Bgg.@HRiO՘>]Ɋ¼A0"$#H,Y+,´]Pdk5vFJAt H5*?sj  ADQ !AA0"$ FAA"$ !AA#$ A  HAA"$~4,XSA"$͐ HA"$DH$B HA"$DHXk׮[N~Ϛ5m۶ݟ'{w7,p }G"$a"|Wv}hEݺu۴iӵkWf۝~QУ%KxV[Cu۷W ٿC uOJ|[*+6H."_rw&L~<8z#GlذDx _B 6EPE)Yc^z%$~D#f͚!  h;ӧ'G|j̘1dR< gϞ@rv0 G?F5F8sÇ#D# Ǐ' "uDn!s>,X$r @!Ut*MvD4mڴVZ pY7ƿl_',e!l޼s < +=wo6!A$ Q@7d00LE}Fmƍ+ :#۷ow5{ӧO]Gs=|@Z P=z~ovń@;w?2xצM槊rF=Jʁ7ahBc>hp~zP<s=J5Fd"ٳ3 %1>}DS7%wbQQÐv =l޼Y,f`#<5; (\MO){onݔҢd~!ZP5kt ӌ=Zxbu M+x(}x{[zQX+VV5dC<8X{ nc=7oD6mxԨQ Y>W1b8ux#fηm0P%E3Tzx衇  Ux?F8p\~^z@ȉjT$?x RRzԢ2d ! 0#~L4 NgN+I"R y(|.&Y#B0Rhx6Q\`y9F`z=ks=7|Gz^A&?V@ҽKhU>YLFÎ+3CLM 4\#"3"a귪az*ȧ HޫW/5OVkqz şșg k(O"G[R)x$rlDD@7Q2 v :(&u˖-ArUUM:U폏j#ܹP#Co}I&҇bku,[P(˗oذVZcǎs@BU*/(qd6 ,\S+.]vZh.7 ;6n܈D/|=`}RuE$*p:|$>, J >%X;gh,gO}$vE= "]ve3hΰ!W_}5^>ah/fc_ )p`g"+.\[Q:ŪUo0_$C͙N>}~T\u%^9ș\DU -/'#;)\X2@$ kxv.\w`.a֒ J/x-9^Qxr'+(So$% 8n82Ȫr o[o^+?هaRůGh[pV``Yg%:[E<&B ` 4D`Qdmڴy ( ZeeԐMЩS'8@HS]GVUU95&VD?яxb .*-|eg1I ,5M> "P>@:+Wࣈi0Hb6mo<B1 JԬYk+7og{o|}2^ Jd"*(D>ap )+Uf'W d!G}Lv=J5?;^_9JGp =h3,xb_~ot8d3آh7'` IG"|?s&NGj%$5X+qqQС~Ϟ=pp]csL>] =ꧪHx%-rBpArs\'CxnZ^=ȩl_Cfdޜ ޽{wr*ĉ3f8s2xeTK..)N!EĂ_<8 L<5"@&F R0b胮5jJ HAXf̘ W/eWj+t2zC8&3gԙ~4ڈ"BRgtTQQle':'I믗(#aTVVF*Zfl䛖V'^$G xe@`q 4Sy&nu 7oެDb0` 8V q_*I> 3Y0ov~5dxzjd ίH!gvUHk_( _NB"BFNT߿?J BIvÇ4i ڵk}/νIy_|9@۶mQ=z@h"j5*j)UU[^GfYF_&BC_>QChy=f yDz)t>+Yf)̼^(䌥EQ8 !C~9C}c*[)$E*Y,t9,3_dL>׏Ο?_]у,#q'`ј7oT\rr<8(" D޽;)(54I铼a6n܈I3b9s<z*\me.ņ l@QL׭[{Td!-*5J*g۹sTj+F?f[[)"#ؘ9k|"DK n:#QTA2pt^x>"D9ߤISPGaY7,'Baj /K'XiӦɄسgOaߨDT,rzi9[ҁUht {مO"P1(pժU[lAv>5U⒜-4SZ+jLڵW^,^瞻3s~B\yZ R @կ~ b-[o^\(利>B<~]vDBixbҀRV6M6lrPdnXp$h3+cW%7B=8py3{ DbRqx^W_}u Wz" ڝzːd@$DUweObϳ,nDP>*`e fE.ڦMYOؽ{wmР<&5/U3f%\t.] l׮ͧ.?堰nݺ _-*hJxBg]z'F! ]x ,@ <~ ^{$ȮƠ"_׉̋4h|ܹBIv){xLJ  Ŵo>(# KVPz/"o ґ͙mLqWw'S K&"MiTf͚*P^K:p_s\kTA)(_4 m^yYG+cO>}qSAaNԒޢ'U^X~;7Q}* 4V@"_NGp.\t' ē'zQ_U9[@yyC ,Bc%T {"!p#/IらXjՌ3r4ZXH qev pվW8(σxjwޜ ԩSG K.y9;$[x 1" oD̚SR!X@ 7o~7oٲ*WD?O:YʻF jCz@Twڥʜ-Z*=*;Db : Y]}1g}{ 9Oj#tXi#~aOyZd:g hݺ-\dFg,GI?OWVV]}do#| =d! j֬ C֔l2Z"FA'93y*B)X? A&pɒ%>HJi {إQV>;/_@ƢQt^?cg* ڏ:׭,GlP#H}HAJx@9 0Ee,I])!5N*3p"$ ;bXQH Zbe"!Aiw HXDH HAp HA"L|&84j(]RFC HVUUG$B RD&&2A"$"]DH$B r]wE-A DHA$B  AD*PAA DHA$B H8FHA0"$ FA  HA"SuperCollider-3.5.beta-OSX.dmgOSX2Users/lijon/Desktop/SuperCollider-3.5.beta-OSX.dmg/ #@,#?#?#@#@Tnone #@H)2H_h}%&/1:CLMOTUV_.icvtshor .pictblob22 SuperCollider7ɭH+background.png<*  SuperCollider7<SuperCollider:background.pngbackground.png SuperCollider/background.png/Volumes/SuperCollider Macintosh HDE:H+SuperCollider-3.5beta1-10.5.dmg< Ny mapp 2E<տHHpuLMacintosh HD:Users:ifields:Desktop:Ny mapp 2:SuperCollider-3.5beta1-10.5.dmg@SuperCollider-3.5beta1-10.5.dmg Macintosh HD?Users/ifields/Desktop/Ny mapp 2/SuperCollider-3.5beta1-10.5.dmg/.vstltype .backgroundfwi0blobdWicnv .backgroundfwvhshor~ ApplicationsIlocblob5background.pngIlocblob 4L@ SuperColliderIlocblob4 E DSDB `(0@ @ @top:SuperCollider-3.5.beta-OSX.dmg>SuperCollider-3.5.beta-OSX.dmgOSX2Users/lijon/Desktop/SuperCollider-3.5.beta-OSX.dmg/ #@,#?#?#@#@Tnone #@H)2H_h}%&/1:CLMOTUV_.icvtshor .pictblob22 SuperCollider7ɭH+background.png<*  SuperCollider7<SuperCollider:background.pngbackground.png SuperCollider/background.png/Volumes/SuperCollider Macintosh HDE:H+SuperCollider-Source/package/git-archive-all.py000644 000765 000024 00000015604 12727214752 022611 0ustar00crucialstaff000000 000000 #! /usr/bin/env python import sys from os import path, chdir from subprocess import Popen, PIPE from sys import argv, stdout from fnmatch import fnmatch class GitArchiver(object): """ GitArchiver Scan a git repository and export all tracked files, and submodules. Checks for .gitattributes files in each directory and uses 'export-ignore' pattern entries for ignore files in the archive. Automatically detects output format extension: zip, tar, bz2, or gz """ def __init__(self, prefix='', verbose=False, exclude=True, force_sub=False, extra=[]): self.prefix = prefix self.verbose = verbose self.exclude = exclude self.extra = extra self.force_sub = force_sub self._excludes = [] def create(self, output_file): """ create(str output_file) -> None Creates the archive, written to the given output_file Filetype may be one of: gz, zip, bz2, tar, tgz """ # # determine the format # _, _, format = output_file.rpartition(".") format = format.lower() if format == 'zip': from zipfile import ZipFile, ZIP_DEFLATED output_archive = ZipFile(path.abspath(output_file), 'w') add = lambda name, arcname: output_archive.write(name, self.prefix + arcname, ZIP_DEFLATED) elif format in ['tar', 'bz2', 'gz', 'tgz']: import tarfile if format == 'tar': t_mode = 'w' elif format == 'tgz': t_mode = 'w:gz' else: t_mode = ('w:%s' % format) output_archive = tarfile.open(path.abspath(output_file), t_mode) add = lambda name, arcname: output_archive.add(name, self.prefix + arcname) else: raise RuntimeError("Unknown format: '%s'" % format) # # compress # # extra files first (we may change folder later) for name in self.extra: if self.verbose: toPath = '=> %s%s' % (self.prefix, name) if self.prefix else "" print 'Compressing %s %s ...' % (name, toPath) add(name, name) self._excludes = [] for name, arcname in self.listFiles(path.abspath('')): if self.verbose: toPath = '=> %s%s' % (self.prefix, arcname) if self.prefix else "" print 'Compressing %s %s ...' % (arcname, toPath) add(name, arcname) output_archive.close() def listFiles(self, git_repositary_path, baselevel=''): """ listFiles(str git_repository_path, str baselevel='') -> iterator An iterator method that yields a tuple(filepath, fullpath) for each file that should be included in the archive. Skips those that match the exclusion patterns found in any discovered .gitattributes files along the way. Recurses into submodules as well. """ for filepath in self.runShell('git ls-files --cached --full-name --no-empty-directory'): filepath = filepath.decode('string_escape').strip('"') fullpath = path.join(baselevel, filepath) filename = path.basename(filepath) if self.exclude and filename == '.gitattributes': self._excludes = [] fh = open(filepath, 'r') for line in fh: if not line: break tokens = line.strip().split() if 'export-ignore' in tokens[1:]: self._excludes.append(tokens[0]) fh.close() # Only list symlinks and files that don't start with git if not filename.startswith('.git') \ and (path.islink(filepath) or not path.isdir(filepath)): # check the patterns first ignore = False for pattern in self._excludes: if fnmatch(fullpath, pattern) or fnmatch(filename, pattern): if self.verbose: print 'Exclude pattern matched (%s): %s' % (pattern, fullpath) ignore = True break if ignore: continue # baselevel is needed to tell the arhiver where it have to extract file yield filepath, fullpath if self.force_sub : self.runShell("git submodule init") self.runShell("git submodule update") # get paths for every submodule for submodule in self.runShell("git submodule --quiet foreach 'pwd'"): chdir(submodule) # in order to get output path we need to exclude repository path from the submodule path submodule = submodule[len(git_repositary_path)+1:] # recursion allows us to process repositories with more than one level of submodules for git_file in self.listFiles(git_repositary_path, submodule): yield git_file @staticmethod def runShell(cmd): return Popen(cmd, shell=True, stdout=PIPE).stdout.read().splitlines() if __name__ == "__main__": from optparse import OptionParser parser = OptionParser(usage="usage: %prog [-v] [--prefix PREFIX] [--no-exclude] OUTPUT_FILE", version="%prog 1.3") parser.add_option('--prefix', type='string', dest='prefix', default='', help="prepend PREFIX to each filename in the archive") parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='enable verbose mode') parser.add_option('--no-exclude', action='store_false', dest='exclude', default=True, help="Don't read .gitattributes files for patterns containing export-ignore attrib") parser.add_option('--force-submodules', action='store_true', dest='force_sub', help="Force a git submodule init && git submodule update at each level before iterating submodules.") parser.add_option('--extra', action='append', dest='extra', default=[], help="Any additional files to include in the archive.") options, args = parser.parse_args() if len(args) != 1: parser.error('You must specify exactly one output file') outFile = args[0] if path.isdir(outFile): parser.error('You cannot use directory as output') archiver = GitArchiver(options.prefix, options.verbose, options.exclude, options.force_sub, options.extra) try: archiver.create(outFile) except Exception, e: parser.exit(2, "%s\n" % e) sys.exit(0) SuperCollider-Source/package/git-archive-all.sh000755 000765 000024 00000013246 12321461511 022561 0ustar00crucialstaff000000 000000 #!/bin/bash - # # File: git-archive-all.sh # # Description: A utility script that builds an archive file(s) of all # git repositories and submodules in the current path. # Useful for creating a single tarfile of a git super- # project that contains other submodules. # # Examples: Use git-archive-all.sh to create archive distributions # from git repositories. To use, simply do: # # cd $GIT_DIR; git-archive-all.sh # # where $GIT_DIR is the root of your git superproject. # DEBUGGING set -e set -C # noclobber # TRAP SIGNALS trap 'cleanup' QUIT EXIT # For security reasons, explicitly set the internal field separator # to newline, space, tab OLD_IFS=$IFS IFS=' ' function cleanup () { rm -f $TMPFILE rm -f $TOARCHIVE IFS="$OLD_IFS" } function usage () { echo "Usage is as follows:" echo echo "$PROGRAM <--version>" echo " Prints the program version number on a line by itself and exits." echo echo "$PROGRAM <--usage|--help|-?>" echo " Prints this usage output and exits." echo echo "$PROGRAM [--format ] [--prefix ] [--separate|-s] [output_file]" echo " Creates an archive for the entire git superproject, and its submodules" echo " using the passed parameters, described below." echo echo " If '--format' is specified, the archive is created with the named" echo " git archiver backend. Obviously, this must be a backend that git-archive" echo " understands. The format defaults to 'tar' if not specified." echo echo " If '--prefix' is specified, the archive's superproject and all submodules" echo " are created with the prefix named. The default is to not use one." echo echo " If '--separate' or '-s' is specified, individual archives will be created" echo " for each of the superproject itself and its submodules. The default is to" echo " concatenate individual archives into one larger archive." echo echo " If 'output_file' is specified, the resulting archive is created as the" echo " file named. This parameter is essentially a path that must be writeable." echo " When combined with '--separate' ('-s') this path must refer to a directory." echo " Without this parameter or when combined with '--separate' the resulting" echo " archive(s) are named with a dot-separated path of the archived directory and" echo " a file extension equal to their format (e.g., 'superdir.submodule1dir.tar')." } function version () { echo "$PROGRAM version $VERSION" } # Internal variables and initializations. readonly PROGRAM=`basename "$0"` readonly VERSION=0.2 OLD_PWD="`pwd`" TMPDIR=${TMPDIR:-/tmp} TMPFILE=`mktemp "$TMPDIR/$PROGRAM.XXXXXX"` # Create a place to store our work's progress TOARCHIVE=`mktemp "$TMPDIR/$PROGRAM.toarchive.XXXXXX"` OUT_FILE=$OLD_PWD # assume "this directory" without a name change by default SEPARATE=0 FORMAT=tar PREFIX= TREEISH=HEAD # RETURN VALUES/EXIT STATUS CODES readonly E_BAD_OPTION=254 readonly E_UNKNOWN=255 # Process command-line arguments. while test $# -gt 0; do case $1 in --format ) shift FORMAT="$1" shift ;; --prefix ) shift PREFIX="$1" shift ;; --separate | -s ) shift SEPARATE=1 ;; --version ) version exit ;; -? | --usage | --help ) usage exit ;; -* ) echo "Unrecognized option: $1" >&2 usage exit $E_BAD_OPTION ;; * ) break ;; esac done if [ ! -z "$1" ]; then OUT_FILE="$1" shift fi # Validate parameters; error early, error often. if [ $SEPARATE -eq 1 -a ! -d $OUT_FILE ]; then echo "When creating multiple archives, your destination must be a directory." echo "If it's not, you risk being surprised when your files are overwritten." exit elif [ `git config -l | grep -q '^core\.bare=false'; echo $?` -ne 0 ]; then echo "$PROGRAM must be run from a git working copy (i.e., not a bare repository)." exit fi # Create the superproject's git-archive git archive --format=$FORMAT --prefix="$PREFIX" $TREEISH > $TMPDIR/$(basename $(pwd)).$FORMAT echo $TMPDIR/$(basename $(pwd)).$FORMAT >| $TMPFILE # clobber on purpose superfile=`head -n 1 $TMPFILE` # find all '.git' dirs, these show us the remaining to-be-archived dirs find . -name '.git' -type d -print | sed -e 's/^\.\///' -e 's/\.git$//' | grep -v '^$' >> $TOARCHIVE while read path; do TREEISH=$(git submodule | grep "^ .*${path%/} " | cut -d ' ' -f 2) # git-submodule does not list trailing slashes in $path cd "$path" git archive --format=$FORMAT --prefix="${PREFIX}$path" ${TREEISH:-HEAD} > "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT if [ $FORMAT == 'zip' ]; then # delete the empty directory entry; zipped submodules won't unzip if we don't do this zip -d "$(tail -n 1 $TMPFILE)" "${PREFIX}${path%/}" >/dev/null # remove trailing '/' fi echo "$TMPDIR"/"$(echo "$path" | sed -e 's/\//./g')"$FORMAT >> $TMPFILE cd "$OLD_PWD" done < $TOARCHIVE # Concatenate archives into a super-archive. if [ $SEPARATE -eq 0 ]; then if [ $FORMAT == 'tar' ]; then sed -e '1d' $TMPFILE | while read file; do tar --concatenate -f "$superfile" "$file" && rm -f "$file" done elif [ $FORMAT == 'zip' ]; then sed -e '1d' $TMPFILE | while read file; do # zip incorrectly stores the full path, so cd and then grow cd `dirname "$file"` zip -g "$superfile" `basename "$file"` && rm -f "$file" done cd "$OLD_PWD" fi echo "$superfile" >| $TMPFILE # clobber on purpose fi while read file; do mv "$file" "$OUT_FILE" done < $TMPFILE SuperCollider-Source/package/OPTIONALS_README_OSX.rtf000644 000765 000024 00000003551 12321461511 023103 0ustar00crucialstaff000000 000000 {\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf480 {\fonttbl\f0\fnil\fcharset77 LucidaGrande-Bold;\f1\fnil\fcharset77 LucidaGrande;\f2\fnil\fcharset77 Monaco; } {\colortbl;\red255\green255\blue255;} \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural \f0\b\fs36 \cf0 Installation Instructions \f1\b0\fs24 \ \ \f0\b\fs26 Quarks \f1\b0\fs24 \ \ Quarks are the standard method for handling the distribution of class library extensions.\ \ 1) To install for one user move the \f2\fs22 quarks \f1\fs24 directory to \f2\fs22 ~/Library/Application Support/SuperCollider \f1\fs24 . To install for all users, move the \f2\fs22 quarks \f1\fs24 directory to \f2\fs22 /Library/Application Support/SuperCollider \f1\fs24 .\ NOTE: you might see a folder called " \f2\fs22 Extensions \f1\fs24 " but \f0\b DON'T \f1\b0 put the quarks directory directly in there!\ \ 2) From within the SuperCollider application, follow the steps outlined inside the Quarks helpfile to actually install a Quark. You do NOT need to download the quarks (you already have), at this point, you should be able to start installing Quarks by running:\ \ Quarks.gui\ \fs22 \ \ \f0\b\fs26 sc3-plugins \f1\b0\fs22 \ \fs24 \ sc3-plugins are some of the more common extension libraries, maintained at:\ \ {\field{\*\fldinst{HYPERLINK "http://sourceforge.net/projects/sc3-plugins/"}}{\fldrslt http://sourceforge.net/projects/sc3-plugins/}}\ \ 1) Move the \f2\fs22 sc3-plugin-extensions \f1\fs24 folder to \f2\fs22 ~/Library/Application Support/SuperCollider/Extensions \f1\fs24 , creating any necessary directories.\ \ 2) Restart SuperCollider.\ \ \ \f0\b\fs26 SwingOSC\ \ \f1\b0\fs24 SwingOSC is a system for creating graphical user interfaces using Java. To install it, follow the SwingOSC installation instructions in SwingOSC/SuperCollider/readme.html.}SuperCollider-Source/package/OPTIONALS_README_SOURCE.txt000644 000765 000024 00000002274 12321461511 023457 0ustar00crucialstaff000000 000000 INSTALLATION INSTRUCTIONS ------------------------- QUARKS ------ Quarks are the standard method for handling the distribution of class library extensions. 1) To install for one user move the quarks directory to "~/share/SuperCollider". To install for all users, move the quarks directory to "/usr/local/share/SuperCollider". NOTE: you might see a folder called "Extensions" but DON'T put the quarks directory directly in there! 2) Follow the steps outlined inside the Quarks helpfile to actually install a Quark.You do NOT need to download the quarks (you already have), at this point, you should be able to start installing Quarks by running: Quarks.gui SC3-PLUGINS ----------- sc3-plugins are some of the more common extension libraries, maintained at: http://sourceforge.net/projects/sc3-plugins/ 1) Execute "scons ./distro_linux" in the sc3-plugin-extensions folder and move the "./sc3-plugin-extensions/Extensions" folder to "~/share/SuperCollider/Extensions". 2) Restart SuperCollider. SWINGOSC -------- SwingOSC is a system for creating graphical user interfaces using Java. To install it, follow the SwingOSC installation instructions in "SwingOSC/SuperCollider/readme.html". SuperCollider-Source/package/package000755 000765 000024 00000011211 12756531745 020604 0ustar00crucialstaff000000 000000 #!/bin/bash basename=`basename $PWD` if [ $basename != "package" ]; then echo "This script must be ran from within the 'package' directory." exit 1 fi version=`date "+%Y-%m-%d"` include_optionals=false if [ `uname` = 'Darwin' ]; then package_type="osx" else package_type="source" fi while getopts ":v:os" Option do case $Option in v ) version=$OPTARG ;; o ) include_optionals=true ;; s ) package_type="source" ;; esac done shift $(($OPTIND - 1)) revision=`git rev-list HEAD -1 | sed -E 's/([[:alnum:]]{1,10}).*/\1/'` if [ "`git status -s -uno`" != "" ]; then echo "WARNING: The working copy has uncommitted changes which will NOT be included in the package." fi if [ $package_type == "source" ]; then if [ -d SuperCollider-Source ]; then echo "Please remove the ./SuperCollider-Source directory before running this script." exit 1 fi returndir=`pwd` cd ../ python package/git-archive-all.py --prefix SuperCollider-Source/ "$returndir/SuperCollider-Source.tmp.tar" cd "$returndir" # NB we only need one instance of boost, so we exclude one of its two appearances as a submodule in the following tar -x --exclude ".gitignore" --exclude ".gitmodules" \ --exclude "SuperCollider-Source/external_libraries/nova-tt/boost_lockfree" \ -f SuperCollider-Source.tmp.tar if $include_optionals; then cp -Rp optional SuperCollider-Source/optional_installs cp OPTIONALS_README_SOURCE.txt SuperCollider-Source/optional_installs/README.txt filename="SuperCollider-$version-Source-With-Extras.tar.bz2" filenamelinux="SuperCollider-$version-Source-With-Extras-linux.tar.bz2" else filename="SuperCollider-$version-Source.tar.bz2" filenamelinux="SuperCollider-$version-Source-linux.tar.bz2" fi # Here we build a list of (many) files that are useless on linux, so as to build a slimline source.tar.bz2 find SuperCollider-Source -iname windows -or -iname osx -or -name "*.xcodeproj" -or -name scide_scapp -or -iname "iPhone*" \ | grep -v "external_libraries/boost/boost/asio/windows" > LinuxExclusions.txt echo 'SuperCollider-Source/README_OS_X.md SuperCollider-Source/README_WINDOWS.md SuperCollider-Source/README_IPHONE.md SuperCollider-Source/README_JAILBROKEN_IPHONE.md SuperCollider-Source/external_libraries/libsndfile SuperCollider-Source/external_libraries/curl SuperCollider-Source/external_libraries/icu SuperCollider-Source/platform/mac SuperCollider-Source/platform/iphone SuperCollider-Source/platform/windows SuperCollider-Source/lang/LangPrimSource/HID_Utilities SuperCollider-Source/lang/LangPrimSource/WiiMote_OSX' >> LinuxExclusions.txt tar cfj "$filename" SuperCollider-Source tar cfjX "$filenamelinux" LinuxExclusions.txt SuperCollider-Source rm -rf SuperCollider-Source SuperCollider-Source.tmp.tar exit else if [ -d SuperCollider ]; then echo "Please remove the ./SuperCollider directory before running this script." exit 1 fi if $include_optionals; then opt_options='--copy dmg_with_optionals.ds_store:/.DS_Store --copy optional/:/Optional\ Installs --copy OPTIONALS_README_OSX.rtf:/Optional\ Installs/README.rtf' filename="SuperCollider-$version-With-Extras.dmg" else opt_options='--copy dmg_without_optionals.ds_store:/.DS_Store' filename="SuperCollider-$version.dmg" fi about_version="$version (Revision $revision)" echo "About box version string:" $about_version mkdir -p SuperCollider/plugins returndir=`pwd` cd ../platform/mac/build git archive $revision | tar -x -C "$returndir/SuperCollider" cp -R SuperCollider.app scsynth sclang "$returndir/SuperCollider/" cp plugins/* "$returndir/SuperCollider/plugins/" cd $returndir cd ../ cp -R ChangeLog COPYING examples Help SCClassLibrary README sounds "$returndir/SuperCollider/" cd $returndir find SuperCollider/Help/ \( -name "*.htm" -or -name "*.html" \) -exec /Developer/Tools/SetFile -c SCjm {} \; defaults write $PWD/SuperCollider/SuperCollider.app/Contents/Info CFBundleVersion -string "$about_version" defaults write $PWD/SuperCollider/SuperCollider.app/Contents/Info CFBundleGetInfoString -string "$version" plutil -convert xml1 $PWD/SuperCollider/SuperCollider.app/Contents/Info.plist # use eval to force any escapes or quotes in $opt_options to be evaluated eval './pkg-dmg --verbosity 0 --source ./SuperCollider --target "$filename" --sourcefile --volname SuperCollider --mkdir /.background --copy background.png:/.background/background.png --symlink /Applications:/Applications '$opt_options rm -rf ./SuperCollider fi SuperCollider-Source/package/pkg-dmg000755 000765 000024 00000143644 12321461511 020534 0ustar00crucialstaff000000 000000 #!/usr/bin/perl # ***** BEGIN LICENSE BLOCK ***** # Version: MPL 1.1/GPL 2.0/LGPL 2.1 # # The contents of this file are subject to the Mozilla Public License Version # 1.1 (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # http://www.mozilla.org/MPL/ # # Software distributed under the License is distributed on an "AS IS" basis, # WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License # for the specific language governing rights and limitations under the # License. # # The Original Code is pkg-dmg, a Mac OS X disk image (.dmg) packager # # The Initial Developer of the Original Code is # Mark Mentovai . # Portions created by the Initial Developer are Copyright (C) 2005 # the Initial Developer. All Rights Reserved. # # Contributor(s): # # Alternatively, the contents of this file may be used under the terms of # either the GNU General Public License Version 2 or later (the "GPL"), or # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), # in which case the provisions of the GPL or the LGPL are applicable instead # of those above. If you wish to allow use of your version of this file only # under the terms of either the GPL or the LGPL, and not to allow others to # use your version of this file under the terms of the MPL, indicate your # decision by deleting the provisions above and replace them with the notice # and other provisions required by the GPL or the LGPL. If you do not delete # the provisions above, a recipient may use your version of this file under # the terms of any one of the MPL, the GPL or the LGPL. # # ***** END LICENSE BLOCK ***** use strict; use warnings; =pod =head1 NAME B - Mac OS X disk image (.dmg) packager =head1 SYNOPSIS B B<--source> I B<--target> I [B<--format> I] [B<--volname> I] [B<--tempdir> I] [B<--mkdir> I] [B<--copy> I[:I]] [B<--symlink> I[:I]] [B<--license> I] [B<--resource> I] [B<--icon> I] [B<--attribute> I:I[:I...] [B<--idme>] [B<--sourcefile>] [B<--verbosity> I] [B<--dry-run>] =head1 DESCRIPTION I takes a directory identified by I and transforms it into a disk image stored as I. The disk image will occupy the least space possible for its format, or the least space that the authors have been able to figure out how to achieve. =head1 OPTIONS =over 5 ==item B<--source> I Identifies the directory that will be packaged up. This directory is not touched, a copy will be made in a temporary directory for staging purposes. See B<--tempdir>. ==item B<--target> I The disk image to create. If it exists and is not in use, it will be overwritten. If I already contains a suitable extension, it will be used unmodified. If no extension is present, or the extension is incorrect for the selected format, the proper extension will be added. See B<--format>. ==item B<--format> I The format to create the disk image in. Valid values for I are: - UDZO - zlib-compressed, read-only; extension I<.dmg> - UDBZ - bzip2-compressed, read-only; extension I<.dmg>; create and use on 10.4 ("Tiger") and later only - UDRW - read-write; extension I<.dmg> - UDSP - read-write, sparse; extension I<.sparseimage> UDZO is the default format. See L for a description of these formats. =item B<--volname> I The name of the volume in the disk image. If not specified, I defaults to the name of the source directory from B<--source>. =item B<--tempdir> I A temporary directory to stage intermediate files in. I must have enough space available to accommodate twice the size of the files being packaged. If not specified, defaults to the same directory that the I is to be placed in. B will remove any temporary files it places in I. =item B<--mkdir> I Specifies a directory that should be created in the disk image. I and any ancestor directories will be created. This is useful in conjunction with B<--copy>, when copying files to directories that may not exist in I. B<--mkdir> may appear multiple times. =item B<--copy> I[:I] Additional files to copy into the disk image. If I is specified, I is copied to the location I identifies, otherwise, I is copied to the root of the new volume. B<--copy> provides a way to package up a I by adding files to it without modifying the original I. B<--copy> may appear multiple times. This option is useful for adding .DS_Store files and window backgrounds to disk images. =item B<--symlink> I[:I] Like B<--copy>, but allows symlinks to point out of the volume. Empty symlink destinations are interpreted as "like the source path, but inside the dmg" This option is useful for adding symlinks to external resources, e.g. to /Applications. =item B<--license> I A plain text file containing a license agreement to be displayed before the disk image is mounted. English is the only supported language. To include license agreements in other languages, in multiple languages, or to use formatted text, prepare a resource and use L<--resource>. =item B<--resource> I A resource file to merge into I. If I is UDZO or UDBZ, the disk image will be flattened to a single-fork file that contains the resource but may be freely transferred without any special encodings. I must be in a format suitable for L. See L for a description of the format, and L for a discussion on flattened disk images. B<--resource> may appear multiple times. This option is useful for adding license agreements and other messages to disk images. =item B<--icon> I Specifies an I file that will be used as the icon for the root of the volume. This file will be copied to the new volume and the custom icon attribute will be set on the root folder. =item B<--attribute> I:I[:I...] Sets the attributes of I to the attribute list in I. See L =item B<--idme> Enable IDME to make the disk image "Internet-enabled." The first time the image is mounted, if IDME processing is enabled on the system, the contents of the image will be copied out of the image and the image will be placed in the trash with IDME disabled. =item B<--sourcefile> If this option is present, I is treated as a file, and is placed as a file within the volume's root folder. Without this option, I is treated as the volume root itself. =item B<--verbosity> I Adjusts the level of loudness of B. The possible values for I are: 0 - Only error messages are displayed. 1 - Print error messages and command invocations. 2 - Print everything, including command output. The default I is 2. =item B<--dry-run> When specified, the commands that would be executed are printed, without actually executing them. When commands depend on the output of previous commands, dummy values are displayed. =back =head1 NON-OPTIONS =over 5 =item Resource forks aren't copied. =item The root folder of the created volume is designated as the folder to open when the volume is mounted. See L. =item All files in the volume are set to be world-readable, only writable by the owner, and world-executable when appropriate. All other permissions bits are cleared. =item When possible, disk images are created without any partition tables. This is what L refers to as I<-layout NONE>, and saves a handful of kilobytes. The alternative, I, contains a partition table that is not terribly handy on disk images that are not intended to represent any physical disk. =item Read-write images are created with journaling off. Any read-write image created by this tool is expected to be transient, and the goal of this tool is to create images which consume a minimum of space. =back =head1 EXAMPLE pkg-dmg --source /Applications/DeerPark.app --target ~/DeerPark.dmg --sourcefile --volname DeerPark --icon ~/DeerPark.icns --mkdir /.background --copy DeerParkBackground.png:/.background/background.png --copy DeerParkDSStore:/.DS_Store --symlink /Applications:"/Drag to here" =head1 REQUIREMENTS I has been tested with Mac OS X releases 10.2 ("Jaguar") through 10.4 ("Tiger"). Certain adjustments to behavior are made depending on the host system's release. Mac OS X 10.3 ("Panther") or later are recommended. =head1 LICENSE MPL 1.1/GPL 2.0/LGPL 2.1. Your choice. =head1 AUTHOR Mark Mentovai =head1 SEE ALSO L, L, L, L, L, L, L =cut use Fcntl; use POSIX; use Getopt::Long; sub argumentEscape(@); sub cleanupDie($); sub command(@); sub commandInternal($@); sub commandInternalVerbosity($$@); sub commandOutput(@); sub commandOutputVerbosity($@); sub commandVerbosity($@); sub copyFiles($@); sub diskImageMaker($$$$$$$$); sub giveExtension($$); sub hdidMountImage($@); sub isFormatCompressed($); sub licenseMaker($$); sub pathSplit($); sub setAttributes($@); sub trapSignal($); sub usage(); # Variables used as globals my(@gCleanup, %gConfig, $gDarwinMajor, $gDryRun, $gVerbosity); # Use the commands by name if they're expected to be in the user's # $PATH (/bin:/sbin:/usr/bin:/usr/sbin). Otherwise, go by absolute # path. These may be overridden with --config. %gConfig = ('cmd_bless' => 'bless', 'cmd_chmod' => 'chmod', 'cmd_diskutil' => 'diskutil', 'cmd_du' => 'du', 'cmd_hdid' => 'hdid', 'cmd_hdiutil' => 'hdiutil', 'cmd_mkdir' => 'mkdir', 'cmd_mktemp' => 'mktemp', 'cmd_Rez' => '/Developer/Tools/Rez', 'cmd_rm' => 'rm', 'cmd_rsync' => 'rsync', 'cmd_SetFile' => '/Developer/Tools/SetFile', # create_directly indicates whether hdiutil create supports # -srcfolder and -srcdevice. It does on >= 10.3 (Panther). # This is fixed up for earlier systems below. If false, # hdiutil create is used to create empty disk images that # are manually filled. 'create_directly' => 1, # If hdiutil attach -mountpoint exists, use it to avoid # mounting disk images in the default /Volumes. This reduces # the likelihood that someone will notice a mounted image and # interfere with it. Only available on >= 10.3 (Panther), # fixed up for earlier systems below. # # This is presently turned off for all systems, because there # is an infrequent synchronization problem during ejection. # diskutil eject might return before the image is actually # unmounted. If pkg-dmg then attempts to clean up its # temporary directory, it could remove items from a read-write # disk image or attempt to remove items from a read-only disk # image (or a read-only item from a read-write image) and fail, # causing pkg-dmg to abort. This problem is experienced # under Tiger, which appears to eject asynchronously where # previous systems treated it as a synchronous operation. # Using hdiutil attach -mountpoint didn't always keep images # from showing up on the desktop anyway. 'hdiutil_mountpoint' => 0, # hdiutil makehybrid results in optimized disk images that # consume less space and mount more quickly. Use it when # it's available, but that's only on >= 10.3 (Panther). # If false, hdiutil create is used instead. Fixed up for # earlier systems below. 'makehybrid' => 1, # hdiutil create doesn't allow specifying a folder to open # at volume mount time, so those images are mounted and # their root folders made holy with bless -openfolder. But # only on >= 10.3 (Panther). Earlier systems are out of luck. # Even on Panther, bless refuses to run unless root. # Fixed up below. 'openfolder_bless' => 1, # It's possible to save a few more kilobytes by including the # partition only without any partition table in the image. # This is a good idea on any system, so turn this option off. # # Except it's buggy. "-layout NONE" seems to be creating # disk images with more data than just the partition table # stripped out. You might wind up losing the end of the # filesystem - the last file (or several) might be incomplete. 'partition_table' => 1, # To create a partition table-less image from something # created by makehybrid, the hybrid image needs to be # mounted and a new image made from the device associated # with the relevant partition. This requires >= 10.4 # (Tiger), presumably because earlier systems have # problems creating images from devices themselves attached # to images. If this is false, makehybrid images will # have partition tables, regardless of the partition_table # setting. Fixed up for earlier systems below. 'recursive_access' => 1); # --verbosity $gVerbosity = 2; # --dry-run $gDryRun = 0; # %gConfig fix-ups based on features and bugs present in certain releases. my($ignore, $uname_r, $uname_s); ($uname_s, $ignore, $uname_r, $ignore, $ignore) = POSIX::uname(); if($uname_s eq 'Darwin') { ($gDarwinMajor, $ignore) = split(/\./, $uname_r, 2); # $major is the Darwin major release, which for our purposes, is 4 higher # than the interesting digit in a Mac OS X release. if($gDarwinMajor <= 6) { # <= 10.2 (Jaguar) # hdiutil create does not support -srcfolder or -srcdevice $gConfig{'create_directly'} = 0; # hdiutil attach does not support -mountpoint $gConfig{'hdiutil_mountpoint'} = 0; # hdiutil mkhybrid does not exist $gConfig{'makehybrid'} = 0; } if($gDarwinMajor <= 7) { # <= 10.3 (Panther) # Can't mount a disk image and then make a disk image from the device $gConfig{'recursive_access'} = 0; # bless does not support -openfolder on 10.2 (Jaguar) and must run # as root under 10.3 (Panther) $gConfig{'openfolder_bless'} = 0; } } else { # If it's not Mac OS X, just assume all of those good features are # available. They're not, but things will fail long before they # have a chance to make a difference. # # Now, if someone wanted to document some of these private formats... print STDERR ($0.": warning, not running on Mac OS X, ". "this could be interesting.\n"); } # Non-global variables used in Getopt my(@attributes, @copyFiles, @createSymlinks, $iconFile, $idme, $licenseFile, @makeDirs, $outputFormat, @resourceFiles, $sourceFile, $sourceFolder, $targetImage, $tempDir, $volumeName); # --format $outputFormat = 'UDZO'; # --idme $idme = 0; # --sourcefile $sourceFile = 0; # Leaving this might screw up the Apple tools. delete $ENV{'NEXT_ROOT'}; # This script can get pretty messy, so trap a few signals. $SIG{'INT'} = \&trapSignal; $SIG{'HUP'} = \&trapSignal; $SIG{'TERM'} = \&trapSignal; Getopt::Long::Configure('pass_through'); GetOptions('source=s' => \$sourceFolder, 'target=s' => \$targetImage, 'volname=s' => \$volumeName, 'format=s' => \$outputFormat, 'tempdir=s' => \$tempDir, 'mkdir=s' => \@makeDirs, 'copy=s' => \@copyFiles, 'symlink=s' => \@createSymlinks, 'license=s' => \$licenseFile, 'resource=s' => \@resourceFiles, 'icon=s' => \$iconFile, 'attribute=s' => \@attributes, 'idme' => \$idme, 'sourcefile' => \$sourceFile, 'verbosity=i' => \$gVerbosity, 'dry-run' => \$gDryRun, 'config=s' => \%gConfig); # "hidden" option not in usage() if(@ARGV) { # All arguments are parsed by Getopt usage(); exit(1); } if($gVerbosity<0 || $gVerbosity>2) { usage(); exit(1); } if(!defined($sourceFolder) || $sourceFolder eq '' || !defined($targetImage) || $targetImage eq '') { # --source and --target are required arguments usage(); exit(1); } # Make sure $sourceFolder doesn't contain trailing slashes. It messes with # rsync. while(substr($sourceFolder, -1) eq '/') { chop($sourceFolder); } if(!defined($volumeName)) { # Default volumeName is the name of the source directory. my(@components); @components = pathSplit($sourceFolder); $volumeName = pop(@components); } my(@tempDirComponents, $targetImageFilename); @tempDirComponents = pathSplit($targetImage); $targetImageFilename = pop(@tempDirComponents); if(defined($tempDir)) { @tempDirComponents = pathSplit($tempDir); } else { # Default tempDir is the same directory as what is specified for # targetImage $tempDir = join('/', @tempDirComponents); } # Ensure that the path of the target image has a suitable extension. If # it didn't, hdiutil would add one, and we wouldn't be able to find the # file. # # Note that $targetImageFilename is not being reset. This is because it's # used to build other names below, and we don't need to be adding all sorts # of extra unnecessary extensions to the name. my($originalTargetImage, $requiredExtension); $originalTargetImage = $targetImage; if($outputFormat eq 'UDSP') { $requiredExtension = '.sparseimage'; } else { $requiredExtension = '.dmg'; } $targetImage = giveExtension($originalTargetImage, $requiredExtension); if($targetImage ne $originalTargetImage) { print STDERR ($0.": warning: target image extension is being added\n"); print STDERR (' The new filename is '. giveExtension($targetImageFilename,$requiredExtension)."\n"); } # Make a temporary directory in $tempDir for our own nefarious purposes. my(@output, $tempSubdir, $tempSubdirTemplate); $tempSubdirTemplate=join('/', @tempDirComponents, 'pkg-dmg.'.$$.'.XXXXXXXX'); if(!(@output = commandOutput($gConfig{'cmd_mktemp'}, '-d', $tempSubdirTemplate)) || $#output != 0) { cleanupDie('mktemp failed'); } if($gDryRun) { (@output)=($tempSubdirTemplate); } ($tempSubdir) = @output; push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempSubdir);}); my($tempMount, $tempRoot, @tempsToMake); $tempRoot = $tempSubdir.'/stage'; $tempMount = $tempSubdir.'/mount'; push(@tempsToMake, $tempRoot); if($gConfig{'hdiutil_mountpoint'}) { push(@tempsToMake, $tempMount); } if(command($gConfig{'cmd_mkdir'}, @tempsToMake) != 0) { cleanupDie('mkdir tempRoot/tempMount failed'); } # This cleanup object is not strictly necessary, because $tempRoot is inside # of $tempSubdir, but the rest of the script relies on this object being # on the cleanup stack and expects to remove it. push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempRoot);}); # If $sourceFile is true, it means that $sourceFolder is to be treated as # a file and placed as a file within the volume root, as opposed to being # treated as the volume root itself. rsync will do this by default, if no # trailing '/' is present. With a trailing '/', $sourceFolder becomes # $tempRoot, instead of becoming an entry in $tempRoot. if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $sourceFolder.($sourceFile?'':'/'),$tempRoot) != 0) { cleanupDie('rsync failed'); } if(@makeDirs) { my($makeDir, @tempDirsToMake); foreach $makeDir (@makeDirs) { if($makeDir =~ /^\//) { push(@tempDirsToMake, $tempRoot.$makeDir); } else { push(@tempDirsToMake, $tempRoot.'/'.$makeDir); } } if(command($gConfig{'cmd_mkdir'}, '-p', @tempDirsToMake) != 0) { cleanupDie('mkdir failed'); } } # copy files and/or create symlinks copyFiles($tempRoot, 'copy', @copyFiles); copyFiles($tempRoot, 'symlink', @createSymlinks); if($gConfig{'create_directly'}) { # If create_directly is false, the contents will be rsynced into a # disk image and they would lose their attributes. setAttributes($tempRoot, @attributes); } if(defined($iconFile)) { if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $iconFile, $tempRoot.'/.VolumeIcon.icns') != 0) { cleanupDie('rsync failed for volume icon'); } # It's pointless to set the attributes of the root when diskutil create # -srcfolder is being used. In that case, the attributes will be set # later, after the image is already created. if(isFormatCompressed($outputFormat) && (command($gConfig{'cmd_SetFile'}, '-a', 'C', $tempRoot) != 0)) { cleanupDie('SetFile failed'); } } if(command($gConfig{'cmd_chmod'}, '-R', 'a+rX,a-st,u+w,go-w', $tempRoot) != 0) { cleanupDie('chmod failed'); } my($unflattenable); if(isFormatCompressed($outputFormat)) { $unflattenable = 1; } else { $unflattenable = 0; } diskImageMaker($tempRoot, $targetImage, $outputFormat, $volumeName, $tempSubdir, $tempMount, $targetImageFilename, defined($iconFile)); if(defined($licenseFile) && $licenseFile ne '') { my($licenseResource); $licenseResource = $tempSubdir.'/license.r'; if(!licenseMaker($licenseFile, $licenseResource)) { cleanupDie('licenseMaker failed'); } push(@resourceFiles, $licenseResource); # Don't add a cleanup object because licenseResource is in tempSubdir. } if(@resourceFiles) { # Add resources, such as a license agreement. # Only unflatten read-only and compressed images. It's not supported # on other image times. if($unflattenable && (command($gConfig{'cmd_hdiutil'}, 'unflatten', $targetImage)) != 0) { cleanupDie('hdiutil unflatten failed'); } # Don't push flatten onto the cleanup stack. If we fail now, we'll be # removing $targetImage anyway. # Type definitions come from Carbon.r. if(command($gConfig{'cmd_Rez'}, 'Carbon.r', @resourceFiles, '-a', '-o', $targetImage) != 0) { cleanupDie('Rez failed'); } # Flatten. This merges the resource fork into the data fork, so no # special encoding is needed to transfer the file. if($unflattenable && (command($gConfig{'cmd_hdiutil'}, 'flatten', $targetImage)) != 0) { cleanupDie('hdiutil flatten failed'); } } # $tempSubdir is no longer needed. It's buried on the stack below the # rm of the fresh image file. Splice in this fashion is equivalent to # pop-save, pop, push-save. splice(@gCleanup, -2, 1); # No need to remove licenseResource separately, it's in tempSubdir. if(command($gConfig{'cmd_rm'}, '-rf', $tempSubdir) != 0) { cleanupDie('rm -rf tempSubdir failed'); } if($idme) { if(command($gConfig{'cmd_hdiutil'}, 'internet-enable', '-yes', $targetImage) != 0) { cleanupDie('hdiutil internet-enable failed'); } } # Done. exit(0); # argumentEscape(@arguments) # # Takes a list of @arguments and makes them shell-safe. sub argumentEscape(@) { my(@arguments); @arguments = @_; my($argument, @argumentsOut); foreach $argument (@arguments) { $argument =~ s%([^A-Za-z0-9_\-/.=+,])%\\$1%g; push(@argumentsOut, $argument); } return @argumentsOut; } # cleanupDie($message) # # Displays $message as an error message, and then runs through the # @gCleanup stack, performing any cleanup operations needed before # exiting. Does not return, exits with exit status 1. sub cleanupDie($) { my($message); ($message) = @_; print STDERR ($0.': '.$message.(@gCleanup?' (cleaning up)':'')."\n"); while(@gCleanup) { my($subroutine); $subroutine = pop(@gCleanup); &$subroutine; } exit(1); } # command(@arguments) # # Runs the specified command at the verbosity level defined by $gVerbosity. # Returns nonzero on failure, returning the exit status if appropriate. # Discards command output. sub command(@) { my(@arguments); @arguments = @_; return commandVerbosity($gVerbosity,@arguments); } # commandInternal($command, @arguments) # # Runs the specified internal command at the verbosity level defined by # $gVerbosity. # Returns zero(!) on failure, because commandInternal is supposed to be a # direct replacement for the Perl system call wrappers, which, unlike shell # commands and C equivalent system calls, return true (instead of 0) to # indicate success. sub commandInternal($@) { my(@arguments, $command); ($command, @arguments) = @_; return commandInternalVerbosity($gVerbosity, $command, @arguments); } # commandInternalVerbosity($verbosity, $command, @arguments) # # Run an internal command, printing a bogus command invocation message if # $verbosity is true. # # If $command is unlink: # Removes the files specified by @arguments. Wraps unlink. # # If $command is symlink: # Creates the symlink specified by @arguments. Wraps symlink. sub commandInternalVerbosity($$@) { my(@arguments, $command, $verbosity); ($verbosity, $command, @arguments) = @_; if($command eq 'unlink') { if($verbosity || $gDryRun) { print(join(' ', 'rm', '-f', argumentEscape(@arguments))."\n"); } if($gDryRun) { return $#arguments+1; } return unlink(@arguments); } elsif($command eq 'symlink') { if($verbosity || $gDryRun) { print(join(' ', 'ln', '-s', argumentEscape(@arguments))."\n"); } if($gDryRun) { return 1; } my($source, $target); ($source, $target) = @arguments; return symlink($source, $target); } } # commandOutput(@arguments) # # Runs the specified command at the verbosity level defined by $gVerbosity. # Output is returned in an array of lines. undef is returned on failure. # The exit status is available in $?. sub commandOutput(@) { my(@arguments); @arguments = @_; return commandOutputVerbosity($gVerbosity, @arguments); } # commandOutputVerbosity($verbosity, @arguments) # # Runs the specified command at the verbosity level defined by the # $verbosity argument. Output is returned in an array of lines. undef is # returned on failure. The exit status is available in $?. # # If an error occurs in fork or exec, an error message is printed to # stderr and undef is returned. # # If $verbosity is 0, the command invocation is not printed, and its # stdout is not echoed back to stdout. # # If $verbosity is 1, the command invocation is printed. # # If $verbosity is 2, the command invocation is printed and the output # from stdout is echoed back to stdout. # # Regardless of $verbosity, stderr is left connected. sub commandOutputVerbosity($@) { my(@arguments, $verbosity); ($verbosity, @arguments) = @_; my($pid); if($verbosity || $gDryRun) { print(join(' ', argumentEscape(@arguments))."\n"); } if($gDryRun) { return(1); } if (!defined($pid = open(*COMMAND, '-|'))) { printf STDERR ($0.': fork: '.$!."\n"); return undef; } elsif ($pid) { # parent my(@lines); while(!eof(*COMMAND)) { my($line); chop($line = ); if($verbosity > 1) { print($line."\n"); } push(@lines, $line); } close(*COMMAND); if ($? == -1) { printf STDERR ($0.': fork: '.$!."\n"); return undef; } elsif ($? & 127) { printf STDERR ($0.': exited on signal '.($? & 127). ($? & 128 ? ', core dumped' : '')."\n"); return undef; } return @lines; } else { # child; this form of exec is immune to shell games if(!exec {$arguments[0]} (@arguments)) { printf STDERR ($0.': exec: '.$!."\n"); exit(-1); } } } # commandVerbosity($verbosity, @arguments) # # Runs the specified command at the verbosity level defined by the # $verbosity argument. Returns nonzero on failure, returning the exit # status if appropriate. Discards command output. sub commandVerbosity($@) { my(@arguments, $verbosity); ($verbosity, @arguments) = @_; if(!defined(commandOutputVerbosity($verbosity, @arguments))) { return -1; } return $?; } # copyFiles($tempRoot, $method, @arguments) # # Copies files or create symlinks in the disk image. # See --copy and --symlink descriptions for details. # If $method is 'copy', @arguments are interpreted as source:target, if $method # is 'symlink', @arguments are interpreted as symlink:target. sub copyFiles($@) { my(@fileList, $method, $tempRoot); ($tempRoot, $method, @fileList) = @_; my($file, $isSymlink); $isSymlink = ($method eq 'symlink'); foreach $file (@fileList) { my($source, $target); ($source, $target) = split(/:/, $file); if(!defined($target) and $isSymlink) { # empty symlink targets would result in an invalid target and fail, # but they shall be interpreted as "like source path, but inside dmg" $target = $source; } if(!defined($target)) { $target = $tempRoot; } elsif($target =~ /^\//) { $target = $tempRoot.$target; } else { $target = $tempRoot.'/'.$target; } my($success); if($isSymlink) { $success = commandInternal('symlink', $source, $target); } else { $success = !command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $source, $target); } if(!$success) { cleanupDie('copyFiles failed for method '.$method); } } } # diskImageMaker($source, $destination, $format, $name, $tempDir, $tempMount, # $baseName, $setRootIcon) # # Creates a disk image in $destination of format $format corresponding to the # source directory $source. $name is the volume name. $tempDir is a good # place to write temporary files, which should be empty (aside from the other # things that this script might create there, like stage and mount). # $tempMount is a mount point for temporary disk images. $baseName is the # name of the disk image, and is presently unused. $setRootIcon is true if # a volume icon was added to the staged $source and indicates that the # custom volume icon bit on the volume root needs to be set. sub diskImageMaker($$$$$$$$) { my($baseName, $destination, $format, $name, $setRootIcon, $source, $tempDir, $tempMount); ($source, $destination, $format, $name, $tempDir, $tempMount, $baseName, $setRootIcon) = @_; if(isFormatCompressed($format)) { my($uncompressedImage); if($gConfig{'makehybrid'}) { my($hybridImage); $hybridImage = giveExtension($tempDir.'/hybrid', '.dmg'); if(command($gConfig{'cmd_hdiutil'}, 'makehybrid', '-hfs', '-hfs-volume-name', $name, '-hfs-openfolder', $source, '-ov', $source, '-o', $hybridImage) != 0) { cleanupDie('hdiutil makehybrid failed'); } $uncompressedImage = $hybridImage; # $source is no longer needed and will be removed before anything # else can fail. splice in this form is the same as pop/push. splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $hybridImage);}); if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { cleanupDie('rm -rf failed'); } if(!$gConfig{'partition_table'} && $gConfig{'recursive_access'}) { # Even if we do want to create disk images without partition tables, # it's impossible unless recursive_access is set. my($rootDevice, $partitionDevice, $partitionMountPoint); if(!(($rootDevice, $partitionDevice, $partitionMountPoint) = hdidMountImage($tempMount, '-readonly', $hybridImage))) { cleanupDie('hdid mount failed'); } push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);}); my($udrwImage); $udrwImage = giveExtension($tempDir.'/udrw', '.dmg'); if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', 'UDRW', '-ov', '-srcdevice', $partitionDevice, $udrwImage) != 0) { cleanupDie('hdiutil create failed'); } $uncompressedImage = $udrwImage; # Going to eject before anything else can fail. Get the eject off # the stack. pop(@gCleanup); # $hybridImage will be removed soon, but until then, it needs to # stay on the cleanup stack. It needs to wait until after # ejection. $udrwImage is staying around. Make it appear as # though it's been done before $hybridImage. # # splice in this form is the same as popping one element to # @tempCleanup and pushing the subroutine. my(@tempCleanup); @tempCleanup = splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $udrwImage);}); push(@gCleanup, @tempCleanup); if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) { cleanupDie('diskutil eject failed'); } # Pop unlink of $uncompressedImage pop(@gCleanup); if(commandInternal('unlink', $hybridImage) != 1) { cleanupDie('unlink hybridImage failed: '.$!); } } } else { # makehybrid is not available, fall back to making a UDRW and # converting to a compressed image. It ought to be possible to # create a compressed image directly, but those come out far too # large (journaling?) and need to be read-write to fix up the # volume icon anyway. Luckily, we can take advantage of a single # call back into this function. my($udrwImage); $udrwImage = giveExtension($tempDir.'/udrw', '.dmg'); diskImageMaker($source, $udrwImage, 'UDRW', $name, $tempDir, $tempMount, $baseName, $setRootIcon); # The call back into diskImageMaker already removed $source. $uncompressedImage = $udrwImage; } # The uncompressed disk image is now in its final form. Compress it. # Jaguar doesn't support hdiutil convert -ov, but it always allows # overwriting. # bzip2-compressed UDBZ images can only be created and mounted on 10.4 # and later. The bzip2-level imagekey is only effective when creating # images in 10.5. In 10.4, bzip2-level is harmlessly ignored, and the # default value of 1 is always used. if(command($gConfig{'cmd_hdiutil'}, 'convert', '-format', $format, '-imagekey', ($format eq 'UDBZ' ? 'bzip2-level=9' : 'zlib-level=9'), (defined($gDarwinMajor) && $gDarwinMajor <= 6 ? () : ('-ov')), $uncompressedImage, '-o', $destination) != 0) { cleanupDie('hdiutil convert failed'); } # $uncompressedImage is going to be unlinked before anything else can # fail. splice in this form is the same as pop/push. splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $destination);}); if(commandInternal('unlink', $uncompressedImage) != 1) { cleanupDie('unlink uncompressedImage failed: '.$!); } # At this point, the only thing that the compressed block has added to # the cleanup stack is the removal of $destination. $source has already # been removed, and its cleanup entry has been removed as well. } elsif($format eq 'UDRW' || $format eq 'UDSP') { my(@extraArguments); if(!$gConfig{'partition_table'}) { @extraArguments = ('-layout', 'NONE'); } if($gConfig{'create_directly'}) { # Use -fs HFS+ to suppress the journal. if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', $format, @extraArguments, '-fs', 'HFS+', '-volname', $name, '-ov', '-srcfolder', $source, $destination) != 0) { cleanupDie('hdiutil create failed'); } # $source is no longer needed and will be removed before anything # else can fail. splice in this form is the same as pop/push. splice(@gCleanup, -1, 1, sub {commandInternalVerbosity(0, 'unlink', $destination);}); if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { cleanupDie('rm -rf failed'); } } else { # hdiutil create does not support -srcfolder or -srcdevice, it only # knows how to create blank images. Figure out how large an image # is needed, create it, and fill it. This is needed for Jaguar. # Use native block size for hdiutil create -sectors. delete $ENV{'BLOCKSIZE'}; my(@duOutput, $ignore, $sizeBlocks, $sizeOverhead, $sizeTotal, $type); if(!(@output = commandOutput($gConfig{'cmd_du'}, '-s', $tempRoot)) || $? != 0) { cleanupDie('du failed'); } ($sizeBlocks, $ignore) = split(' ', $output[0], 2); # The filesystem itself takes up 152 blocks of its own blocks for the # filesystem up to 8192 blocks, plus 64 blocks for every additional # 4096 blocks or portion thereof. $sizeOverhead = 152 + 64 * POSIX::ceil( (($sizeBlocks - 8192) > 0) ? (($sizeBlocks - 8192) / (4096 - 64)) : 0); # The number of blocks must be divisible by 8. my($mod); if($mod = ($sizeOverhead % 8)) { $sizeOverhead += 8 - $mod; } # sectors is taken as the size of a disk, not a filesystem, so the # partition table eats into it. if($gConfig{'partition_table'}) { $sizeOverhead += 80; } # That was hard. Leave some breathing room anyway. Use 1024 sectors # (512kB). These read-write images wouldn't be useful if they didn't # have at least a little free space. $sizeTotal = $sizeBlocks + $sizeOverhead + 1024; # Minimum sizes - these numbers are larger on Jaguar than on later # systems. Just use the Jaguar numbers, since it's unlikely to wind # up here on any other release. if($gConfig{'partition_table'} && $sizeTotal < 8272) { $sizeTotal = 8272; } if(!$gConfig{'partition_table'} && $sizeTotal < 8192) { $sizeTotal = 8192; } # hdiutil create without -srcfolder or -srcdevice will not accept # -format. It uses -type. Fortunately, the two supported formats # here map directly to the only two supported types. if ($format eq 'UDSP') { $type = 'SPARSE'; } else { $type = 'UDIF'; } if(command($gConfig{'cmd_hdiutil'}, 'create', '-type', $type, @extraArguments, '-fs', 'HFS+', '-volname', $name, '-ov', '-sectors', $sizeTotal, $destination) != 0) { cleanupDie('hdiutil create failed'); } push(@gCleanup, sub {commandInternalVerbosity(0, 'unlink', $destination);}); # The rsync will occur shortly. } my($mounted, $rootDevice, $partitionDevice, $partitionMountPoint); $mounted=0; if(!$gConfig{'create_directly'} || $gConfig{'openfolder_bless'} || $setRootIcon) { # The disk image only needs to be mounted if: # create_directly is false, because the content needs to be copied # openfolder_bless is true, because bless -openfolder needs to run # setRootIcon is true, because the root needs its attributes set. if(!(($rootDevice, $partitionDevice, $partitionMountPoint) = hdidMountImage($tempMount, $destination))) { cleanupDie('hdid mount failed'); } $mounted=1; push(@gCleanup, sub {commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);}); } if(!$gConfig{'create_directly'}) { # Couldn't create and copy directly in one fell swoop. Now that # the volume is mounted, copy the files. --copy-unsafe-links is # unnecessary since it was used to copy everything to the staging # area. There can be no more unsafe links. if(command($gConfig{'cmd_rsync'}, '-a', $source.'/',$partitionMountPoint) != 0) { cleanupDie('rsync to new volume failed'); } # We need to get the rm -rf of $source off the stack, because it's # being cleaned up here. There are two items now on top of it: # removing the target image and, above that, ejecting it. Splice it # out. my(@tempCleanup); @tempCleanup = splice(@gCleanup, -2); # The next splice is the same as popping once and pushing @tempCleanup. splice(@gCleanup, -1, 1, @tempCleanup); if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { cleanupDie('rm -rf failed'); } } if($gConfig{'openfolder_bless'}) { # On Tiger, the bless docs say to use --openfolder, but only # --openfolder is accepted on Panther. Tiger takes it with a single # dash too. Jaguar is out of luck. if(command($gConfig{'cmd_bless'}, '-openfolder', $partitionMountPoint) != 0) { cleanupDie('bless failed'); } } setAttributes($partitionMountPoint, @attributes); if($setRootIcon) { # When "hdiutil create -srcfolder" is used, the root folder's # attributes are not copied to the new volume. Fix up. if(command($gConfig{'cmd_SetFile'}, '-a', 'C', $partitionMountPoint) != 0) { cleanupDie('SetFile failed'); } } if($mounted) { # Pop diskutil eject pop(@gCleanup); if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) { cleanupDie('diskutil eject failed'); } } # End of UDRW/UDSP section. At this point, $source has been removed # and its cleanup entry has been removed from the stack. } else { cleanupDie('unrecognized format'); print STDERR ($0.": unrecognized format\n"); exit(1); } } # giveExtension($file, $extension) # # If $file does not end in $extension, $extension is added. The new # filename is returned. sub giveExtension($$) { my($extension, $file); ($file, $extension) = @_; if(substr($file, -length($extension)) ne $extension) { return $file.$extension; } return $file; } # hdidMountImage($mountPoint, @arguments) # # Runs the hdid command with arguments specified by @arguments. # @arguments may be a single-element array containing the name of the # disk image to mount. Returns a three-element array, with elements # corresponding to: # - The root device of the mounted image, suitable for ejection # - The device corresponding to the mounted partition # - The mounted partition's mount point # # If running on a system that supports easy mounting at points outside # of the default /Volumes with hdiutil attach, it is used instead of hdid, # and $mountPoint is used as the mount point. # # The root device will differ from the partition device when the disk # image contains a partition table, otherwise, they will be identical. # # If hdid fails, undef is returned. sub hdidMountImage($@) { my(@arguments, @command, $mountPoint); ($mountPoint, @arguments) = @_; my(@output); if($gConfig{'hdiutil_mountpoint'}) { @command=($gConfig{'cmd_hdiutil'}, 'attach', @arguments, '-mountpoint', $mountPoint); } else { @command=($gConfig{'cmd_hdid'}, @arguments); } if(!(@output = commandOutput(@command)) || $? != 0) { return undef; } if($gDryRun) { return('/dev/diskX','/dev/diskXsY','/Volumes/'.$volumeName); } my($line, $restOfLine, $rootDevice); foreach $line (@output) { my($device, $mountpoint); if($line !~ /^\/dev\//) { # Consider only lines that correspond to /dev entries next; } ($device, $restOfLine) = split(' ', $line, 2); if(!defined($rootDevice) || $rootDevice eq '') { # If this is the first device seen, it's the root device to be # used for ejection. Keep it. $rootDevice = $device; } if($restOfLine =~ /(\/.*)/) { # The first partition with a mount point is the interesting one. It's # usually Apple_HFS and usually the last one in the list, but beware of # the possibility of other filesystem types and the Apple_Free partition. # If the disk image contains no partition table, the partition will not # have a type, so look for the mount point by looking for a slash. $mountpoint = $1; return($rootDevice, $device, $mountpoint); } } # No mount point? This is bad. If there's a root device, eject it. if(defined($rootDevice) && $rootDevice ne '') { # Failing anyway, so don't care about failure commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice); } return undef; } # isFormatCompressed($format) # # Returns true if $format corresponds to a compressed disk image format. # Returns false otherwise. sub isFormatCompressed($) { my($format); ($format) = @_; return $format eq 'UDZO' || $format eq 'UDBZ'; } # licenseMaker($text, $resource) # # Takes a plain text file at path $text and creates a license agreement # resource containing the text at path $license. English-only, and # no special formatting. This is the bare-bones stuff. For more # intricate license agreements, create your own resource. # # ftp://ftp.apple.com/developer/Development_Kits/SLAs_for_UDIFs_1.0.dmg sub licenseMaker($$) { my($resource, $text); ($text, $resource) = @_; if(!sysopen(*TEXT, $text, O_RDONLY)) { print STDERR ($0.': licenseMaker: sysopen text: '.$!."\n"); return 0; } if(!sysopen(*RESOURCE, $resource, O_WRONLY|O_CREAT|O_EXCL)) { print STDERR ($0.': licenseMaker: sysopen resource: '.$!."\n"); return 0; } print RESOURCE << '__EOT__'; // See /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Script.h for language IDs. data 'LPic' (5000) { // Default language ID, 0 = English $"0000" // Number of entries in list $"0001" // Entry 1 // Language ID, 0 = English $"0000" // Resource ID, 0 = STR#/TEXT/styl 5000 $"0000" // Multibyte language, 0 = no $"0000" }; resource 'STR#' (5000, "English") { { // Language (unused?) = English "English", // Agree "Agree", // Disagree "Disagree", __EOT__ # This stuff needs double-quotes for interpolations to work. print RESOURCE (" // Print, ellipsis is 0xC9\n"); print RESOURCE (" \"Print\xc9\",\n"); print RESOURCE (" // Save As, ellipsis is 0xC9\n"); print RESOURCE (" \"Save As\xc9\",\n"); print RESOURCE (' // Descriptive text, curly quotes are 0xD2 and 0xD3'. "\n"); print RESOURCE (' "If you agree to the terms of this license '. "agreement, click \xd2Agree\xd3 to access the software. If you ". "do not agree, press \xd2Disagree.\xd3\"\n"); print RESOURCE << '__EOT__'; }; }; // Beware of 1024(?) byte (character?) line length limitation. Split up long // lines. // If straight quotes are used ("), remember to escape them (\"). // Newline is \n, to leave a blank line, use two of them. // 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly // single quotes ('), 0xD5 is also the apostrophe. data 'TEXT' (5000, "English") { __EOT__ while(!eof(*TEXT)) { my($line); chop($line = ); while(defined($line)) { my($chunk); # Rez doesn't care for lines longer than (1024?) characters. Split # at less than half of that limit, in case everything needs to be # backwhacked. if(length($line)>500) { $chunk = substr($line, 0, 500); $line = substr($line, 500); } else { $chunk = $line; $line = undef; } if(length($chunk) > 0) { # Unsafe characters are the double-quote (") and backslash (\), escape # them with backslashes. $chunk =~ s/(["\\])/\\$1/g; print RESOURCE ' "'.$chunk.'"'."\n"; } } print RESOURCE ' "\n"'."\n"; } close(*TEXT); print RESOURCE << '__EOT__'; }; data 'styl' (5000, "English") { // Number of styles following = 1 $"0001" // Style 1. This is used to display the first two lines in bold text. // Start character = 0 $"0000 0000" // Height = 16 $"0010" // Ascent = 12 $"000C" // Font family = 1024 (Lucida Grande) $"0400" // Style bitfield, 0x1=bold 0x2=italic 0x4=underline 0x8=outline // 0x10=shadow 0x20=condensed 0x40=extended $"00" // Style, unused? $"02" // Size = 12 point $"000C" // Color, RGB $"0000 0000 0000" }; __EOT__ close(*RESOURCE); return 1; } # pathSplit($pathname) # # Splits $pathname into an array of path components. sub pathSplit($) { my($pathname); ($pathname) = @_; return split(/\//, $pathname); } # setAttributes($root, @attributeList) # # @attributeList is an array, each element of which must be in the form # :. is a list of attributes, per SetFile. is a file # which is taken as relative to $root (even if it appears as an absolute # path.) SetFile is called to set the attributes on each file in # @attributeList. sub setAttributes($@) { my(@attributes, $root); ($root, @attributes) = @_; my($attribute); foreach $attribute (@attributes) { my($attrList, $file, @fileList, @fixedFileList); ($attrList, @fileList) = split(/:/, $attribute); if(!defined($attrList) || !@fileList) { cleanupDie('--attribute requires :'); } @fixedFileList=(); foreach $file (@fileList) { if($file =~ /^\//) { push(@fixedFileList, $root.$file); } else { push(@fixedFileList, $root.'/'.$file); } } if(command($gConfig{'cmd_SetFile'}, '-a', $attrList, @fixedFileList)) { cleanupDie('SetFile failed to set attributes'); } } return; } sub trapSignal($) { my($signalName); ($signalName) = @_; cleanupDie('exiting on SIG'.$signalName); } sub usage() { print STDERR ( "usage: pkg-dmg --source \n". " --target \n". " [--format ] (default: UDZO)\n". " [--volname ] (default: same name as source)\n". " [--tempdir ] (default: same dir as target)\n". " [--mkdir ] (make directory in image)\n". " [--copy [:]] (extra files to add)\n". " [--symlink [:]] (extra symlinks to add)\n". " [--license ] (plain text license agreement)\n". " [--resource ] (flat .r files to merge)\n". " [--icon ] (volume icon)\n". " [--attribute :] (set file attributes)\n". " [--idme] (make Internet-enabled image)\n". " [--sourcefile] (treat --source as a file)\n". " [--verbosity ] (0, 1, 2; default=2)\n". " [--dry-run] (print what would be done)\n"); return; } SuperCollider-Source/package/USAGE000644 000765 000024 00000001507 12321461511 020036 0ustar00crucialstaff000000 000000 ./package usage: -v version: Specify a version number. If this option is not specified the default is to use the date (YYYY-MM-DD) as the version. -s: Build a source package. If this option is not specified the default is to build a DMG. -o: Include the optional installs located in the ./optional directory. If this option is not specified the default is to not include the optional installs. ----------------------------------------------------------------------- Typical usage when posting a new release on SourceForge: # Place the mac optional installs in the ./optional directory. ./package -v 3.2 ./package -v 3.2 -o # Place the source optional installs in the ./optional directory. ./package -v 3.2 -s ./package -v 3.2 -s -o -----------------------------------------------------------------------SuperCollider-Source/lang/CMakeLists.txt000644 000765 000024 00000034761 12766171707 021367 0ustar00crucialstaff000000 000000 cmake_minimum_required(VERSION 2.8.11) # This makes sclang/scide work with a Qt installation at a fixed location. SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) include_directories(${CMAKE_SOURCE_DIR}/include/common ${CMAKE_SOURCE_DIR}/include/lang ${CMAKE_SOURCE_DIR}/include/plugin_interface ${CMAKE_SOURCE_DIR}/include/server ${CMAKE_SOURCE_DIR}/common ${YAMLCPP_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/external_libraries/boost_sync/include LangSource LangPrimSource ${CMAKE_SOURCE_DIR}/external_libraries/hidapi/hidapi ${CMAKE_SOURCE_DIR}/external_libraries/hidapi/hidapi_parser ${CMAKE_SOURCE_DIR}/external_libraries/nova-tt LangSource/Bison ) if(CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(ALSA) endif() find_package(Readline 5.0) find_package(Sndfile) if (SC_QT OR SC_IDE) set(LOCALSOCK_UTIL_FILE ${CMAKE_SOURCE_DIR}/editors/sc-ide/primitives/localsocket_utils.cpp) else () set(LOCALSOCK_UTIL_FILE) endif () set(sclang_sources LangPrimSource/SC_HID_api.cpp LangPrimSource/SC_Wii.cpp LangPrimSource/PyrSignalPrim.cpp LangPrimSource/PyrSched.cpp LangPrimSource/PyrPrimitive.cpp LangPrimSource/PyrMathPrim.cpp LangPrimSource/SC_ComPort.cpp LangPrimSource/OSCData.cpp LangPrimSource/PyrArchiver.cpp LangPrimSource/PyrArrayPrimitives.cpp LangPrimSource/PyrBitPrim.cpp LangPrimSource/PyrCharPrim.cpp LangPrimSource/PyrFilePrim.cpp LangPrimSource/PyrListPrim.cpp LangPrimSource/PyrPlatformPrim.cpp LangPrimSource/PyrStringPrim.cpp LangPrimSource/PyrSymbolPrim.cpp LangPrimSource/PyrUnixPrim.cpp LangSource/AdvancingAllocPool.cpp LangSource/ByteCodeArray.cpp LangSource/DumpParseNode.cpp LangSource/GC.cpp LangSource/InitAlloc.cpp LangSource/PyrInterpreter3.cpp LangSource/PyrLexer.cpp LangSource/PyrMathOps.cpp LangSource/PyrMathSupport.cpp LangSource/PyrMessage.cpp LangSource/PyrObject.cpp LangSource/PyrParseNode.cpp LangSource/PyrSignal.cpp LangSource/PyrSymbolTable.cpp LangSource/SC_LanguageClient.cpp LangSource/SC_LanguageConfig.cpp LangSource/SC_TerminalClient.cpp LangSource/SimpleStack.cpp LangSource/VMGlobals.cpp LangSource/dumpByteCodes.cpp ${CMAKE_SOURCE_DIR}/common/fftlib.c ${CMAKE_SOURCE_DIR}/common/Samp.cpp ${CMAKE_SOURCE_DIR}/common/SC_AllocPool.cpp ${CMAKE_SOURCE_DIR}/common/SC_DirUtils.cpp ${CMAKE_SOURCE_DIR}/common/SC_Reply.cpp ${CMAKE_SOURCE_DIR}/common/SC_StandAloneInfo_Darwin.cpp ${CMAKE_SOURCE_DIR}/common/SC_StringBuffer.cpp ${CMAKE_SOURCE_DIR}/common/SC_StringParser.cpp ${CMAKE_SOURCE_DIR}/common/SC_TextUtils.cpp ${LOCALSOCK_UTIL_FILE} ${CMAKE_SOURCE_DIR}/common/sc_popen.cpp ) if(APPLE) set_property(SOURCE ${CMAKE_SOURCE_DIR}/common/SC_DirUtils.cpp PROPERTY COMPILE_FLAGS -xobjective-c++) list(APPEND sclang_sources ${CMAKE_SOURCE_DIR}/common/SC_Apple.mm) set_source_files_properties(${CMAKE_SOURCE_DIR}/common/SC_Apple.mm PROPERTIES COMPILE_FLAGS "-x objective-c++ -fobjc-exceptions") endif() if (NOT Boost_FOUND) file(GLOB boost_system_sources ../external_libraries/boost/libs/system/src/*cpp) file(GLOB boost_fs_sources ../external_libraries/boost/libs/filesystem/src/*cpp) file(GLOB boost_regex_sources ../external_libraries/boost/libs/regex/src/*cpp) list(APPEND sclang_sources ${boost_fs_sources} ${boost_system_sources} ${boost_regex_sources}) endif() file(GLOB_RECURSE headers ../include/*.h* ) file(GLOB_RECURSE external_headers ../external_libraries/*.h* ) list(APPEND sclang_sources ${headers} ${external_headers}) # make qt creator happy if(NOT WIN32) list(APPEND sclang_sources LangPrimSource/PyrSerialPrim.cpp) endif() set(sclang_parser_source LangSource/Bison/lang11d_tab.cpp) if(UNIX) if(APPLE) list(APPEND sclang_sources LangPrimSource/SC_CoreMIDI.cpp LangPrimSource/SC_CoreAudioPrim.cpp LangPrimSource/SC_Speech.mm ) add_definitions(-DHAVE_SPEECH) else(APPLE) if(ALSA_FOUND) list(APPEND sclang_sources LangPrimSource/SC_AlsaMIDI.cpp) endif() if(LINUX) list(APPEND sclang_sources LangPrimSource/SC_LID.cpp) add_definitions(-DHAVE_LID) endif(LINUX) endif(APPLE) endif(UNIX) if(WIN32) list(APPEND sclang_sources ${CMAKE_SOURCE_DIR}/common/SC_Win32Utils.cpp) include_directories (../platform/windows/compat_stuff) if(NOT MINGW) # mingw-w64 provides getopt list(APPEND sclang_sources ../platform/windows/compat_stuff/getopt/getopt.c) include_directories(../platform/windows/compat_stuff/getopt) endif() list(APPEND sclang_sources LangPrimSource/SC_PortMidi.cpp) endif() # This sets up the exe icon for windows. if(WIN32) set(RES_FILES ${CMAKE_SOURCE_DIR}/platform/windows/Resources/sclang.rc) set(CMAKE_RC_COMPILER_INIT windres) ENABLE_LANGUAGE(RC) SET(CMAKE_RC_COMPILE_OBJECT " -O coff -i -o ") endif(WIN32) if(SC_WII) if(CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(CWiid) find_package(Bluetooth) if (BLUETOOTH_FOUND AND CWIID_FOUND) add_definitions(-DHAVE_WII) include_directories(${CWIID_INCLUDE_DIRS} ${BLUETOOTH_INCLUDE_DIRS}) message(STATUS "Compiling with WiiMote support") else() message(SEND_ERROR "Cannot find libcwiid or libbluetooth.\n (If Wii support is not required, then set SC_WII=no)") endif() elseif(APPLE) add_definitions(-DHAVE_WII) list(APPEND sclang_sources LangPrimSource/WiiMote_OSX/wiiremote.c) include_directories(LangPrimSource/WiiMote_OSX) endif() endif() if(SC_QT OR SC_IDE) set(QT_COLLIDER_LANG_CLIENT ON) include(../QtCollider/CMakeLists.txt) list(APPEND sclang_sources ${QT_COLLIDER_SRCS}) endif() if(SC_IDE) add_definitions(-DSC_IDE -DQT_NO_KEYWORDS) qt5_wrap_cpp( SCLANG_MOC_SRCS ../editors/sc-ide/primitives/sc_ipc_client.hpp ) list(APPEND sclang_sources ../editors/sc-ide/primitives/sc_ipc_client.cpp) list(APPEND sclang_sources ${SCLANG_MOC_SRCS}) endif() include(../SCDoc/CMakeLists.txt) list(APPEND sclang_sources ${SCDOC_SRCS}) if(0 AND FINAL_BUILD) # sclang final-builds are broken CREATE_FINAL_FILE(libsclang_final.cpp ${sclang_sources}) add_library(libsclang STATIC libsclang_final.cpp ${sclang_parser_source}) else() add_library(libsclang STATIC ${sclang_sources} ${sclang_parser_source}) endif() target_compile_definitions(libsclang PRIVATE YYSTACK_USE_ALLOC) target_link_libraries(libsclang tlsf ${PTHREADS_LIBRARIES}) if(SC_IDE OR SC_QT) find_package(Qt5Core) get_target_property(QtCore_location Qt5::Core LOCATION) message(STATUS "Found Qt: " ${QtCore_location} ) get_filename_component(QT_BIN_PATH ${QtCore_location} DIRECTORY CACHE) target_link_libraries(libsclang ${QT_COLLIDER_LIBS}) endif() if(FALSE) # libsclang is a shared library target_compile_definitions(libsclang PRIVATE BUILDING_SCLANG) target_compile_definitions(libsclang INTERFACE BUILDING_SCLANG) endif() target_compile_definitions(libsclang PRIVATE HAVE_HIDAPI) target_link_libraries( libsclang hidapi hidapi_parser ) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux" AND HID_HIDRAW) target_link_libraries( libsclang ${UDEV_LIBRARIES}) endif() if(HID_LIBUSB) target_link_libraries( libsclang ${LIBUSB_1_LIBRARIES}) endif() if (SC_WII OR APPLE) if (BLUETOOTH_FOUND AND CWIID_FOUND) target_link_libraries(libsclang ${BLUETOOTH_LIBRARIES} ${CWIID_LIBRARIES}) elseif(APPLE) target_link_libraries(libsclang "-framework IOBluetooth") endif() endif() if (Boost_FOUND) target_include_directories(libsclang PUBLIC ${Boost_INCLUDE_DIRS}) target_link_libraries(libsclang ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_FILESYSTEM_LIBRARY}) else() target_include_directories(libsclang PUBLIC ${CMAKE_SOURCE_DIR}/external_libraries/boost) target_link_libraries(libsclang boost_thread) endif() if (SCLANG_SERVER) target_link_libraries(libsclang libscsynth) else() target_compile_definitions(libsclang PUBLIC NO_INTERNAL_SERVER) endif() if (NOT WIN32) set_property(TARGET libsclang PROPERTY OUTPUT_NAME sclang) endif() ## external libraries if(READLINE_FOUND) message(STATUS "Compiling with Readline support") target_compile_definitions(libsclang PUBLIC HAVE_READLINE) target_include_directories(libsclang PUBLIC ${READLINE_INCLUDE_DIR}) target_link_libraries(libsclang ${READLINE_LIBRARY}) endif(READLINE_FOUND) mark_as_advanced(READLINE_INCLUDE_DIR READLINE_LIBRARY) if (APPLE) target_link_libraries(libsclang "-framework Carbon") target_link_libraries(libsclang "-framework CoreAudio") target_link_libraries(libsclang "-framework CoreMIDI") target_link_libraries(libsclang "-framework CoreServices") target_link_libraries(libsclang "-framework IOKit") target_link_libraries(libsclang "-framework CoreFoundation") endif() if(ALSA_FOUND) message(STATUS "Compiling with ALSA midi support") target_compile_definitions(libsclang PUBLIC HAVE_ALSA=1) target_link_libraries(libsclang ${ALSA_LIBRARY}) endif(ALSA_FOUND) if(SNDFILE_FOUND) target_include_directories(libsclang PUBLIC ${SNDFILE_INCLUDE_DIR}) target_link_libraries(libsclang ${SNDFILE_LIBRARIES}) elseif(NOT NO_LIBSNDFILE) message(SEND_ERROR "Cannot find libsndfile") endif(SNDFILE_FOUND) if (FFTW3F_FOUND) target_include_directories (libsclang ${FFTW3F_INCLUDE_DIR}) target_link_libraries(libsclang ${FFTW3F_LIBRARY}) endif() if (WIN32) target_link_libraries(libsclang wsock32 ws2_32 portmidi iphlpapi hid) endif() if (GC_SANITYCHECK) target_compile_definitions(libsclang PUBLIC GC_SANITYCHECK) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") target_link_libraries(libsclang rt) endif() target_link_libraries(libsclang ${YAMLCPP_LIBRARY}) add_executable(sclang LangSource/cmdLineFuncs.cpp ${RES_FILES}) target_link_libraries(sclang libsclang) target_link_libraries(sclang ${ICU_LIBRARIES}) target_compile_definitions(sclang PUBLIC USE_SC_TERMINAL_CLIENT) if(LTO) target_compile_definitions(libsclang PUBLIC -flto -flto-report) set_property(TARGET sclang libsclang APPEND PROPERTY LINK_FLAGS "-flto -flto-report -fwhole-program") endif() if(APPLE) add_custom_command(TARGET sclang POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/../MacOS/ COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/../MacOS) elseif(WIN32) if(NOT MSVC) set_target_properties(sclang PROPERTIES RUNTIME_OUTPUT_DIRECTORY "$") endif(NOT MSVC) add_custom_command(TARGET sclang PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/SCClassLibrary" $/SCClassLibrary COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/HelpSource" $/HelpSource COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/examples" $/examples COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/sounds" $/sounds ) if(NOT SC_QT) # TODP: clean (and cross platform) solution for language boot for case SC_QT=OFF (this is a quick fix for language boot error) add_custom_command(TARGET sclang PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/SCClassLibrary/Common/GUI" $/SCClassLibrary/scide_scqt/Common/GUI COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/SCClassLibrary/JITLib/GUI" $/SCClassLibrary/scide_scqt/JITLib/GUI COMMAND ${CMAKE_COMMAND} -E remove_directory $/SCClassLibrary/Common/GUI COMMAND ${CMAKE_COMMAND} -E remove_directory $/SCClassLibrary/JITLib/GUI ) endif(NOT SC_QT) set(SC_WIN_DLL_DIRS) if(SNDFILE_LIBRARY_DIR) list(APPEND SC_WIN_DLL_DIRS "${SNDFILE_LIBRARY_DIR}") endif(SNDFILE_LIBRARY_DIR) if(FFTW3F_LIBRARY_DIR) list(APPEND SC_WIN_DLL_DIRS "${FFTW3F_LIBRARY_DIR}") endif(FFTW3F_LIBRARY_DIR) if(READLINE_LIBRARY_DIR) file(GLOB READLINE_DLL "${READLINE_LIBRARY_DIR}/*readline*.dll") list(APPEND SC_WIN_DLL_DIRS "${READLINE_LIBRARY_DIR}") add_custom_command(TARGET sclang POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${READLINE_DLL}" $ ) endif(READLINE_LIBRARY_DIR) if(QT_BIN_PATH) list(APPEND SC_WIN_DLL_DIRS "${QT_BIN_PATH}") endif(QT_BIN_PATH) if(SC_IDE) add_custom_command(TARGET sclang POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory $ $ ) endif(SC_IDE) install(TARGETS sclang PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION "${SC_WIN_BUNDLE_NAME}" ) if(SC_QT) SET(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "${CMAKE_INSTALL_PREFIX}/${SC_WIN_BUNDLE_NAME}") include(InstallRequiredSystemLibraries) if(MSYS) SET(QT_PLUGINS_DIR "${QT_BIN_PATH}/../share/qt5/plugins" CACHE PATH "Location of qt plugins for windows as provided by MSYS2") else() SET(QT_PLUGINS_DIR "${QT_BIN_PATH}/../plugins" CACHE PATH "Location of qt plugins for windows") endif() foreach(plugin ${Qt5Network_PLUGINS} ${Qt5Gui_PLUGINS} ${Qt5Sensors_PLUGINS} ${Qt5Sql_PLUGINS} ${Qt5PrintSupport_PLUGINS}) get_target_property(_loc ${plugin} LOCATION) get_filename_component(_parent_dir ${_loc} DIRECTORY) get_filename_component(_name_we ${_loc} NAME_WE) get_filename_component(_abs ${QT_PLUGINS_DIR} ABSOLUTE) string(REPLACE "${_abs}/" "" _dest_dir ${_parent_dir}) install(FILES "${_parent_dir}/${_name_we}$<$:d>.dll" DESTINATION "${CMAKE_INSTALL_PREFIX}/${SC_WIN_BUNDLE_NAME}/${_dest_dir}" ) endforeach() endif(SC_QT) if(NOT SC_IDE) install(CODE " include(BundleUtilities) fixup_bundle( \"${CMAKE_INSTALL_PREFIX}/${SC_WIN_BUNDLE_NAME}/sclang.exe\" \"\" \"${SC_WIN_DLL_DIRS}\" ) " COMMENT "Looking for libraries..." VERBATIM ) endif(NOT SC_IDE) else() install(TARGETS sclang RUNTIME DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() SuperCollider-Source/lang/LangPrimSource/000755 000765 000024 00000000000 13007315613 021467 5ustar00crucialstaff000000 000000 SuperCollider-Source/lang/LangSource/000755 000765 000024 00000000000 13007315613 020637 5ustar00crucialstaff000000 000000 SuperCollider-Source/lang/LangSource/AdvancingAllocPool.cpp000644 000765 000024 00000006166 12321461511 025050 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "AdvancingAllocPool.h" #include "SC_AllocPool.h" //#include AdvancingAllocPool::AdvancingAllocPool() { mAllocPool = 0; mInitSize = 0; mGrowSize = 0; mTooBig = 0; mCurSize = 0; mChunks = NULL; mFatties = NULL; } void AdvancingAllocPool::Init(AllocPool *inAllocPool, size_t initSize, size_t growSize, size_t tooBigSize) { mAllocPool = inAllocPool; mInitSize = initSize; mGrowSize = growSize; mTooBig = tooBigSize; mChunks = NULL; AddChunk(initSize); mFatties = NULL; //assert(SanityCheck()); } void AdvancingAllocPool::AddChunk(size_t inSize) { size_t chunkSize = sizeof(AdvancingAllocPoolChunkHdr) + inSize; AdvancingAllocPoolChunk* chunk = (AdvancingAllocPoolChunk*)mAllocPool->Alloc(chunkSize); FailNil(chunk); chunk->mNext = mChunks; mChunks = chunk; chunk->mSize = mGrowSize; mCurSize = 0; } void* AdvancingAllocPool::Alloc(size_t reqsize) { //assert(SanityCheck()); //assert(mAllocPool); size_t size = (reqsize + 15) & ~15; // round up to 16 byte alignment if (size < mTooBig) { if (!mChunks) AddChunk(mInitSize); else if (mCurSize + size > mChunks->mSize) AddChunk(mGrowSize); char* space = mChunks->mSpace + mCurSize; mCurSize += size; //assert(SanityCheck()); return (void*)space; } else { size_t chunkSize = sizeof(AdvancingAllocPoolChunkHdr) + size; AdvancingAllocPoolChunk* fatty = (AdvancingAllocPoolChunk*)mAllocPool->Alloc(chunkSize); FailNil(fatty); fatty->mNext = mFatties; mFatties = fatty; fatty->mSize = size; //assert(SanityCheck()); return (void*)fatty->mSpace; } } void AdvancingAllocPool::FreeAll() { //assert(SanityCheck()); AdvancingAllocPoolChunk *chunk, *next; for (chunk = mChunks; chunk; chunk = next) { next = chunk->mNext; mAllocPool->Free(chunk); } for (chunk = mFatties; chunk; chunk = next) { next = chunk->mNext; mAllocPool->Free(chunk); } mChunks = NULL; mFatties = NULL; mCurSize = 0; //assert(SanityCheck()); } bool AdvancingAllocPool::SanityCheck() { AdvancingAllocPoolChunk *chunk, *next; for (chunk = mChunks; chunk; chunk = next) { next = chunk->mNext; mAllocPool->DoCheckInUseChunk(AllocPool::MemToChunk(chunk)); } for (chunk = mFatties; chunk; chunk = next) { next = chunk->mNext; mAllocPool->DoCheckInUseChunk(AllocPool::MemToChunk(chunk)); } return true; } SuperCollider-Source/lang/LangSource/AdvancingAllocPool.h000644 000765 000024 00000003747 12321461511 024517 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* AdvancingAllocPool implements a simple advancing pointer allocation scheme. There is no Free(). All objects in the pool are freed at once with FreeAll(). Thus it is very fast. */ #ifndef _AdvancingAllocPool_ #define _AdvancingAllocPool_ #include #include class AllocPool; struct AdvancingAllocPoolChunk; typedef int int32; inline void FailNil(void *ptr) { if (!ptr) throw std::runtime_error("alloc failed"); } struct AdvancingAllocPoolChunkHdr { AdvancingAllocPoolChunk *mNext; size_t mSize; int32 mPad1, mPad2; }; struct AdvancingAllocPoolChunk { AdvancingAllocPoolChunk *mNext; size_t mSize; int32 mPad1, mPad2; char mSpace[16]; }; class AdvancingAllocPool { public: AdvancingAllocPool(); ~AdvancingAllocPool() { FreeAll(); } void Init(AllocPool *inAllocPool, size_t initSize, size_t growSize, size_t tooBigSize); void *Alloc(size_t inBytes); void FreeAll(); bool SanityCheck(); private: void AddChunk(size_t inSize); AllocPool* mAllocPool; size_t mInitSize; size_t mGrowSize; size_t mCurSize; size_t mTooBig; AdvancingAllocPoolChunk *mChunks; AdvancingAllocPoolChunk *mFatties; }; #endif SuperCollider-Source/lang/LangSource/AllocPools.h000644 000765 000024 00000002026 12321461511 023054 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Pools for memory allocation. */ #ifndef _AllocPools_ #define _AllocPools_ class AllocPool; extern AllocPool *pyr_pool_compile; extern AllocPool *pyr_pool_runtime; #endif SuperCollider-Source/lang/LangSource/Bison/000755 000765 000024 00000000000 13007315613 021711 5ustar00crucialstaff000000 000000 SuperCollider-Source/lang/LangSource/ByteCodeArray.cpp000644 000765 000024 00000011550 12321461511 024037 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "SCBase.h" #include "InitAlloc.h" #include "ByteCodeArray.h" #include "Opcodes.h" ByteCodes gCompilingByteCodes; long totalByteCodes = 0; void initByteCodes() { if (gCompilingByteCodes) { freeByteCodes(gCompilingByteCodes); gCompilingByteCodes = NULL; } } int compileOpcode(long opcode, long operand1) { int retc; if (operand1 <= 15) { compileByte((opcode<<4) | operand1); retc = 1; } else { compileByte(opcode); compileByte(operand1); if (opcode == opSendMsg || opcode == opSendSpecialMsg || opcode == opSendSuper) { // these expect numKeyArgsPushed to be passed. compileByte(0); } retc = 2; } return retc; } void compileJump(long opcode, long jumplen) { compileByte((opSpecialOpcode<<4) | opcode); compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); } void compileByte(long byte) { if (gCompilingByteCodes == NULL) { gCompilingByteCodes = allocByteCodes(); } if ((gCompilingByteCodes->ptr - gCompilingByteCodes->bytes) >= gCompilingByteCodes->size) { reallocByteCodes(gCompilingByteCodes); } totalByteCodes++; *gCompilingByteCodes->ptr++ = byte; } int compileNumber(unsigned long value) { compileByte((value >> 24) & 0xFF); compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); return 4; } int compileNumber24(unsigned long value) { compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); return 4; } void compileAndFreeByteCodes(ByteCodes byteCodes) { compileByteCodes(byteCodes); freeByteCodes(byteCodes); } void copyByteCodes(Byte *dest, ByteCodes byteCodes) { memcpy(dest, byteCodes->bytes, byteCodeLength(byteCodes)); } ByteCodes getByteCodes() { ByteCodes curByteCodes; curByteCodes = gCompilingByteCodes; gCompilingByteCodes = NULL; return curByteCodes; } ByteCodes saveByteCodeArray() { ByteCodes curByteCodes; curByteCodes = gCompilingByteCodes; gCompilingByteCodes = NULL; return curByteCodes; } void restoreByteCodeArray(ByteCodes byteCodes) { gCompilingByteCodes = byteCodes; } size_t byteCodeLength(ByteCodes byteCodes) { if (!byteCodes) return 0; return (byteCodes->ptr - byteCodes->bytes); } /*********************************************************************** * * Internal routines. * ***********************************************************************/ void compileByteCodes(ByteCodes byteCodes) { Byte *ptr; int i; if (byteCodes == NULL) return; //postfl("[%d]\n", byteCodes->ptr - byteCodes->bytes); for (i=0, ptr = byteCodes->bytes; ptr < byteCodes->ptr; ptr++, ++i) { compileByte(*ptr); //postfl("%02X ", *ptr); //if ((i & 15) == 15) postfl("\n"); } //postfl("\n\n"); } ByteCodes allocByteCodes() { ByteCodes newByteCodes; // pyrmalloc: I think that all bytecodes are copied to objects // lifetime: kill after compile newByteCodes = (ByteCodes)pyr_pool_compile->Alloc(sizeof(ByteCodeArray)); MEMFAIL(newByteCodes); newByteCodes->bytes = (Byte *)pyr_pool_compile->Alloc(BYTE_CODE_CHUNK_SIZE); MEMFAIL(newByteCodes->bytes); newByteCodes->ptr = newByteCodes->bytes; newByteCodes->size = BYTE_CODE_CHUNK_SIZE; //postfl("allocByteCodes %0X\n", newByteCodes); return newByteCodes; } void reallocByteCodes(ByteCodes byteCodes) { Byte *newBytes; if (byteCodes->size != (byteCodes->ptr - byteCodes->bytes)) { error("reallocByteCodes called with size != byteCode len"); } size_t newLen = byteCodes->size << 1; // pyrmalloc: I think that all bytecodes are copied to objects // lifetime: kill after compile newBytes = (Byte *)pyr_pool_compile->Alloc(newLen); MEMFAIL(newBytes); memcpy(newBytes, byteCodes->bytes, byteCodes->size); pyr_pool_compile->Free(byteCodes->bytes); byteCodes->bytes = newBytes; byteCodes->ptr = newBytes + byteCodes->size; byteCodes->size = newLen; } void freeByteCodes(ByteCodes byteCodes) { //postfl("freeByteCodes %0X\n", byteCodes); if (byteCodes != NULL) { pyr_pool_compile->Free(byteCodes->bytes); pyr_pool_compile->Free(byteCodes); } } SuperCollider-Source/lang/LangSource/ByteCodeArray.h000644 000765 000024 00000003374 12321461511 023511 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LANG_BYTECODEARRAY_H #define LANG_BYTECODEARRAY_H typedef unsigned char Byte; #define BYTE_CODE_CHUNK_SIZE 64 typedef struct { Byte *bytes; Byte *ptr; size_t size; } ByteCodeArray, *ByteCodes; extern ByteCodes gCompilingByteCodes; extern long totalByteCodes; void initByteCodes(); void compileByte(long byte); void compileAndFreeByteCodes(ByteCodes byteCodes); void copyByteCodes(Byte *dest, ByteCodes byteCodes); ByteCodes getByteCodes(); ByteCodes saveByteCodeArray(); void restoreByteCodeArray(ByteCodes byteCodes); size_t byteCodeLength(ByteCodes byteCodes); void compileByteCodes(ByteCodes byteCodes); ByteCodes allocByteCodes(); void reallocByteCodes(ByteCodes byteCodes); void freeByteCodes(ByteCodes byteCodes); int compileOpcode(long opcode, long operand1); void compileJump(long opcode, long jumplen); int compileNumber(unsigned long value); int compileNumber24(unsigned long value); #endif SuperCollider-Source/lang/LangSource/cmdLineFuncs.cpp000644 000765 000024 00000002137 12321461511 023715 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_LanguageClient.h" int main(int argc, char** argv) { SC_LanguageClient * client = createLanguageClient("sclang"); if (!client) return 1; int returnCode = client->run(argc, argv); destroyLanguageClient(client); return returnCode; } SuperCollider-Source/lang/LangSource/dumpByteCodes.cpp000644 000765 000024 00000106142 12321461511 024113 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrParseNode.h" #include "PyrSymbol.h" #include "SCBase.h" void numBlockTemps(PyrBlock *block, long level, long *numArgNames, long *numVarNames); void numBlockTemps(PyrBlock *block, long level, long *numArgNames, long *numVarNames) { long i; for (i=0; icontextDef); } *numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; *numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; } unsigned char* dumpOneByteCode(PyrBlock *theBlock, PyrClass* theClass, unsigned char *ip); unsigned char* dumpOneByteCode(PyrBlock *theBlock, PyrClass* theClass, unsigned char *ip) { PyrClass *classobj; PyrBlock *block; PyrSlot *slot; PyrSymbol *selector; char str[256]; long op1, op2, op3, op4, op5; long i, n, ival, jmplen; long numArgNames, numVarNames, numTemps; unsigned char *ipbeg; if (theClass == NULL) { block = theBlock; theClass = 0; while (block) { //dumpObject((PyrObject*)block); //post("block->classptr %d class_method %d %d\n", // block->classptr, class_method, isKindOf((PyrObject*)block, class_method)); //if (block->classptr == class_method) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; //error("dumpByteCodes: no Class found.\n"); //return NULL; } } ipbeg = slotRawInt8Array(&theBlock->code)->b; n = ip - ipbeg; op1 = *ip++; post("%3d %02X", n, op1); switch (op1) { case 0 : // push class op2 = *ip++; // get literal index post(" %02X PushClassX '%s'\n", op2, slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2])->name); break; case 1 : // Extended, PushInstVar op2 = *ip++; // get inst var index post(" %02X PushInstVarX '%s'\n", op2, slotRawSymbolArray(&theClass->instVarNames)->symbols[op2]->name); break; case 2 : // Extended, PushTempVar op2 = *ip++; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = numTemps - *ip++ - 1; // get temp var index if (op3 < numArgNames) { post(" %02X %02X PushTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else { post(" %02X %02X PushTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 3 : // Extended, PushTempZeroVar block = theBlock; numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op2 = numTemps - *ip++ - 1; // get temp var index if (op2 < numArgNames) { post(" %02X PushTempZeroVarX '%s'\n", op2, slotRawSymbolArray(&theBlock->argNames)->symbols[op2]->name); } else { post(" %02X PushTempZeroVarX '%s'\n", op2, slotRawSymbolArray(&theBlock->varNames)->symbols[op2-numArgNames]->name); } break; case 4 : // Extended, PushLiteral op2 = *ip++; // get literal index // push a block if it is one slot = slotRawObject(&theBlock->selectors)->slots + op2; slotString(slot, str); post(" %02X PushLiteralX %s\n", op2, str); break; case 5 : // Extended, PushClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index post(" %02X %02X PushClassVarX\n", op2, op3); break; case 6 : // Extended, PushSpecialValue == push a special class op2 = *ip++; // get class name index classobj = gSpecialClasses[op2]->u.classobj; post(" %02X PushSpecialClass '%s'\n", op2, slotRawSymbol(&classobj->name)->name); break; case 7 : // Extended, StoreInstVar op2 = *ip++; // get inst var index post(" %02X StoreInstVarX '%s'\n", op2, slotRawSymbolArray(&theClass->instVarNames)->symbols[op2]->name); break; case 8 : // Extended, StoreTempVar op2 = *ip++; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = *ip++; // get temp var index if (op3 < numArgNames) { post(" %02X %02X StoreTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else { post(" %02X %02X StoreTempVarX '%s'\n", op2, op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 9 : // Extended, StoreClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index post(" %02X %02X StoreClassVarX\n", op2, op3); break; case 10 : // Extended, SendMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); post(" %02X %02X %02X SendMsgX '%s'\n", op2, op3, op4, selector->name); break; case 11 : // Extended, SuperMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); post(" %02X %02X %02X SuperMsgX '%s'\n", op2, op3, op4, selector->name); break; case 12 : // Extended, SendSpecialMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index post(" %02X %02X %02X SendSpecialMsgX '%s'\n", op2, op3, op4, gSpecialSelectors[op4]->name); break; case 13 : // Extended, SendSpecialUnaryArithMsg op2 = *ip++; // get selector index post(" %02X SendSpecialUnaryArithMsgX '%s'\n", op2, gSpecialUnarySelectors[op2]->name); break; case 14 : // Extended, SendSpecialBinaryArithMsg op2 = *ip++; // get selector index post(" %02X SendSpecialBinaryArithMsgX '%s'\n", op2, gSpecialBinarySelectors[op2]->name); break; case 15 : // Extended, SpecialOpcode (none yet) op2 = *ip++; // get extended special opcode switch (op2) { case opgProcess : // push thisProcess post(" %02X opgProcess\n", op1, op2); break; case opgThread : // push thisThread post(" %02X opgThread\n", op1, op2); break; case opgMethod : // push thisMethod post(" %02X opgMethod\n", op1, op2); break; case opgFunctionDef : // push thisBlock post(" %02X opgFunctionDef\n", op1, op2); break; case opgFunction : // push thisClosure post(" %02X opgFunction\n", op1, op2); break; } break; // PushInstVar, 0..15 case 16 : case 17 : case 18 : case 19 : case 20 : case 21 : case 22 : case 23 : case 24 : case 25 : case 26 : case 27 : case 28 : case 29 : case 30 : case 31 : post(" PushInstVar '%s'\n", slotRawSymbolArray(&theClass->instVarNames)->symbols[op1&15]->name); break; case 32 : op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfTrue %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 33 : case 34 : case 35 : case 36 : case 37 : case 38 : case 39 : op2 = op1 & 15; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = numTemps - *ip++ - 1; // get temp var index if (op3 >= 0 && op3 < numArgNames) { post(" %02X PushTempVar '%s'\n", op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else if (op3 >= 0) { post(" %02X PushTempVar '%s'\n", op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 40 : op5 = *ip++; ival = op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X PushConstant %s\n", op5, str); break; case 41 : op4 = *ip++; op5 = *ip++; ival = (op4 << 8) | op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X %02X PushConstant %s\n", op4, op5, str); break; case 42 : op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (op3 << 16) | (op4 << 8) | op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X %02X %02X PushConstant %s\n", op3, op4, op5, str); break; case 43 : op2 = *ip++; op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (op2 << 24) | (op3 << 16) | (op4 << 8) | op5; slot = slotRawObject(&theBlock->constants)->slots + ival; slotString(slot, str); post(" %02X %02X %02X %02X PushConstant %s\n", op2, op3, op4, op5, str); break; case 44 : op5 = *ip++; ival = (int32)(op5 << 24) >> 24; post(" %02X PushInt %d\n", op5, ival); break; case 45 : op4 = *ip++; op5 = *ip++; ival = (int32)((op4 << 24) | (op5 << 16)) >> 16; post(" %02X %02X PushInt %d\n", op4, op5, ival); break; case 46 : op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (int32)((op3 << 24) | (op4 << 16) | (op5 << 8)) >> 8; post(" %02X %02X %02X PushInt %d\n", op3, op4, op5, ival); break; case 47 : op2 = *ip++; op3 = *ip++; op4 = *ip++; op5 = *ip++; ival = (int32)((op2 << 24) | (op3 << 16) | (op4 << 8) | op5); post(" %02X %02X %02X %02X PushInt %d\n", op2, op3, op4, op5, ival); break; case 48 : case 49 : case 50 : case 51 : case 52 : case 53 : case 54 : case 55 : case 56 : case 57 : case 58 : case 59 : case 60 : case 61 : case 62 : case 63 : op2 = op1 & 15; // get temp var index block = theBlock; numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; if (op2 < numArgNames) { post(" PushTempZeroVar '%s'\n", slotRawSymbolArray(&theBlock->argNames)->symbols[op2]->name); } else { post(" PushTempZeroVar '%s'\n", slotRawSymbolArray(&theBlock->varNames)->symbols[op2-numArgNames]->name); } break; case 64 : case 65 : case 66 : case 67 : case 68 : case 69 : case 70 : case 71 : case 72 : case 73 : case 74 : case 75 : case 76 : case 77 : case 78 : case 79 : op2 = op1 & 15; // get temp var level slot = slotRawObject(&theBlock->constants)->slots + op2; slotString(slot, str); post(" PushLiteral %s\n", str); break; // PushClassVar case 80 : case 81 : case 82 : case 83 : case 84 : case 85 : case 86 : case 87 : case 88 : case 89 : case 90 : case 91 : case 92 : case 93 : case 94 : case 95 : op2 = op1 & 15; op3 = *ip++; // get class var index post(" %02X %02X PushClassVar\n", op2, op3); break; // PushSpecialValue case 96 : post(" PushSpecialValue this\n"); break; case 97 : post(" PushOneAndSubtract\n"); break; case 98 : post(" PushSpecialValue -1\n"); break; case 99 : post(" PushSpecialValue 0\n"); break; case 100 : post(" PushSpecialValue 1\n"); break; case 101 : post(" PushSpecialValue 2\n"); break; case 102 : post(" PushSpecialValue 0.5\n"); break; case 103 : post(" PushSpecialValue -1.0\n"); break; case 104 : post(" PushSpecialValue 0.0\n"); break; case 105 : post(" PushSpecialValue 1.0\n"); break; case 106 : post(" PushSpecialValue 2.0\n"); break; case 107 : post(" PushOneAndAdd\n"); break; case 108 : post(" PushSpecialValue true\n"); break; case 109 : post(" PushSpecialValue false\n"); break; case 110 : post(" PushSpecialValue nil\n"); break; case 111 : post(" PushSpecialValue 'end'\n"); break; // StoreInstVar, 0..15 case 112 : case 113 : case 114 : case 115 : case 116 : case 117 : case 118 : case 119 : case 120 : case 121 : case 122 : case 123 : case 124 : case 125 : case 126 : case 127 : post(" StoreInstVar '%s'\n", slotRawSymbolArray(&theClass->instVarNames)->symbols[op1 & 15]->name); break; // StoreTempVar case 128 : case 129 : case 130 : case 131 : case 132 : case 133 : case 134 : case 135 : op2 = op1 & 15; // get temp var level block = theBlock; for (i=op2; i--; block = slotRawBlock(&block->contextDef)) { /* noop */ } numArgNames = slotRawSymbolArray(&block->argNames) ? slotRawSymbolArray(&block->argNames)->size : 0; numVarNames = slotRawSymbolArray(&block->varNames) ? slotRawSymbolArray(&block->varNames)->size : 0; numTemps = numArgNames + numVarNames; op3 = *ip++; // get temp var index if (op3 < numArgNames) { post(" %02X StoreTempVar '%s'\n", op3, slotRawSymbolArray(&block->argNames)->symbols[op3]->name); } else { post(" %02X StoreTempVar '%s'\n", op3, slotRawSymbolArray(&block->varNames)->symbols[op3-numArgNames]->name); } break; case 136 : op2 = *ip++; // get inst var index op3 = *ip++; // get selector index selector = gSpecialSelectors[op3]; post(" %02X %02X PushInstVarAndSendSpecialMsg '%s' '%s'\n", op2, op3, slotRawSymbolArray(&theClass->instVarNames)->symbols[op2]->name, selector->name); break; case 137 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X PushAllArgs+SendMsg '%s'\n", op2, selector->name); break; case 138 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X PushAllButFirstArg+SendMsg '%s'\n", op2, selector->name); break; case 139 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X PushAllArgs+SendSpecialMsg '%s'\n", op2, selector->name); break; case 140 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X PushAllButFirstArg+SendSpecialMsg '%s'\n", op2, selector->name); break; case 141 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X PushAllButFirstTwoArgs+SendMsg '%s'\n", op2, selector->name); break; case 142 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X PushAllButFirstTwoArgs+SendSpecialMsg '%s'\n", op2, selector->name); break; case 143 : op2 = *ip++; // get loop opcode if (op2 < 23 || op2 > 27) { post(" %02X ControlOpcode\n", op2); break; } else { op3 = *ip++; // jump op4 = *ip++; // jump jmplen = ((op3 & 0xFF)<<8) | (op4 & 0xFF); post(" %02X %02X %02X ControlOpcode %d (%d)\n", op2, op3, op4, jmplen, n + jmplen + 3); break; } break; // StoreClassVar case 144 : case 145 : case 146 : case 147 : case 148 : case 149 : case 150 : case 151 : case 152 : case 153 : case 154 : case 155 : case 156 : case 157 : case 158 : case 159 : op2 = op1 & 15; op3 = *ip++; // get class var index post(" %02X StoreClassVar\n", op3); break; // SendMsg case 160 : case 161 : case 162 : case 163 : case 164 : case 165 : case 166 : case 167 : case 168 : case 169 : case 170 : case 171 : case 172 : case 173 : case 174 : case 175 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X SendMsg '%s'\n", op2, selector->name); break; // TailCallReturnFromFunction case 176 : post(" TailCallReturnFromFunction\n"); break; // SuperMsg case 177 : case 178 : case 179 : case 180 : case 181 : case 182 : case 183 : case 184 : case 185 : case 186 : case 187 : case 188 : case 189 : case 190 : case 191 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); post(" %02X SuperMsg '%s'\n", op2, selector->name); break; // SendSpecialMsg case 192 : case 193 : case 194 : case 195 : case 196 : case 197 : case 198 : case 199 : case 200 : case 201 : case 202 : case 203 : case 204 : case 205 : case 206 : case 207 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; post(" %02X SendSpecialMsg '%s'\n", op2, selector->name); break; // SendSpecialUnaryArithMsg case 208 : case 209 : case 210 : case 211 : case 212 : case 213 : case 214 : case 215 : case 216 : case 217 : case 218 : case 219 : case 220 : case 221 : case 222 : case 223 : op2 = op1 & 15; selector = gSpecialUnarySelectors[op2]; post(" SendSpecialUnaryArithMsg '%s'\n", selector->name); break; // SendSpecialBinaryArithMsg case 224 : case 225 : case 226 : case 227 : case 228 : case 229 : case 230 : case 231 : case 232 : case 233 : case 234 : case 235 : case 236 : case 237 : case 238 : case 239 : op2 = op1 & 15; selector = gSpecialBinarySelectors[op2]; post(" SendSpecialBinaryArithMsg '%s'\n", selector->name); break; // SpecialOpcodes case 240 : post(" Drop\n"); break; case 241 : post(" Dup\n"); break; // Dup case 242 : post(" BlockReturn\n"); break; // BlockReturn case 243 : post(" Return\n"); break; // Return case 244 : post(" ReturnSelf\n"); break; // ReturnSelf case 245 : post(" ReturnTrue\n"); break; // ReturnTrue case 246 : post(" ReturnFalse\n"); break; // ReturnFalse case 247 : post(" ReturnNil\n"); break; // ReturnNil case 248 : // JumpIfFalse op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfFalse %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 249 : // JumpIfFalsePushNil op2 = *ip++; op3 = *ip++; jmplen = ((op2 & 0xFF)<<8) | (op3 & 0xFF); post(" %02X %02X JumpIfFalsePushNil %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 250 : // JumpIfFalsePushFalse op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfFalsePushFalse %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 251 : // JumpIfTruePushTrue op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpIfTruePushTrue %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 252 : // JumpFwd op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpFwd %d (%d)\n", op2, op3, jmplen, n + jmplen + 3); break; case 253 : // JumpBak op2 = *ip++; op3 = *ip++; jmplen = (op2<<8) | op3; post(" %02X %02X JumpBak %d (%d)\n", op2, op3, jmplen, n - jmplen + 1); break; case 254 : op2 = *ip++; post(" %02X SpecialBinaryOpWithAdverb\n", op2); break; case 255 : post(" TailCallReturnFromMethod\n"); break; } return ip; } bool detectSendSelector(PyrBlock *theBlock, PyrClass* theClass, unsigned char **ipp, PyrSymbol *testSelector); bool detectSendSelector(PyrBlock *theBlock, PyrClass* theClass, unsigned char **ipp, PyrSymbol *testSelector) { PyrBlock *block; PyrSymbol *selector = 0; long op1, op2, op3, op4, op5, op6; unsigned char *ip = *ipp; if (theClass == NULL) { block = theBlock; theClass = 0; while (block) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; } } op1 = *ip++; switch (op1) { case 0 : // push class op2 = *ip++; // get literal index break; case 1 : // Extended, PushInstVar op2 = *ip++; // get inst var index break; case 2 : // Extended, PushTempVar op2 = *ip++; // get temp var level op3 = *ip++; // get temp var index break; case 3 : // Extended, PushTempZeroVar op2 = *ip++; // get temp var level break; case 4 : // Extended, PushLiteral op2 = *ip++; // get literal index break; case 5 : // Extended, PushClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index break; case 6 : // Extended, PushSpecialValue == push a special class op2 = *ip++; // get class name index break; case 7 : // Extended, StoreInstVar op2 = *ip++; // get inst var index break; case 8 : // Extended, StoreTempVar op2 = *ip++; // get temp var level op3 = *ip++; // get class var index break; case 9 : // Extended, StoreClassVar op2 = *ip++; // get class var literal index op3 = *ip++; // get class var index break; case 10 : // Extended, SendMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); break; case 11 : // Extended, SuperMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op4]); break; case 12 : // Extended, SendSpecialMsg op2 = *ip++; // get num args op3 = *ip++; // get num key args op4 = *ip++; // get selector index selector = gSpecialSelectors[op4]; break; case 13 : // Extended, SendSpecialUnaryArithMsg op2 = *ip++; // get selector index selector = gSpecialUnarySelectors[op2]; break; case 14 : // Extended, SendSpecialBinaryArithMsg op2 = *ip++; // get selector index selector = gSpecialBinarySelectors[op2]; break; case 15 : // Extended, SpecialOpcode (none yet) op2 = *ip++; // get extended special opcode break; // PushInstVar, 0..15 case 16 : case 17 : case 18 : case 19 : case 20 : case 21 : case 22 : case 23 : case 24 : case 25 : case 26 : case 27 : case 28 : case 29 : case 30 : case 31 : break; case 32 : case 33 : case 34 : case 35 : case 36 : case 37 : case 38 : case 39 : case 40 : case 41 : case 42 : case 43 : case 44 : case 45 : case 46 : case 47 : op2 = op1 & 15; // get temp var level op3 = *ip++; // get num key args break; case 48 : case 49 : case 50 : case 51 : case 52 : case 53 : case 54 : case 55 : case 56 : case 57 : case 58 : case 59 : case 60 : case 61 : case 62 : case 63 : break; case 64 : case 65 : case 66 : case 67 : case 68 : case 69 : case 70 : case 71 : case 72 : case 73 : case 74 : case 75 : case 76 : case 77 : case 78 : case 79 : break; // PushClassVar case 80 : case 81 : case 82 : case 83 : case 84 : case 85 : case 86 : case 87 : case 88 : case 89 : case 90 : case 91 : case 92 : case 93 : case 94 : case 95 : op2 = op1 & 15; op3 = *ip++; // get class var index break; // PushSpecialValue case 96 : case 97 : case 98 : case 99 : case 100 : case 101 : case 102 : case 103 : case 104 : case 105 : case 106 : case 107 : case 108 : case 109 : case 110 : case 111 : break; // StoreInstVar, 0..15 case 112 : case 113 : case 114 : case 115 : case 116 : case 117 : case 118 : case 119 : case 120 : case 121 : case 122 : case 123 : case 124 : case 125 : case 126 : case 127 : break; // StoreTempVar case 128 : case 129 : case 130 : case 131 : case 132 : case 133 : case 134 : case 135 : op2 = op1 & 15; // get temp var level op3 = *ip++; // get class var index break; case 136 : op2 = *ip++; // get inst var index op3 = *ip++; // get selector index selector = gSpecialSelectors[op3]; break; case 137 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; case 138 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; case 139 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; case 140 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; case 141 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; case 142 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; case 143 : op2 = *ip++; // get selector index break; // StoreClassVar case 144 : case 145 : case 146 : case 147 : case 148 : case 149 : case 150 : case 151 : case 152 : case 153 : case 154 : case 155 : case 156 : case 157 : case 158 : case 159 : op2 = op1 & 15; op3 = *ip++; // get class var index break; // SendMsg case 160 : case 161 : case 162 : case 163 : case 164 : case 165 : case 166 : case 167 : case 168 : case 169 : case 170 : case 171 : case 172 : case 173 : case 174 : case 175 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; // SuperMsg case 176 : case 177 : case 178 : case 179 : case 180 : case 181 : case 182 : case 183 : case 184 : case 185 : case 186 : case 187 : case 188 : case 189 : case 190 : case 191 : op2 = *ip++; // get selector index selector = slotRawSymbol(&slotRawObject(&theBlock->selectors)->slots[op2]); break; // SendSpecialMsg case 192 : case 193 : case 194 : case 195 : case 196 : case 197 : case 198 : case 199 : case 200 : case 201 : case 202 : case 203 : case 204 : case 205 : case 206 : case 207 : op2 = *ip++; // get selector index selector = gSpecialSelectors[op2]; break; // SendSpecialUnaryArithMsg case 208 : case 209 : case 210 : case 211 : case 212 : case 213 : case 214 : case 215 : case 216 : case 217 : case 218 : case 219 : case 220 : case 221 : case 222 : case 223 : op2 = op1 & 15; selector = gSpecialUnarySelectors[op2]; break; // SendSpecialBinaryArithMsg case 224 : case 225 : case 226 : case 227 : case 228 : case 229 : case 230 : case 231 : case 232 : case 233 : case 234 : case 235 : case 236 : case 237 : case 238 : case 239 : op2 = op1 & 15; selector = gSpecialBinarySelectors[op2]; break; // SpecialOpcodes case 240 : case 241 : case 242 : case 243 : case 244 : case 245 : case 246 : case 247 : break; case 248 : // JumpIfFalse case 249 : // JumpIfFalsePushNil case 250 : // JumpIfFalsePushFalse case 251 : // JumpIfTruePushTrue case 252 : // JumpFwd case 253 : // JumpBak op2 = *ip++; op3 = *ip++; break; case 254 : // PushPosInt case 255 : // PushNegInt op2 = *ip++; if (op2 & 0x80) { op3 = *ip++; if (op3 & 0x80) { op4 = *ip++; if (op4 & 0x80) { op5 = *ip++; if (op5 & 0x80) { op6 = *ip++; } } } } break; } *ipp = ip; return testSelector == selector; } void dumpByteCodes(PyrBlock *theBlock); void dumpByteCodes(PyrBlock *theBlock) { PyrClass *theClass; PyrBlock *block; long size; unsigned char *ip, *ipbeg, *ipend; if (slotRawInt8Array(&theBlock->code) == NULL) { post("Code empty.\n"); return; } block = theBlock; theClass = 0; while (block) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; } ip = ipbeg = slotRawInt8Array(&theBlock->code)->b; size = slotRawInt8Array(&theBlock->code)->size; ipend = ip + size; post("BYTECODES: (%d)\n", size); while (ipcode) == NULL) { PyrMethodRaw* methraw = METHRAW(theBlock); switch (methraw->methType) { case methRedirect : case methRedirectSuper : case methForwardInstVar : case methForwardClassVar : selector = slotRawSymbol(&theBlock->selectors); return selector == testSelector; default : return false; } } block = theBlock; theClass = 0; while (block) { if (isKindOf((PyrObject*)block, class_method)) { theClass = slotRawClass(&((PyrMethod*)block)->ownerclass); break; } block = slotRawBlock(&block->contextDef); } if (theClass == NULL) { theClass = s_interpreter->u.classobj; } ip = ipbeg = slotRawInt8Array(&theBlock->code)->b; size = slotRawInt8Array(&theBlock->code)->size; ipend = ip + size; bool res = false; while (ip #include #include #include #ifdef _WIN32 # define snprintf _snprintf # define PATH_MAX _MAX_PATH #endif extern int textpos; void dumpNodeList(PyrParseNode *node) { for (; node; node = node->mNext) { DUMPNODE(node, 0); } } void PyrCurryArgNode::dump(int level) { postfl("%2d CurryArg %d\n", level, mArgNum); } void PyrSlotNode::dump(int level) { if (mClassno == pn_PushLitNode) dumpPushLit(level); else if (mClassno == pn_PushNameNode) postfl("%2d PushName '%s'\n", level, slotRawSymbol(&mSlot)->name); else if (mClassno == pn_LiteralNode) dumpLiteral(level); else { postfl("%2d SlotNode\n", level); dumpPyrSlot(&mSlot); } DUMPNODE(mNext, level); } void PyrPushKeyArgNode::dump(int level) { postfl("%2d PushKeyArgNode\n", level); DUMPNODE(mSelector, level+1); DUMPNODE(mExpr, level+1); DUMPNODE(mNext, level); } void PyrClassExtNode::dump(int level) { postfl("%2d ClassExt '%s'\n", level, slotRawSymbol(&mClassName->mSlot)->name); DUMPNODE(mMethods, level+1); DUMPNODE(mNext, level); } void PyrClassNode::dump(int level) { postfl("%2d Class '%s'\n", level, slotRawSymbol(&mClassName->mSlot)->name); DUMPNODE(mSuperClassName, level+1); DUMPNODE(mVarlists, level+1); DUMPNODE(mMethods, level+1); DUMPNODE(mNext, level); } void PyrMethodNode::dump(int level) { postfl("%2d MethodNode '%s' %s\n", level, slotRawSymbol(&mMethodName->mSlot)->name, mPrimitiveName ? slotRawSymbol(&mPrimitiveName->mSlot)->name:""); DUMPNODE(mArglist, level+1); DUMPNODE(mBody, level+1); DUMPNODE(mNext, level); } void PyrArgListNode::dump(int level) { postfl("%2d ArgList\n", level); DUMPNODE(mVarDefs, level+1); DUMPNODE(mRest, level+1); DUMPNODE(mNext, level); } void PyrVarListNode::dump(int level) { postfl("%2d VarList\n", level); DUMPNODE(mVarDefs, level+1); DUMPNODE(mNext, level); } void PyrVarDefNode::dump(int level) { postfl("%2d VarDef '%s'\n", level, slotRawSymbol(&mVarName->mSlot)->name); DUMPNODE(mDefVal, level); DUMPNODE(mNext, level); } void PyrCallNode::dump(int level) { postfl("%2d Call '%s'\n", level, slotRawSymbol(&mSelector->mSlot)->name); DUMPNODE(mArglist, level+1); DUMPNODE(mKeyarglist, level+1); DUMPNODE(mNext, level); } void PyrBinopCallNode::dump(int level) { postfl("%2d BinopCall '%s'\n", level, slotRawSymbol(&mSelector->mSlot)->name); DUMPNODE(mArglist, level+1); DUMPNODE(mNext, level); } void PyrDropNode::dump(int level) { postfl("%2d Drop (\n", level); DUMPNODE(mExpr1, level+1); postfl(" -> %2d Drop\n", level); DUMPNODE(mExpr2, level+1); postfl(") %2d Drop\n", level); DUMPNODE(mNext, level); } void PyrSlotNode::dumpPushLit(int level) { postfl("%2d PushLit\n", level); if (!IsPtr(&mSlot)) dumpPyrSlot(&mSlot); else { DUMPNODE((PyrParseNode*)slotRawObject(&mSlot), level); } } void PyrSlotNode::dumpLiteral(int level) { postfl("%2d Literal\n", level); if (!IsPtr(&mSlot)) dumpPyrSlot(&mSlot); else { DUMPNODE((PyrParseNode*)slotRawObject(&mSlot), level); } } void PyrReturnNode::dump(int level) { postfl("%2d Return (\n", level); DUMPNODE(mExpr, level+1); postfl(") %2d Return \n", level); DUMPNODE(mNext, level); } void PyrBlockReturnNode::dump(int level) { postfl("%2d FuncReturn\n", level); DUMPNODE(mNext, level); } void PyrAssignNode::dump(int level) { postfl("%2d Assign '%s'\n", level, slotRawSymbol(&mVarName->mSlot)->name); DUMPNODE(mVarName, level+1); DUMPNODE(mExpr, level+1); DUMPNODE(mNext, level); } void PyrSetterNode::dump(int level) { //postfl("%2d Assign '%s'\n", level, slotRawSymbol(&mVarName->mSlot)->name); DUMPNODE(mSelector, level+1); DUMPNODE(mExpr1, level+1); DUMPNODE(mExpr2, level+1); } void PyrMultiAssignNode::dump(int level) { postfl("%2d MultiAssign\n", level); DUMPNODE(mVarList, level+1); DUMPNODE(mExpr, level+1); DUMPNODE(mNext, level); } void PyrMultiAssignVarListNode::dump(int level) { postfl("%2d MultiAssignVarList\n", level); DUMPNODE(mVarNames, level+1); DUMPNODE(mRest, level+1); DUMPNODE(mNext, level); } void PyrDynDictNode::dump(int level) { postfl("%2d DynDict\n", level); DUMPNODE(mElems, level+1); DUMPNODE(mNext, level); } void PyrDynListNode::dump(int level) { postfl("%2d DynList\n", level); DUMPNODE(mElems, level+1); DUMPNODE(mNext, level); } void PyrLitListNode::dump(int level) { postfl("%2d LitList\n", level); postfl(" %2d mElems\n", level); DUMPNODE(mElems, level+1); postfl(" %2d mNext\n", level); DUMPNODE(mNext, level); } void PyrBlockNode::dump(int level) { postfl("%2d Func\n", level); DUMPNODE(mArglist, level+1); DUMPNODE(mBody, level+1); DUMPNODE(mNext, level); } void dumpPyrSlot(PyrSlot* slot) { char str[1024]; slotString(slot, str); post(" %s\n", str); } void slotString(PyrSlot *slot, char *str) { switch (GetTag(slot)) { case tagInt : sprintf(str, "Integer %d", slotRawInt(slot)); break; case tagChar : sprintf(str, "Character %d '%c'", static_cast(slotRawChar(slot)), static_cast(slotRawChar(slot))); break; case tagSym : if (strlen(slotRawSymbol(slot)->name) > 240) { char str2[256]; memcpy(str2, slotRawSymbol(slot)->name, 240); str2[240] = 0; snprintf(str, 256, "Symbol '%s...'", str2); } else { snprintf(str, 256, "Symbol '%s'", slotRawSymbol(slot)->name); } break; case tagObj : if (slotRawObject(slot)) { PyrClass * classptr = slotRawObject(slot)->classptr; if (classptr == class_class) { sprintf(str, "class %s (%p)", slotRawSymbol(&((PyrClass*)slotRawObject(slot))->name)->name, slotRawObject(slot)); } else if (classptr == class_string) { char str2[48]; int len; if (slotRawObject(slot)->size > 47) { memcpy(str2, (char*)slotRawObject(slot)->slots, 44); str2[44] = '.'; str2[45] = '.'; str2[46] = '.'; str2[47] = 0; } else { len = sc_min(47, slotRawObject(slot)->size); memcpy(str2, (char*)slotRawObject(slot)->slots, len); str2[len] = 0; } sprintf(str, "\"%s\"", str2); } else if (classptr == class_method) { sprintf(str, "instance of Method %s:%s (%p)", slotRawSymbol(&slotRawClass(&slotRawMethod(slot)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(slot)->name)->name, slotRawMethod(slot)); } else if (classptr == class_fundef) { PyrSlot *context, *nextcontext; // find function's method nextcontext = &slotRawBlock(slot)->contextDef; if (NotNil(nextcontext)) { do { context = nextcontext; nextcontext = &slotRawBlock(context)->contextDef; } while (NotNil(nextcontext)); if (isKindOf(slotRawObject(context), class_method)) { sprintf(str, "instance of FunctionDef in Method %s:%s", slotRawSymbol(&slotRawClass(&slotRawMethod(context)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(context)->name)->name); } else { sprintf(str, "instance of FunctionDef in closed FunctionDef"); } } else { sprintf(str, "instance of FunctionDef - closed"); } } else if (classptr == class_frame) { if (!slotRawFrame(slot)) { sprintf(str, "Frame (%0X)", slotRawInt(slot)); } else if (slotRawBlock(&slotRawFrame(slot)->method)->classptr == class_method) { sprintf(str, "Frame (%p) of %s:%s", slotRawObject(slot), slotRawSymbol(&slotRawClass(&slotRawMethod(&slotRawFrame(slot)->method)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(&slotRawFrame(slot)->method)->name)->name); } else { sprintf(str, "Frame (%p) of Function", slotRawFrame(slot)); } } else { sprintf(str, "instance of %s (%p, size=%d, set=%d)", slotRawSymbol(&classptr->name)->name, slotRawObject(slot), slotRawObject(slot)->size, slotRawObject(slot)->obj_sizeclass); } } else { sprintf(str, "NULL Object Pointer"); } break; case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : sprintf(str, "RawPointer %p", slotRawPtr(slot)); break; default : { union { int32 i[2]; double f; } u; u.f = slotRawFloat(slot); sprintf(str, "Float %f %08X %08X", u.f, u.i[0], u.i[1]); break; } } } static void printObject(PyrSlot * slot, PyrObject * obj, char *str) { assert(obj); PyrClass * classptr = obj->classptr; if (classptr == class_class) { sprintf(str, "class %s", slotRawSymbol(&((PyrClass*)obj)->name)->name); } else if (classptr == class_string) { char str2[32]; int len; if (obj->size > 31) { memcpy(str2, (char*)obj->slots, 28); str2[28] = '.'; str2[29] = '.'; str2[30] = '.'; str2[31] = 0; } else { len = sc_min(31, obj->size); memcpy(str2, (char*)obj->slots, len); str2[len] = 0; } sprintf(str, "\"%s\"", str2); } else if (classptr == class_method) { sprintf(str, "%s:%s", slotRawSymbol(&slotRawClass(&slotRawMethod(slot)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(slot)->name)->name); } else if (classptr == class_fundef) { PyrSlot *context, *nextcontext; // find function's method nextcontext = &slotRawBlock(slot)->contextDef; if (NotNil(nextcontext)) { do { context = nextcontext; nextcontext = &slotRawBlock(context)->contextDef; } while (NotNil(nextcontext)); if (isKindOf(slotRawObject(context), class_method)) { sprintf(str, "< FunctionDef in Method %s:%s >", slotRawSymbol(&slotRawClass(&slotRawMethod(context)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(context)->name)->name); } else { sprintf(str, "< FunctionDef in closed FunctionDef >"); } } else { sprintf(str, "< closed FunctionDef >"); } } else if (classptr == class_frame) { if (!slotRawFrame(slot)) { sprintf(str, "Frame (null)"); } else if (!slotRawBlock(&slotRawFrame(slot)->method)) { sprintf(str, "Frame (null method)"); } else if (slotRawBlock(&slotRawFrame(slot)->method)->classptr == class_method) { sprintf(str, "Frame (%p) of %s:%s", obj, slotRawSymbol(&slotRawClass(&slotRawMethod(&slotRawFrame(slot)->method)->ownerclass)->name)->name, slotRawSymbol(&slotRawMethod(&slotRawFrame(slot)->method)->name)->name); } else { sprintf(str, "Frame (%p) of Function", obj); } } else if (classptr == class_array) { sprintf(str, "[*%d]", obj->size); } else { sprintf(str, "", slotRawSymbol(&classptr->name)->name); } } void slotOneWord(PyrSlot *slot, char *str) { str[0] = 0; switch (GetTag(slot)) { case tagInt : sprintf(str, "%d", slotRawInt(slot)); break; case tagChar : sprintf(str, "$%c", static_cast(slotRawChar(slot))); break; case tagSym : if (strlen(slotRawSymbol(slot)->name) > 240) { char str2[256]; memcpy(str2, slotRawSymbol(slot)->name, 240); str2[240] = 0; snprintf(str, 256, "'%s...'", str2); } else { snprintf(str, 256, "'%s'", slotRawSymbol(slot)->name); } break; case tagObj : { PyrObject * slotObj = slotRawObject(slot); if (slotObj) printObject(slot, slotObj, str); else sprintf(str, "NULL Object Pointer"); break; } case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : sprintf(str, "ptr%p", slotRawPtr(slot)); break; default : sprintf(str, "%.14g", slotRawFloat(slot)); break; } } bool postString(PyrSlot *slot, char *str) { bool res = true; switch (GetTag(slot)) { case tagInt : sprintf(str, "%d", slotRawInt(slot)); break; case tagChar : sprintf(str, "%c", slotRawChar(slot)); break; case tagSym : str[0] = 0; res = false; break; case tagObj : { PyrObject * slotObj = slotRawObject(slot); if (slotObj) { PyrClass * classptr = slotRawObject(slot)->classptr; if (classptr == class_class || classptr == class_method || classptr == class_fundef || classptr == class_frame) printObject(slot, slotObj, str); else { str[0] = 0; res = false; } } else sprintf(str, "NULL Object Pointer"); break; } case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : sprintf(str, "%p", slotRawPtr(slot)); break; default : sprintf(str, "%.14g", slotRawFloat(slot)); break; } return res; } int asCompileString(PyrSlot *slot, char *str) { switch (GetTag(slot)) { case tagInt : sprintf(str, "%d", slotRawInt(slot)); break; case tagChar : { int c = slotRawChar(slot); if (isprint(c)) { sprintf(str, "$%c", c); } else { switch (c) { case '\n' : strcpy(str, "$\\n"); break; case '\r' : strcpy(str, "$\\r"); break; case '\t' : strcpy(str, "$\\t"); break; case '\f' : strcpy(str, "$\\f"); break; case '\v' : strcpy(str, "$\\v"); break; default: sprintf(str, "%d.asAscii", c); } } break; } case tagSym : return errFailed; case tagObj : return errFailed; case tagNil : sprintf(str, "nil"); break; case tagFalse : sprintf(str, "false"); break; case tagTrue : sprintf(str, "true"); break; case tagPtr : strcpy(str, "/*Ptr*/ nil"); break; default : sprintf(str, "%f", slotRawFloat(slot)); break; } return errNone; } void stringFromPyrString(PyrString *obj, char *str, int maxlength); void stringFromPyrString(PyrString *obj, char *str, int maxlength) { if (obj->classptr == class_string) { int len; if (obj->size > maxlength-4) { memcpy(str, obj->s, maxlength-4); str[maxlength-4] = '.'; str[maxlength-3] = '.'; str[maxlength-2] = '.'; str[maxlength-1] = 0; } else { len = sc_min(maxlength-1, obj->size); memcpy(str, obj->s, len); str[len] = 0; } } else { sprintf(str, "not a string"); } } void pstrncpy(unsigned char *s1, unsigned char *s2, int n); void pstringFromPyrString(PyrString *obj, unsigned char *str, int maxlength) { static const char not_a_string[] = "not a string"; const char * src; int len; if (obj && obj->classptr == class_string) { len = sc_min(maxlength-1, obj->size); src = obj->s; } else { len = sizeof(not_a_string); src = not_a_string; } memcpy(str+1, src, len); str[0] = len; } SuperCollider-Source/lang/LangSource/GC.cpp000644 000765 000024 00000074101 12756531745 021657 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "GC.h" #include "PyrKernel.h" #include "PyrObjectProto.h" #include "PyrSymbol.h" #include "InitAlloc.h" #include #include #define PAUSETIMES 0 double pauseBeginTime = 0.; double totalPauseTime = 0.; double maxPauseTime = 0.; double minPauseTime = 1e9; int pauseCount = 0; int numPausesGreaterThanOneMillisecond = 0; int maxPauseStackScans = 0; int maxPauseFlips = 0; int maxPauseScans = 0; int maxPausePartialScans = 0; int maxPauseNumToScan = 0; int maxPauseSlotsScanned = 0; int checkStackScans = 0; int checkFlips = 0; int checkNumToScan = 0; int checkScans = 0; int checkPartialScans = 0; int checkSlotsScanned = 0; double elapsedTime(); inline void PyrGC::beginPause() { checkStackScans = mStackScans; checkFlips = mFlips; checkScans = mScans; checkNumToScan = mNumToScan; checkPartialScans = mNumPartialScans; checkSlotsScanned = mSlotsScanned; pauseBeginTime = elapsedTime(); } inline void PyrGC::endPause() { double pauseTime = elapsedTime() - pauseBeginTime; if (pauseTime > 0.001) numPausesGreaterThanOneMillisecond++; if (pauseTime > maxPauseTime) { maxPauseTime = pauseTime; maxPauseStackScans = mStackScans - checkStackScans; maxPauseFlips = mFlips - checkFlips; maxPauseScans = mScans - checkScans; maxPauseNumToScan = checkNumToScan; maxPausePartialScans = mNumPartialScans - checkPartialScans; maxPauseSlotsScanned = mSlotsScanned - checkSlotsScanned; } if (pauseTime < minPauseTime) minPauseTime = pauseTime; totalPauseTime += pauseTime; pauseCount ++; } void PyrGC::reportPause() { post("pauses %d\n", pauseCount); post("total pause time %g\n", totalPauseTime); post("num pauses > 1 ms %d\n", numPausesGreaterThanOneMillisecond); post("avg pause time %g\n", totalPauseTime / pauseCount); post("min pause time %g\n", minPauseTime); post("max pause time %g\n", maxPauseTime); post("max pause scans %d\n", maxPauseScans); post("max pause partial obj scans %d\n", maxPausePartialScans); post("max pause num to scan %d\n", maxPauseNumToScan); post("max pause flips %d\n", maxPauseFlips); post("max pause stack scans %d\n", maxPauseStackScans); post("max pause slots scanned %d\n", maxPauseSlotsScanned); pauseBeginTime = 0.; totalPauseTime = 0.; maxPauseTime = 0.; minPauseTime = 1e9; pauseCount = 0; numPausesGreaterThanOneMillisecond = 0; } #if PAUSETIMES #define BEGINPAUSE beginPause(); #define ENDPAUSE endPause(); #define REPORTPAUSE reportPause(); #else #define BEGINPAUSE #define ENDPAUSE #define REPORTPAUSE #endif /* --- list segments: black gray white free sweep scan phase: clear list of new nonlocal reached objects. when a non local object is reached, mark it, and put it on the list if not retained. sweep phase: send any new retained objects to other system send any no longer reatined objects to the other system. send this list to enqueue finalization messages finalize: call finalize method, move from sweep area to free area list of nonlocal objects. list of nonlocal reached objects. */ void fatalerror(const char*str); void fatalerror(const char*str) { fputs(str, stderr); postfl(str); throw std::runtime_error(str); //exit(-1); } inline int ScanSize(PyrObjectHdr *obj) { return obj->obj_format <= obj_slot ? obj->size : 0; } HOT void PyrGC::ScanSlots(PyrSlot *inSlots, long inNumToScan) { if (inNumToScan == 0) return; unsigned char whiteColor = mWhiteColor; unsigned char greyColor = mGreyColor; mSlotsScanned += inNumToScan; int foundGreyObjects = 0; PyrObjectHdr * grey = &mGrey; PyrObjectHdr * greyNext = grey->next; PyrSlot *slot = inSlots; PyrSlot *endslot = inSlots + inNumToScan; do { if (IsObj(slot)) { PyrObject *obj = slotRawObject(slot); if (obj->gc_color == whiteColor) { /* used to be ToGrey2(obj), but rearranged for slightly better performance * * move obj from white to grey */ PyrObjectHdr * objPrev = obj->prev; PyrObjectHdr * objNext = obj->next; /* link in grey set */ greyNext->prev = obj; grey->next = obj; obj->prev = grey; obj->next = greyNext; greyNext = obj; // remove from old set objNext->prev = objPrev; objPrev->next = objNext; obj->gc_color = greyColor; foundGreyObjects++; } } ++slot; } while (slot != endslot); mNumGrey += foundGreyObjects; } void GCSet::Init(int inGCSet) { mBlack.classptr = NULL; mBlack.obj_sizeclass = inGCSet; mBlack.size = 0; mBlack.gc_color = obj_gcmarker; mWhite.classptr = NULL; mWhite.obj_sizeclass = inGCSet; mWhite.size = 0; mWhite.gc_color = obj_gcmarker; mFree = &mBlack; mBlack.next = &mWhite; mWhite.next = &mBlack; mBlack.prev = &mWhite; mWhite.prev = &mBlack; } void GCSet::MajorFlip() { // move all white items to beginning of free list mFree = mWhite.next; if (!PyrGC::IsMarker(mBlack.next)) { // move all black items to white list mWhite.next = mBlack.next; mFree->prev = mWhite.prev; mBlack.next->prev = &mWhite; mWhite.prev->next = mFree; // black list empty mBlack.next = &mWhite; mWhite.prev = &mBlack; } } void GCSet::MinorFlip() { // move all white items to beginning of free list mFree = mWhite.next; } PyrProcess* newPyrProcess(VMGlobals *g, PyrClass *procclassobj); PyrGC::PyrGC(VMGlobals *g, AllocPool *inPool, PyrClass *mainProcessClass, long poolSize) { mVMGlobals = g; mPool = inPool; //mCurSet = 0; mNumToScan = 0; mFlips = 0; mCollects = 0; mAllocTotal = 0; mNumAllocs = 0; mScans = 0; mStackScans = 0; mNumPartialScans = 0; mSlotsScanned = 0; mGreyColor = 3<<2; mBlackColor = 2<<2; mWhiteColor = 1<<2; mFreeColor = 0; mRunning = false; mCanSweep = false; mPartialScanObj = NULL; mPartialScanSlot = 0; mUncollectedAllocations = 0; mGrey.classptr = NULL; mGrey.obj_sizeclass = 0; mGrey.size = 0; mGrey.gc_color = obj_gcmarker; mGrey.prev = &mGrey; mGrey.next = &mGrey; mNumGrey = 0; mNewPool.Init(mPool, poolSize, poolSize, 9000); // initialize treadmills for (int i=0; iprocess = NULL; // initPyrThread checks to see if process has been started mProcess = newPyrProcess(g, mainProcessClass); mStack = slotRawObject(&slotRawThread(&mProcess->mainThread)->stack); ToBlack(mStack); SetNil(&slotRawThread(&mProcess->mainThread)->stack); mNumGrey = 0; ToGrey2(mProcess); g->sp = mStack->slots - 1; g->process = mProcess; mRunning = true; SanityCheck(); //assert(SanityCheck()); } PyrObject *PyrGC::NewPermanent(size_t inNumBytes, long inFlags, long inFormat) { // obtain size info int32 alignedSize = (inNumBytes + kAlignMask) & ~kAlignMask; // 16 byte align int32 numSlots = alignedSize / sizeof(PyrSlot); numSlots = numSlots < 1 ? 1 : numSlots; int32 sizeclass = LOG2CEIL(numSlots); sizeclass = sc_min(sizeclass, kNumGCSizeClasses-1); int32 allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); // allocate permanent objects PyrObject* obj = (PyrObject*)pyr_pool_runtime->Alloc(allocSize); obj->gc_color = obj_permanent; obj->next = obj->prev = NULL; obj->obj_sizeclass = sizeclass; obj->obj_format = inFormat; obj->obj_flags = inFlags; obj->size = 0; obj->classptr = class_object; return obj; } void PyrGC::BecomePermanent(PyrObject *inObject) { if (IsGrey(inObject)) mNumGrey--; DLRemove(inObject); inObject->gc_color = obj_permanent; inObject->obj_flags |= obj_immutable; inObject->next = inObject->prev = inObject; } void PyrGC::BecomeImmutable(PyrObject *inObject) { inObject->obj_flags |= obj_immutable; } void DumpBackTrace(VMGlobals *g); HOT PyrObject *PyrGC::New(size_t inNumBytes, long inFlags, long inFormat, bool inRunCollection) { PyrObject *obj = NULL; if (inFlags & obj_permanent) { return NewPermanent(inNumBytes, inFlags, inFormat); } #ifdef GC_SANITYCHECK SanityCheck(); #endif // obtain size info int32 alignedSize = (inNumBytes + kAlignMask) & ~kAlignMask; // 16 byte align int32 numSlots = alignedSize / sizeof(PyrSlot); numSlots = numSlots < 1 ? 1 : numSlots; int32 sizeclass = LOG2CEIL(numSlots); sizeclass = sc_min(sizeclass, kNumGCSizeClasses-1); int32 credit = 1L << sizeclass; mAllocTotal += credit; mNumAllocs++; mNumToScan += credit; obj = Allocate(inNumBytes, sizeclass, inRunCollection); obj->obj_format = inFormat; obj->obj_flags = inFlags & 255; obj->size = 0; obj->classptr = class_object; obj->gc_color = mWhiteColor; #ifdef GC_SANITYCHECK SanityCheck(); #endif return obj; } HOT PyrObject *PyrGC::NewFrame(size_t inNumBytes, long inFlags, long inFormat, bool inAccount) { PyrObject *obj = NULL; #ifdef GC_SANITYCHECK SanityCheck(); #endif // obtain size info int32 alignedSize = (inNumBytes + kAlignMask) & ~kAlignMask; // 16 byte align int32 numSlots = alignedSize / sizeof(PyrSlot); numSlots = numSlots < 1 ? 1 : numSlots; int32 sizeclass = LOG2CEIL(numSlots); sizeclass = sc_min(sizeclass, kNumGCSizeClasses-1); int32 credit = 1L << sizeclass; mAllocTotal += credit; mNumAllocs++; mNumToScan += credit; obj = Allocate(inNumBytes, sizeclass, inAccount); obj->obj_format = inFormat; obj->obj_flags = inFlags; obj->size = 0; obj->classptr = class_frame; obj->gc_color = mWhiteColor; #ifdef GC_SANITYCHECK SanityCheck(); #endif return obj; } PyrObject *PyrGC::NewFinalizer(ObjFuncPtr finalizeFunc, PyrObject *inObject, bool inRunCollection) { PyrObject *obj = NULL; #ifdef GC_SANITYCHECK SanityCheck(); #endif // obtain size info int32 sizeclass = 1; int32 credit = 1L << sizeclass; mNumToScan += credit; mAllocTotal += credit; mNumAllocs++; if (inRunCollection && mNumToScan >= kScanThreshold) { Collect(); } GCSet *gcs = mSets + kFinalizerSet; obj = (PyrObject*)gcs->mFree; if (!IsMarker(obj)) { // from free list gcs->mFree = obj->next; } else { if (sizeclass > kMaxPoolSet) { SweepBigObjects(); int32 allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); obj = (PyrObject*)mPool->Alloc(allocSize); } else { int32 allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); obj = (PyrObject*)mNewPool.Alloc(allocSize); } if (!obj) { post("Finalizer alloc failed.\n"); MEMFAILED; } DLInsertAfter(&gcs->mWhite, obj); } obj->obj_sizeclass = sizeclass; obj->obj_format = obj_slot; obj->obj_flags = 0; obj->size = 2; obj->classptr = class_finalizer; obj->gc_color = mWhiteColor; SetPtr(obj->slots+0, (void*)finalizeFunc); SetObject(obj->slots+1, inObject); #ifdef GC_SANITYCHECK SanityCheck(); #endif return obj; } void PyrGC::SweepBigObjects() { if (!mCanSweep) return; for (int i=kMaxPoolSet+1; imFree; if (!IsMarker(obj)) { // unlink chain of free objects gcs->mFree = obj->prev->next = &gcs->mBlack; gcs->mBlack.prev = obj->prev; do { PyrObjectHdr *nextobj = obj->next; void* ptr = (void*)obj; mPool->Free(ptr); obj = nextobj; } while (!IsMarker(obj)); } } mCanSweep = false; } void PyrGC::CompletePartialScan(PyrObject *obj) { if (mPartialScanObj == obj) { int32 remain = obj->size - mPartialScanSlot; ScanSlots(mPartialScanObj->slots + mPartialScanSlot, remain); } } HOT void PyrGC::DoPartialScan(int32 inObjSize) { int32 remain = inObjSize - mPartialScanSlot; mNumPartialScans++; if (remain <= 0) { mPartialScanObj = NULL; mNumToScan -= 4; if (mNumToScan<0) mNumToScan = 0; return; } int32 numtoscan = sc_min(remain, mNumToScan); ScanSlots(mPartialScanObj->slots + mPartialScanSlot, numtoscan); if (numtoscan == remain) { mPartialScanObj = NULL; mNumToScan -= numtoscan + 4; } else { mPartialScanSlot += numtoscan; mNumToScan -= numtoscan; } if (mNumToScan < 0) mNumToScan = 0; //post("partial %5d xx %4d %2d %s\n", mScans, mNumToScan, mNumGrey); //post("partial %5d %2d %4d %2d %s\n", mScans, i, mNumToScan, mNumGrey, slotRawSymbol(&obj->classptr->name)->name); } HOT bool PyrGC::ScanOneObj() { // Find a set that has a grey object PyrObject* obj; obj = (PyrObject*)mGrey.next; if (IsMarker(obj)) { if (mNumGrey) fatalerror("grey count error\n"); return false; } /*if (!IsGrey(obj)) { postfl("Object on grey list not grey %d %d\n", obj->gc_color, mGreyColor); fatalerror("C1"); }*/ mScans++; //post("-> scan %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan); // Found a grey object // move obj from grey to black ToBlack(obj); int32 size = ScanSize(obj); //post("<- scan %d %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan, size); if (size > mNumToScan + 32) { mPartialScanObj = obj; mPartialScanSlot = 0; DoPartialScan(size); } else if (size > 0) { ScanSlots(obj->slots, size); mNumToScan -= 1L << obj->obj_sizeclass; if (mNumToScan < 0) mNumToScan = 0; } else { mNumToScan -= 1L << obj->obj_sizeclass; if (mNumToScan < 0) mNumToScan = 0; } return true; } void PyrGC::ScanStack() { // scan the stack PyrObject* obj = mStack; VMGlobals *g = mVMGlobals; PyrSlot* slot = obj->slots; int32 size = obj->size = g->sp - slot + 1; ScanSlots(slot, size); } void PyrGC::ScanFrames() { VMGlobals *g = mVMGlobals; PyrFrame* frame = g->frame; while (frame) { #if 1 // this is more incremental if (IsWhite(frame)) { ToGrey2(frame); } #else // this is more efficient if (!IsBlack(frame)) { ToBlack(frame); int32 size = ScanSize(frame); PyrSlot *slots = ((PyrObject*)frame)->slots; ScanSlots(slots, size); } #endif frame = slotRawFrame(&frame->caller); } } void PyrGC::Flip() { #ifdef GC_SANITYCHECK SanityCheck(); #endif ScanFinalizers(); GCSet *gcs = mSets; if ((mFlips & 3) == 0) { // major flip for (int i=0; iMajorFlip(); } // advance colors mBlackColor += 4; mWhiteColor += 4; mGreyColor += 4; mFreeColor += 4; } else { // minor flip for (int i=0; iMinorFlip(); } } // move root to grey area mNumGrey = 0; ToGrey2(mProcess); ToBlack(mStack); // reset counts mNumToScan = 0; mCanSweep = true; mFlips++; //post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips, mCollects, mNumAllocs, mAllocTotal, mNumGrey); #ifdef GC_SANITYCHECK SanityCheck(); #endif } void PyrGC::FullCollection() { Collect(100000000); // collect space SweepBigObjects(); } void PyrGC::Collect(int32 inNumToScan) { mNumToScan = sc_max(mNumToScan, inNumToScan); Collect(); // collect space } HOT void PyrGC::Collect() { BEGINPAUSE bool stackScanned = false; mCollects++; #ifdef GC_SANITYCHECK SanityCheck(); #endif if (mNumToScan > 0) { //post("->Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans); //DumpInfo(); mNumToScan += mNumToScan >> 3; //post("->Collect2 ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans); //mCurSet = 0; while (mNumToScan > 0) { while (mNumToScan > 0 && (mNumGrey > 0 || mPartialScanObj)) { if (mPartialScanObj) { DoPartialScan(ScanSize(mPartialScanObj)); } else { if (!ScanOneObj()) break; } } if (mNumGrey == 0 && mPartialScanObj == NULL) { if (!stackScanned) { stackScanned = true; mStackScans++; ScanStack(); ScanFrames(); } if (mNumGrey == 0 && mPartialScanObj == NULL && stackScanned) { Flip(); break; } } } //post("<-Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans); //DumpInfo(); //post("size9:\n"); //TraceAnyPathToObjsOfSize(9); //post("greys:\n"); //TraceAnyPathToAllGrey(); } //post("mNumToScan %d\n", mNumToScan); mUncollectedAllocations = 0; #ifdef GC_SANITYCHECK SanityCheck(); #endif ENDPAUSE } void PyrGC::Finalize(PyrObject *finalizer) { if (!IsPtr(finalizer->slots+0)) return; if (!IsObj(finalizer->slots+1)) return; ObjFuncPtr func = (ObjFuncPtr)slotRawPtr(&finalizer->slots[0]); PyrObject *obj = slotRawObject(&finalizer->slots[1]); //post("FINALIZE %s %p\n", slotRawSymbol(&obj->classptr->name)->name, obj); (func)(mVMGlobals, obj); SetNil(obj->slots+0); SetNil(obj->slots+1); } void PyrGC::ScanFinalizers() { GCSet *gcs = &mSets[kFinalizerSet]; PyrObjectHdr *obj = gcs->mWhite.next; PyrObjectHdr *firstFreeObj = gcs->mFree; while (obj != firstFreeObj) { Finalize((PyrObject*)obj); obj = obj->next; } } void PyrGC::RunAllFinalizers() { GCSet *gcs = &mSets[kFinalizerSet]; PyrObjectHdr *obj = gcs->mBlack.next; while (!IsMarker(obj)) { Finalize((PyrObject*)obj); obj = obj->next; } obj = gcs->mWhite.next; PyrObjectHdr *firstFreeObj = gcs->mFree; while (obj != firstFreeObj) { Finalize((PyrObject*)obj); obj = obj->next; } obj = mGrey.next; while (!IsMarker(obj)) { if (obj->classptr == class_finalizer) Finalize((PyrObject*)obj); obj = obj->next; } } bool PyrGC::SanityCheck2() { int numgrey = 0; PyrObjectHdr *grey = mGrey.next; while (!IsMarker(grey)) { numgrey++; if (!IsGrey(grey)) { postfl("sc Object on grey list not grey %d %d %d\n", grey->gc_color, mGreyColor, numgrey); return false; } grey = grey->next; } //postfl("sc %d %d\n", mNumGrey, numgrey); return mNumGrey == numgrey; } bool PyrGC::SanityCheck() { if (!mRunning) return true; //postfl("PyrGC::SanityCheck\n"); bool res = LinkSanity() && ListSanity() // && SanityMarkObj((PyrObject*)mProcess,NULL,0) && SanityMarkObj(mStack,NULL,0) // && SanityClearObj((PyrObject*)mProcess,0) && SanityClearObj(mStack,0) && SanityCheck2() ; //if (!res) DumpInfo(); //if (!res) Debugger(); return res; } bool PyrGC::ListSanity() { bool found; if (StackDepth() < 0) { fprintf(stderr, "stack underflow %d\n", (int)StackDepth()); return false; } //postfl("PyrGC::ListSanity\n"); for (int i=0; imBlack; if (!IsMarker(obj)) { //debugf("set %d black marker color wrong %d %p\n", i, obj->gc_color, obj); fprintf(stderr, "set %d black marker color wrong %d %p\n", i, obj->gc_color, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } // check white marker obj = &set->mWhite; if (!IsMarker(obj)) { //debugf("set %d white marker color wrong %d %p\n", i, obj->gc_color, obj); fprintf(stderr, "set %d white marker color wrong %d %p\n", i, obj->gc_color, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } // check free pointer between white and black marker if (set->mFree != &set->mBlack) { obj = set->mWhite.next; found = false; while (!IsMarker(obj)) { if (obj == set->mFree) { found = true; break; } obj = obj->next; } if (!found) { //debugf("set %d free pointer not between white and black\n", i); fprintf(stderr, "set %d free pointer not between white and black\n", i); fprintf(stderr, "set->mFree %p\n", set->mFree); fprintf(stderr, "set->mWhite %p\n", &set->mWhite); fprintf(stderr, "set->mBlack %p\n", &set->mBlack); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)set->mFree); fprintf(stderr, "black %d white %d grey %d\n", mBlackColor, mWhiteColor, mGreyColor); obj = &set->mWhite; int count = 0; do { if (obj == set->mFree) fprintf(stderr, "%4d %p %3d %d FREE\n", count, obj, obj->gc_color, obj->obj_sizeclass); else if (obj == &set->mWhite) fprintf(stderr, "%4d %p %3d %d WHITE\n", count, obj, obj->gc_color, obj->obj_sizeclass); else if (obj == &set->mBlack) fprintf(stderr, "%4d %p %3d %d BLACK\n", count, obj, obj->gc_color, obj->obj_sizeclass); else fprintf(stderr, "%4d %p %3d %d\n", count, obj, obj->gc_color, obj->obj_sizeclass); obj = obj->next; count++; } while (obj != &set->mWhite); return false; } } // scan black list obj = set->mBlack.next; while (!IsMarker(obj)) { if (obj->gc_color != mBlackColor) { //debugf("set %d black list obj color wrong %d (%d, %d, %d) %p\n", // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); fprintf(stderr, "set %d black list obj color wrong %d (%d, %d, %d) %p\n", i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } if (GetGCSet(obj) != set) { //debugf("set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); fprintf(stderr, "set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); setPostFile(stderr); dumpBadObject((PyrObject*)obj); return false; } if (obj->next->prev != obj) { fprintf(stderr, "set %d black obj->next->prev != obj\n", i); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); } // scan for refs to white. if (!BlackToWhiteCheck((PyrObject*)obj)) return false; obj = obj->next; } // scan white list obj = set->mWhite.next; while (obj != set->mFree) { if (obj->gc_color != mWhiteColor) { //debugf("set %d white list obj color wrong %d (%d, %d, %d) %p\n", // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); //debugf("hmmm free %p black %p\n", set->mFree, set->black); fprintf(stderr, "set %d white list obj color wrong %d (%d, %d, %d) %p\n", i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj); fprintf(stderr, "hmmm free %p black %p\n", set->mFree, &set->mBlack); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } if (GetGCSet(obj) != set) { //debugf("set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); fprintf(stderr, "set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); return false; } if (obj->next->prev != obj) { fprintf(stderr, "set %d white obj->next->prev != obj\n", i); setPostFile(stderr); DumpBackTrace(mVMGlobals); dumpBadObject((PyrObject*)obj); } obj = obj->next; } // mark all free list items free obj = set->mFree; while (!IsMarker(obj)) { /*if (obj->gc_color == mGreyColor) { //debugf("grey obj on free list\n"); fprintf(stderr, "grey obj on free list\n"); return false; }*/ //post("FREE\n"); //dumpObject((PyrObject*)(PyrObject*)obj); obj->gc_color = mFreeColor; if (GetGCSet(obj) != set) { //debugf("set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); fprintf(stderr, "set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj); //dumpObject((PyrObject*)obj); return false; } if (obj->next->prev != obj) { fprintf(stderr, "set %d free obj->next->prev != obj\n", i); //dumpObject((PyrObject*)obj); } obj = obj->next; } } int numgrey = 0; PyrObjectHdr *grey = mGrey.next; while (!IsMarker(grey)) { numgrey++; if (!IsGrey(grey)) { fprintf(stderr, "sc Object on grey list not grey %d %d %d\n", grey->gc_color, mGreyColor, numgrey); fprintf(stderr, "%p <- %p -> %p grey %p process %p\n", mGrey.prev, &mGrey, mGrey.next, grey, mProcess); return false; } grey = grey->next; } if (numgrey != mNumGrey) { fprintf(stderr, "grey count off %d %d\n", numgrey, mNumGrey); DumpInfo(); fprintf(stderr, "."); return false; } return true; } bool PyrGC::LinkSanity() { //postfl("PyrGC::LinkSanity\n"); for (int i=0; imBlack; do { if (obj->next->prev != obj) { fprintf(stderr, "set %d black obj->next->prev != obj\n", i); //dumpObject((PyrObject*)obj); return false; } if (obj->prev->next != obj) { fprintf(stderr, "set %d black obj->prev->next != obj\n", i); //dumpObject((PyrObject*)obj); return false; } obj = obj->next; } while (obj != &set->mBlack); } return true; } #define DUMPINSANITY 1 bool PyrGC::BlackToWhiteCheck(PyrObject *objA) { if (objA->obj_format > obj_slot) return true; // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject * objB = NULL; if (IsObj(slot) && slotRawObject(slot)) { objB = slotRawObject(slot); } if (objB && (unsigned long)objB < 100) { fprintf(stderr, "weird obj ptr\n"); return false; } if (objB) { if (objA == mStack) continue; if (objA->gc_color == mBlackColor && objA != mPartialScanObj) { if (objB->gc_color == mWhiteColor) { if (objA->classptr == class_frame) { // jmc: black stack frames pointing to white nodes can be ignore PyrFrame * frameA = (PyrFrame*)objA; PyrMethod * meth = slotRawMethod(&frameA->method); PyrMethodRaw * methraw = METHRAW(meth); if (methraw->needsHeapContext) continue; } #if DUMPINSANITY fprintf(stderr, "black frame to white ref %p %p\n", objA, objB); dumpBadObject(objA); dumpBadObject(objB); fprintf(stderr, "\n"); #endif return false; } } } } } return true; } bool PyrGC::SanityMarkObj(PyrObject *objA, PyrObject *fromObj, int level) { if (objA->IsPermanent()) return true; if (objA->IsMarked()) return true; if (objA->size > MAXINDEXSIZE(objA)) { fprintf(stderr, "obj indexed size larger than max: %d > %ld\n", objA->size, MAXINDEXSIZE(objA)); //dumpObject((PyrObject*)objA); return false; } objA->SetMark(); // mark it if (!BlackToWhiteCheck(objA)) return false; if (objA->obj_format <= obj_slot) { // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject * objB = NULL; int tag = GetTag(slot); if (tag == tagObj && slotRawObject(slot)) objB = slotRawObject(slot); if (objB) { /* if (level > 40) { fprintf(stderr, "40 levels deep!\n"); dumpBadObject(objA); dumpBadObject(objB); return false; } */ bool err = SanityMarkObj(objB, objA, level + 1); if (!err) return false; } } } } return true; } bool PyrGC::SanityClearObj(PyrObject *objA, int level) { if (!(objA->IsMarked())) return true; if (objA->IsPermanent()) return true; objA->ClearMark(); // unmark it if (objA->obj_format <= obj_slot) { // scan it int size = objA->size; if (size > 0) { PyrSlot *slot = objA->slots; for (int j=size; j--; ++slot) { PyrObject *objB = NULL; if (IsObj(slot) && slotRawObject(slot)) { objB = slotRawObject(slot); } if (objB) { /*if (level > 40) { fprintf(stderr, "40 levels deep!\n"); dumpBadObject(objA); //dumpObject((PyrObject*)objB); //newPyrFrame return errFailed; }*/ bool err = SanityClearObj(objB, level+1); if (!err) return false; } } } } return true; } void PyrGC::DumpInfo() { int i; PyrObjectHdr *obj; int numblack, numwhite, numfree, settotal, setsiztotal; int totblack, totgrey, totwhite, totfree, totref, total, siztotal; REPORTPAUSE post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips, mCollects, mNumAllocs, mAllocTotal, mNumGrey); totblack = 0; totgrey = 0; totwhite = 0; totfree = 0; totref = 0; total = 0; siztotal = 0; for (i=0; imBlack.next; while (!IsMarker(obj)) { numblack++; obj = obj->next; } // scan white list numwhite = 0; obj = set->mWhite.next; while (obj != set->mFree) { numwhite++; obj = obj->next; } // scan free list numfree = 0; obj = set->mFree; while (!IsMarker(obj)) { numfree++; obj = obj->next; } settotal = numblack + numwhite + numfree; setsiztotal = settotal << (i + 3); siztotal += setsiztotal; totblack += numblack; totwhite += numwhite; totfree += numfree; total += settotal; if (settotal) { post("%2d bwf t sz: %6d %6d %6d %6d %8d\n", i, numblack, numwhite, numfree, settotal, setsiztotal); } } post("tot bwf t sz: %6d %6d %6d %6d %8d\n", totblack, totwhite, totfree, total, siztotal); } void PyrGC::DumpGrey() { // scan grey list PyrObjectHdr *obj = mGrey.next; while (!IsMarker(obj)) { post("grey %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } } void PyrGC::DumpSet(int i) { GCSet *set = mSets + i; // scan black list PyrObjectHdr *obj = set->mBlack.next; while (!IsMarker(obj)) { post("black %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } // scan white list obj = set->mWhite.next; while (obj != set->mFree) { post("white %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } // scan free list obj = set->mFree; while (!IsMarker(obj)) { post("free %s %d %d\n", slotRawSymbol(&obj->classptr->name)->name, obj->obj_sizeclass, obj->size); obj = obj->next; } } void PyrGC::ClearMarks() { for (int i=0; imBlack.next; while (!IsMarker(obj)) { obj->ClearMark(); // unmark it obj = obj->next; } // scan grey list obj = mGrey.next; while (!IsMarker(obj)) { obj->ClearMark(); // unmark it obj = obj->next; } // scan white list obj = set->mWhite.next; while (obj != set->mFree) { obj->ClearMark(); // unmark it obj = obj->next; } // scan free list obj = set->mFree; while (!IsMarker(obj)) { obj->ClearMark(); // unmark it obj = obj->next; } } } void PyrGC::throwMemfailed(size_t inNumBytes) { post("alloc failed. size = %d\n", inNumBytes); MEMFAILED; } SuperCollider-Source/lang/LangSource/GC.h000644 000765 000024 00000021610 12756531745 021321 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* The garbage collector for SuperCollider. Based on Wilson and Johnstone's real time collector and the Baker treadmill. */ #ifndef _GC_ #define _GC_ #include "PyrObject.h" #include "VMGlobals.h" #include "AdvancingAllocPool.h" #include "function_attributes.h" void DumpSimpleBackTrace(VMGlobals *g); const int kMaxPoolSet = 7; const int kNumGCSizeClasses = 28; const int kFinalizerSet = kNumGCSizeClasses; const int kNumGCSets = kNumGCSizeClasses + 1; const int kScanThreshold = 256; class GCSet { public: GCSet() {} void Init(int inSizeClass); bool HasFree() { return mFree != &mBlack; } private: friend class PyrGC; void MajorFlip(); void MinorFlip(); PyrObjectHdr mBlack; PyrObjectHdr mWhite; PyrObjectHdr* mFree; }; struct SlotRef { SlotRef(PyrObject* inObj, int32 inIndex) : obj(inObj), slotIndex(inIndex) {} PyrObject *obj; int32 slotIndex; }; class PyrGC { static const int kLazyCollectThreshold = 1024; public: PyrGC(VMGlobals *g, AllocPool *inPool, PyrClass *mainProcessClass, long poolSize); MALLOC PyrObject* New(size_t inNumBytes, long inFlags, long inFormat, bool inCollect); MALLOC PyrObject* NewFrame(size_t inNumBytes, long inFlags, long inFormat, bool inAccount); MALLOC static PyrObject* NewPermanent(size_t inNumBytes, long inFlags, long inFormat); MALLOC PyrObject* NewFinalizer(ObjFuncPtr finalizeFunc, PyrObject *inObject, bool inCollect); bool IsBlack(PyrObjectHdr* inObj) { return inObj->gc_color == mBlackColor; } bool IsWhite(PyrObjectHdr* inObj) { return inObj->gc_color == mWhiteColor; } bool IsGrey(PyrObjectHdr* inObj) { return inObj->gc_color == mGreyColor; } static bool IsMarker(PyrObjectHdr* inObj) { return inObj->gc_color == obj_gcmarker; } bool IsFree(PyrObjectHdr* inObj) { return (!(IsMarker(inObj) || inObj->IsPermanent() || IsBlack(inObj) || IsWhite(inObj) || IsGrey(inObj))); } bool ObjIsBlack(PyrObjectHdr* inObj) { return IsBlack(inObj); } bool ObjIsGrey(PyrObjectHdr* inObj) { return IsGrey(inObj); } bool ObjIsFree(PyrObjectHdr* inObj) { return IsFree(inObj); } // general purpose write barriers: void GCWrite(PyrObjectHdr* inParent, PyrSlot* inSlot) { if (IsBlack(inParent) && IsObj(inSlot) && IsWhite(slotRawObject(inSlot))) { ToGrey(slotRawObject(inSlot)); } } void GCWrite(PyrObjectHdr* inParent, PyrObjectHdr* inChild) { if (IsBlack(inParent) && IsWhite(inChild)) { ToGrey(inChild); } } // when you know the parent is black: void GCWriteBlack(PyrSlot* inSlot) { if (IsObj(inSlot)) { if (IsWhite(slotRawObject(inSlot))) { ToGrey(slotRawObject(inSlot)); } } } void GCWriteBlack(PyrObjectHdr* inChild) { if (IsWhite(inChild)) { ToGrey(inChild); } } // when you know the child is white void GCWriteNew(PyrObjectHdr* inParent, PyrObjectHdr* inChild) { assert(IsWhite(inChild)); if (IsBlack(inParent)) { ToGrey(inChild); } } // users should not call anything below. void Collect(); void Collect(int32 inNumToScan); void LazyCollect() { if (mUncollectedAllocations > kLazyCollectThreshold) Collect(); } void FullCollection(); void ScanFinalizers(); void RunAllFinalizers(); GCSet* GetGCSet(PyrObjectHdr* inObj); void CompletePartialScan(PyrObject *obj); inline void ToGrey(PyrObjectHdr* inObj); inline void ToGrey2(PyrObjectHdr* inObj); void ToBlack(PyrObjectHdr* inObj); void ToWhite(PyrObjectHdr *inObj); void Free(PyrObjectHdr* inObj); long StackDepth() { return mVMGlobals->sp - mStack->slots + 1; } PyrObject* Stack() { return mStack; } void SetStack(PyrObject* inStack) { mStack = inStack; } bool SanityCheck(); bool SanityCheck2(); bool LinkSanity(); bool ListSanity(); bool BlackToWhiteCheck(PyrObject *objA); bool SanityMarkObj(PyrObject *objA, PyrObject *fromObj, int level); bool SanityClearObj(PyrObject *objA, int level); void DumpInfo(); void DumpGrey(); void DumpSet(int set); void BecomePermanent(PyrObject *inObject); void BecomeImmutable(PyrObject *inObject); bool IsPartialScanObject(PyrObject* inObject) const { return inObject == mPartialScanObj; } int32 GetPartialScanIndex() const { return mPartialScanSlot; } private: inline PyrObject * Allocate(size_t inNumBytes, int32 sizeclass, bool inCollect); static void throwMemfailed(size_t inNumBytes); void ScanSlots(PyrSlot *inSlots, long inNumToScan); void SweepBigObjects(); void DoPartialScan(int32 inObjSize); bool ScanOneObj(); void Flip(); void ScanStack(); void ScanFrames(); void DLRemove(PyrObjectHdr *obj); void DLInsertAfter(PyrObjectHdr *after, PyrObjectHdr *obj); void DLInsertBefore(PyrObjectHdr *before, PyrObjectHdr *obj); void ClearMarks(); void Finalize(PyrObject *obj); void beginPause(); void endPause(); void reportPause(); VMGlobals *mVMGlobals; AllocPool *mPool; AdvancingAllocPool mNewPool; GCSet mSets[kNumGCSets]; PyrProcess *mProcess; // the root is the pyrprocess which contains this struct PyrObject *mStack; PyrObject *mPartialScanObj; PyrObjectHdr mGrey; int32 mPartialScanSlot; int32 mNumToScan; int32 mNumGrey; int32 mCurSet; int32 mFlips, mCollects, mAllocTotal, mScans, mNumAllocs, mStackScans, mNumPartialScans, mSlotsScanned, mUncollectedAllocations; unsigned char mBlackColor, mGreyColor, mWhiteColor, mFreeColor; bool mCanSweep; bool mRunning; }; inline void PyrGC::DLRemove(PyrObjectHdr *obj) { obj->next->prev = obj->prev; obj->prev->next = obj->next; } inline void PyrGC::DLInsertAfter(PyrObjectHdr *after, PyrObjectHdr *obj) { obj->next = after->next; obj->prev = after; after->next->prev = obj; after->next = obj; } inline void PyrGC::DLInsertBefore(PyrObjectHdr *before, PyrObjectHdr *obj) { obj->prev = before->prev; obj->next = before; before->prev->next = obj; before->prev = obj; } inline GCSet* PyrGC::GetGCSet(PyrObjectHdr* inObj) { return mSets + (inObj->classptr == class_finalizer ? kFinalizerSet : inObj->obj_sizeclass); } inline void PyrGC::ToBlack(PyrObjectHdr *obj) { if (IsGrey(obj)) { mNumGrey--; //post("ToBlack %d\n", mNumGrey); } DLRemove(obj); GCSet *gcs = GetGCSet(obj); DLInsertAfter(&gcs->mBlack, obj); obj->gc_color = mBlackColor; } inline void PyrGC::ToWhite(PyrObjectHdr *obj) { if (IsGrey(obj)) { mNumGrey--; //post("ToWhite %d\n", mNumGrey); } DLRemove(obj); GCSet *gcs = GetGCSet(obj); DLInsertAfter(&gcs->mWhite, obj); obj->gc_color = mWhiteColor; } inline void PyrGC::Free(PyrObjectHdr* obj) { if (IsGrey(obj)) { mNumGrey--; //post("ToWhite %d\n", mNumGrey); } DLRemove(obj); GCSet *gcs = GetGCSet(obj); DLInsertBefore(gcs->mFree, obj); gcs->mFree = obj; obj->gc_color = mFreeColor; obj->size = 0; } inline void PyrGC::ToGrey(PyrObjectHdr* obj) { /* move obj from white to grey */ /* link around object */ DLRemove(obj); /* link in new place */ DLInsertAfter(&mGrey, obj); /* set grey list pointer to obj */ obj->gc_color = mGreyColor; mNumGrey ++ ; mNumToScan += 1L << obj->obj_sizeclass; } inline void PyrGC::ToGrey2(PyrObjectHdr* obj) { /* move obj from white to grey */ /* link around object */ DLRemove(obj); /* link in new place */ DLInsertAfter(&mGrey, obj); /* set grey list pointer to obj */ obj->gc_color = mGreyColor; mNumGrey ++ ; } inline PyrObject * PyrGC::Allocate(size_t inNumBytes, int32 sizeclass, bool inRunCollection) { if (inRunCollection && mNumToScan >= kScanThreshold) Collect(); else { if (inRunCollection) mUncollectedAllocations = 0; else ++mUncollectedAllocations; } GCSet *gcs = mSets + sizeclass; PyrObject * obj = (PyrObject*)gcs->mFree; if (!IsMarker(obj)) { // from free list gcs->mFree = obj->next; assert(obj->obj_sizeclass == sizeclass); } else { if (sizeclass > kMaxPoolSet) { SweepBigObjects(); size_t allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); obj = (PyrObject*)mPool->Alloc(allocSize); } else { size_t allocSize = sizeof(PyrObjectHdr) + (sizeof(PyrSlot) << sizeclass); obj = (PyrObject*)mNewPool.Alloc(allocSize); } if (!obj) throwMemfailed(inNumBytes); DLInsertAfter(&gcs->mWhite, obj); obj->obj_sizeclass = sizeclass; } return obj; } #endif SuperCollider-Source/lang/LangSource/HashTable.h000644 000765 000024 00000013642 12321461511 022646 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _HashTable_ #define _HashTable_ #include "SC_Types.h" #include "SC_BoundsMacros.h" #include "Hash.h" #include template class HashTable { Allocator *mPool; int32 mNumItems, mMaxItems, mTableSize, mHashMask; T** mItems; bool mCanResize; public: HashTable(Allocator *inPool, int32 inMaxItems, bool inCanResize = true) : mPool(inPool) { mNumItems = 0; mMaxItems = inMaxItems; mTableSize = mMaxItems << 1; mItems = AllocTable(mTableSize); mHashMask = mTableSize - 1; mCanResize = inCanResize; } ~HashTable() { mPool->Free(mItems); } int32 TableSize() const { return mTableSize; } int32 MaxItems() const { return mMaxItems; } int32 NumItems() const { return mNumItems; } T** AllocTable(int inTableSize) { size_t size = inTableSize * sizeof(T*); T** items = static_cast(mPool->Alloc(size)); for (int i=0; i> 1; mHashMask = mTableSize - 1; mPool->Free(oldItems); //printf("mMaxItems %d mTableSize %d newSize %d\n", mMaxItems, mTableSize, newSize); } bool Add(T* inItem) { //printf("mNumItems %d\n", mNumItems); //printf("mMaxItems %d\n", mMaxItems); //printf("mCanResize %d\n", mCanResize); if (mNumItems >= mMaxItems) { if (!mCanResize) return false; Resize(); } //printf("GetHash(inItem) %d\n", GetHash(inItem)); //printf("GetKey(inItem) %s\n", GetKey(inItem)); int32 index = IndexFor(GetHash(inItem), GetKey(inItem)); //printf("index %d\n", index); T *item = mItems[index]; if (item) return item == inItem; mItems[index] = inItem; mNumItems++; return true; } bool Remove(T* inItem) { int32 index = IndexFor(GetHash(inItem), GetKey(inItem)); if (mItems[index] != inItem) return false; mItems[index] = 0; FixCollisionsFrom(index); mNumItems--; return true; } int32 IndexFor(int32 inHashID, KeyType inKey) const { int index = inHashID & mHashMask; for(;;) { T *item = mItems[index]; if (!item) return index; if (GetHash(item) == inHashID && strcmp(inKey, GetKey(item)) == 0) return index; index = (index + 1) & mHashMask; } } T* Get(KeyType inKey) const { return Get(Hash(inKey), inKey); } T* Get(int32 inHashID, KeyType inKey) const { int32 index = IndexFor(inHashID, inKey); return mItems[index]; } bool Includes(T* inItem) const { return Get(GetHash(inItem), GetKey(inItem)) == inItem; } T* AtIndex(int32 inIndex) const { return mItems[inIndex]; } private: void FixCollisionsFrom(int32 inIndex) { int oldIndex = inIndex; for (;;) { oldIndex = (oldIndex + 1) & mHashMask; T *oldItem = mItems[oldIndex]; if (!oldItem) break; int newIndex = IndexFor(GetHash(oldItem), GetKey(oldItem)); if (oldIndex != newIndex) { mItems[oldIndex] = mItems[newIndex]; mItems[newIndex] = oldItem; } } } }; template class StaticHashTable { int32 mNumItems, mTableSize, mHashMask; T* mItems[kMaxItems*2]; public: StaticHashTable() { mNumItems = 0; mTableSize = kMaxItems << 1; ClearTable(); mHashMask = mTableSize - 1; } ~StaticHashTable() { } int32 TableSize() const { return mTableSize; } int32 MaxItems() const { return kMaxItems; } int32 NumItems() const { return mNumItems; } void ClearTable() { for (int i=0; i= kMaxItems) return false; int32 index = IndexFor(GetHash(inItem), GetKey(inItem)); T *item = mItems[index]; if (item) return item == inItem; mItems[index] = inItem; mNumItems++; return true; } bool Remove(T* inItem) { int32 index = IndexFor(GetHash(inItem), GetKey(inItem)); if (mItems[index] != inItem) return false; mItems[index] = 0; FixCollisionsFrom(index); mNumItems--; return true; } int32 IndexFor(int32 inHashID, KeyType inKey) const { int index = inHashID & mHashMask; for(;;) { T *item = mItems[index]; if (!item) return index; if (GetHash(item) == inHashID && strcmp(inKey, GetKey(item)) == 0) return index; index = (index + 1) & mHashMask; } } T* Get(KeyType inKey) const { return Get(Hash(inKey), inKey); } T* Get(int32 inHashID, KeyType inKey) const { int32 index = IndexFor(inHashID, inKey); return mItems[index]; } bool Includes(T* inItem) const { return Get(GetHash(inItem), GetKey(inItem)) == inItem; } T* AtIndex(int32 inIndex) const { return mItems[inIndex]; } private: void FixCollisionsFrom(int32 inIndex) { int oldIndex = inIndex; for (;;) { oldIndex = (oldIndex + 1) & mHashMask; T *oldItem = mItems[oldIndex]; if (!oldItem) break; int newIndex = IndexFor(GetHash(oldItem), GetKey(oldItem)); if (oldIndex != newIndex) { mItems[oldIndex] = mItems[newIndex]; mItems[newIndex] = oldItem; } } } }; #endif SuperCollider-Source/lang/LangSource/InitAlloc.cpp000644 000765 000024 00000003435 12524671173 023237 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "InitAlloc.h" #include "../../server/supernova/utilities/malloc_aligned.hpp" AllocPool *pyr_pool_compile = 0; AllocPool *pyr_pool_runtime = 0; #define AREASIZE 65536L static void* pyr_new_area(size_t size) { return nova::malloc_aligned(size); } static void pyr_free_area(void *ptr) { nova::free_aligned(ptr); } static void* pyr_new_area_from_runtime(size_t size) { void *ptr = pyr_pool_runtime->Alloc(size); MEMFAIL(ptr); return ptr; } static void pyr_free_area_from_runtime(void *ptr) { pyr_pool_runtime->Free(ptr); } SCLANG_DLLEXPORT_C bool pyr_init_mem_pools(int runtime_space, int runtime_grow) { pyr_pool_runtime = new AllocPool(pyr_new_area, pyr_free_area, runtime_space, runtime_grow); if (!pyr_pool_runtime) return false; pyr_pool_compile = new AllocPool(pyr_new_area_from_runtime, pyr_free_area_from_runtime, 0L, AREASIZE); if (!pyr_pool_compile) return false; //pyr_pool_runtime->DoCheckPool(); return true; } SuperCollider-Source/lang/LangSource/InitAlloc.h000644 000765 000024 00000002155 12321461511 022666 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _InitAlloc_ #define _InitAlloc_ #include "SCBase.h" #include "SC_AllocPool.h" #include #define MEMFAIL(ptr) if (!(ptr)) { throw std::runtime_error("Out of memory!\n"); } #define MEMFAILED throw std::runtime_error("Out of memory!\n"); #endif SuperCollider-Source/lang/LangSource/MiscInlineMath.h000644 000765 000024 00000003306 12321461511 023653 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LANG_MISCINLINEMATH_H #define LANG_MISCINLINEMATH_H #define NUMPRIMES 6542 long nthPrime(int n); long findPrime(int n); long prevPrime(int n); long nextPrime(int n); inline double linlin(double x, double a, double b, double c, double d) { if (x <= a) return c; if (x >= b) return d; return (x-a)/(b-a) * (d-c) + c; } inline double explin(double x, double a, double b, double c, double d) { if (x <= a) return c; if (x >= b) return d; return (log(x/a)) / (log(b/a)) * (d-c) + c; } inline double expexp(double x, double a, double b, double c, double d) { if (x <= a) return c; if (x >= b) return d; return pow(d/c, log(x/a)) / (log(b/a)) * c; } inline double linexp(double x, double a, double b, double c, double d) { if (x <= a) return c; if (x >= b) return d; return pow(d/c, (x-a)/(b-a)) * c; } #endif SuperCollider-Source/lang/LangSource/Opcodes.h000644 000765 000024 00000014715 12321461511 022411 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _OPCODES_H_ #define _OPCODES_H_ /* opcodes */ enum { opExtended, // 0 opPushInstVar, opPushTempVar, opPushTempZeroVar, opPushLiteral, opPushClassVar, // 5 opPushSpecialValue, opStoreInstVar, opStoreTempVar, opStoreClassVar, opSendMsg, // 10 opSendSuper, opSendSpecialMsg, opSendSpecialUnaryArithMsg, opSendSpecialBinaryArithMsg, opSpecialOpcode, // 15 opNumOpcodes }; /* special opcodes */ enum { opcDrop, // 0 opcDup, opcFunctionReturn, opcReturn, opcReturnSelf, opcReturnTrue, // 5 opcReturnFalse, opcReturnNil, opcJumpIfFalse, // IF 3 args opcJumpIfFalsePushNil, // IF 2 args opcJumpIfFalsePushFalse, // AND: (10) opcJumpIfTruePushTrue, // OR: opcJumpFwd, opcJumpBak, opcSpecialBinaryOpWithAdverb, opcSuperSpecial, // 15 opcNewList, opcNumSpecialOpcodes /* opcSlotAt, opcByteAt, // 15 opcShortAt, opcInt32At, opcColorAt, opcFloatAt, opcDoubleAt */ }; /* special unary math operators */ enum { opNeg, opNot, opIsNil, opNotNil, opBitNot, opAbs, opAsFloat, opAsInt, opCeil, //5 opFloor, opFrac, opSign, opSquared, opCubed, //10 opSqrt, opExp, opRecip, opMIDICPS, opCPSMIDI, //15 opMIDIRatio, opRatioMIDI, opDbAmp, opAmpDb, opOctCPS, //20 opCPSOct, opLog, opLog2, opLog10, opSin, //25 opCos, opTan, opArcSin, opArcCos, opArcTan, opSinH, opCosH, //30 opTanH, opRand, opRand2, opLinRand, opBiLinRand, // opExpRand, // opBiExpRand, opSum3Rand, // opGammaRand, // opGaussRand, // opPoiRand, opDistort, opSoftClip, opCoin, opDigitValue, opSilence, opThru, opRectWindow, opHanWindow, opWelchWindow, opTriWindow, opRamp, opSCurve, opNumUnarySelectors }; #define IS_UNARY_BOOL_OP(op) ((op)>=opCoin && (op)<=opOdd) #define IS_BINARY_BOOL_OP(op) ((op)>=opEQ && (op)<=opGE) /* special binary math operators */ enum { opAdd, opSub, opMul, opIDiv, opFDiv, opMod, opEQ, opNE, opLT, opGT, opLE, opGE, //opIdentical, //opNotIdentical, opMin, opMax, opBitAnd, opBitOr, opBitXor, opLCM, opGCD, opRound, opRoundUp, opTrunc, opAtan2, opHypot, opHypotx, opPow, opShiftLeft, opShiftRight, opUnsignedShift, opFill, opRing1, // a * (b + 1) == a * b + a opRing2, // a * b + a + b opRing3, // a*a*b opRing4, // a*a*b - a*b*b opDifSqr, // a*a - b*b opSumSqr, // a*a + b*b opSqrSum, // (a + b)^2 opSqrDif, // (a - b)^2 opAbsDif, // |a - b| opThresh, opAMClip, opScaleNeg, opClip2, opExcess, opFold2, opWrap2, opFirstArg, opRandRange, opExpRandRange, opNumBinarySelectors }; /* other special math operators */ enum { /* 3 operands */ opDivz, opClip, opWrap, opFold, opRampMult, opMix, /* 4 operands */ opPoly3, /* 5 operands */ opMapRange }; enum { opmNew, opmInit, opmAt, opmPut, opmNext, opmReset, opmValue, opmCopyToEnd, // used by multi assign opmAdd, // used by dynamic list //opmIsNil, //opmNotNil, opmSize, opmClass, opmIf, opmWhile, opmFor, opmAnd, opmOr, opmCase, opmSwitch, opmIdentical, opmNotIdentical, opmPrint, opmRemove, opmIndexOf, opmWrapAt, opmClipAt, opmFoldAt, opmWrapPut, opmClipPut, opmFoldPut, opmDo, opmCollect, opmSelect, opmReject, opmAny, opmEvery, opmFind, opmChoose, opmValueList, opmAddFirst, opmPrimitiveFailed, opmSubclassResponsibility, opmShouldNotImplement, opmNotYetImplemented, opmDoesNotUnderstand, opmAtSign, opmWrapAtSign, opmClipAtSign, opmFoldAtSign, opmNewClear, opmNewCopyArgs, opmMultiNew, opmMultiNewList, opmAR, opmKR, opmIR, opmCopy, opmPerformList, opmIsKindOf, opmPostln, opmAsString, opmEnvirGet, opmEnvirPut, opmHalt, opmForBy, opmForSeries, opmReverseDo, opmLoop, opmNonBooleanError, opmPlusPlus, opmLTLT, opmQuestionMark, opmDoubleQuestionMark, opmExclamationQuestionMark, opmYield, opmName, opmMulAdd, opmSeries, opmNumSpecialSelectors }; enum { opsvSelf, // 0 opsvMinusOne, opsvNegOne, opsvZero, opsvOne, opsvTwo, // 5 opsvFHalf, opsvFNegOne, opsvFZero, opsvFOne, opsvFTwo, // 10 opsvPlusOne, opsvTrue, opsvFalse, opsvNil, opsvInf, // 15 opsvNumSpecialValues }; enum { opgProcess, opgMethod, opgFunctionDef, opgFunction, opgThread, //opgSampleRate, //opgAudioClock, //opgLogicalClock, opgNumPseudoVars }; /* selector types */ enum { selNormal, selSpecial, selUnary, selBinary, selIf, selWhile, selAnd, selOr, selCase, selSwitch, selLoop, selSuperNew, selQuestionMark, selDoubleQuestionMark, selExclamationQuestionMark, selNumSelectorTypes }; /* special classes: Object, List, Number, Int, Float, Signal, Complex, Point */ enum { op_class_object, op_class_symbol, op_class_nil, op_class_boolean, op_class_true, op_class_false, op_class_magnitude, op_class_char, op_class_number, op_class_complex, op_class_simple_number, op_class_int, op_class_float, op_class_method, op_class_fundef, op_class_stream, op_class_func, op_class_frame, op_class_process, op_class_main, op_class_class, op_class_string, op_class_collection, op_class_sequenceable_collection, op_class_arrayed_collection, op_class_array, op_class_int8array, op_class_int16array, op_class_int32array, op_class_floatarray, op_class_signal, op_class_doublearray, op_class_symbolarray, op_class_list, op_class_linkedlist, op_class_bag, op_class_set, op_class_identityset, op_class_dictionary, op_class_identitydictionary, op_class_sortedlist, op_class_synth, op_class_ref, op_class_environment, op_class_event, op_class_wavetable, op_class_env, op_class_routine, op_class_color, op_class_rect, op_NumSpecialClasses }; #endif SuperCollider-Source/lang/LangSource/PowerOfTwoAllocPool.h000644 000765 000024 00000010461 12321461511 024667 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // Implements a power of two size class allocator. // There is no consolidation of free space. Once a chunk is allocated it // remains at that size from then on whether free or allocated. // It uses AdvancingAllocPool as its parent allocator. // It is very fast. This is used to allocate Unit output buffers. #ifndef _PowerOfTwoAllocPool_ #define _PowerOfTwoAllocPool_ #include #include #include "clz.h" #include "AdvancingAllocPool.h" #include "SC_AllocPool.h" void post(const char *fmt, ...); void postbuf(const char *fmt, ...); template class PowerOfTwoAllocPool { public: PowerOfTwoAllocPool(::AllocPool *inPool, size_t initSize = 64*1024, size_t growSize = 64*1024 ) { mLargeObjPool = inPool; mNumLargeObjects = 0; mNumAlloc = 0; mNumFree = 0; size_t tooBigSize = (sizeof(Hdr) + (sizeof(Elem) << (LargeObjSizeClass-1))) + 1; mSmallObjPool.Init(inPool, initSize, growSize, tooBigSize); Init(); //assert(SanityCheck()); } ~PowerOfTwoAllocPool() { //assert(SanityCheck()); //assert(mNumLargeObjects == 0); // you have to free the big ones yourself mSmallObjPool.FreeAll(); } Obj* Alloc(int32 inNumElems) { //mNumAlloc++; //assert(SanityCheck()); int sizeclass = LOG2CEIL(inNumElems); if (sizeclass >= LargeObjSizeClass) { mNumLargeObjects++; size_t size = sizeof(Hdr) + (sizeof(Elem) * inNumElems); return (Obj*)mLargeObjPool->Alloc(size); } // get from free list Obj* obj = mFreeLists[sizeclass]; if (obj != NULL) { // set free list to next element. mFreeLists[sizeclass] = *(Obj**)obj; } else { // have to allocate it size_t size = mSizes[sizeclass]; obj = (Obj*)mSmallObjPool.Alloc(size); if (!obj) throw runtime_error("PowerOfTwoAllocPool out of memory"); } //obj->mMagic = 'magk'; //assert(SanityCheck()); return obj; } void Free(Obj* inObjPtr) { //mNumFree++; //assert(SanityCheck()); if (inObjPtr == 0) return; /* free(0) has no effect */ /*if (inObjPtr->mMagic != 'magk') { postbuf("bad object\n"); throw runtime_error("bad object"); }*/ int sizeclass = inObjPtr->SizeClass(); if (sizeclass >= LargeObjSizeClass) { mLargeObjPool->Free(inObjPtr); mNumLargeObjects--; } else { Obj* nextfree = mFreeLists[sizeclass]; mFreeLists[sizeclass] = inObjPtr; *(Obj**)inObjPtr = nextfree; } //assert(SanityCheck()); } void FreeAll() { //assert(mNumLargeObjects == 0); // you have to free the big ones yourself mSmallObjPool.FreeAll(); Init(); } bool SanityCheck() { //postbuf("PowerOfTwoAllocPool::SanityCheck %d %d\n", mNumAlloc, mNumFree); mLargeObjPool->DoCheckPool(); mSmallObjPool.SanityCheck(); for (int i=0; i=1000) { post("linked loop??\n"); throw runtime_error("linked loop??\n"); return false; } obj = *(Obj**)obj; } } return true; } private: void Init() { for (int i=0; i #include #include # include #include #include #define kBigBigFloat DBL_MAX #define kSmallSmallFloat DBL_MIN #include #include "InitAlloc.h" #include "function_attributes.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Warray-bounds" #endif //void tellPlugInsAboutToRun(); double timeNow(); int32 timeseed() { using namespace std::chrono; high_resolution_clock::time_point now = high_resolution_clock::now(); high_resolution_clock::duration since_epoch = now.time_since_epoch(); seconds secs = duration_cast(since_epoch); nanoseconds nanosecs = since_epoch - secs; int_least64_t seed = secs.count() ^ nanosecs.count(); return (int32)seed; } VMGlobals gVMGlobals; VMGlobals *gMainVMGlobals = &gVMGlobals; void debugf(char *fmt, ...) ; #define DEBUGINTERPRETER 0 #define METHODMETER 0 #define BCSTAT 0 #define CHECK_MAX_STACK_USE 0 #if CHECK_MAX_STACK_USE int gMaxStackDepth = 0; #endif unsigned char* dumpOneByteCode(PyrBlock *theBlock, PyrClass* theClass, unsigned char *ip); void dumpSlotOneWord(const char *tagstr, PyrSlot *slot); //bool checkAllObjChecksum(PyrObject* obj); bool gTraceInterpreter = false; //bool gTraceInterpreter = true; const char* byteCodeString(int code); extern int gNumClasses; extern PyrClass *gClassList; // runInterpreter has 7 call sites: // compileLibrary (4) // runLibrary // interpretCmdLine static void endInterpreter(VMGlobals *g); SCLANG_DLLEXPORT_C void runInterpreter(VMGlobals *g, PyrSymbol *selector, int numArgsPushed) { //postfl("->runInterpreter\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //postfl(" >initInterpreter\n"); if (initInterpreter(g, selector, numArgsPushed)) { #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // if (strcmp(selector->name, "tick") != 0) post("%s %d execMethod %d\n", selector->name, numArgsPushed, g->execMethod); //post("->Interpret thread %p\n", g->thread); if (g->execMethod) Interpret(g); //post("<-Interpret thread %p\n", g->thread); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } //postfl(" >endInterpreter\n"); endInterpreter(g); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //postfl("<-runInterpreter\n"); //dumpGCStats(g->gc); } static bool initAwakeMessage(VMGlobals *g); void runAwakeMessage(VMGlobals *g) { if (initAwakeMessage(g)) { if (g->execMethod) Interpret(g); } endInterpreter(g); } void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray, double beats, double seconds, PyrSlot* clock, bool runGC); int32 timeseed(); PyrProcess* newPyrProcess(VMGlobals *g, PyrClass *procclassobj) { PyrGC* gc = g->gc; PyrProcess * proc = (PyrProcess*)instantiateObject(gc, procclassobj, 0, true, false); PyrObject *sysSchedulerQueue = newPyrArray(gc, 4096, 0, false); sysSchedulerQueue->size = 1; SetInt(sysSchedulerQueue->slots + 0, 0); // stability count SetObject(&proc->sysSchedulerQueue, sysSchedulerQueue); PyrObject *classVars = newPyrArray(gc, gNumClassVars, 0, false); classVars->size = gNumClassVars; nilSlots(classVars->slots, gNumClassVars); SetObject(&proc->classVars, classVars); g->classvars = classVars; // fill class vars from prototypes: PyrClass * classobj = gClassList; while (classobj) { if (IsObj(&classobj->cprototype)) { int numClassVars = slotRawObject(&classobj->cprototype)->size; if (numClassVars > 0) { memcpy(g->classvars->slots + slotRawInt(&classobj->classVarIndex), slotRawObject(&classobj->cprototype)->slots, numClassVars * sizeof(PyrSlot)); } } classobj = slotRawClass(&classobj->nextclass); } SetNil(&proc->nowExecutingPath); class_thread = getsym("Thread")->u.classobj; if (class_thread) { SetNil(&proc->curThread); PyrThread * thread = (PyrThread*)instantiateObject(gc, class_thread, 0, true, false); //SetObject(&threadsArray->slots[0], thread); SetObject(&proc->mainThread, thread); PyrInt32Array *rgenArray = newPyrInt32Array(gc, 4, 0, false); rgenArray->size = 4; rgenArray->i[0] = 0; rgenArray->i[1] = 0; rgenArray->i[2] = 0; rgenArray->i[3] = 0; ((RGen*)(rgenArray->i))->init(timeseed()); PyrSlot clockSlot; SetObject(&clockSlot, s_systemclock->u.classobj); initPyrThread(g, thread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false); //postfl("elapsedTime %.6f\n", elapsedTime()); } else { error("Class Thread not found.\n"); } PyrSymbol * contextsym = getsym("functionCompileContext"); size_t index = slotRawInt(&class_interpreter->classIndex) + contextsym->u.index; PyrMethod * meth = gRowTable[index]; if (!meth || slotRawSymbol(&meth->name) != contextsym) { error("compile context method 'functionCompileContext' not found.\n"); //SetNil(&proc->interpreter); } else { PyrObject *proto; PyrFrame *frame; PyrMethodRaw *methraw; PyrInterpreter * interpreter = (PyrInterpreter*)instantiateObject(gc, class_interpreter, 0, true, false); SetObject(&proc->interpreter, interpreter); proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); frame = (PyrFrame*)gc->New(methraw->frameSize, 0, obj_slot, false); frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; /// <- IS THIS WRONG ?? SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetInt(&frame->caller, 0); SetNil(&frame->context); SetPtr(&frame->ip, 0); SetObject(&frame->vars[0], interpreter); SetObject(&interpreter->context, frame); } return proc; } #if BCSTAT int prevop = 0; int bcstat[256]; int bcpair[256][256]; void clearbcstat(); void clearbcstat() { int i, j; for (i=0; i<256; ++i) { bcstat[i] = 0; for (j=0; j<256; ++j) { bcpair[i][j] = 0; } } } void dumpbcstat(); void dumpbcstat() { FILE *file; int i, j, k, total; file = fopen("bcstat", "w"); if (file) { fprintf(file, "----------\n"); total = 0; for (i=0; i<256; ++i) { total += bcstat[i]; if (bcstat[i]) fprintf(file, "%3d %8d %-32s\n", i, bcstat[i], byteCodeString(i)); } fprintf(file, "\ntotal %d\n", total); fprintf(file, "-----cur,next-----\n"); for (i=0, k=0; i<256; ++i) { for (j=0; j<256; j++) { if (bcpair[i][j] > 0) { fprintf(file, "%4d %3d %3d %8d %-32s %-32s\n", k++, i, j, bcpair[i][j], byteCodeString(i), byteCodeString(j)); } } } fprintf(file, "-----cur,prev-----\n"); for (i=0, k=0; i<256; ++i) { for (j=0; j<256; j++) { if (bcpair[j][i] > 0) { fprintf(file, "%4d %3d %3d %8d %-32s %-32s\n", k++, i, j, bcpair[j][i], byteCodeString(i), byteCodeString(j)); } } } } fclose(file); } #endif void initPatterns(); void initThreads(); void initGUI(); #ifndef _WIN32 bool running = true; static void handleSigUsr1(int param) { printf("handleSigUsr1()...\n"); running = false; } #endif bool initRuntime(VMGlobals *g, int poolSize, AllocPool *inPool) { /* create a GC environment create a vmachine instance of main initialize VMGlobals */ PyrClass * class_main = s_main->u.classobj; if (!class_main) { error("Class 'Main' not defined.\n"); return false; } if (!isSubclassOf(class_main, class_process)) { error("Class Main is not a subclass of Process.\n"); return false; } // create GC environment, process g->allocPool = inPool; g->gc = (PyrGC*)g->allocPool->Alloc(sizeof(PyrGC)); new (g->gc) PyrGC(g, g->allocPool, class_main, poolSize); g->thread = slotRawThread(&g->process->mainThread); SetObject(&g->receiver, g->process); // these will be set up when the run method is called g->method = NULL; g->block = NULL; g->frame = NULL; g->ip = NULL; // initialize process random number generator g->rgen = (RGen*)(slotRawObject(&g->thread->randData)->slots); //initUGenFuncs(); signal_init_globs(); initThreads(); initPatterns(); initUniqueMethods(); initGUI(); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //tellPlugInsAboutToRun(); #ifndef _WIN32 signal(SIGUSR1,handleSigUsr1); #endif assert((g->gc->SanityCheck())); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif return true; } static bool initAwakeMessage(VMGlobals *g) { //post("initAwakeMessage %p %p\n", g->thread, slotRawThread(&g->process->mainThread)); slotCopy(&g->process->curThread, &g->process->mainThread); //?? g->thread = slotRawThread(&g->process->mainThread); //?? // these will be set up when the run method is called g->method = NULL; g->block = NULL; g->frame = NULL; g->ip = NULL; g->execMethod = 0; // set process as the receiver PyrSlot *slot = g->sp - 3; slotCopy(&g->receiver, slot); SetFloat(&g->thread->beats, slotRawFloat(&slot[1])); SetFloat(&g->thread->seconds, slotRawFloat(&slot[2])); slotCopy(&g->thread->clock, &slot[3]); g->gc->GCWrite(g->thread, slot+3); // start it sendMessage(g, s_awake, 4); return g->method != NULL; } bool initInterpreter(VMGlobals *g, PyrSymbol *selector, int numArgsPushed) { slotCopy(&g->process->curThread, &g->process->mainThread); g->thread = slotRawThread(&g->process->mainThread); // these will be set up when the run method is called #if TAILCALLOPTIMIZE g->tailCall = 0; #endif g->method = NULL; g->block = NULL; g->frame = NULL; g->ip = NULL; g->execMethod = 0; double elapsed = elapsedTime(); SetFloat(&g->thread->beats, elapsed); SetFloat(&g->thread->seconds, elapsed); SetObject(&g->thread->clock, s_systemclock->u.classobj); g->gc->GCWrite(g->thread, s_systemclock->u.classobj); // set process as the receiver PyrSlot *slot = g->sp - numArgsPushed + 1; slotCopy(&g->receiver, slot); // start it sendMessage(g, selector, numArgsPushed); return g->method != NULL; } static void endInterpreter(VMGlobals *g) { slotCopy(&g->result, g->sp); // dumpObjectSlot(&g->result); g->gc->Stack()->size = 0; g->sp = g->gc->Stack()->slots - 1; g->gc->LazyCollect(); } static void StoreToImmutableA(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip) { // only the value is on the stack slotCopy(sp + 1, sp); // copy value up one slotCopy(sp, &g->receiver); // put receiver in place sp++; g->sp = sp; g->ip = ip; post("StoreToImmutableA\n"); dumpObjectSlot(sp-1); dumpObjectSlot(sp); sendMessage(g, getsym("immutableError"), 2); sp = g->sp; ip = g->ip; } void StoreToImmutableB(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip) { // receiver and value are on the stack. sp++; g->sp = sp; g->ip = ip; post("StoreToImmutableB\n"); dumpObjectSlot(sp-1); dumpObjectSlot(sp); PyrSymbol *selector = getsym("immutableError"); sendMessage(g, selector, 2); sp = g->sp; ip = g->ip; } void dumpByteCodes(PyrBlock *theBlock); static inline void handlePushClassVar(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned char op2) { unsigned char op3 = ip[1]; ++ip; // get class var index slotCopy(++sp, &g->classvars->slots[(op2<<8)|op3]); } static inline void handleStoreInstVar(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned int index) { PyrObject* obj = slotRawObject(&g->receiver); if (obj->IsImmutable()) StoreToImmutableA(g, sp, ip); else { PyrSlot * slot = obj->slots + index; slotCopy(slot, sp--); g->gc->GCWrite(obj, slot); } } static inline void handleSendSpecialUnaryArithMsg(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned char op1) { g->sp = sp; g->ip = ip; g->primitiveIndex = op1 & 15; doSpecialUnaryArithMsg(g, -1); sp = g->sp; ip = g->ip; } static inline void handleSendSpecialBinaryArithMsg(VMGlobals* g, PyrSlot *& sp, unsigned char *& ip, unsigned char op1) { g->sp = sp; g->ip = ip; g->primitiveIndex = op1 & 15; doSpecialBinaryArithMsg(g, 2, false); sp = g->sp; ip = g->ip; } static inline bool checkStackOverflow(VMGlobals* g, PyrSlot * sp) { PyrObject * stack = g->gc->Stack(); int depth = sp - stack->slots; return depth < slotRawInt(&g->thread->stackSize); } static inline void checkStackDepth(VMGlobals* g, PyrSlot * sp) { #if CHECK_MAX_STACK_USE int stackDepth = sp - g->sp + 1; if (stackDepth > gMaxStackDepth) { gMaxStackDepth = stackDepth; printf("gMaxStackDepth %d\n", gMaxStackDepth); } #endif } #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define LABELS_AS_VALUES #endif #ifdef LABELS_AS_VALUES #define dispatch_opcode \ op1 = ip[1]; \ ++ip; \ checkStackDepth(g, sp); \ assert(checkStackOverflow(g, sp)); \ goto *opcode_labels[op1] #else #define dispatch_opcode break #endif #if defined(__GNUC__) #define LIKELY(x) __builtin_expect((x),1) #define UNLIKELY(x) __builtin_expect((x),0) #else #define LIKELY(x) x #define UNLIKELY(x) x #endif #if defined(__GNUC__) && !defined(__clang__) // gcc manual: // Note: When compiling a program using computed gotos, a GCC extension, you may get better run-time performance if // you disable the global common subexpression elimination pass by adding -fno-gcse to the command line. #pragma GCC push_options #pragma GCC optimize("-fno-gcse") #endif HOT void Interpret(VMGlobals *g) { // byte code values unsigned char *ip; unsigned char op1; // interpreter globals int numArgsPushed, numKeyArgsPushed; PyrSymbol *selector; PyrClass *classobj; // temporary variables used in the interpreter PyrSlot *slot; PyrSlot *sp; #ifdef LABELS_AS_VALUES static void * opcode_labels[] = { &&handle_op_0, &&handle_op_1, &&handle_op_2, &&handle_op_3, &&handle_op_4, &&handle_op_5, &&handle_op_6, &&handle_op_7, &&handle_op_8, &&handle_op_9, &&handle_op_10, &&handle_op_11, &&handle_op_12, &&handle_op_13, &&handle_op_14, &&handle_op_15, &&handle_op_16, &&handle_op_17, &&handle_op_18, &&handle_op_19, &&handle_op_20, &&handle_op_21, &&handle_op_22, &&handle_op_23, &&handle_op_24, &&handle_op_25, &&handle_op_26, &&handle_op_27, &&handle_op_28, &&handle_op_29, &&handle_op_30, &&handle_op_31, &&handle_op_32, &&handle_op_33, &&handle_op_34, &&handle_op_35, &&handle_op_36, &&handle_op_37, &&handle_op_38, &&handle_op_39, &&handle_op_40, &&handle_op_41, &&handle_op_42, &&handle_op_43, &&handle_op_44, &&handle_op_45, &&handle_op_46, &&handle_op_47, &&handle_op_48, &&handle_op_49, &&handle_op_50, &&handle_op_51, &&handle_op_52, &&handle_op_53, &&handle_op_54, &&handle_op_55, &&handle_op_56, &&handle_op_57, &&handle_op_58, &&handle_op_59, &&handle_op_60, &&handle_op_61, &&handle_op_62, &&handle_op_63, &&handle_op_64, &&handle_op_65, &&handle_op_66, &&handle_op_67, &&handle_op_68, &&handle_op_69, &&handle_op_70, &&handle_op_71, &&handle_op_72, &&handle_op_73, &&handle_op_74, &&handle_op_75, &&handle_op_76, &&handle_op_77, &&handle_op_78, &&handle_op_79, &&handle_op_80, &&handle_op_81, &&handle_op_82, &&handle_op_83, &&handle_op_84, &&handle_op_85, &&handle_op_86, &&handle_op_87, &&handle_op_88, &&handle_op_89, &&handle_op_90, &&handle_op_91, &&handle_op_92, &&handle_op_93, &&handle_op_94, &&handle_op_95, &&handle_op_96, &&handle_op_97, &&handle_op_98, &&handle_op_99, &&handle_op_100, &&handle_op_101, &&handle_op_102, &&handle_op_103, &&handle_op_104, &&handle_op_105, &&handle_op_106, &&handle_op_107, &&handle_op_108, &&handle_op_109, &&handle_op_110, &&handle_op_111, &&handle_op_112, &&handle_op_113, &&handle_op_114, &&handle_op_115, &&handle_op_116, &&handle_op_117, &&handle_op_118, &&handle_op_119, &&handle_op_120, &&handle_op_121, &&handle_op_122, &&handle_op_123, &&handle_op_124, &&handle_op_125, &&handle_op_126, &&handle_op_127, &&handle_op_128, &&handle_op_129, &&handle_op_130, &&handle_op_131, &&handle_op_132, &&handle_op_133, &&handle_op_134, &&handle_op_135, &&handle_op_136, &&handle_op_137, &&handle_op_138, &&handle_op_139, &&handle_op_140, &&handle_op_141, &&handle_op_142, &&handle_op_143, &&handle_op_144, &&handle_op_145, &&handle_op_146, &&handle_op_147, &&handle_op_148, &&handle_op_149, &&handle_op_150, &&handle_op_151, &&handle_op_152, &&handle_op_153, &&handle_op_154, &&handle_op_155, &&handle_op_156, &&handle_op_157, &&handle_op_158, &&handle_op_159, &&handle_op_160, &&handle_op_161, &&handle_op_162, &&handle_op_163, &&handle_op_164, &&handle_op_165, &&handle_op_166, &&handle_op_167, &&handle_op_168, &&handle_op_169, &&handle_op_170, &&handle_op_171, &&handle_op_172, &&handle_op_173, &&handle_op_174, &&handle_op_175, &&handle_op_176, &&handle_op_177, &&handle_op_178, &&handle_op_179, &&handle_op_180, &&handle_op_181, &&handle_op_182, &&handle_op_183, &&handle_op_184, &&handle_op_185, &&handle_op_186, &&handle_op_187, &&handle_op_188, &&handle_op_189, &&handle_op_190, &&handle_op_191, &&handle_op_192, &&handle_op_193, &&handle_op_194, &&handle_op_195, &&handle_op_196, &&handle_op_197, &&handle_op_198, &&handle_op_199, &&handle_op_200, &&handle_op_201, &&handle_op_202, &&handle_op_203, &&handle_op_204, &&handle_op_205, &&handle_op_206, &&handle_op_207, &&handle_op_208, &&handle_op_209, &&handle_op_210, &&handle_op_211, &&handle_op_212, &&handle_op_213, &&handle_op_214, &&handle_op_215, &&handle_op_216, &&handle_op_217, &&handle_op_218, &&handle_op_219, &&handle_op_220, &&handle_op_221, &&handle_op_222, &&handle_op_223, &&handle_op_224, &&handle_op_225, &&handle_op_226, &&handle_op_227, &&handle_op_228, &&handle_op_229, &&handle_op_230, &&handle_op_231, &&handle_op_232, &&handle_op_233, &&handle_op_234, &&handle_op_235, &&handle_op_236, &&handle_op_237, &&handle_op_238, &&handle_op_239, &&handle_op_240, &&handle_op_241, &&handle_op_242, &&handle_op_243, &&handle_op_244, &&handle_op_245, &&handle_op_246, &&handle_op_247, &&handle_op_248, &&handle_op_249, &&handle_op_250, &&handle_op_251, &&handle_op_252, &&handle_op_253, &&handle_op_254, &&handle_op_255 }; #endif #if 0 unsigned char *bzero; PyrSlot *szero; char str[80]; #endif #if BCSTAT //clearbcstat(); op1 = 0; prevop = 0; #endif #if 0 bzero = g->ip; szero = g->sp; //SetSymbol(g->sp, getsym("STACK TOP")); // just for debugging //g->sp++; // just for debugging #endif // Codewarrior puts them in registers. take advantage.. sp = g->sp; ip = g->ip; numKeyArgsPushed = 0; if (setjmp(g->escapeInterpreter) != 0) { return; } #ifndef _WIN32 while (running) { // not going to indent body to save line space #else while (true) { #endif checkStackDepth(g, sp); #if BCSTAT prevop = op1; #endif op1 = ip[1]; ++ip; assert(checkStackOverflow(g, sp)); #if BCSTAT ++bcstat[op1]; ++bcpair[prevop][op1]; prevop = op1; #endif //printf("op1 %d\n", op1); //postfl("sp %p frame %p caller %p ip %p\n", sp, g->frame, g->frame->caller.uof, slotRawInt(&g->frame->caller.uof->ip)); //postfl("sp %p frame %p diff %d caller %p\n", sp, g->frame, ((int)sp - (int)g->frame)>>3, g->frame->caller.uof); #if DEBUGINTERPRETER if (gTraceInterpreter) { //DumpStack(g, sp); if (FrameSanity(g->frame, "dbgint")) { //Debugger(); } //g->gc->SanityCheck(); //assert(g->gc->SanityCheck()); g->sp = sp; g->ip = ip; g->gc->FullCollection(); sp = g->sp; ip = g->ip; postfl("[%3d] %20s-%-16s ", (sp - g->gc->Stack()->slots) + 1, slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name); dumpOneByteCode(g->block, NULL, ip); } #endif #ifdef GC_SANITYCHECK // gcLinkSanity(g->gc); g->gc->SanityCheck(); // do_check_pool(pyr_pool_runtime); // do_check_pool(pyr_pool_compile); #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&g->method->byteMeter)++; } #endif switch (op1) { case 0 : // push class handle_op_0: { int op2 = ip[1]; ++ip; // get literal index classobj = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2])->u.classobj; if (classobj) { ++sp; SetObject(sp, classobj); } else { postfl("Execution warning: Class '%s' not found\n", slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2])->name); slotCopy(++sp, &gSpecialValues[svNil]); } dispatch_opcode; } case 1 : // opExtended, opPushInstVar handle_op_1: { int op2 = ip[1]; ++ip; // get inst var index slotCopy(++sp, &slotRawObject(&g->receiver)->slots[op2]); dispatch_opcode; } case 2 : // opExtended, opPushTempVar handle_op_2: { int op2 = ip[1]; // get temp var level int op3 = ip[2]; // get temp var index ip += 2; PyrFrame *tframe = g->frame; for (; op2--; tframe = slotRawFrame(&tframe->context)) { /* noop */ } slotCopy(++sp, &tframe->vars[op3]); dispatch_opcode; } case 3 : // opExtended, opPushTempZeroVar handle_op_3: { int op2 = ip[1]; ++ip; // get temp var index slotCopy(++sp, &g->frame->vars[op2]); dispatch_opcode; } case 4 : // opExtended, opPushLiteral handle_op_4: { int op2 = ip[1]; ++ip; // get literal index // push a block as a closure if it is one slot = slotRawObject(&g->block->selectors)->slots + op2; if (IsObj(slot) && slotRawObject(slot)->classptr == gSpecialClasses[op_class_fundef]->u.classobj) { // push a closure g->sp = sp; // gc may push the stack PyrClosure * closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true); sp = g->sp; closure->classptr = gSpecialClasses[op_class_func]->u.classobj; closure->size = 2; slotCopy(&closure->block, slot); if (IsNil(&slotRawBlock(slot)->contextDef)) { slotCopy(&closure->context, &slotRawInterpreter(&g->process->interpreter)->context); } else { SetObject(&closure->context, g->frame); } ++sp; SetObject(sp, closure); } else { slotCopy(++sp, slot); } dispatch_opcode; } case 5 : // opExtended, opPushClassVar handle_op_5: { int op2 = ip[1]; // get class int op3 = ip[2]; // get class var index ip += 2; slotCopy(++sp, &g->classvars->slots[(op2<<8)|op3]); dispatch_opcode; } case 6 : // opExtended, opPushSpecialValue == push a special class handle_op_6: { int op2 = ip[1]; ++ip; // get class name index classobj = gSpecialClasses[op2]->u.classobj; if (classobj) { ++sp; SetObject(sp, classobj); } else { slotCopy(++sp, &gSpecialValues[svNil]); } dispatch_opcode; } case 7 : // opExtended, opStoreInstVar handle_op_7: { int op2 = ip[1]; ++ip; // get inst var index PyrObject * obj = slotRawObject(&g->receiver); if (obj->IsImmutable()) { StoreToImmutableA(g, sp, ip); } else { slot = obj->slots + op2; slotCopy(slot, sp); g->gc->GCWrite(obj, slot); } dispatch_opcode; } case 8 : // opExtended, opStoreTempVar handle_op_8: { int op2 = ip[1]; // get temp var level int op3 = ip[2]; // get temp var index ip += 2; PyrFrame * tframe = g->frame; for (; op2--; tframe = slotRawFrame(&tframe->context)) { /* noop */ } slot = tframe->vars + op3; slotCopy(slot, sp); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 9 : // opExtended, opStoreClassVar handle_op_9: { int op2 = ip[1]; // get index of class name literal int op3 = ip[2]; // get class var index ip += 2; slotCopy(&g->classvars->slots[(op2<<8)|op3], sp); g->gc->GCWrite(g->classvars, sp); dispatch_opcode; } case 10 : // opExtended, opSendMsg handle_op_10: { numArgsPushed = ip[1]; // get num args numKeyArgsPushed = ip[2]; // get num keyword args int op3 = ip[3]; // get selector index ip += 3; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op3]); slot = sp - numArgsPushed + 1; if (numKeyArgsPushed) goto key_class_lookup; else goto class_lookup; } case 11 : // opExtended, opSendSuper handle_op_11: { numArgsPushed = ip[1]; // get num args numKeyArgsPushed = ip[2]; // get num keyword args int op3 = ip[3]; // get selector index ip += 3; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op3]); slot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; if (numKeyArgsPushed) goto key_msg_lookup; else goto msg_lookup; } case 12 : // opExtended, opSendSpecialMsg handle_op_12: { numArgsPushed = ip[1]; // get num args numKeyArgsPushed = ip[2]; // get num keyword args int op3 = ip[3]; // get selector index ip += 3; selector = gSpecialSelectors[op3]; slot = sp - numArgsPushed + 1; if (numKeyArgsPushed) goto key_class_lookup; else goto class_lookup; } case 13 : // opExtended, opSendSpecialUnaryArithMsg handle_op_13: { int op2 = ip[1]; ++ip; // get selector index g->sp = sp; g->ip = ip; g->primitiveIndex = op2; doSpecialUnaryArithMsg(g, -1); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif sp = g->sp; ip = g->ip; dispatch_opcode; } case 14 : // opExtended, opSendSpecialBinaryArithMsg handle_op_14: { int op2 = ip[1]; ++ip; // get selector index g->sp = sp; g->ip = ip; g->primitiveIndex = op2; doSpecialBinaryArithMsg(g, 2, false); sp = g->sp; ip = g->ip; dispatch_opcode; } case 15 : // opExtended, opSpecialOpcode (none yet) handle_op_15: { int op2 = ip[1]; ++ip; // get extended special opcode switch (op2) { case opgProcess : // push thisProcess ++sp; SetObject(sp, g->process); break; case opgThread : // push thisProcess ++sp; SetObject(sp, g->thread); break; case opgMethod : // push thisMethod ++sp; SetObject(sp, g->method); break; case opgFunctionDef : // push thisFunctionDef ++sp; SetObject(sp, g->block); break; case opgFunction : { // push thisFunc // push a closure g->sp = sp; // gc may push the stack PyrClosure * closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true); sp = g->sp; closure->classptr = gSpecialClasses[op_class_func]->u.classobj; closure->size = 2; SetObject(&closure->block, g->block); SetObject(&closure->context, slotRawFrame(&g->frame->context)); ++sp; SetObject(sp, closure); break; } default : slotCopy(++sp, &gSpecialValues[svNil]); break; } dispatch_opcode; } // opPushInstVar, 0..15 case 16 : handle_op_16: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 0]); dispatch_opcode; case 17 : handle_op_17: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 1]); dispatch_opcode; case 18 : handle_op_18: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 2]); dispatch_opcode; case 19 : handle_op_19: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 3]); dispatch_opcode; case 20 : handle_op_20: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 4]); dispatch_opcode; case 21 : handle_op_21: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 5]); dispatch_opcode; case 22 : handle_op_22: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 6]); dispatch_opcode; case 23 : handle_op_23: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 7]); dispatch_opcode; case 24 : handle_op_24: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 8]); dispatch_opcode; case 25 : handle_op_25: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[ 9]); dispatch_opcode; case 26 : handle_op_26: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[10]); dispatch_opcode; case 27 : handle_op_27: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[11]); dispatch_opcode; case 28 : handle_op_28: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[12]); dispatch_opcode; case 29 : handle_op_29: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[13]); dispatch_opcode; case 30 : handle_op_30: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[14]); dispatch_opcode; case 31 : handle_op_31: slotCopy(++sp, &slotRawObject(&g->receiver)->slots[15]); dispatch_opcode; case 32 : // JumpIfTrue handle_op_32: // cannot compare with o_false because it is NaN if ( IsTrue(sp) ) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else if ( IsFalse(sp)) { ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } --sp; dispatch_opcode; // opPushTempVar, levels 1..7 case 33 : handle_op_33: slotCopy(++sp, &slotRawFrame(&g->frame->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 34 : handle_op_34: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&g->frame->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 35 : handle_op_35: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 36 : handle_op_36: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context)-> context)->vars[ip[1]]); ++ip; dispatch_opcode; case 37 : handle_op_37: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)-> context)->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 38 : handle_op_38: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)-> context)->context)->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; case 39 : handle_op_39: slotCopy(++sp, &slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)-> context)->context)->context)->context)->context)->context)->vars[ip[1]]); ++ip; dispatch_opcode; // push literal constants. case 40 : handle_op_40: { int ival = ip[1]; ip+=1; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; } case 41 : handle_op_41: { int ival = (ip[1] << 8) | ip[2]; ip+=2; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; } case 42 : handle_op_42: { int ival = (ip[1] << 16) | (ip[2] << 8) | ip[3]; ip+=3; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; } case 43 : handle_op_43: { int ival = (ip[1] << 24) | (ip[2] << 16) | (ip[3] << 8) | ip[4]; ip+=4; slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ival]); dispatch_opcode; } // push integers. case 44 : handle_op_44: { int ival = (int32)(ip[1] << 24) >> 24; ip+=1; ++sp; SetInt(sp, ival); dispatch_opcode; } case 45 : handle_op_45: { int ival = (int32)((ip[1] << 24) | (ip[2] << 16)) >> 16; ip+=2; ++sp; SetInt(sp, ival); dispatch_opcode; } case 46 : handle_op_46: { int ival = (int32)((ip[1] << 24) | (ip[2] << 16) | (ip[3] << 8)) >> 8; ip+=3; ++sp; SetInt(sp, ival); dispatch_opcode; } case 47 : handle_op_47: { int ival = (int32)((ip[1] << 24) | (ip[2] << 16) | (ip[3] << 8) | ip[4]); ip+=4; ++sp; SetInt(sp, ival); dispatch_opcode; } // opPushTempZeroVar case 48 : handle_op_48: slotCopy(++sp, &g->frame->vars[ 0]); dispatch_opcode; case 49 : handle_op_49: slotCopy(++sp, &g->frame->vars[ 1]); dispatch_opcode; case 50 : handle_op_50: slotCopy(++sp, &g->frame->vars[ 2]); dispatch_opcode; case 51 : handle_op_51: slotCopy(++sp, &g->frame->vars[ 3]); dispatch_opcode; case 52 : handle_op_52: slotCopy(++sp, &g->frame->vars[ 4]); dispatch_opcode; case 53 : handle_op_53: slotCopy(++sp, &g->frame->vars[ 5]); dispatch_opcode; case 54 : handle_op_54: slotCopy(++sp, &g->frame->vars[ 6]); dispatch_opcode; case 55 : handle_op_55: slotCopy(++sp, &g->frame->vars[ 7]); dispatch_opcode; case 56 : handle_op_56: slotCopy(++sp, &g->frame->vars[ 8]); dispatch_opcode; case 57 : handle_op_57: slotCopy(++sp, &g->frame->vars[ 9]); dispatch_opcode; case 58 : handle_op_58: slotCopy(++sp, &g->frame->vars[10]); dispatch_opcode; case 59 : handle_op_59: slotCopy(++sp, &g->frame->vars[11]); dispatch_opcode; case 60 : handle_op_60: slotCopy(++sp, &g->frame->vars[12]); dispatch_opcode; case 61 : handle_op_61: slotCopy(++sp, &g->frame->vars[13]); dispatch_opcode; case 62 : handle_op_62: slotCopy(++sp, &g->frame->vars[14]); dispatch_opcode; case 63 : handle_op_63: slotCopy(++sp, &g->frame->vars[15]); dispatch_opcode; // case opPushLiteral case 64 : handle_op_64: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 0]); dispatch_opcode; case 65 : handle_op_65: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 1]); dispatch_opcode; case 66 : handle_op_66: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 2]); dispatch_opcode; case 67 : handle_op_67: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 3]); dispatch_opcode; case 68 : handle_op_68: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 4]); dispatch_opcode; case 69 : handle_op_69: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 5]); dispatch_opcode; case 70 : handle_op_70: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 6]); dispatch_opcode; case 71 : handle_op_71: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 7]); dispatch_opcode; case 72 : handle_op_72: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 8]); dispatch_opcode; case 73 : handle_op_73: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[ 9]); dispatch_opcode; case 74 : handle_op_74: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[10]); dispatch_opcode; case 75 : handle_op_75: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[11]); dispatch_opcode; case 76 : handle_op_76: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[12]); dispatch_opcode; case 77 : handle_op_77: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[13]); dispatch_opcode; case 78 : handle_op_78: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[14]); dispatch_opcode; case 79 : handle_op_79: slotCopy(++sp, &slotRawObject(&g->block->constants)->slots[15]); dispatch_opcode; // opPushClassVar case 80: handle_op_80: handlePushClassVar(g, sp, ip, 0); dispatch_opcode; case 81: handle_op_81: handlePushClassVar(g, sp, ip, 1); dispatch_opcode; case 82: handle_op_82: handlePushClassVar(g, sp, ip, 2); dispatch_opcode; case 83: handle_op_83: handlePushClassVar(g, sp, ip, 3); dispatch_opcode; case 84: handle_op_84: handlePushClassVar(g, sp, ip, 4); dispatch_opcode; case 85: handle_op_85: handlePushClassVar(g, sp, ip, 5); dispatch_opcode; case 86: handle_op_86: handlePushClassVar(g, sp, ip, 6); dispatch_opcode; case 87: handle_op_87: handlePushClassVar(g, sp, ip, 7); dispatch_opcode; case 88: handle_op_88: handlePushClassVar(g, sp, ip, 8); dispatch_opcode; case 89: handle_op_89: handlePushClassVar(g, sp, ip, 9); dispatch_opcode; case 90: handle_op_90: handlePushClassVar(g, sp, ip, 10); dispatch_opcode; case 91: handle_op_91: handlePushClassVar(g, sp, ip, 11); dispatch_opcode; case 92: handle_op_92: handlePushClassVar(g, sp, ip, 12); dispatch_opcode; case 93: handle_op_93: handlePushClassVar(g, sp, ip, 13); dispatch_opcode; case 94: handle_op_94: handlePushClassVar(g, sp, ip, 14); dispatch_opcode; case 95: handle_op_95: handlePushClassVar(g, sp, ip, 15); dispatch_opcode; // opPushSpecialValue case 96 : handle_op_96: slotCopy(++sp, &g->receiver); dispatch_opcode; case 97 : // push one and subtract handle_op_97: if (IsInt(sp)) { SetRaw(sp, slotRawInt(sp) - 1); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { slotCopy(++sp, &gSpecialValues[svOne]); g->sp = sp; g->ip = ip; g->primitiveIndex = opSub; prSubNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 98 : handle_op_98: slotCopy(++sp, &gSpecialValues[svNegOne]); dispatch_opcode; case 99 : handle_op_99: slotCopy(++sp, &gSpecialValues[svZero]); dispatch_opcode; case 100 : handle_op_100: slotCopy(++sp, &gSpecialValues[svOne]); dispatch_opcode; case 101 : handle_op_101: slotCopy(++sp, &gSpecialValues[svTwo]); dispatch_opcode; case 102 : handle_op_102: slotCopy(++sp, &gSpecialValues[svFHalf]); dispatch_opcode; case 103 : handle_op_103: slotCopy(++sp, &gSpecialValues[svFNegOne]); dispatch_opcode; case 104 : handle_op_104: slotCopy(++sp, &gSpecialValues[svFZero]); dispatch_opcode; case 105 : handle_op_105: slotCopy(++sp, &gSpecialValues[svFOne]); dispatch_opcode; case 106 : handle_op_106: slotCopy(++sp, &gSpecialValues[svFTwo]); dispatch_opcode; case 107 : // push one and add handle_op_107: if (IsInt(sp)) { SetRaw(sp, slotRawInt(sp) + 1); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { slotCopy(++sp, &gSpecialValues[svOne]); g->sp = sp; g->ip = ip; g->primitiveIndex = opAdd; prAddNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 108 : handle_op_108: slotCopy(++sp, &gSpecialValues[svTrue]); dispatch_opcode; case 109 : handle_op_109: slotCopy(++sp, &gSpecialValues[svFalse]); dispatch_opcode; case 110 : handle_op_110: slotCopy(++sp, &gSpecialValues[svNil]); dispatch_opcode; case 111 : handle_op_111: slotCopy(++sp, &gSpecialValues[svInf]); dispatch_opcode; // opStoreInstVar, 0..15 case 112 : handle_op_112: handleStoreInstVar(g, sp, ip, 0); dispatch_opcode; case 113 : handle_op_113: handleStoreInstVar(g, sp, ip, 1); dispatch_opcode; case 114 : handle_op_114: handleStoreInstVar(g, sp, ip, 2); dispatch_opcode; case 115 : handle_op_115: handleStoreInstVar(g, sp, ip, 3); dispatch_opcode; case 116 : handle_op_116: handleStoreInstVar(g, sp, ip, 4); dispatch_opcode; case 117 : handle_op_117: handleStoreInstVar(g, sp, ip, 5); dispatch_opcode; case 118 : handle_op_118: handleStoreInstVar(g, sp, ip, 6); dispatch_opcode; case 119 : handle_op_119: handleStoreInstVar(g, sp, ip, 7); dispatch_opcode; case 120 : handle_op_120: handleStoreInstVar(g, sp, ip, 8); dispatch_opcode; case 121 : handle_op_121: handleStoreInstVar(g, sp, ip, 9); dispatch_opcode; case 122 : handle_op_122: handleStoreInstVar(g, sp, ip, 10); dispatch_opcode; case 123 : handle_op_123: handleStoreInstVar(g, sp, ip, 11); dispatch_opcode; case 124 : handle_op_124: handleStoreInstVar(g, sp, ip, 12); dispatch_opcode; case 125 : handle_op_125: handleStoreInstVar(g, sp, ip, 13); dispatch_opcode; case 126 : handle_op_126: handleStoreInstVar(g, sp, ip, 14); dispatch_opcode; case 127 : handle_op_127: handleStoreInstVar(g, sp, ip, 15); dispatch_opcode; // opStoreTempVar case 128 : handle_op_128: { int op3 = ip[1]; ++ip; // get temp var index PyrFrame * tframe = g->frame; // zero level slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 129 : handle_op_129: { int op3 = ip[1]; ++ip; // get temp var index PyrFrame * tframe = slotRawFrame(&g->frame->context); // one level slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 130 : handle_op_130: { int op3 = ip[1]; ++ip; // get temp var index PyrFrame * tframe = slotRawFrame(&slotRawFrame(&g->frame->context)->context); // two levels slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 131 : handle_op_131: { int op3 = ip[1]; ++ip; // get temp var index PyrFrame * tframe = slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context); // three levels slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 132 : handle_op_132: { int op3 = ip[1]; ++ip; // get temp var index PyrFrame * tframe = slotRawFrame(&slotRawFrame(&slotRawFrame(&slotRawFrame(&g->frame->context)->context)->context)->context); // four levels slot = tframe->vars + op3; slotCopy(slot, sp--); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 133 : case 134 : case 135 : handle_op_133: handle_op_134: handle_op_135: { int op2 = op1 & 15; int op3 = ip[1]; ++ip; // get temp var index PyrFrame * tframe = g->frame; for (;op2--; tframe = slotRawFrame(&tframe->context)) { /* noop */ } slot = tframe->vars + op3; slotCopy(slot, sp); g->gc->GCWrite(tframe, slot); dispatch_opcode; } case 136 : // push inst var, send special selector handle_op_136: { int op2 = ip[1]; // get inst var index int op3 = ip[2]; // get selector ip+=2; slotCopy(++sp, &slotRawObject(&g->receiver)->slots[op2]); numArgsPushed = 1; selector = gSpecialSelectors[op3]; slot = sp; goto class_lookup; } case 137 : // push all args, send msg handle_op_137: { numArgsPushed = METHRAW(g->block)->numargs; PyrSlot * pslot = g->frame->vars - 1; for (int m=0; mblock->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; } case 138 : // push all but first arg, send msg handle_op_138: { numArgsPushed = METHRAW(g->block)->numargs; PyrSlot * pslot = g->frame->vars; for (int m=0; mblock->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; } case 139 : // push all args, send special handle_op_139: { numArgsPushed = METHRAW(g->block)->numargs; PyrSlot * pslot = g->frame->vars - 1; for (int m=0 ; mblock)->numargs; PyrSlot * pslot = g->frame->vars; for (int m=0; mblock)->numargs + 1; PyrSlot * pslot = g->frame->vars; for (int m=0; mblock->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; } case 142 : // one arg pushed, push all but first arg, send special handle_op_142: { numArgsPushed = METHRAW(g->block)->numargs + 1; PyrSlot * pslot = g->frame->vars; for (int m=0; mframe->vars; if (slotRawInt(&vars[2]) < slotRawInt(&g->receiver)) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[2]); // push i // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } case 1 : -- sp ; // Drop SetRaw(&g->frame->vars[2], slotRawInt(&g->frame->vars[2]) + 1); // inc i ip -= 4; dispatch_opcode; // Integer-reverseDo : 143 2, 143 3, 143 4 case 2 : SetRaw(&g->frame->vars[2], slotRawInt(&g->receiver) - 1); dispatch_opcode; case 3 : { PyrSlot *vars = g->frame->vars; if (slotRawInt(&vars[2]) >= 0) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[3]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } case 4 : { -- sp ; // Drop PyrSlot *vars = g->frame->vars; SetRaw(&vars[2], slotRawInt(&vars[2]) - 1); // dec i SetRaw(&vars[3], slotRawInt(&vars[3]) + 1); // inc j ip -= 4; dispatch_opcode; } // Integer-for : 143 5, 143 6, 143 16 case 5 : { PyrSlot * vars = g->frame->vars; int tag = GetTag(&vars[1]); if (tag != tagInt) { if (IsFloat(&vars[1])) { // coerce to int SetInt(&vars[1], (int32)(slotRawFloat(&vars[1]))); } else { error("Integer-for : endval not a SimpleNumber.\n"); slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = gSpecialSelectors[opmPrimitiveFailed]; slot = sp; goto class_lookup; } } if (slotRawInt(&g->receiver) <= slotRawInt(&vars[1])) { SetRaw(&vars[5], 1); } else { SetRaw(&vars[5], -1); } slotCopy(&vars[3], &g->receiver); dispatch_opcode; } case 6 : { PyrSlot * vars = g->frame->vars; if ((slotRawInt(&vars[5]) > 0 && slotRawInt(&vars[3]) <= slotRawInt(&vars[1])) || (slotRawInt(&vars[5]) < 0 && slotRawInt(&vars[3]) >= slotRawInt(&vars[1]))) { slotCopy(++sp, &vars[2]); // push function slotCopy(++sp, &vars[3]); // push i slotCopy(++sp, &vars[4]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } // Integer-forBy : 143 7, 143 8, 143 9 case 7 : { PyrSlot * vars = g->frame->vars; if (IsFloat(vars+1)) { SetInt(&vars[1], (int32)(slotRawFloat(&vars[1]))); } if (IsFloat(vars+2)) { SetInt(&vars[2], (int32)(slotRawFloat(&vars[2]))); } int tag = GetTag(&vars[1]); if ((tag != tagInt) || NotInt(&vars[2])) { error("Integer-forBy : endval or stepval not an Integer.\n"); slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = gSpecialSelectors[opmPrimitiveFailed]; slot = sp; goto class_lookup; } slotCopy(&vars[4], &g->receiver); dispatch_opcode; } case 8 : { PyrSlot * vars = g->frame->vars; if ((slotRawInt(&vars[2]) >= 0 && slotRawInt(&vars[4]) <= slotRawInt(&vars[1])) || (slotRawInt(&vars[2]) < 0 && slotRawInt(&vars[4]) >= slotRawInt(&vars[1]))) { slotCopy(++sp, &vars[3]); // push function slotCopy(++sp, &vars[4]); // push i slotCopy(++sp, &vars[5]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } case 9 : { --sp ; // Drop PyrSlot * vars = g->frame->vars; SetRaw(&vars[4], slotRawInt(&vars[4]) + slotRawInt(&vars[2])); // inc i SetRaw(&vars[5], slotRawInt(&vars[5]) + 1); // inc j ip -= 4; dispatch_opcode; } // ArrayedCollection-do : 143 10, 143 1 case 10 : { // 0 this, 1 func, 2 i PyrSlot * vars = g->frame->vars; if (slotRawInt(&vars[2]) < slotRawObject(&g->receiver)->size) { slotCopy(++sp, &vars[1]); // push function getIndexedSlot(slotRawObject(&g->receiver), ++sp, slotRawInt(&vars[2])); // push this.at(i) slotCopy(++sp, &vars[2]); // push i // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } // ArrayedCollection-reverseDo : 143 11, 143 12, 143 4 case 11 : SetRaw(&g->frame->vars[2], slotRawObject(&g->receiver)->size - 1); dispatch_opcode; case 12 : { PyrSlot * vars = g->frame->vars; if (slotRawInt(&vars[2]) >= 0) { slotCopy(++sp, &vars[1]); // push function getIndexedSlot(slotRawObject(&g->receiver), ++sp, slotRawInt(&vars[2])); // push this.at(i) slotCopy(++sp, &vars[3]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; // class_lookup: } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } // Dictionary-keysValuesArrayDo case 13 : { PyrSlot * vars = g->frame->vars; int m = slotRawInt(&vars[3]); PyrObject * obj = slotRawObject(&vars[1]); if ( m < obj->size ) { slot = obj->slots + m; // key while (IsNil(slot)) { m += 2; if ( m >= obj->size ) { SetRaw(&vars[3], m); goto keysValuesArrayDo_return; } slot = obj->slots + m; // key } SetRaw(&vars[3], m); slotCopy(++sp, &vars[2]); // function slotCopy(++sp, &slot[0]); // key slotCopy(++sp, &slot[1]); // val slotCopy(++sp, &vars[4]); // j SetRaw(&vars[4], slotRawInt(&vars[4]) + 1); // SendSpecialMsg value numArgsPushed = 4; selector = gSpecialSelectors[opmValue]; slot = sp - 3; goto class_lookup; // class_lookup: } else { keysValuesArrayDo_return: slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } case 14 : -- sp; // Drop SetRaw(&g->frame->vars[3], slotRawInt(&g->frame->vars[3]) + 2); // inc i ip -= 4; dispatch_opcode; case 15 : // unused opcode. break; case 16 : { -- sp ; // Drop PyrSlot * vars = g->frame->vars; SetRaw(&vars[3], slotRawInt(&vars[3]) + slotRawInt(&vars[5])); // inc i by stepval SetRaw(&vars[4], slotRawInt(&vars[4]) + 1); // inc j ip -= 4; dispatch_opcode; } // Float-do : 143 17, 143 18 case 17 : { PyrSlot * vars = g->frame->vars; if (slotRawFloat(&vars[2]) + 0.5 < slotRawFloat(&g->receiver)) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[2]); // push i // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } case 18 : { -- sp ; // Drop SetRaw(&g->frame->vars[2], slotRawFloat(&g->frame->vars[2]) + 1.0); // inc i ip -= 4; dispatch_opcode; } // Float-reverseDo : 143 19, 143 20, 143 21 case 19 : { SetFloat(&g->frame->vars[2], slotRawFloat(&g->receiver) - 1.0); dispatch_opcode; } case 20 : { PyrSlot * vars = g->frame->vars; if (slotRawFloat(&vars[2]) + 0.5 >= 0.0) { slotCopy(++sp, &vars[1]); // push function slotCopy(++sp, &vars[2]); // push i slotCopy(++sp, &vars[3]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } dispatch_opcode; } case 21 : { -- sp ; // Drop PyrSlot * vars = g->frame->vars; SetRaw(&g->frame->vars[2], slotRawFloat(&g->frame->vars[2]) - 1.0); // dec i SetRaw(&g->frame->vars[3], slotRawFloat(&g->frame->vars[3]) - 1.0); // inc j ip -= 4; dispatch_opcode; } case 22 : // ? question mark method --sp; if (IsNil(sp)) { *sp = *(sp+1); } dispatch_opcode; case 23 : // if not nil push this and jump. used to implement ?? if (NotNil(sp)) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { --sp; ip+=2; } dispatch_opcode; case 24 : // ifNil if ( NotNil(sp) ) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { ip+=2; } --sp; dispatch_opcode; case 25 : // ifNotNil if ( IsNil(sp) ) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { ip+=2; } --sp; dispatch_opcode; case 26 : // ifNotNilPushNil if ( NotNil(sp) ) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; slotCopy(sp, &gSpecialValues[svNil]); } else { ip+=2; --sp; } dispatch_opcode; case 27 : // ifNilPushNil if ( IsNil(sp) ) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else { ip+=2; --sp; } dispatch_opcode; case 28 :{ // switch PyrObject * obj = slotRawObject(sp); op2 = 1 + arrayAtIdentityHashInPairs(obj, (sp-1)); sp-=2; ip += slotRawInt(&obj->slots[op2]); dispatch_opcode; } // Number-forSeries : 143 29, 143 30, 143 31 case 29 : { PyrSlot * vars = g->frame->vars; // 0 receiver, 1 step, 2 last, 3 function, 4 i, 5 j if (IsInt(vars+0) && (IsInt(vars+1) || IsNil(vars+1)) && (IsInt(vars+2) || IsNil(vars+2))) { if (IsNil(vars+1)) { if (IsNil(vars+2)) SetInt(vars+2, 0x7FFFFFFF); if (slotRawInt(&vars[0]) < slotRawInt(&vars[2])) SetInt(vars+1, 1); else SetInt(vars+1, -1); } else { if (IsNil(vars+2)) { if (slotRawInt(&vars[1]) < slotRawInt(&vars[0])) SetInt(vars+2, 0x80000000); else SetInt(vars+2, 0x7FFFFFFF); } SetInt(vars+1, slotRawInt(&vars[1]) - slotRawInt(&vars[0])); } slotCopy(&vars[4], &vars[0]); } else { if (IsInt(vars+0)) { SetFloat(&vars[4], slotRawInt(&vars[0])); } else if (IsFloat(vars+0)) { SetFloat(&vars[4], slotRawFloat(&vars[0])); } else { bailFromNumberSeries: error("Number-forSeries : first, second or last not an Integer or Float.\n"); slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = gSpecialSelectors[opmPrimitiveFailed]; slot = sp; goto class_lookup; } if (IsNil(vars+1)) { if (IsNil(vars+2)) SetFloat(vars+2, kBigBigFloat); else if (IsInt(vars+2)) SetFloat(&vars[2], slotRawInt(&vars[2])); else if (!IsFloat(vars+2)) goto bailFromNumberSeries; if (slotRawFloat(&vars[4]) < slotRawFloat(&vars[2])) SetFloat(vars+1, 1.); else SetFloat(vars+1, -1.); } else { if (IsInt(vars+1)) SetFloat(&vars[1], slotRawInt(&vars[1])); else if (!IsFloat(vars+1)) goto bailFromNumberSeries; if (IsNil(vars+2)) { if (slotRawFloat(&vars[1]) < slotRawFloat(&vars[4])) SetFloat(vars+2, kSmallSmallFloat); else SetFloat(vars+2, kBigBigFloat); } else if (IsInt(vars+2)) SetFloat(&vars[2], slotRawInt(&vars[2])); else if (!IsFloat(vars+2)) goto bailFromNumberSeries; SetFloat(vars+1, slotRawFloat(&vars[1]) - slotRawFloat(&vars[4])); } } dispatch_opcode; } case 30 : { PyrSlot * vars = g->frame->vars; int tag = GetTag(&vars[1]); if (tag == tagInt) { if ((slotRawInt(&vars[1]) >= 0 && slotRawInt(&vars[4]) <= slotRawInt(&vars[2])) || (slotRawInt(&vars[1]) < 0 && slotRawInt(&vars[4]) >= slotRawInt(&vars[2]))) { slotCopy(++sp, &vars[3]); // push function slotCopy(++sp, &vars[4]); // push i slotCopy(++sp, &vars[5]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } } else { if ((slotRawFloat(&vars[1]) >= 0. && slotRawFloat(&vars[4]) <= slotRawFloat(&vars[2])) || (slotRawFloat(&vars[1]) < 0. && slotRawFloat(&vars[4]) >= slotRawFloat(&vars[2]))) { slotCopy(++sp, &vars[3]); // push function slotCopy(++sp, &vars[4]); // push i slotCopy(++sp, &vars[5]); // push j // SendSpecialMsg value numArgsPushed = 3; selector = gSpecialSelectors[opmValue]; slot = sp - 2; goto class_lookup; } else { slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; } } dispatch_opcode; } case 31 : { -- sp ; // Drop PyrSlot * vars = g->frame->vars; int tag = GetTag(&vars[1]); if (tag == tagInt) { SetRaw(&vars[4], slotRawInt(&vars[4]) + slotRawInt(&vars[1])); // inc i } else { SetRaw(&vars[4], slotRawFloat(&vars[4]) + slotRawFloat(&vars[1])); // inc i } SetRaw(&vars[5], slotRawInt(&vars[5]) + 1); // inc j ip -= 4; dispatch_opcode; } } dispatch_opcode; } // opStoreClassVar case 144 : case 145 : case 146 : case 147 : case 148 : case 149 : case 150 : case 151 : case 152 : case 153 : case 154 : case 155 : case 156 : case 157 : case 158 : case 159 : handle_op_144: handle_op_145: handle_op_146: handle_op_147: handle_op_148: handle_op_149: handle_op_150: handle_op_151: handle_op_152: handle_op_153: handle_op_154: handle_op_155: handle_op_156: handle_op_157: handle_op_158: handle_op_159: { int op2 = op1 & 15; int op3 = ip[1]; ++ip; // get class var index slotCopy(&g->classvars->slots[(op2<<8)|op3], sp--); g->gc->GCWrite(g->classvars, (sp+1)); dispatch_opcode; } // opSendMsg case 160 : handle_op_160: { // special case for this as only arg int op2 = ip[1]; ++ip; // get selector index slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp; goto class_lookup; } case 161 : case 162 : case 163 : case 164 : case 165 : case 166 : case 167 : case 168 : case 169 : case 170 : case 171 : case 172 : case 173 : case 174 : case 175 : handle_op_161: handle_op_162: handle_op_163: handle_op_164: handle_op_165: handle_op_166: handle_op_167: handle_op_168: handle_op_169: handle_op_170: handle_op_171: handle_op_172: handle_op_173: handle_op_174: handle_op_175: { int op2 = ip[1]; ++ip; // get selector index numArgsPushed = op1 & 15; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; goto class_lookup; } case 176 : // opcTailCallReturnFromFunction handle_op_176: #if TAILCALLOPTIMIZE g->tailCall = 2; #endif dispatch_opcode; // opSuperMsg case 177 : handle_op_177: { // special case for this as only arg int op2 = ip[1]; ++ip; // get selector index slotCopy(++sp, &g->receiver); numArgsPushed = 1; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; goto msg_lookup; } case 178 : case 179 : case 180 : case 181 : case 182 : case 183 : case 184 : case 185 : case 186 : case 187 : case 188 : case 189 : case 190 : case 191 : handle_op_178: handle_op_179: handle_op_180: handle_op_181: handle_op_182: handle_op_183: handle_op_184: handle_op_185: handle_op_186: handle_op_187: handle_op_188: handle_op_189: handle_op_190: handle_op_191: { int op2 = ip[1]; ++ip; // get selector index numArgsPushed = op1 & 15; selector = slotRawSymbol(&slotRawObject(&g->block->selectors)->slots[op2]); slot = sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; goto msg_lookup; } // opSendSpecialMsg case 192 : handle_op_192: { slotCopy(++sp, &g->receiver); int op2 = ip[1]; ++ip; // get selector index numArgsPushed = 1; selector = gSpecialSelectors[op2]; slot = sp; goto class_lookup; } case 193 : case 194 : case 195 : case 196 : case 197 : case 198 : case 199 : case 200 : case 201 : case 202 : case 203 : case 204 : case 205 : case 206 : case 207 : handle_op_193: handle_op_194: handle_op_195: handle_op_196: handle_op_197: handle_op_198: handle_op_199: handle_op_200: handle_op_201: handle_op_202: handle_op_203: handle_op_204: handle_op_205: handle_op_206: handle_op_207: { int op2 = ip[1]; ++ip; // get selector index numArgsPushed = op1 & 15; selector = gSpecialSelectors[op2]; slot = sp - numArgsPushed + 1; goto class_lookup; } // opSendSpecialUnaryArithMsg case 208 : // opNeg handle_op_208: if (IsFloat(sp)) { SetFloat(sp, -slotRawFloat(sp)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else if (IsInt(sp)) { SetRaw(sp, -slotRawInt(sp)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 209 : // opNot handle_op_209: if (IsTrue(sp)) { SetTagRaw(sp, tagFalse); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else if (IsFalse(sp)) { SetTagRaw(sp, tagTrue); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 210 : // opIsNil handle_op_210: if (IsNil(sp)) { SetTagRaw(sp, tagTrue); } else { slotCopy(sp, &gSpecialValues[svFalse]); } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; case 211 : // opNotNil handle_op_211: if (NotNil(sp)) { slotCopy(sp, &gSpecialValues[svTrue]); } else { SetTagRaw(sp, tagFalse); } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; case 212 : handle_op_212: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 213 : handle_op_213: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 214 : handle_op_214: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 215 : handle_op_215: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 216 : handle_op_216: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 217 : handle_op_217: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 218 : handle_op_218: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 219 : handle_op_219: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 220 : handle_op_220: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 221 : handle_op_221: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 222 : handle_op_222: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 223 : handle_op_223: handleSendSpecialUnaryArithMsg(g, sp, ip, op1); dispatch_opcode; // opSendSpecialBinaryArithMsg case 224 : // add handle_op_224: if (IsInt(sp - 1)) { if (IsInt(sp)) { --sp; SetRaw(sp, slotRawInt(sp) + slotRawInt(sp + 1)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opAdd; prAddInt(g, -1); sp = g->sp; ip = g->ip; } } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opAdd; prAddNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 225 : // subtract handle_op_225: if (IsInt(sp - 1)) { if (IsInt(sp)) { --sp; SetRaw(sp, slotRawInt(sp) - slotRawInt(sp + 1)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opSub; prSubInt(g, -1); sp = g->sp; ip = g->ip; } } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opSub; prSubNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 226 : // multiply handle_op_226: if (IsInt(sp - 1)) { if (IsInt(sp)) { --sp; SetRaw(sp, slotRawInt(sp) * slotRawInt(sp + 1)); #if TAILCALLOPTIMIZE g->tailCall = 0; #endif } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opMul; prMulInt(g, -1); sp = g->sp; ip = g->ip; } } else { g->sp = sp; g->ip = ip; g->primitiveIndex = opMul; prMulNum(g, -1); sp = g->sp; ip = g->ip; } dispatch_opcode; case 227 : handle_op_227: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 228 : handle_op_228: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 229 : handle_op_229: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 230 : handle_op_230: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 231 : handle_op_231: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 232 : handle_op_232: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 233 : handle_op_233: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 234 : handle_op_234: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 235 : handle_op_235: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 236 : handle_op_236: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 237 : handle_op_237: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 238 : handle_op_238: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; case 239 : handle_op_239: handleSendSpecialBinaryArithMsg(g, sp, ip, op1); dispatch_opcode; // opSpecialOpcodes case 240 : handle_op_240: --sp; dispatch_opcode; // opDrop case 241 : handle_op_241: ++sp; *sp = sp[-1]; dispatch_opcode; // opDup case 242 : // opcFunctionReturn handle_op_242: g->sp = sp; g->ip = ip; returnFromBlock(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 243 : // opcReturn handle_op_243: g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 244 : // opcReturnSelf handle_op_244: slotCopy(++sp, &g->receiver); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 245 : // opcReturnTrue handle_op_245: slotCopy(++sp, &gSpecialValues[svTrue]); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 246 : // opcReturnFalse handle_op_246: slotCopy(++sp, &gSpecialValues[svFalse]); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 247 : // opcReturnNil handle_op_247: slotCopy(++sp, &gSpecialValues[svNil]); g->sp = sp; g->ip = ip; returnFromMethod(g); sp = g->sp; ip = g->ip; dispatch_opcode; case 248 : // opcJumpIfFalse handle_op_248: // cannot compare with o_false because it is NaN if ( IsFalse(sp) ) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; } else if ( IsTrue(sp)) { ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } --sp; dispatch_opcode; case 249 : // opcJumpIfFalsePushNil handle_op_249: if ( IsFalse(sp)) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; slotCopy(sp, &gSpecialValues[svNil]); } else if ( IsTrue(sp)) { --sp; ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } dispatch_opcode; case 250 : // opcJumpIfFalsePushFalse handle_op_250: if (IsFalse(sp)) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; //*sp = r_false; } else if (IsTrue(sp)) { --sp; ip+=2; } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } dispatch_opcode; case 251 : // opcJumpIfTruePushTrue handle_op_251: if (IsFalse(sp)) { --sp; ip+=2; } else if (IsTrue(sp)) { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; slotCopy(sp, &gSpecialValues[svTrue]); } else { numArgsPushed = 1; selector = gSpecialSelectors[opmNonBooleanError]; slot = sp; goto class_lookup; } dispatch_opcode; case 252 : // opcJumpFwd handle_op_252: { int jmplen = (ip[1]<<8) | ip[2]; ip += jmplen + 2; dispatch_opcode; } case 253 : // opcJumpBak handle_op_253: { --sp; // also drops the stack. This saves an opcode in the while loop // which is the only place this opcode is used. int jmplen = (ip[1]<<8) | ip[2]; ip -= jmplen; //assert(g->gc->SanityCheck()); dispatch_opcode; } case 254 : // opcSpecialBinaryOpWithAdverb handle_op_254: { int op2 = ip[1]; ++ip; // get selector index g->sp = sp; g->ip = ip; g->primitiveIndex = op2; doSpecialBinaryArithMsg(g, 3, false); sp = g->sp; ip = g->ip; dispatch_opcode; } case 255 : // opcTailCallReturnFromMethod handle_op_255: #if TAILCALLOPTIMIZE g->tailCall = 1; #endif dispatch_opcode; //////////////////////////////////// class_lookup: // normal class lookup classobj = classOfSlot(slot); // message sends handled here: msg_lookup: { size_t index = slotRawInt(&classobj->classIndex) + selector->u.index; PyrMethod *meth = NULL; if( UNLIKELY( ( selector->flags & sym_Class ) != 0 ) ) { // You have sent a message which is a class name. This is a bad thing. // There are two cases. It is either an illegitimate classname like // 1 FooBaz: 2 // in which case selector->u.index == 0 and you get a message or it is a real one like // 1 Object: 2 // in which case selector->u.index isn't pointing to a method and you get a segfault. So... meth = NULL; } else { meth = gRowTable[index]; } // and now if meth is null, bail out just like if I don't understand it if (UNLIKELY(meth == NULL || ( slotRawSymbol(&meth->name) != selector))) { g->sp = sp; g->ip = ip; doesNotUnderstand(g, selector, numArgsPushed); sp = g->sp; ip = g->ip; } else { PyrMethodRaw *methraw = METHRAW(meth); switch (methraw->methType) { case methNormal : /* normal msg send */ g->sp = sp; g->ip = ip; executeMethod(g, meth, numArgsPushed); sp = g->sp; ip = g->ip; break; case methReturnSelf : /* return self */ sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(slot)->slots[index]); break; case methAssignInstVar : { /* assign inst var */ sp -= numArgsPushed - 1; index = methraw->specialIndex; PyrObject * obj = slotRawObject(slot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { slotCopy(&obj->slots[index], &gSpecialValues[svNil]); } slotCopy(sp, slot); } break; } case methReturnClassVar : /* return class var */ sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else slotCopy(&g->classvars->slots[methraw->specialIndex], &gSpecialValues[svNil]); slotCopy(sp, slot); break; case methRedirect : /* send a different selector to self */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); goto msg_lookup; case methRedirectSuper : /* send a different selector to self */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto msg_lookup; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(slot, &slotRawObject(slot)->slots[index]); classobj = classOfSlot(slot); goto msg_lookup; case methForwardClassVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *qslot; int m, mmax; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; } selector = slotRawSymbol(&meth->selectors); slotCopy(slot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(slot); goto msg_lookup; case methPrimitive : /* primitive */ g->sp = sp; g->ip = ip; doPrimitive(g, meth, numArgsPushed); sp = g->sp; ip = g->ip; break; } // switch (meth->methType) } // end handle message #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; } //////////////////////////////////// key_class_lookup: // normal class lookup classobj = classOfSlot(slot); // message sends handled here: key_msg_lookup: { size_t index = slotRawInt(&classobj->classIndex) + selector->u.index; PyrMethod *meth = gRowTable[index]; if (UNLIKELY(slotRawSymbol(&meth->name) != selector)) { g->sp = sp; g->ip = ip; doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); sp = g->sp; ip = g->ip; } else { PyrMethodRaw *methraw; methraw = METHRAW(meth); switch (methraw->methType) { case methNormal : /* normal msg send */ g->sp = sp; g->ip = ip; executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); sp = g->sp; ip = g->ip; break; case methReturnSelf : /* return self */ sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(slot)->slots[index]); break; case methAssignInstVar : { /* assign inst var */ sp -= numArgsPushed - 1; numArgsPushed -= numKeyArgsPushed << 1; index = methraw->specialIndex; PyrObject * obj = slotRawObject(slot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else slotCopy(&obj->slots[index], &gSpecialValues[svNil]); slotCopy(sp, slot); } break; } case methReturnClassVar : /* return class var */ sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else slotCopy(&g->classvars->slots[methraw->specialIndex], &gSpecialValues[svNil]); slotCopy(sp, slot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); goto msg_lookup; case methRedirectSuper : /* send a different selector to super */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto msg_lookup; case methForwardInstVar : /* forward to an instance variable */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(slot, &slotRawObject(slot)->slots[index]); classobj = classOfSlot(slot); goto msg_lookup; case methForwardClassVar : /* forward to an instance variable */ g->sp = sp; numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; sp = g->sp; selector = slotRawSymbol(&meth->selectors); slotCopy(slot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(slot); goto msg_lookup; case methPrimitive : /* primitive */ g->sp = sp; g->ip = ip; doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); sp = g->sp; ip = g->ip; break; } // switch (meth->methType) } // end handle message numKeyArgsPushed = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif dispatch_opcode; } } // switch(op1) } // end while(running) #ifndef _WIN32 running = true; // reset the signal #endif g->sp = sp; g->ip = ip; } #if defined(__GNUC__) && !defined(__clang__) #pragma GCC pop_options #endif void DumpSimpleBackTrace(VMGlobals *g); void DumpSimpleBackTrace(VMGlobals *g) { int i; PyrFrame *frame; post("CALL STACK:\n"); // print the variables and arguments for the most recent frames in the // call graph frame = g->frame; for (i=0; i<16; ++i) { char str[256]; slotOneWord(&frame->method, str); post("%s ip %d\n", str, (char*)slotRawPtr(&frame->ip) - (char*)slotRawObject(&slotRawMethod(&frame->method)->code)->slots); frame = slotRawFrame(&frame->caller); if (!frame) break; } if (frame) { post("...\n"); } //DumpStack(g, g->sp); } void DumpBackTrace(VMGlobals *g) { int i; PyrFrame *frame; post("CALL STACK:\n"); // print the variables and arguments for the most recent frames in the // call graph frame = g->frame; for (i=0; i<16; ++i) { if (FrameSanity(frame, "DumpBackTrace")) { post("FRAME CORRUPTED\n"); return; } DumpFrame(frame); frame = slotRawFrame(&frame->caller); if (!frame) break; } if (frame) { post("...\n"); } //DumpStack(g, g->sp); } void DumpDetailedFrame(PyrFrame *frame); void DumpDetailedBackTrace(VMGlobals *g); void DumpDetailedBackTrace(VMGlobals *g) { int i; PyrFrame *frame; post("CALL STACK:\n"); // print the variables and arguments for the most recent frames in the // call graph frame = g->frame; for (i=0; i<16; ++i) { if (FrameSanity(frame, "DumpDetailedBackTrace")) { post("FRAME CORRUPTED\n"); return; } DumpDetailedFrame(frame); frame = slotRawFrame(&frame->caller); if (!frame) break; } if (frame) { post("...\n"); } //DumpStack(g, g->sp); } void DumpStack(VMGlobals *g, PyrSlot *sp) { PyrSlot *slot; char str[128]; #if BCSTAT dumpbcstat(); #endif postfl("STACK:\n"); slot = sp - 64; if (slot < g->gc->Stack()->slots) slot = g->gc->Stack()->slots; for (size_t i=slot - g->gc->Stack()->slots; slot<=sp; slot++, ++i) { slotString(slot, str); post(" %2d %s\n", i, str); } } SuperCollider-Source/lang/LangSource/PyrKernel.h000644 000765 000024 00000014150 12321461511 022721 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This file contains the definitions of the core objects that implement the class system. */ #ifndef _PYRKERNEL_H_ #define _PYRKERNEL_H_ #include "PyrObject.h" #include "VMGlobals.h" #define classClassNumInstVars 19 enum { classIsIntrinsic = 1, classHasIndexableInstances = 2 }; struct PyrClass : public PyrObjectHdr { PyrSlot name; PyrSlot nextclass; PyrSlot superclass; PyrSlot subclasses; PyrSlot methods; PyrSlot instVarNames; PyrSlot classVarNames; PyrSlot iprototype; // instance prototype PyrSlot cprototype; // class var prototype PyrSlot constNames; PyrSlot constValues; // const values PyrSlot instanceFormat; PyrSlot instanceFlags; PyrSlot classIndex; PyrSlot classFlags; PyrSlot maxSubclassIndex; // used by isKindOf PyrSlot filenameSym; PyrSlot charPos; PyrSlot classVarIndex; }; inline bool isKindOf(PyrObjectHdr *obj, struct PyrClass *testclass) { int objClassIndex = slotRawInt(&obj->classptr->classIndex); return objClassIndex >= slotRawInt(&testclass->classIndex) && objClassIndex <= slotRawInt(&testclass->maxSubclassIndex); } inline bool isKindOfSlot(PyrSlot *slot, struct PyrClass *testclass) { return IsObj(slot) && isKindOf(slotRawObject(slot), testclass); } /* operations on class: numInstVars() numClassVars() */ struct PyrFrame : public PyrObjectHdr { PyrSlot method; PyrSlot caller; PyrSlot context; PyrSlot homeContext; PyrSlot ip; PyrSlot vars[1]; }; #define FRAMESIZE 5 struct PyrProcess : public PyrObjectHdr { PyrSlot classVars; PyrSlot interpreter; PyrSlot curThread, mainThread; PyrSlot sysSchedulerQueue; PyrSlot nowExecutingPath; }; enum { tInit, tStart, tReady, tRunning, tSleeping, tSuspended, tDone }; struct PyrThread : public PyrObjectHdr { PyrSlot state, func, stack, method, block, frame, ip, sp; PyrSlot numpop, receiver, numArgsPushed; PyrSlot parent, terminalValue; PyrSlot primitiveError; PyrSlot primitiveIndex; PyrSlot randData; PyrSlot beats, seconds, clock, nextBeat, endBeat, endValue; PyrSlot environment; PyrSlot exceptionHandler; PyrSlot threadPlayer; PyrSlot executingPath; PyrSlot oldExecutingPath; PyrSlot stackSize; }; #define EVALSTACKDEPTH 512 struct PyrMethodRaw { #ifdef PYR_SLOTS_GENERIC long padding; // used for the tag in the generic pyrslot implementation #endif unsigned short unused1; unsigned short specialIndex; unsigned short methType; unsigned short frameSize; #ifdef PYR_SLOTS_GENERIC long padding2; // used for the tag in generic pyrslot implementation, second slot #endif unsigned char unused2; unsigned char numargs; unsigned char varargs; unsigned char numvars; unsigned char numtemps; unsigned char needsHeapContext; unsigned char popSize; unsigned char posargs; }; #define METHRAW(obj) ((PyrMethodRaw*)&(((PyrBlock*)obj)->rawData1)) struct PyrBlock : public PyrObjectHdr { PyrSlot rawData1; PyrSlot rawData2; PyrSlot code; // byte codes, nil if inlined PyrSlot selectors; // method selectors, class names, closures table PyrSlot constants; // floating point constants table (to alleviate the literal table problem) PyrSlot prototypeFrame; // prototype of an activation frame PyrSlot contextDef; // ***defining block context PyrSlot argNames; // ***arguments to block PyrSlot varNames; // ***variables in block PyrSlot sourceCode; // source code if it is a closed function. }; struct PyrMethod : public PyrBlock { PyrSlot ownerclass; PyrSlot name; PyrSlot primitiveName; PyrSlot filenameSym; PyrSlot charPos; //PyrSlot byteMeter; //PyrSlot callMeter; }; enum { methNormal = 0, methReturnSelf, methReturnLiteral, methReturnArg, methReturnInstVar, methAssignInstVar, methReturnClassVar, methAssignClassVar, methRedirect, methRedirectSuper, methForwardInstVar, methForwardClassVar, methPrimitive, methBlock }; struct PyrClosure : public PyrObjectHdr { PyrSlot block; PyrSlot context; }; struct PyrInterpreter : public PyrObjectHdr { PyrSlot cmdLine, context; PyrSlot a, b, c, d, e, f, g, h, i, j; PyrSlot k, l, m, n, o, p, q, r, s, t; PyrSlot u, v, w, x, y, z; PyrSlot codeDump, preProcessor; }; /* special values */ enum { svNil, svFalse, svTrue, svNegOne, svZero, svOne, svTwo, svFHalf, svFNegOne, svFZero, svFOne, svFTwo, svInf, svNumSpecialValues }; extern PyrSlot gSpecialValues[svNumSpecialValues]; extern PyrMethod *gNullMethod; // used to fill row table PyrObject* instantiateObject(class PyrGC *gc, PyrClass* classobj, int size, bool fill, bool collect); PyrObject* newPyrObject(class PyrGC *gc, size_t inNumBytes, int inFlags, int inFormat, bool inCollect); PyrString* newPyrString(class PyrGC *gc, const char *s, int flags, bool collect); PyrString* newPyrStringN(class PyrGC *gc, int size, int flags, bool collect); PyrObject* newPyrArray(class PyrGC *gc, int size, int flags, bool collect); PyrSymbolArray* newPyrSymbolArray(class PyrGC *gc, int size, int flags, bool collect); PyrInt8Array* newPyrInt8Array(class PyrGC *gc, int size, int flags, bool collect); PyrInt32Array* newPyrInt32Array(class PyrGC *gc, int size, int flags, bool collect); PyrDoubleArray* newPyrDoubleArray(class PyrGC *gc, int size, int flags, bool collect); PyrObject* copyObject(class PyrGC *gc, PyrObject *inobj, bool collect); PyrObject* copyObjectRange(class PyrGC *gc, PyrObject *inobj, int start, int end, bool collect); #endif SuperCollider-Source/lang/LangSource/PyrKernelProto.h000644 000765 000024 00000004423 12321461511 023747 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRKERNELPROTO_H_ #define _PYRKERNELPROTO_H_ PyrClass* newClassObj(PyrClass *classObjSuperClass, PyrSymbol* className, PyrSymbol* superClassName, int numInstVars, int numClassVars, int numConsts, int numInstMethods, int instFormat, int instFlags); void reallocClassObj(PyrClass* classobj, int numInstVars, int numClassVars, int numConsts, int numMethods, int instFormat, int instFlags); int numInstVars(PyrClass* classobj); int numClassVars(PyrClass* classobj); int numSuperInstVars(PyrClass *superclassobj); bool classFindInstVar(PyrClass* classobj, PyrSymbol *name, int *index); bool classFindClassVar(PyrClass** classobj, PyrSymbol *name, int *index); bool classFindConst(PyrClass** classobj, PyrSymbol *name, int *index); void buildClassTree(); void indexClassTree(PyrClass *classobj, int numSuperMethods); void postClassTree(PyrClass *classobj, int level); void setSelectorFlags(); void buildBigMethodMatrix(); bool funcFindArg(PyrBlock* func, PyrSymbol *name, int *index); bool funcFindVar(PyrBlock* func, PyrSymbol *name, int *index); void addMethod(PyrClass *classobj, PyrMethod *method); PyrMethod* classFindDirectMethod(PyrClass* classobj, PyrSymbol *name); PyrBlock* newPyrBlock(int flags); PyrMethod* newPyrMethod(); PyrClass* makeIntrinsicClass(PyrSymbol *className, PyrSymbol *superClassName, int numInstVars, int numClassVars); void addIntrinsicVar(PyrClass *classobj, const char *varName, PyrSlot *slot); #endif SuperCollider-Source/lang/LangSource/PyrLexer.cpp000644 000765 000024 00000140225 12756531745 023141 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 # include #else # include #endif #include #include "PyrParseNode.h" #include "Bison/lang11d_tab.h" #include "SCBase.h" #include "PyrObject.h" #include "PyrObjectProto.h" #include "PyrLexer.h" #include "PyrSched.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "GC.h" #include "SimpleStack.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "InitAlloc.h" #include "PredefinedSymbols.h" #ifdef _WIN32 #else # include "dirent.h" #endif #include #include "SC_LanguageConfig.hpp" #include "SC_DirUtils.h" #include "SC_TextUtils.hpp" int yyparse(); int processaccidental1(char *s); int processaccidental2(char *s); extern bool gFullyFunctional; double compileStartTime; int gNumCompiledFiles; /* thisProcess.interpreter.executeFile("Macintosh HD:score").size.postln; */ PyrSymbol *gCompilingFileSym = 0; VMGlobals *gCompilingVMGlobals = 0; static char gCompileDir[MAXPATHLEN]; //#define DEBUGLEX 1 bool gDebugLexer = false; bool gShowWarnings = false; LongStack brackets; LongStack closedFuncCharNo; LongStack generatorStack; int lastClosedFuncCharNo = 0; const char *binopchars = "!@%&*-+=|<>?/"; char yytext[MAXYYLEN]; char curfilename[PATH_MAX]; int yylen; int lexCmdLine = 0; bool compilingCmdLine = false; bool compilingCmdLineErrorWindow = false; intptr_t zzval; int lineno, charno, linepos; int *linestarts; int maxlinestarts; char *text; int textlen; int textpos; int errLineOffset, errCharPosOffset; int parseFailed = 0; bool compiledOK = false; std::set compiledDirectories; /* so the text editor's dumb paren matching will work */ #define OPENPAREN '(' #define OPENCURLY '{' #define OPENSQUAR '[' #define CLOSSQUAR ']' #define CLOSCURLY '}' #define CLOSPAREN ')' int sc_strtoi(const char *str, int n, int base) { int z = 0; for (int i=0; i= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0'; else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10; else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10; } return z; } double sc_strtof(const char *str, int n, int base) { double z = 0.; int decptpos = 0; for (int i=0; i= '0' && c <= '0' + sc_min(10,base) - 1) z = z * base + c - '0'; else if (c >= 'a' && c <= 'a' + sc_min(36,base) - 11) z = z * base + c - 'a' + 10; else if (c >= 'A' && c <= 'A' + sc_min(36,base) - 11) z = z * base + c - 'A' + 10; else if (c == '.') decptpos = i; } //calculation previously included decimal point in count of columns (was n-decptpos); there are 1 less than n characters which are columns in the number contribution z = z / pow((double)base, n -1- decptpos); return z; } static void sc_InitCompileDirectory(void) { // main class library folder: only used for relative path resolution sc_GetResourceDirectory(gCompileDir, MAXPATHLEN-32); sc_AppendToPath(gCompileDir, MAXPATHLEN, "SCClassLibrary"); } extern void asRelativePath(char *inPath, char *outPath) { uint32 len = strlen(gCompileDir); if (strlen(inPath) < len || memcmp(inPath, gCompileDir, len) != 0) { // gCompileDir is not the prefix. strcpy(outPath, inPath); return; } strcpy(outPath, inPath + len); } static bool getFileText(char* filename, char **text, int *length) { FILE *file; char *ltext; int llength; #ifdef _WIN32 file = fopen(filename, "rb"); #else file = fopen(filename, "r"); #endif if (!file) return false; fseek(file, 0L, SEEK_END); llength = ftell(file); fseek(file, 0L, SEEK_SET); ltext = (char*)pyr_pool_compile->Alloc((llength+1) * sizeof(char)); #ifdef _WIN32 // win32 isprint( ) doesn't like the 0xcd after the end of file when // there is a mismatch in lengths due to line endings.... memset(ltext,0,(llength+1) * sizeof(char)); #endif //_WIN32 MEMFAIL(ltext); size_t size = fread(ltext, 1, llength, file); if (size != llength) { error("error when reading file"); fclose(file); return false; } ltext[llength] = 0; //ltext[llength] = 0; *length = llength; fclose(file); *text = ltext; return true; } int bugctr = 0; bool startLexer(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset) { char *filename = fileSym->name; textlen = -1; if(!fileSym->u.source) { if (!getFileText(filename, &text, &textlen)) return false; fileSym->u.source = text; rtf2txt(text); } else text = fileSym->u.source; if((startPos >= 0) && (endPos > 0)) { textlen = endPos - startPos; text += startPos; } else if(textlen == -1) textlen = strlen(text); if(lineOffset > 0) errLineOffset = lineOffset; else errLineOffset = 0; if(startPos > 0) errCharPosOffset = startPos; else errCharPosOffset = 0; initLongStack(&brackets); initLongStack(&closedFuncCharNo); initLongStack(&generatorStack); lastClosedFuncCharNo = 0; textpos = 0; linepos = 0; lineno = 1; charno = 0; yylen = 0; zzval = 0; parseFailed = 0; lexCmdLine = 0; strcpy(curfilename, filename); maxlinestarts = 1000; linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*)); linestarts[0] = 0; linestarts[1] = 0; return true; } void startLexerCmdLine(char *textbuf, int textbuflen) { // pyrmalloc: // lifetime: kill after compile. (this one gets killed anyway) text = (char*)pyr_pool_compile->Alloc((textbuflen+2) * sizeof(char)); MEMFAIL(text); memcpy(text, textbuf, textbuflen); text[textbuflen] = ' '; text[textbuflen+1] = 0; textlen = textbuflen + 1; rtf2txt(text); initLongStack(&brackets); initLongStack(&closedFuncCharNo); initLongStack(&generatorStack); lastClosedFuncCharNo = 0; textpos = 0; linepos = 0; lineno = 1; charno = 0; yylen = 0; zzval = 0; parseFailed = 0; lexCmdLine = 1; strcpy(curfilename, "selected text"); maxlinestarts = 1000; linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*)); linestarts[0] = 0; linestarts[1] = 0; errLineOffset = 0; errCharPosOffset = 0; } void finiLexer() { pyr_pool_compile->Free(linestarts); freeLongStack(&brackets); freeLongStack(&closedFuncCharNo); freeLongStack(&generatorStack); } void initLexer() { //strcpy(binopchars, "!@%&*-+=|:<>?/"); } int input() { int c; if (textpos >= textlen) { c = 0; } else { c = text[textpos++]; charno++; } if (c == '\n' || c == '\r') { lineno++; linepos = textpos; if (linestarts) { if (lineno >= maxlinestarts) { maxlinestarts += maxlinestarts; linestarts = (int*)pyr_pool_compile->Realloc( linestarts, maxlinestarts * sizeof(int*)); } linestarts[lineno] = linepos; } charno = 0; } if (c != 0 && yylen < MAXYYLEN-2) yytext[yylen++] = c; //if (gDebugLexer) postfl("input '%c' %d\n",c,c); return c; } int input0() { int c; if (textpos >= textlen) { c = 0; textpos++; // so unput will work properly } else { c = text[textpos++]; charno++; } if (c == '\n' || c == '\r') { lineno++; linepos = textpos; if (linestarts) { if (lineno >= maxlinestarts) { maxlinestarts += maxlinestarts; linestarts = (int*)pyr_pool_compile->Realloc( linestarts, maxlinestarts * sizeof(int*)); } linestarts[lineno] = linepos; } charno = 0; } //if (gDebugLexer) postfl("input0 '%c' %d\n",c,c); return c; } void unput(int c) { if (textpos>0) textpos--; if (c) { if (yylen) --yylen; if (charno) --charno; if (c == '\n' || c == '\r') { --lineno; } } } void unput0(int c) { if (textpos>0) textpos--; if (charno) --charno; if (c == '\n' || c == '\r') { --lineno; } } int yylex() { int r, c, c2; intptr_t d; int radix; char extPath[MAXPATHLEN]; // for error reporting yylen = 0; // finite state machine to parse input stream into tokens if (lexCmdLine == 1) { lexCmdLine = 2; r = INTERPRET; goto leave; } start: c = input(); if (c == 0) { r = 0; goto leave; } else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') { yylen = 0; goto start; } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto ident; else if (c == '/') { c = input(); if (c == '/') goto comment1; else if (c == '*') goto comment2; else { unput(c); goto binop; } } else if (c >= '0' && c <= '9') goto digits_1; else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) { pushls(&brackets, (intptr_t)c); if (c == OPENCURLY) { pushls(&closedFuncCharNo, (intptr_t)(linestarts[lineno] + charno - 1)); } r = c; goto leave; } else if (c == CLOSSQUAR) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != (intptr_t) OPENSQUAR) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error2; } } else { fatal(); post("unmatched '%c'\n",c); goto error2; } r = c; goto leave; } else if (c == CLOSPAREN) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENPAREN) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error2; } } else { fatal(); post("unmatched '%c'\n",c); goto error2; } r = c; goto leave; } else if (c == CLOSCURLY) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENCURLY) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error2; } lastClosedFuncCharNo = popls(&closedFuncCharNo); } else { fatal(); post("unmatched '%c'\n",c); goto error2; } r = c; goto leave; } else if (c == '^') { r = c; goto leave; } else if (c == '~') { r = c; goto leave; } else if (c == ';') { r = c; goto leave; } else if (c == ':') { r = c; goto leave; } else if (c == '`') { r = c; goto leave; } else if (c == '\\') goto symbol1; else if (c == '\'') goto symbol3; else if (c == '"') goto string1; else if (c == '.') { if ((c = input()) == '.') { if ((c = input()) == '.') { r = ELLIPSIS; goto leave; } else { r = DOTDOT; unput(c); goto leave; } } else { unput(c); r = '.'; goto leave; } } else if (c == '#') { if ((c = input()) == OPENCURLY) { pushls(&brackets, (intptr_t)OPENCURLY); pushls(&closedFuncCharNo, (intptr_t)(linestarts[lineno] + charno - 2)); r = BEGINCLOSEDFUNC; } else { unput(c); r = '#'; } goto leave; } else if (c == '$') { c = input(); if (c == '\\') { c = input(); switch (c) { case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; case 't' : c = '\t'; break; case 'f' : c = '\f'; break; case 'v' : c = '\v'; break; } } r = processchar(c); goto leave; } else if (c == ',') { r = c; goto leave; } else if (c == '=') { c = input(); if (strchr(binopchars, c)) goto binop; else { unput(c); r = '='; goto leave; } } else if (strchr(binopchars, c)) goto binop; else if(!(isprint(c) || isspace(c) || c == 0)) { yylen = 0; goto start; } else goto error1; ident: c = input(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) goto ident; else if (c == ':') { yytext[yylen] = 0; r = processkeywordbinop(yytext) ; goto leave; } else { unput(c); yytext[yylen] = 0; r = processident(yytext) ; goto leave; } symbol1: c = input(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') goto symbol2; else if (c >= '0' && c <= '9') goto symbol4; else { unput(c); yytext[yylen] = 0; r = processsymbol(yytext) ; goto leave; } symbol2: c = input(); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9')) goto symbol2; else { unput(c); yytext[yylen] = 0; r = processsymbol(yytext) ; goto leave; } symbol4: c = input(); if (c >= '0' && c <= '9') goto symbol4; else { unput(c); yytext[yylen] = 0; r = processsymbol(yytext) ; goto leave; } binop: c = input(); if (c == 0) goto binop2; if (strchr(binopchars, c)) goto binop; else { binop2: unput(c); yytext[yylen] = 0; r = processbinop(yytext) ; goto leave; } radix_digits_1: c = input(); if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_1; if (c >= 'a' && c <= 'a' + sc_min(36,radix) - 11) goto radix_digits_1; if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_1; if (c == '.') { goto radix_digits_2; } unput(c); yytext[yylen] = 0; r = processintradix(yytext, yylen, radix); goto leave; radix_digits_2: c = input(); if (c >= '0' && c <= '0' + sc_min(10,radix) - 1) goto radix_digits_2; if (c >= 'A' && c <= 'A' + sc_min(36,radix) - 11) goto radix_digits_2; // do not allow lower case after decimal point. unput(c); yytext[yylen] = 0; r = processfloatradix(yytext, yylen, radix); goto leave; hexdigits: c = input(); if (c >= '0' && c <= '9') goto hexdigits; if (c >= 'a' && c <= 'f') goto hexdigits; if (c >= 'A' && c <= 'F') goto hexdigits; unput(c); yytext[yylen] = 0; r = processhex(yytext); goto leave; digits_1: /* number started with digits */ c = input(); if (c >= '0' && c <= '9') goto digits_1; else if (c == 'r') { radix = sc_strtoi(yytext, yylen-1, 10); yylen = 0; goto radix_digits_1; } else if (c == 'e' || c == 'E') goto expon_1; else if (c == '.') { c2 = input(); if (c2 >= '0' && c2 <= '9') goto digits_2; else { unput(c2); unput(c); yytext[yylen] = 0; r = processint(yytext); goto leave; } } else if (c == 'b' || c == 's') { d = input(); if (d >= '0' && d <= '9') goto accidental1; if (d == c) goto accidental2; goto accidental3; accidental1: d = input(); if (d >= '0' && d <= '9') goto accidental1; unput(d); yytext[yylen] = 0; r = processaccidental1(yytext); goto leave; accidental2: d = input(); if (d == c) goto accidental2; accidental3: unput(d); yytext[yylen] = 0; r = processaccidental2(yytext); goto leave; } else if (c == 'x') { yylen = 0; goto hexdigits; } else { unput(c); yytext[yylen] = 0; r = processint(yytext); goto leave; } digits_2: c = input(); if (c >= '0' && c <= '9') goto digits_2; else if (c == 'e' || c == 'E') goto expon_1; // else if (c == 'π' || c == '∏') { // --yylen; // yytext[yylen] = 0; // r = processfloat(yytext, 1); // goto leave; // } else { unput(c); yytext[yylen] = 0; r = processfloat(yytext, 0); goto leave; } expon_1: /* e has been seen, need digits */ c = input(); if (c >= '0' && c <= '9') goto expon_3; else if (c == '+' || c == '-') goto expon_2; else goto error1; expon_2: /* + or - seen but still need digits */ c = input(); if (c >= '0' && c <= '9') goto expon_3; else goto error1; expon_3: c = input(); if (c >= '0' && c <= '9') goto expon_3; // else if (c == 'π' || c == '∏') { // --yylen; // yytext[yylen] = 0; // r = processfloat(yytext, 1); // goto leave; // } else { unput(c); yytext[yylen] = 0; r = processfloat(yytext, 0); goto leave; } symbol3 : { int startline, endchar; startline = lineno; endchar = '\''; /*do { c = input(); } while (c != endchar && c != 0);*/ for (;yylen0) postfl("yylex: %d '%s'\n",r,yytext); return r; } int processbinop(char *token) { PyrSymbol *sym; PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processbinop: '%s'\n",token); #endif sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; if (strcmp(token, "<-")==0) return LEFTARROW; if (strcmp(token, "<>")==0) return READWRITEVAR; if (strcmp(token, "|")==0) return '|'; if (strcmp(token, "<")==0) return '<'; if (strcmp(token, ">")==0) return '>'; if (strcmp(token, "-")==0) return '-'; if (strcmp(token, "*")==0) return '*'; if (strcmp(token, "+")==0) return '+'; return BINOP; } int processkeywordbinop(char *token) { PyrSymbol *sym; PyrSlot slot; PyrSlotNode *node; //post("'%s' file '%s'\n", token, curfilename); #if DEBUGLEX if (gDebugLexer) postfl("processkeywordbinop: '%s'\n",token); #endif token[strlen(token)-1] = 0; // strip off colon sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return KEYBINOP; } int processident(char *token) { char c; PyrSymbol *sym; PyrSlot slot; PyrParseNode *node; c = token[0]; zzval = (intptr_t) -1; #if DEBUGLEX if (gDebugLexer) postfl("word: '%s'\n",token); #endif /* strcpy(uptoken, token); for (str = uptoken; *str; ++str) { if (*str >= 'a' && *str <= 'z') *str += 'A' - 'a'; }*/ if (token[0] == '_') { if (token[1] == 0) { node = newPyrCurryArgNode(); zzval = (intptr_t)node; return CURRYARG; } else { sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return PRIMITIVENAME; } } if (token[0] >= 'A' && token[0] <= 'Z') { sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; #if DEBUGLEX if (gDebugLexer) postfl("CLASSNAME: '%s'\n",token); #endif return CLASSNAME; } if (strcmp("var",token) ==0) return VAR; if (strcmp("arg",token) ==0) return ARG; if (strcmp("classvar",token) ==0) return CLASSVAR; if (strcmp("const",token) ==0) return SC_CONST; if (strcmp("while",token) ==0) { sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return WHILE; } if (strcmp("pi",token) ==0) { SetFloat(&slot, pi); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return PIE; } if (strcmp("true",token) ==0) { SetTrue(&slot); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return TRUEOBJ; } if (strcmp("false",token) ==0) { SetFalse(&slot); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return FALSEOBJ; } if (strcmp("nil",token) ==0) { SetNil(&slot); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return NILOBJ; } if (strcmp("inf",token) ==0) { SetFloat(&slot, std::numeric_limits::infinity()); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return SC_FLOAT; } sym = getsym(token); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return NAME; } int processhex(char *s) { PyrSlot slot; PyrSlotNode *node; char *c; int val; #if DEBUGLEX if (gDebugLexer) postfl("processhex: '%s'\n",s); #endif c = s; val = 0; while (*c) { if (*c >= '0' && *c <= '9') val = val*16 + *c - '0'; else if (*c >= 'a' && *c <= 'z') val = val*16 + *c - 'a' + 10; else if (*c >= 'A' && *c <= 'Z') val = val*16 + *c - 'A' + 10; c++; } SetInt(&slot, val); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return INTEGER; } int processintradix(char *s, int n, int radix) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processintradix: '%s'\n",s); #endif SetInt(&slot, sc_strtoi(s, n, radix)); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return INTEGER; } int processfloatradix(char *s, int n, int radix) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processfloatradix: '%s'\n",s); #endif SetFloat(&slot, sc_strtof(s, n, radix)); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return SC_FLOAT; } int processint(char *s) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processint: '%s'\n",s); #endif SetInt(&slot, atoi(s)); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return INTEGER; } int processchar(int c) { PyrSlot slot; PyrSlotNode *node; #if DEBUGLEX if (gDebugLexer) postfl("processhex: '%c'\n",c); #endif SetChar(&slot, c); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return ASCII; } int processfloat(char *s, int sawpi) { PyrSlot slot; PyrSlotNode *node; double z; #if DEBUGLEX if (gDebugLexer) postfl("processfloat: '%s'\n",s); #endif if (sawpi) { z = atof(s)*pi; SetFloat(&slot, z); } else { SetFloat(&slot, atof(s)); } node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return SC_FLOAT; } int processaccidental1(char *s) { PyrSlot slot; PyrSlotNode *node; char *c; double degree=0.; double cents=0.; double centsdiv=1000.; #if 0 printf("processaccidental1: '%s'\n",s); #endif c = s; while (*c) { if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0'; else break; c++; } if (*c == 'b') centsdiv = -1000.; else if (*c == 's') centsdiv = 1000.; c++; while (*c) { if (*c >= '0' && *c <= '9') { cents = cents*10. + *c - '0'; } else break; c++; } if (cents > 499.) cents = 499.; SetFloat(&slot, degree + cents/centsdiv); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return ACCIDENTAL; } int processaccidental2(char *s) { PyrSlot slot; PyrSlotNode *node; char *c; double degree=0.; double semitones=0.; #if 0 printf("processaccidental2: '%s'\n",s); #endif c = s; while (*c) { if (*c >= '0' && *c <= '9') degree = degree*10. + *c - '0'; else break; c++; } while (*c) { if (*c == 'b') semitones -= 1.; else if (*c == 's') semitones += 1.; c++; } if (semitones > 4.) semitones = 4.; else if (semitones < -4.) semitones = -4.; SetFloat(&slot, degree + semitones/10.); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return ACCIDENTAL; } int processsymbol(char *s) { PyrSlot slot; PyrSlotNode *node; PyrSymbol *sym; #if DEBUGLEX if (gDebugLexer) postfl("processsymbol: '%s'\n",s); #endif sym = getsym(s+1); SetSymbol(&slot, sym); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return SYMBOL; } int processstring(char *s) { PyrSlot slot; PyrSlotNode *node; PyrString *string; #if DEBUGLEX if (gDebugLexer) postfl("processstring: '%s'\n",s); #endif int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; string = newPyrString(gMainVMGlobals->gc, s+1, flags, false); SetObject(&slot, string); node = newPyrSlotNode(&slot); zzval = (intptr_t)node; return STRING; } void yyerror(const char *s) { parseFailed = 1; yytext[yylen] = 0; error("%s\n",s); postErrorLine(lineno, linepos, charno); //Debugger(); } void fatal() { parseFailed = 1; yytext[yylen] = 0; error("Parse error\n"); postErrorLine(lineno, linepos, charno); //Debugger(); } #if 0 void postErrorLine() { int i, j, start, end; char str[256]; parseFailed = true; for (i=textpos-1; i>=0; --i) { if (text[i] == '\r' || text[i] == '\n') break; } start = i+1; for (i=textpos; i < textlen; ++i) { if (text[i] == '\r' || text[i] == '\n') break; } end=i; for (i=start, j=0; i s2[i]) return 1; } if (len1 < len2) return -1; if (len1 > len2) return 1; return 0; } bool scanForClosingBracket() { int r, c, startLevel; intptr_t d; bool res = true; // finite state machine to parse input stream into tokens #if DEBUGLEX if (gDebugLexer) postfl("->scanForClosingBracket\n"); #endif startLevel = brackets.num; start: c = input0(); if (c == 0) goto leave; else if (c==' ' || c=='\t' || c=='\n' || c=='\r' || c=='\v' || c=='\f') { goto start; } else if (c == '\'') goto symbol3; else if (c == '"') goto string1; else if (c == '/') { c = input0(); if (c == '/') goto comment1; else if (c == '*') goto comment2; else { unput(c); goto start; } } else if (c == '$') { c = input0(); if (c == '\\') { c = input0(); switch (c) { case 'n' : c = '\n'; break; case 'r' : c = '\r'; break; case 't' : c = '\t'; break; case 'f' : c = '\f'; break; case 'v' : c = '\v'; break; } } goto start; } else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) { pushls(&brackets, (intptr_t)c); r = c; goto start; } else if (c == CLOSSQUAR) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENSQUAR) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error1; } } else { fatal(); post("unmatched '%c'\n",c); goto error1; } r = c; if (brackets.num < startLevel) goto leave; else goto start; } else if (c == CLOSPAREN) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != (intptr_t) OPENPAREN) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error1; } } else { fatal(); post("unmatched '%c'\n",c); goto error1; } if (brackets.num < startLevel) goto leave; else goto start; } else if (c == CLOSCURLY) { if (!emptyls(&brackets)) { if ((d = popls(&brackets)) != OPENCURLY) { fatal(); post("opening bracket was a '%c', but found a '%c'\n",d,c); goto error1; } } else { fatal(); post("unmatched '%c'\n",c); goto error1; } if (brackets.num < startLevel) goto leave; else goto start; } else { goto start; } symbol3 : { int startline, endchar; startline = lineno; endchar = '\''; do { c = input0(); if (c == '\\') { c = input0(); } } while (c != endchar && c != 0); if (c == 0) { char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post("Open ended symbol ... started on line %d in file '%s'\n", startline, extPath); goto error2; } goto start; } string1 : { int startline, endchar; startline = lineno; endchar = '\"'; do { c = input0(); if (c == '\\') { c = input0(); } } while (c != endchar && c != 0); if (c == 0) { char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post("Open ended string ... started on line %d in file '%s'\n", startline, extPath); goto error2; } goto start; } comment1: /* comment -- to end of line */ do { c = input0(); } while (c != '\n' && c != '\r' && c != 0); if (c == 0) { goto leave; } else goto start; comment2 : { int startline, clevel, prevc; startline = lineno; prevc = 0; clevel = 1; do { c = input0(); if (c == '/' && prevc == '*') { if (--clevel <= 0) break; } else if (c == '*' && prevc == '/') clevel++; prevc = c; } while (c != 0); if (c == 0) { char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post("Open ended comment ... started on line %d in file '%s'\n", startline, extPath); goto error2; } goto start; } error1: char extPath[MAXPATHLEN]; asRelativePath(curfilename, extPath); post(" in file '%s' line %d char %d\n", extPath, lineno, charno); res = false; goto leave; error2: res = false; goto leave; leave: #if DEBUGLEX if (gDebugLexer) postfl("<-scanForClosingBracket\n"); #endif return res; } int numClassDeps; static ClassExtFile* sClassExtFiles; static ClassExtFile* eClassExtFiles; ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos); ClassExtFile* newClassExtFile(PyrSymbol *fileSym, int startPos, int endPos) { ClassExtFile* classext; classext = (ClassExtFile*)pyr_pool_compile->Alloc(sizeof(ClassExtFile)); classext->fileSym = fileSym; classext->next = 0; classext->startPos = startPos; classext->endPos = endPos; if (!sClassExtFiles) sClassExtFiles = classext; else eClassExtFiles->next = classext; eClassExtFiles = classext; return classext; } ClassDependancy* newClassDependancy(PyrSymbol *className, PyrSymbol *superClassName, PyrSymbol *fileSym, int startPos, int endPos, int lineOffset) { ClassDependancy* classdep; //post("classdep '%s' '%s' '%s' %d %d\n", className->name, superClassName->name, // fileSym->name, className, superClassName); // pyrmalloc: // lifetime: kill after compile. numClassDeps++; if (className->classdep) { error("duplicate Class found: '%s' \n", className->name); post("%s\n",className->classdep->fileSym->name); postfl("%s\n\n",fileSym->name); return className->classdep; } classdep = (ClassDependancy*)pyr_pool_compile->Alloc(sizeof(ClassDependancy)); MEMFAIL(text); classdep->className = className; classdep->superClassName = superClassName; classdep->fileSym = fileSym; classdep->superClassDep = NULL; classdep->next = NULL; classdep->subclasses = NULL; classdep->startPos = startPos; classdep->endPos = endPos; classdep->lineOffset = lineOffset; className->classdep = classdep; return classdep; } void buildDepTree() { ClassDependancy *next; SymbolTable* symbolTable = gMainVMGlobals->symbolTable; //postfl("->buildDepTree\n"); fflush(stdout); for (int i=0; iTableSize(); ++i) { PyrSymbol *sym = symbolTable->Get(i); if (sym && (sym->flags & sym_Class)) { if (sym->classdep) { if (sym->classdep->superClassName->classdep) { next = sym->classdep->superClassName->classdep->subclasses; sym->classdep->superClassName->classdep->subclasses = sym->classdep; sym->classdep->next = next; } else if (sym->classdep->superClassName != s_none) { error("Superclass '%s' of class '%s' is not defined in any file.\n%s\n", sym->classdep->superClassName->name, sym->classdep->className->name,sym->classdep->fileSym->name); } } } } //postfl("<-buildDepTree\n"); fflush(stdout); } extern PyrClass *gClassList; ClassDependancy **gClassCompileOrder; int gClassCompileOrderNum = 0; int gClassCompileOrderSize = 1000; void compileDepTree(); void traverseFullDepTree() { //postfl("->traverseFullDepTree\n"); fflush(stdout); gClassCompileOrderNum = 0; gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Alloc( gClassCompileOrderSize * sizeof(ClassDependancy)); MEMFAIL(gClassCompileOrder); // parse and compile all files initParser(); // sets compiler errors to 0 gParserResult = -1; traverseDepTree(s_object->classdep, 0); compileDepTree(); // compiles backwards using the order defined in gClassCompileOrder compileClassExtensions(); pyr_pool_compile->Free(gClassCompileOrder); finiParser(); //postfl("<-traverseFullDepTree\n"); fflush(stdout); } void traverseDepTree(ClassDependancy *classdep, int level) { ClassDependancy *subclassdep; if (!classdep) return; subclassdep = classdep->subclasses; for (; subclassdep; subclassdep = subclassdep->next) { traverseDepTree(subclassdep, level+1); } if (gClassCompileOrderNum > gClassCompileOrderSize) { gClassCompileOrderSize *= 2; gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Realloc(gClassCompileOrder, gClassCompileOrderSize * sizeof(ClassDependancy)); MEMFAIL(gClassCompileOrder); } /* postfl("traverse level:%d, gClassCompileOrderNum:%d, '%s' '%s' '%s'\n", level, gClassCompileOrderNum, classdep->className->name, classdep->superClassName->name, classdep->fileSym->name); fflush(stdout); */ gClassCompileOrder[gClassCompileOrderNum++] = classdep; } void compileClass(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset) { //fprintf(stderr, "compileClass: %d\n", fileSym->u.index); gCompilingFileSym = fileSym; gCompilingVMGlobals = 0; gRootParseNode = NULL; initParserPool(); if (startLexer(fileSym, startPos, endPos, lineOffset)) { //postfl("->Parsing %s\n", fileSym->name); fflush(stdout); parseFailed = yyparse(); //postfl("<-Parsing %s %d\n", fileSym->name, parseFailed); fflush(stdout); //post("parseFailed %d\n", parseFailed); fflush(stdout); if (!parseFailed && gRootParseNode) { //postfl("Compiling nodes %p\n", gRootParseNode);fflush(stdout); compilingCmdLine = false; compileNodeList(gRootParseNode, true); //postfl("done compiling\n");fflush(stdout); } else { compileErrors++; char extPath[MAXPATHLEN]; asRelativePath(fileSym->name, extPath); error("file '%s' parse failed\n", extPath); postfl("error parsing\n"); } finiLexer(); } else { error("file '%s' open failed\n", fileSym->name); } freeParserPool(); } void compileDepTree() { ClassDependancy *classdep; int i; for (i=gClassCompileOrderNum-1; i>=0; --i) { classdep = gClassCompileOrder[i]; /*postfl("compile %d '%s' '%s' '%s'...%d/%d/%d\n", i, classdep->className->name, classdep->superClassName->name, classdep->fileSym->name, classdep->startLine, classdep->endLine, classDep->lineOffset);*/ compileClass(classdep->fileSym, classdep->startPos, classdep->endPos, classdep->lineOffset); } //postfl("startPos, classext->endPos); compileClass(classext->fileSym, classext->startPos, classext->endPos, -1); classext = classext->next; } while (classext); } } void findDiscrepancy(); void traverseFullDepTree2() { // assign a class index to all classes if (!parseFailed && !compileErrors) { buildClassTree(); gNumClasses = 0; // now I index them during pass one indexClassTree(class_object, 0); setSelectorFlags(); if (2*numClassDeps != gNumClasses) { error("There is a discrepancy.\n"); /* not always correct if(2*numClassDeps < gNumClasses) { post("Duplicate files may exist in the directory structure.\n"); } else { post("Some class files may be missing.\n"); } */ post("numClassDeps %d gNumClasses %d\n", numClassDeps, gNumClasses); findDiscrepancy(); compileErrors++; } else { double elapsed; buildBigMethodMatrix(); SymbolTable* symbolTable = gMainVMGlobals->symbolTable; post("\tNumber of Symbols %d\n", symbolTable->NumItems()); post("\tByte Code Size %d\n", totalByteCodes); //elapsed = TickCount() - compileStartTime; //elapsed = 0; elapsed = elapsedTime() - compileStartTime; post("\tcompiled %d files in %.2f seconds\n", gNumCompiledFiles, elapsed ); if(numOverwrites == 1){ post("\nInfo: One method is currently overwritten by an extension. To see which, execute:\nMethodOverride.printAll\n\n"); } else if(numOverwrites > 1){ post("\nInfo: %i methods are currently overwritten by extensions. To see which, execute:\nMethodOverride.printAll\n\n", numOverwrites); } post("compile done\n"); } } } bool parseOneClass(PyrSymbol *fileSym) { int token; PyrSymbol *className, *superClassName; ClassDependancy *classdep; bool res; int startPos, startLineOffset; res = true; startPos = textpos; startLineOffset = lineno - 1; token = yylex(); if (token == CLASSNAME) { className = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot); // I think this is wrong: zzval is space pool alloced //pyrfree((PyrSlot*)zzval); token = yylex(); if (token == 0) return false; if (token == OPENSQUAR) { scanForClosingBracket(); // eat indexing spec token = yylex(); if (token == 0) return false; } if (token == ':') { token = yylex(); // get super class if (token == 0) return false; if (token == CLASSNAME) { superClassName = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot); // I think this is wrong: zzval is space pool alloced //pyrfree((PyrSlot*)zzval); token = yylex(); if (token == 0) return false; if (token == OPENCURLY) { scanForClosingBracket(); // eat class body classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset); } else { compileErrors++; postfl("Expected %c. got token: '%s' %d\n", OPENCURLY, yytext, token); postErrorLine(lineno, linepos, charno); return false; } } else { compileErrors++; post("Expected superclass name. got token: '%s' %d\n", yytext, token); postErrorLine(lineno, linepos, charno); return false; } } else if (token == OPENCURLY) { if (className == s_object) superClassName = s_none; else superClassName = s_object; scanForClosingBracket(); // eat class body classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset); } else { compileErrors++; post("Expected ':' or %c. got token: '%s' %d\n", OPENCURLY, yytext, token); postErrorLine(lineno, linepos, charno); return false; } } else if (token == '+') { token = yylex(); if (token == 0) return false; scanForClosingBracket(); newClassExtFile(fileSym, startPos, textpos); return false; } else { if (token != 0) { compileErrors++; post("Expected class name. got token: '%s' %d\n", yytext, token); postErrorLine(lineno, linepos, charno); return false; } else { res = false; } } return res; } //void ClearLibMenu(); void aboutToFreeRuntime(); void aboutToFreeRuntime() { //ClearLibMenu(); } //void init_graph_compile(); //void tellPlugInsAboutToCompile(); void pyrmath_init_globs(); void initPassOne() { post("initPassOne started\n"); aboutToFreeRuntime(); //dump_pool_histo(pyr_pool_runtime); pyr_pool_runtime->FreeAllInternal(); //dump_pool_histo(pyr_pool_runtime); //gPermanentObjPool.Init(pyr_pool_runtime, PERMOBJCHUNK); sClassExtFiles = 0; void *ptr = pyr_pool_runtime->Alloc(sizeof(SymbolTable)); gMainVMGlobals->symbolTable = new (ptr) SymbolTable(pyr_pool_runtime, 65536); //gFileSymbolTable = newSymbolTable(512); pyrmath_init_globs(); initSymbols(); // initialize symbol globals //init_graph_compile(); initSpecialSelectors(); initSpecialClasses(); initClasses(); initParserPool(); initParseNodes(); initPrimitives(); //tellPlugInsAboutToCompile(); initLexer(); compileErrors = 0; numClassDeps = 0; compiledOK = false; compiledDirectories.clear(); sc_InitCompileDirectory(); post("initPassOne done\n"); } void finiPassOne() { //postfl("->finiPassOne\n"); freeParserPool(); //postfl("<-finiPassOne\n"); } static bool passOne_ProcessDir(const char *dirname, int level) { if (!sc_DirectoryExists(dirname)) return true; if (compiledDirectories.find(std::string(dirname)) != compiledDirectories.end()) // already compiled return true; bool success = true; if (gLanguageConfig && gLanguageConfig->pathIsExcluded(dirname)) { post("\texcluding dir: '%s'\n", dirname); return success; } if (level == 0) post("\tcompiling dir: '%s'\n", dirname); SC_DirHandle *dir = sc_OpenDir(dirname); if (!dir) { error("open directory failed '%s'\n", dirname); fflush(stdout); return false; } for (;;) { char diritem[MAXPATHLEN]; bool skipItem = true; bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem); if (!validItem) break; if (skipItem) continue; if (sc_DirectoryExists(diritem)) { success = passOne_ProcessDir(diritem, level + 1); } else { success = passOne_ProcessOneFile(diritem, level + 1); } if (!success) break; } compiledDirectories.insert(std::string(dirname)); sc_CloseDir(dir); return success; } bool passOne() { initPassOne(); if (sc_IsStandAlone()) { /// FIXME: this should be moved to the LibraryConfig file if (!passOne_ProcessDir(gCompileDir, 0)) return false; } else if (!gLanguageConfig->forEachIncludedDirectory(passOne_ProcessDir)) return false; finiPassOne(); return true; } // true if filename ends in ".sc" bool isValidSourceFileName(char *filename) { int len = strlen(filename); bool validExtension = (len>3 && strncmp(filename+len-3, ".sc", 3) == 0) || (len>7 && strncmp(filename+len-7, ".sc.rtf", 7) == 0); if (!validExtension) return false; boost::filesystem::path pathname(filename); if (pathname.filename().c_str()[0] == '.') // hidden filename return false; return true; } // sekhar's replacement bool passOne_ProcessOneFile(const char * filenamearg, int level) { bool success = true; bool isAlias = false; char filename[MAXPATHLEN]; int status = sc_ResolveIfAlias(filenamearg, filename, isAlias, MAXPATHLEN); if (status<0) { printf("WARNING: skipping invalid symbolic link: %s\n", filenamearg); return success; } if (gLanguageConfig && gLanguageConfig->pathIsExcluded(filename)) { post("\texcluding file: '%s'\n", filename); return success; } if (isValidSourceFileName(filename)) { gNumCompiledFiles++; PyrSymbol * fileSym = getsym(filename); fileSym->u.source = NULL; if (startLexer(fileSym, -1, -1, -1)) { while (parseOneClass(fileSym)) { }; finiLexer(); } else { error("file '%s' open failed\n", filename); success = false; } } else { if (sc_DirectoryExists(filename)) success = passOne_ProcessDir(filename, level); } return success; } void schedRun(); void compileSucceeded(); void compileSucceeded() { compiledOK = !(parseFailed || compileErrors); if (compiledOK) { compiledOK = true; compiledOK = initRuntime(gMainVMGlobals, 128*1024, pyr_pool_runtime); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; //++g->sp; SetObject(g->sp, g->process); //runInterpreter(g, s_hardwaresetup, 1); ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_startup, 1); g->canCallOS = false; schedRun(); } flushPostBuf(); } } static void runShutdown() { //printf("->aboutToCompileLibrary\n"); gLangMutex.lock(); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, s_shutdown, 1); g->canCallOS = false; } gLangMutex.unlock(); //printf("<-aboutToCompileLibrary\n"); } void closeAllGUIScreens(); void TempoClock_stopAll(void); void closeAllCustomPorts(); void shutdownLibrary() { closeAllGUIScreens(); schedStop(); runShutdown(); TempoClock_stopAll(); gLangMutex.lock(); closeAllCustomPorts(); if (compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; g->gc->RunAllFinalizers(); g->canCallOS = false; } pyr_pool_runtime->FreeAll(); compiledOK = false; gLangMutex.unlock(); deinitPrimitives(); SC_LanguageConfig::freeLibraryConfig(); } SCLANG_DLLEXPORT_C bool compileLibrary(bool standalone) { //printf("->compileLibrary\n"); shutdownLibrary(); gLangMutex.lock(); gNumCompiledFiles = 0; compiledOK = false; SC_LanguageConfig::readLibraryConfig(standalone); compileStartTime = elapsedTime(); totalByteCodes = 0; #ifdef NDEBUG postfl("compiling class library...\n"); #else postfl("compiling class library (debug build)...\n"); #endif bool res = passOne(); if (res) { postfl("\tpass 1 done\n"); if (!compileErrors) { buildDepTree(); traverseFullDepTree(); traverseFullDepTree2(); flushPostBuf(); if (!compileErrors && gShowWarnings) { SymbolTable* symbolTable = gMainVMGlobals->symbolTable; symbolTable->CheckSymbols(); } } pyr_pool_compile->FreeAll(); flushPostBuf(); compileSucceeded(); } else { compiledOK = false; } gLangMutex.unlock(); //printf("<-compileLibrary\n"); return compiledOK; } void signal_init_globs(); void dumpByteCodes(PyrBlock *theBlock); SCLANG_DLLEXPORT_C void runLibrary(PyrSymbol* selector) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; try { if (compiledOK) { ++g->sp; SetObject(g->sp, g->process); runInterpreter(g, selector, 1); } else { postfl("Library has not been compiled successfully.\n"); } } catch (std::exception &ex) { PyrMethod *meth = g->method; if (meth) { int ip = slotRawInt8Array(&meth->code) ? g->ip - slotRawInt8Array(&meth->code)->b : -1; post("caught exception in runLibrary %s:%s %3d\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, ip ); dumpByteCodes(meth); } else { post("caught exception in runLibrary\n"); } error(ex.what()); } catch (...) { postfl("DANGER: OUT of MEMORY. Operation failed.\n"); } g->canCallOS = false; } SuperCollider-Source/lang/LangSource/PyrLexer.h000644 000765 000024 00000007541 12756531745 022611 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRLEXER_H_ #define _PYRLEXER_H_ #include "PyrSlot.h" #include "PyrSymbol.h" #include "SC_Export.h" #include "SCBase.h" extern int charno, lineno, linepos; extern int *linestarts; struct ClassExtFile { struct ClassExtFile *next; PyrSymbol *fileSym; int startPos, endPos, lineOffset; }; typedef struct classdep { struct classdep *next; struct classdep *superClassDep; struct classdep *subclasses; PyrSymbol *className; PyrSymbol *superClassName; PyrSymbol *fileSym; int startPos, endPos, lineOffset; } ClassDependancy; extern PyrSymbol *gCompilingFileSym; ClassDependancy* newClassDependancy(PyrSymbol *className, PyrSymbol *superClassName, PyrSymbol *fileSym, int startPos, int endPos, int lineOffset); bool parseOneClass(PyrSymbol *fileSym); void initPassOne(); void finiPassOne(); bool passOne(); void buildDepTree(); void traverseFullDepTree(); void traverseDepTree(ClassDependancy *classdep, int level); void traverseFullDepTree2(); void traverseDepTree2(ClassDependancy *classdep, int level); void compileClassExtensions(); void compileClass(PyrSymbol *fileSym, int startPos, int endPos, int lineOffset); SCLANG_DLLEXPORT_C void runLibrary(PyrSymbol* selector); void interpretCmdLine(const char *textbuf, int textlen, char *methodname); int input(); int input0(); void unput(int c); void unput0(int c); void finiLexer() ; bool startLexer(char* filename) ; void startLexerCmdLine(char *textbuf, int textbuflen); int yylex() ; void yyerror(const char *s) ; void fatal() ; bool isValidSourceFileName(char *filename); bool passOne_ProcessOneFile(const char *filename, int level); extern void asRelativePath(char *inPath,char *outPath); void initLexer(); void init_SuperCollider(); int processbinop(char *token); int processident(char *token); int processfloat(char *token, int sawpi); int processint(char *token); int processchar(int c); int processintradix(char *s, int n, int radix); int processfloatradix(char *s, int n, int radix); int processhex(char *s); int processsymbol(char *token); int processstring(char *token); int processkeywordbinop(char *token); void postErrorLine(int linenum, int start, int charpos); bool scanForClosingBracket(); void parseClasses(); extern int parseFailed; extern bool compilingCmdLine; extern bool compilingCmdLineErrorWindow; extern bool compiledOK; #define MAXYYLEN 8192 extern int gNumCompiledFiles; extern int gClassCompileOrderNum; extern ClassDependancy **gClassCompileOrder; extern char curfilename[PATH_MAX]; extern int runcount; extern const char *binopchars; extern char yytext[MAXYYLEN]; extern char curfilename[PATH_MAX]; extern int yylen; extern int lexCmdLine; extern bool compilingCmdLine; extern bool compilingCmdLineErrorWindow; extern intptr_t zzval; extern intptr_t gParserResult; extern int lineno, charno, linepos; extern int *linestarts; extern int maxlinestarts; extern char *text; extern int textlen; extern int textpos; extern int parseFailed; extern bool compiledOK; extern int radixcharpos, decptpos; int rtf2txt(char* txt); int html2txt(char* txt); #endif SuperCollider-Source/lang/LangSource/PyrMathOps.cpp000644 000765 000024 00000127564 12524671173 023441 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "Opcodes.h" #include "PyrInterpreter.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrMathPrim.h" #include "PyrKernel.h" #include "PyrMessage.h" #include "PyrParseNode.h" #include "PyrSignal.h" #include "PyrSched.h" #include "PyrSymbol.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "MiscInlineMath.h" #include "PyrKernelProto.h" #include double hypotx(double x, double y); #define IS_BINARY_BOOL_OP(op) ((op)>=opEQ && (op)<=opGE) int doSpecialUnaryArithMsg(VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrSymbol *msg; int opcode = g->primitiveIndex; a = g->sp; switch (GetTag(a)) { case tagInt : switch (opcode) { case opNeg : SetRaw(a, -slotRawInt(a)); break; //case opNot : goto send_normal_1; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opBitNot : SetRaw(a, ~slotRawInt(a)); break; case opAbs : SetRaw(a, sc_abs(slotRawInt(a))); break; case opAsFloat : SetFloat(a, (double)slotRawInt(a)); break; case opAsInt : SetRaw(a, (int)slotRawInt(a)); break; case opCeil : SetRaw(a, slotRawInt(a)); break; case opFloor : SetRaw(a, slotRawInt(a)); break; case opFrac : SetRaw(a, 0); break; case opSign : SetRaw(a, slotRawInt(a) > 0 ? 1 : (slotRawInt(a) == 0 ? 0 : -1)); break; case opSquared : SetRaw(a, slotRawInt(a) * slotRawInt(a)); break; case opCubed : SetRaw(a, slotRawInt(a) * slotRawInt(a) * slotRawInt(a)); break; case opSqrt : SetFloat(a, sqrt((double)slotRawInt(a))); break; case opExp : SetFloat(a, exp((double)slotRawInt(a))); break; case opRecip : SetFloat(a, 1. / slotRawInt(a)); break; case opMIDICPS : SetFloat(a, sc_midicps((double)slotRawInt(a))); break; case opCPSMIDI : SetFloat(a, sc_cpsmidi((double)slotRawInt(a))); break; case opMIDIRatio : SetFloat(a, sc_midiratio((double)slotRawInt(a))); break; case opRatioMIDI : SetFloat(a, sc_ratiomidi((double)slotRawInt(a))); break; case opAmpDb : SetFloat(a, sc_ampdb((double)slotRawInt(a))); break; case opDbAmp : SetFloat(a, sc_dbamp((double)slotRawInt(a))); break; case opOctCPS : SetFloat(a, sc_octcps((double)slotRawInt(a))); break; case opCPSOct : SetFloat(a, sc_cpsoct((double)slotRawInt(a))); break; case opLog : SetFloat(a, log((double)slotRawInt(a))); break; case opLog2 : SetFloat(a, sc_log2((double)slotRawInt(a))); break; case opLog10 : SetFloat(a, log10((double)slotRawInt(a))); break; case opSin : SetFloat(a, sin((double)slotRawInt(a))); break; case opCos : SetFloat(a, cos((double)slotRawInt(a))); break; case opTan : SetFloat(a, tan((double)slotRawInt(a))); break; case opArcSin : SetFloat(a, asin((double)slotRawInt(a))); break; case opArcCos : SetFloat(a, acos((double)slotRawInt(a))); break; case opArcTan : SetFloat(a, atan((double)slotRawInt(a))); break; case opSinH : SetFloat(a, sinh((double)slotRawInt(a))); break; case opCosH : SetFloat(a, cosh((double)slotRawInt(a))); break; case opTanH : SetFloat(a, tanh((double)slotRawInt(a))); break; case opRand : SetRaw(a, g->rgen->irand(slotRawInt(a))); break; case opRand2 : SetRaw(a, g->rgen->irand2(slotRawInt(a))); break; case opLinRand : SetRaw(a, g->rgen->ilinrand(slotRawInt(a))); break; case opBiLinRand : SetRaw(a, g->rgen->ibilinrand(slotRawInt(a))); break; // case opExpRand : SetFloat(a, g->rgen->exprand(slotRawInt(a))); break; // case opBiExpRand : SetFloat(a, g->rgen->biexprand(slotRawInt(a))); break; case opSum3Rand : SetFloat(a, g->rgen->sum3rand(slotRawInt(a))); break; // case opGammaRand : SetFloat(a, g->rgen->gammarand(slotRawInt(a))); break; // case opGaussRand : SetFloat(a, g->rgen->gaussrand(slotRawInt(a))); break; // case opPoiRand : SetFloat(a, g->rgen->poirand(slotRawInt(a))); break; case opDistort : SetFloat(a, sc_distort((double)slotRawInt(a))); break; case opSoftClip : SetFloat(a, sc_softclip((double)slotRawInt(a))); break; case opCoin : SetBool(a, (slotRawInt(a))); break; case opRectWindow : SetFloat(a, sc_rectwindow((double)slotRawInt(a))); break; case opHanWindow : SetFloat(a, sc_hanwindow((double)slotRawInt(a))); break; case opWelchWindow : SetFloat(a, sc_welwindow((double)slotRawInt(a))); break; case opTriWindow : SetFloat(a, sc_triwindow((double)slotRawInt(a))); break; case opSCurve : SetFloat(a, sc_scurve((double)slotRawInt(a))); break; case opRamp : SetFloat(a, sc_ramp((double)slotRawInt(a))); break; default : goto send_normal_1; } break; case tagChar : switch (opcode) { //case opNot : goto send_normal_1; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opAsInt : SetTagRaw(a, tagInt); break; case opDigitValue : if (slotRawInt(a) >= '0' && slotRawInt(a) <= '9') SetInt(a, slotRawInt(a) - '0'); else if (slotRawInt(a) >= 'A' && slotRawInt(a) <= 'Z') SetInt(a, slotRawInt(a) - 'A'); else if (slotRawInt(a) >= 'a' && slotRawInt(a) <= 'z') SetInt(a, slotRawInt(a) - 'a'); else SetInt(a, 0); break; default : goto send_normal_1; } break; case tagPtr : switch (opcode) { case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; default : goto send_normal_1; } break; case tagNil : switch (opcode) { case opIsNil : SetTrue(a); break; case opNotNil : SetFalse(a); break; default : goto send_normal_1; } break; case tagFalse : switch (opcode) { case opNot : SetTrue(a); break; case opIsNil : /*SetFalse(a);*/ break; case opNotNil : SetTrue(a); break; default : goto send_normal_1; } break; case tagTrue : switch (opcode) { case opNot : SetFalse(a); break; case opIsNil : SetFalse(a); break; case opNotNil : /*SetTrue(a);*/ break; default : goto send_normal_1; } break; case tagSym : switch (opcode) { case opAsFloat : case opAsInt : goto send_normal_1; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; default : /* SetSymbol(a, slotRawSymbol(a)); */ break; } break; case tagObj : if (isKindOf(slotRawObject(a), class_signal)) { switch (opcode) { case opNeg : SetRaw(a, signal_invert(g, slotRawObject(a))); break; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opAbs : SetRaw(a, signal_abs(g, slotRawObject(a))); break; case opSign : SetRaw(a, signal_sign(g, slotRawObject(a))); break; case opSquared : SetRaw(a, signal_squared(g, slotRawObject(a))); break; case opCubed : SetRaw(a, signal_cubed(g, slotRawObject(a))); break; case opSqrt : SetRaw(a, signal_sqrt(g, slotRawObject(a))); break; case opExp : SetRaw(a, signal_exp(g, slotRawObject(a))); break; case opRecip : SetRaw(a, signal_recip(g, slotRawObject(a))); break; case opLog : SetRaw(a, signal_log(g, slotRawObject(a))); break; case opLog2 : SetRaw(a, signal_log2(g, slotRawObject(a))); break; case opLog10 : SetRaw(a, signal_log10(g, slotRawObject(a))); break; case opSin : SetRaw(a, signal_sin(g, slotRawObject(a))); break; //case opSin : SetRaw(a, signal_fsin(g, slotRawObject(a))); break; case opCos : SetRaw(a, signal_cos(g, slotRawObject(a))); break; case opTan : SetRaw(a, signal_tan(g, slotRawObject(a))); break; case opArcSin : SetRaw(a, signal_asin(g, slotRawObject(a))); break; case opArcCos : SetRaw(a, signal_acos(g, slotRawObject(a))); break; case opArcTan : SetRaw(a, signal_atan(g, slotRawObject(a))); break; case opSinH : SetRaw(a, signal_sinh(g, slotRawObject(a))); break; case opCosH : SetRaw(a, signal_cosh(g, slotRawObject(a))); break; case opTanH : SetRaw(a, signal_tanh(g, slotRawObject(a))); break; case opDistort : SetRaw(a, signal_distort(g, slotRawObject(a))); break; case opSoftClip : SetRaw(a, signal_softclip(g, slotRawObject(a))); break; default : goto send_normal_1; } } else { goto send_normal_1; } break; default : // double switch (opcode) { case opNeg : SetRaw(a, -slotRawFloat(a)); break; case opIsNil : SetFalse(a); break; case opNotNil : SetTrue(a); break; case opBitNot : SetRaw(a, ~(int)slotRawFloat(a)); break; case opAbs : SetRaw(a, sc_abs(slotRawFloat(a))); break; case opAsFloat : SetRaw(a, (double)slotRawFloat(a)); break; case opAsInt : { double val = slotRawFloat(a); if (val == std::numeric_limits::infinity()) SetInt(a, std::numeric_limits::max()); else SetInt(a, (int)val); break; } case opCeil : SetRaw(a, ceil(slotRawFloat(a))); break; case opFloor : SetRaw(a, floor(slotRawFloat(a))); break; case opFrac : SetRaw(a, sc_frac(slotRawFloat(a))); break; case opSign : SetRaw(a, slotRawFloat(a) > 0. ? 1.0 : (slotRawFloat(a) == 0 ? 0.0 : -1.0)); break; case opSquared : SetRaw(a, slotRawFloat(a) * slotRawFloat(a)); break; case opCubed : SetRaw(a, slotRawFloat(a) * slotRawFloat(a) * slotRawFloat(a)); break; case opSqrt : SetRaw(a, sqrt(slotRawFloat(a))); break; case opExp : SetRaw(a, exp(slotRawFloat(a))); break; case opRecip : SetRaw(a, 1./slotRawFloat(a)); break; case opMIDICPS : SetRaw(a, sc_midicps(slotRawFloat(a))); break; case opCPSMIDI : SetRaw(a, sc_cpsmidi(slotRawFloat(a))); break; case opMIDIRatio : SetRaw(a, sc_midiratio((double)slotRawFloat(a))); break; case opRatioMIDI : SetRaw(a, sc_ratiomidi((double)slotRawFloat(a))); break; case opAmpDb : SetRaw(a, sc_ampdb(slotRawFloat(a))); break; case opDbAmp : SetRaw(a, sc_dbamp(slotRawFloat(a))); break; case opOctCPS : SetRaw(a, sc_octcps(slotRawFloat(a))); break; case opCPSOct : SetRaw(a, sc_cpsoct(slotRawFloat(a))); break; case opLog : SetRaw(a, log(slotRawFloat(a))); break; case opLog2 : SetRaw(a, sc_log2(slotRawFloat(a))); break; case opLog10 : SetRaw(a, log10(slotRawFloat(a))); break; case opSin : SetRaw(a, sin(slotRawFloat(a))); break; case opCos : SetRaw(a, cos(slotRawFloat(a))); break; case opTan : SetRaw(a, tan(slotRawFloat(a))); break; case opArcSin : SetRaw(a, asin(slotRawFloat(a))); break; case opArcCos : SetRaw(a, acos(slotRawFloat(a))); break; case opArcTan : SetRaw(a, atan(slotRawFloat(a))); break; case opSinH : SetRaw(a, sinh(slotRawFloat(a))); break; case opCosH : SetRaw(a, cosh(slotRawFloat(a))); break; case opTanH : SetRaw(a, tanh(slotRawFloat(a))); break; case opRand : SetRaw(a, g->rgen->frand() * slotRawFloat(a)); break; case opRand2 : SetRaw(a, g->rgen->frand2() * slotRawFloat(a)); break; case opLinRand : SetRaw(a, g->rgen->linrand(slotRawFloat(a))); break; case opBiLinRand : SetRaw(a, g->rgen->bilinrand(slotRawFloat(a))); break; // case opExpRand : SetRaw(a, g->rgen->exprand(slotRawFloat(a))); break; // case opBiExpRand : SetRaw(a, g->rgen->biexprand(slotRawFloat(a))); break; case opSum3Rand : SetRaw(a, g->rgen->sum3rand(slotRawFloat(a))); break; // case opGammaRand : SetRaw(a, g->rgen->gammarand(slotRawFloat(a))); break; // case opGaussRand : SetRaw(a, g->rgen->gaussrand(slotRawFloat(a))); break; // case opPoiRand : SetRaw(a, g->rgen->poirand(slotRawFloat(a))); break; case opDistort : SetRaw(a, sc_distort(slotRawFloat(a))); break; case opSoftClip : SetRaw(a, sc_softclip(slotRawFloat(a))); break; case opCoin : SetBool(a, g->rgen->frand() < slotRawFloat(a)); break; case opRectWindow : SetRaw(a, sc_rectwindow(slotRawFloat(a))); break; case opHanWindow : SetRaw(a, sc_hanwindow(slotRawFloat(a))); break; case opWelchWindow : SetRaw(a, sc_welwindow(slotRawFloat(a))); break; case opTriWindow : SetRaw(a, sc_triwindow(slotRawFloat(a))); break; case opSCurve : SetRaw(a, sc_scurve(slotRawFloat(a))); break; case opRamp : SetRaw(a, sc_ramp(slotRawFloat(a))); break; default : goto send_normal_1; } break; } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_1: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; msg = gSpecialUnarySelectors[opcode]; sendMessage(g, msg, 1); return errNone; } int prSpecialBinaryArithMsg(VMGlobals *g, int numArgsPushed) { return doSpecialBinaryArithMsg(g, numArgsPushed, true); } int doSpecialBinaryArithMsg(VMGlobals *g, int numArgsPushed, bool isPrimitive) { PyrSlot *a, *b; PyrSymbol *msg; int opcode = g->primitiveIndex; a = g->sp - (numArgsPushed - 1); b = a + 1; switch (GetTag(a)) { case tagInt : { switch (GetTag(b)) { case tagInt : switch (opcode) { case opAdd : SetRaw(a, slotRawInt(a) + slotRawInt(b)); break; case opSub : SetRaw(a, slotRawInt(a) - slotRawInt(b)); break; case opMul : SetRaw(a, slotRawInt(a) * slotRawInt(b)); break; case opIDiv : SetRaw(a, sc_div(slotRawInt(a), slotRawInt(b))); break; case opFDiv : SetFloat(a, (double)slotRawInt(a) / (double)slotRawInt(b)); break; case opMod : SetRaw(a, sc_mod((int)slotRawInt(a), (int)slotRawInt(b))); break; case opEQ : SetBool(a, slotRawInt(a) == slotRawInt(b)); break; case opNE : SetBool(a, slotRawInt(a) != slotRawInt(b)); break; case opLT : SetBool(a, slotRawInt(a) < slotRawInt(b)); break; case opGT : SetBool(a, slotRawInt(a) > slotRawInt(b)); break; case opLE : SetBool(a, slotRawInt(a) <= slotRawInt(b)); break; case opGE : SetBool(a, slotRawInt(a) >= slotRawInt(b)); break; //case opIdentical : SetBool(a, slotRawInt(a) == slotRawInt(b)); break; //case opNotIdentical : SetBool(a, slotRawInt(a) != slotRawInt(b)); break; case opMin : SetRaw(a, sc_min(slotRawInt(a), slotRawInt(b))); break; case opMax : SetRaw(a, sc_max(slotRawInt(a), slotRawInt(b))); break; case opBitAnd : SetRaw(a, slotRawInt(a) & slotRawInt(b)); break; case opBitOr : SetRaw(a, slotRawInt(a) | slotRawInt(b)); break; case opBitXor : SetRaw(a, slotRawInt(a) ^ slotRawInt(b)); break; case opLCM : SetRaw(a, sc_lcm((long)slotRawInt(a), (long)slotRawInt(b))); break; case opGCD : SetRaw(a, sc_gcd((long)slotRawInt(a), (long)slotRawInt(b))); break; case opRound : SetRaw(a, sc_round((int)slotRawInt(a), (int)slotRawInt(b))); break; case opRoundUp :SetRaw(a, sc_roundUp((int)slotRawInt(a), (int)slotRawInt(b))); break; case opTrunc : SetRaw(a, sc_trunc((int)slotRawInt(a), (int)slotRawInt(b))); break; case opAtan2 : SetFloat(a, atan2((double)slotRawInt(a), (double)slotRawInt(b))); break; case opHypot : SetFloat(a, hypot((double)slotRawInt(a), (double)slotRawInt(b))); break; case opHypotx : SetFloat(a, hypotx((double)slotRawInt(a), (double)slotRawInt(b))); break; case opPow : SetFloat(a, pow((double)slotRawInt(a), (double)slotRawInt(b))); break; case opShiftLeft : { long ia = slotRawInt(a); long ib = slotRawInt(b); if (ib>0) ia <<= ib; else if (ib<0) ia >>= -ib; SetRaw(a, ia); } break; case opShiftRight : { long ia = slotRawInt(a); long ib = slotRawInt(b); if (ib>0) ia >>= ib; else if (ib<0) ia <<= -ib; SetRaw(a, ia); } break; case opUnsignedShift : { unsigned long ia = slotRawInt(a); long ib = slotRawInt(b); if (ib>0) ia >>= ib; else if (ib<0) ia <<= -ib; SetRaw(a, (long)ia); } break; case opRing1 : SetRaw(a, sc_ring1(slotRawInt(a), slotRawInt(b))); break; case opRing2 : SetRaw(a, sc_ring2(slotRawInt(a), slotRawInt(b))); break; case opRing3 : SetRaw(a, sc_ring3(slotRawInt(a), slotRawInt(b))); break; case opRing4 : SetRaw(a, sc_ring4(slotRawInt(a), slotRawInt(b))); break; case opDifSqr : SetRaw(a, sc_difsqr(slotRawInt(a), slotRawInt(b))); break; case opSumSqr : SetRaw(a, sc_sumsqr(slotRawInt(a), slotRawInt(b))); break; case opSqrSum : SetRaw(a, sc_sqrsum(slotRawInt(a), slotRawInt(b))); break; case opSqrDif : SetRaw(a, sc_sqrdif(slotRawInt(a), slotRawInt(b))); break; case opAbsDif : SetRaw(a, sc_abs(slotRawInt(a) - slotRawInt(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawInt(a), slotRawInt(b))); break; case opAMClip : SetRaw(a, sc_amclip(slotRawInt(a), slotRawInt(b))); break; case opScaleNeg : SetRaw(a, sc_scaleneg(slotRawInt(a), slotRawInt(b))); break; case opClip2 : SetRaw(a, sc_clip2(slotRawInt(a), slotRawInt(b))); break; case opFold2 : SetRaw(a, sc_fold2(slotRawInt(a), slotRawInt(b))); break; case opWrap2 : SetRaw(a, sc_wrap2(slotRawInt(a), slotRawInt(b))); break; case opExcess : SetRaw(a, sc_excess(slotRawInt(a), slotRawInt(b))); break; case opFirstArg : SetRaw(a, slotRawInt(a)); break; case opRandRange : SetRaw(a, slotRawInt(b) > slotRawInt(a) ? slotRawInt(a) + g->rgen->irand(slotRawInt(b) - slotRawInt(a) + 1) : slotRawInt(b) + g->rgen->irand(slotRawInt(a) - slotRawInt(b) + 1)); break; case opExpRandRange : SetFloat(a, g->rgen->exprandrng(slotRawInt(a), slotRawInt(b))); break; default : goto send_normal_2; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); else SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { switch (opcode) { case opAdd : SetObject(a, signal_add_xf(g, slotRawObject(b), slotRawInt(a))); break; case opSub : SetObject(a, signal_sub_fx(g, slotRawInt(a), slotRawObject(b))); break; case opMul : SetObject(a, signal_mul_xf(g, slotRawObject(b), slotRawInt(a))); break; case opIDiv : SetObject(a, signal_div_fx(g, slotRawInt(a), slotRawObject(b))); break; case opFDiv : SetObject(a, signal_div_fx(g, slotRawInt(a), slotRawObject(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetObject(a, signal_min_xf(g, slotRawObject(b), slotRawInt(a))); break; case opMax : SetObject(a, signal_max_xf(g, slotRawObject(b), slotRawInt(a))); break; case opRing1 : SetObject(a, signal_ring1_fx(g, slotRawInt(a), slotRawObject(b))); break; case opRing2 : SetObject(a, signal_ring2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opRing3 : SetObject(a, signal_ring3_fx(g, slotRawInt(a), slotRawObject(b))); break; case opRing4 : SetObject(a, signal_ring4_fx(g, slotRawInt(a), slotRawObject(b))); break; case opDifSqr : SetObject(a, signal_difsqr_fx(g, slotRawInt(a), slotRawObject(b))); break; case opSumSqr : SetObject(a, signal_sumsqr_fx(g, slotRawInt(a), slotRawObject(b))); break; case opSqrSum : SetObject(a, signal_sqrsum_fx(g, slotRawInt(a), slotRawObject(b))); break; case opSqrDif : SetObject(a, signal_sqrdif_fx(g, slotRawInt(a), slotRawObject(b))); break; case opAbsDif : SetObject(a, signal_absdif_fx(g, slotRawInt(a), slotRawObject(b))); break; case opThresh : SetObject(a, signal_thresh_fx(g, slotRawInt(a), slotRawObject(b))); break; case opAMClip : SetObject(a, signal_amclip_fx(g, slotRawInt(a), slotRawObject(b))); break; case opScaleNeg : SetObject(a, signal_scaleneg_fx(g, slotRawInt(a), slotRawObject(b))); break; case opClip2 : SetObject(a, signal_clip2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opFold2 : SetObject(a, signal_fold2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opWrap2 : SetObject(a, signal_wrap2_fx(g, slotRawInt(a), slotRawObject(b))); break; case opExcess : SetObject(a, signal_excess_fx(g, slotRawInt(a), slotRawObject(b))); break; case opFirstArg : SetObject(a, slotRawObject(a)); break; default : goto send_normal_2; } } else { goto send_normal_2; } break; default : switch (opcode) { case opAdd : SetFloat(a, slotRawInt(a) + slotRawFloat(b)); break; case opSub : SetFloat(a, slotRawInt(a) - slotRawFloat(b)); break; case opMul : SetFloat(a, slotRawInt(a) * slotRawFloat(b)); break; case opIDiv : SetRaw(a, (long)floor(slotRawInt(a) / slotRawFloat(b))); break; case opFDiv : SetFloat(a, slotRawInt(a) / slotRawFloat(b)); break; case opMod : SetFloat(a, sc_mod((double)slotRawInt(a), slotRawFloat(b))); break; case opEQ : SetBool(a, slotRawInt(a) == slotRawFloat(b)); break; case opNE : SetBool(a, slotRawInt(a) != slotRawFloat(b)); break; case opLT : SetBool(a, slotRawInt(a) < slotRawFloat(b)); break; case opGT : SetBool(a, slotRawInt(a) > slotRawFloat(b)); break; case opLE : SetBool(a, slotRawInt(a) <= slotRawFloat(b)); break; case opGE : SetBool(a, slotRawInt(a) >= slotRawFloat(b)); break; //case opIdentical : SetFalse(a); break; //case opNotIdentical : SetTrue(a); break; case opMin : SetFloat(a, sc_min((double)slotRawInt(a), slotRawFloat(b))); break; case opMax : SetFloat(a, sc_max((double)slotRawInt(a), slotRawFloat(b))); break; case opRound : SetFloat(a, sc_round((double)slotRawInt(a), slotRawFloat(b))); break; case opRoundUp : SetFloat(a, sc_roundUp((double)slotRawInt(a), slotRawFloat(b))); break; case opTrunc : SetFloat(a, sc_trunc((double)slotRawInt(a), slotRawFloat(b))); break; case opAtan2 : SetFloat(a, atan2(slotRawInt(a), slotRawFloat(b))); break; case opHypot : SetFloat(a, hypot(slotRawInt(a), slotRawFloat(b))); break; case opHypotx : SetFloat(a, hypotx(slotRawInt(a), slotRawFloat(b))); break; case opPow : SetFloat(a, pow((double)slotRawInt(a), slotRawFloat(b))); break; case opRing1 : SetFloat(a, sc_ring1((double)slotRawInt(a), slotRawFloat(b))); break; case opRing2 : SetFloat(a, sc_ring2((double)slotRawInt(a), slotRawFloat(b))); break; case opRing3 : SetFloat(a, sc_ring3((double)slotRawInt(a), slotRawFloat(b))); break; case opRing4 : SetFloat(a, sc_ring4((double)slotRawInt(a), slotRawFloat(b))); break; case opDifSqr : SetFloat(a, sc_difsqr((double)slotRawInt(a), slotRawFloat(b))); break; case opSumSqr : SetFloat(a, sc_sumsqr((double)slotRawInt(a), slotRawFloat(b))); break; case opSqrSum : SetFloat(a, sc_sqrsum((double)slotRawInt(a), slotRawFloat(b))); break; case opSqrDif : SetFloat(a, sc_sqrdif((double)slotRawInt(a), slotRawFloat(b))); break; case opAbsDif : SetFloat(a, sc_abs(slotRawInt(a) - slotRawFloat(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawInt(a), slotRawFloat(b))); break; case opAMClip : SetFloat(a, sc_amclip((double)slotRawInt(a), slotRawFloat(b))); break; case opScaleNeg : SetFloat(a, sc_scaleneg((double)slotRawInt(a), slotRawFloat(b))); break; case opClip2 : SetFloat(a, sc_clip2((double)slotRawInt(a), slotRawFloat(b))); break; case opFold2 : SetFloat(a, sc_fold2((double)slotRawInt(a), slotRawFloat(b))); break; case opWrap2 : SetFloat(a, sc_wrap2((double)slotRawInt(a), -slotRawFloat(b))); break; case opExcess : SetFloat(a, sc_excess((double)slotRawInt(a), slotRawFloat(b))); break; case opFirstArg : SetInt(a, slotRawInt(a)); break; case opRandRange : SetFloat(a, slotRawInt(a) + g->rgen->frand() * (slotRawFloat(b) - slotRawInt(a))); break; case opExpRandRange : SetFloat(a, g->rgen->exprandrng(slotRawInt(a), slotRawFloat(b))); break; default : goto send_normal_2; } break; } } break; case tagChar : { if (IsChar(b)) { switch (opcode) { case opEQ : SetBool(a, slotRawChar(a) == slotRawChar(b)); break; case opNE : SetBool(a, slotRawChar(a) != slotRawChar(b)); break; case opLT : SetBool(a, slotRawChar(a) < slotRawChar(b)); break; case opGT : SetBool(a, slotRawChar(a) > slotRawChar(b)); break; case opLE : SetBool(a, slotRawChar(a) <= slotRawChar(b)); break; case opGE : SetBool(a, slotRawChar(a) >= slotRawChar(b)); break; //case opIdentical : SetBool(a, slotRawChar(a) == slotRawChar(b)); break; //case opNotIdentical : SetBool(a, slotRawChar(a) != slotRawChar(b)); break; case opMin : SetRawChar(a, sc_min(slotRawChar(a), slotRawChar(b))); break; case opMax : SetRawChar(a, sc_max(slotRawChar(a), slotRawChar(b))); break; default : goto send_normal_2; } } else { goto send_normal_2; } } break; case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IsSym(b)) { switch (opcode) { case opEQ : SetBool(a, slotRawSymbol(a) == slotRawSymbol(b)); break; case opNE : SetBool(a, slotRawSymbol(a) != slotRawSymbol(b)); break; case opLT : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) < 0); break; case opGT : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) > 0); break; case opLE : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) <= 0); break; case opGE : SetBool(a, strcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name) >= 0); break; //default : leave first operand on stack } } else { if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); } break; case tagObj : { if (isKindOf(slotRawObject(a), class_signal)) { switch (GetTag(b)) { case tagInt : switch (opcode) { case opAdd : SetRaw(a, signal_add_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSub : SetRaw(a, signal_sub_xf(g, slotRawObject(a), slotRawInt(b))); break; case opMul : SetRaw(a, signal_mul_xf(g, slotRawObject(a), slotRawInt(b))); break; case opIDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawInt(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetRaw(a, signal_min_xf(g, slotRawObject(a), slotRawInt(b))); break; case opMax : SetRaw(a, signal_max_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFill : SetRaw(a, signal_fill(slotRawObject(a), slotRawInt(b))); break; case opRing1 : SetRaw(a, signal_ring1_xf(g, slotRawObject(a), slotRawInt(b))); break; case opRing2 : SetRaw(a, signal_ring2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opRing3 : SetRaw(a, signal_ring3_xf(g, slotRawObject(a), slotRawInt(b))); break; case opRing4 : SetRaw(a, signal_ring4_xf(g, slotRawObject(a), slotRawInt(b))); break; case opDifSqr : SetRaw(a, signal_difsqr_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSumSqr : SetRaw(a, signal_sumsqr_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSqrSum : SetRaw(a, signal_sqrsum_xf(g, slotRawObject(a), slotRawInt(b))); break; case opSqrDif : SetRaw(a, signal_sqrdif_xf(g, slotRawObject(a), slotRawInt(b))); break; case opAbsDif : SetRaw(a, signal_absdif_xf(g, slotRawObject(a), slotRawInt(b))); break; case opThresh : SetRaw(a, signal_thresh_xf(g, slotRawObject(a), slotRawInt(b))); break; case opAMClip : SetRaw(a, signal_amclip_xf(g, slotRawObject(a), slotRawInt(b))); break; case opScaleNeg : SetRaw(a, signal_scaleneg_xf(g, slotRawObject(a), slotRawInt(b))); break; case opClip2 : SetRaw(a, signal_clip2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFold2 : SetRaw(a, signal_fold2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opWrap2 : SetRaw(a, signal_wrap2_xf(g, slotRawObject(a), slotRawInt(b))); break; case opExcess : SetRaw(a, signal_excess_xf(g, slotRawObject(a), slotRawInt(b))); break; case opFirstArg : SetRaw(a, slotRawObject(a)); break; default : goto send_normal_2; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); else SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { switch (opcode) { case opAdd : SetRaw(a, signal_add_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSub : SetRaw(a, signal_sub_xx(g, slotRawObject(a), slotRawObject(b))); break; case opMul : SetRaw(a, signal_mul_xx(g, slotRawObject(a), slotRawObject(b))); break; case opIDiv : SetRaw(a, signal_div_xx(g, slotRawObject(a), slotRawObject(b))); break; case opFDiv : SetRaw(a, signal_div_xx(g, slotRawObject(a), slotRawObject(b))); break; case opEQ : SetBool(a, signal_equal_xx(g, slotRawObject(a), slotRawObject(b))); break; case opNE : SetBool(a, !signal_equal_xx(g, slotRawObject(a), slotRawObject(b))); break; case opMin : SetRaw(a, signal_min_xx(g, slotRawObject(a), slotRawObject(b))); break; case opMax : SetRaw(a, signal_max_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing1 : SetRaw(a, signal_ring1_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing2 : SetRaw(a, signal_ring2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing3 : SetRaw(a, signal_ring3_xx(g, slotRawObject(a), slotRawObject(b))); break; case opRing4 : SetRaw(a, signal_ring4_xx(g, slotRawObject(a), slotRawObject(b))); break; case opDifSqr : SetRaw(a, signal_difsqr_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSumSqr : SetRaw(a, signal_sumsqr_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSqrSum : SetRaw(a, signal_sqrsum_xx(g, slotRawObject(a), slotRawObject(b))); break; case opSqrDif : SetRaw(a, signal_sqrdif_xx(g, slotRawObject(a), slotRawObject(b))); break; case opAbsDif : SetRaw(a, signal_absdif_xx(g, slotRawObject(a), slotRawObject(b))); break; case opThresh : SetRaw(a, signal_thresh_xx(g, slotRawObject(a), slotRawObject(b))); break; case opAMClip : SetRaw(a, signal_amclip_xx(g, slotRawObject(a), slotRawObject(b))); break; case opScaleNeg : SetRaw(a, signal_scaleneg_xx(g, slotRawObject(a), slotRawObject(b))); break; case opClip2 : SetRaw(a, signal_clip2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opFold2 : SetRaw(a, signal_fold2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opWrap2 : SetRaw(a, signal_wrap2_xx(g, slotRawObject(a), slotRawObject(b))); break; case opExcess : SetRaw(a, signal_excess_xx(g, slotRawObject(a), slotRawObject(b))); break; case opFirstArg : SetRaw(a, slotRawObject(a)); break; default : goto send_normal_2; } } else goto send_normal_2; break; default : // double switch (opcode) { case opAdd : SetRaw(a, signal_add_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSub : SetRaw(a, signal_sub_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opMul : SetRaw(a, signal_mul_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opIDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFDiv : SetRaw(a, signal_div_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetRaw(a, signal_min_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opMax : SetRaw(a, signal_max_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFill : SetRaw(a, signal_fill(slotRawObject(a), slotRawFloat(b))); break; case opRing1 : SetRaw(a, signal_ring1_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opRing2 : SetRaw(a, signal_ring2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opRing3 : SetRaw(a, signal_ring3_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opRing4 : SetRaw(a, signal_ring4_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opDifSqr : SetRaw(a, signal_difsqr_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSumSqr : SetRaw(a, signal_sumsqr_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSqrSum : SetRaw(a, signal_sqrsum_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opSqrDif : SetRaw(a, signal_sqrdif_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opAbsDif : SetRaw(a, signal_absdif_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opThresh : SetRaw(a, signal_thresh_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opAMClip : SetRaw(a, signal_amclip_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opScaleNeg : SetRaw(a, signal_scaleneg_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opClip2 : SetRaw(a, signal_clip2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFold2 : SetRaw(a, signal_fold2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opWrap2 : SetRaw(a, signal_wrap2_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opExcess : SetRaw(a, signal_excess_xf(g, slotRawObject(a), slotRawFloat(b))); break; case opFirstArg : SetRaw(a, slotRawObject(a)); break; default : goto send_normal_2; } break; } } else { goto send_normal_2; } } break; default : { // double switch (GetTag(b)) { case tagInt : switch (opcode) { case opAdd : SetRaw(a, slotRawFloat(a) + slotRawInt(b)); break; case opSub : SetRaw(a, slotRawFloat(a) - slotRawInt(b)); break; case opMul : SetRaw(a, slotRawFloat(a) * slotRawInt(b)); break; case opIDiv : SetInt(a, (long)floor(slotRawFloat(a) / slotRawInt(b))); break; case opFDiv : SetRaw(a, slotRawFloat(a) / slotRawInt(b)); break; case opMod : SetRaw(a, sc_mod(slotRawFloat(a), (double)slotRawInt(b))); break; case opEQ : SetBool(a, slotRawFloat(a) == slotRawInt(b)); break; case opNE : SetBool(a, slotRawFloat(a) != slotRawInt(b)); break; case opLT : SetBool(a, slotRawFloat(a) < slotRawInt(b)); break; case opGT : SetBool(a, slotRawFloat(a) > slotRawInt(b)); break; case opLE : SetBool(a, slotRawFloat(a) <= slotRawInt(b)); break; case opGE : SetBool(a, slotRawFloat(a) >= slotRawInt(b)); break; //case opIdentical : SetFalse(a); break; //case opNotIdentical : SetTrue(a); break; case opMin : SetRaw(a, sc_min(slotRawFloat(a), (double)slotRawInt(b))); break; case opMax : SetRaw(a, sc_max(slotRawFloat(a), (double)slotRawInt(b))); break; case opRound : SetRaw(a, sc_round(slotRawFloat(a), (double)slotRawInt(b))); break; case opRoundUp : SetRaw(a, sc_roundUp(slotRawFloat(a), (double)slotRawInt(b))); break; case opTrunc : SetRaw(a, sc_trunc(slotRawFloat(a), (double)slotRawInt(b))); break; case opAtan2 : SetRaw(a, atan2(slotRawFloat(a), slotRawInt(b))); break; case opHypot : SetRaw(a, hypot(slotRawFloat(a), slotRawInt(b))); break; case opHypotx : SetRaw(a, hypotx(slotRawFloat(a), slotRawInt(b))); break; case opPow : SetRaw(a, pow(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing1 : SetRaw(a, sc_ring1(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing2 : SetRaw(a, sc_ring2(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing3 : SetRaw(a, sc_ring3(slotRawFloat(a), (double)slotRawInt(b))); break; case opRing4 : SetRaw(a, sc_ring4(slotRawFloat(a), (double)slotRawInt(b))); break; case opDifSqr : SetRaw(a, sc_difsqr(slotRawFloat(a), (double)slotRawInt(b))); break; case opSumSqr : SetRaw(a, sc_sumsqr(slotRawFloat(a), (double)slotRawInt(b))); break; case opSqrSum : SetRaw(a, sc_sqrsum(slotRawFloat(a), (double)slotRawInt(b))); break; case opSqrDif : SetRaw(a, sc_sqrdif(slotRawFloat(a), (double)slotRawInt(b))); break; case opAbsDif : SetRaw(a, sc_abs(slotRawFloat(a) - slotRawInt(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawFloat(a), slotRawInt(b))); break; case opAMClip : SetRaw(a, sc_amclip(slotRawFloat(a), (double)slotRawInt(b))); break; case opScaleNeg : SetRaw(a, sc_scaleneg(slotRawFloat(a), (double)slotRawInt(b))); break; case opClip2 : SetRaw(a, sc_clip2(slotRawFloat(a), (double)slotRawInt(b))); break; case opFold2 : SetRaw(a, sc_fold2(slotRawFloat(a), (double)slotRawInt(b))); break; case opWrap2 : SetRaw(a, sc_wrap2(slotRawFloat(a), (double)slotRawInt(b))); break; case opExcess : SetRaw(a, sc_excess(slotRawFloat(a), (double)slotRawInt(b))); break; case opFirstArg : SetRaw(a, slotRawFloat(a)); break; case opRandRange : SetRaw(a, slotRawFloat(a) + g->rgen->frand() * (slotRawInt(b) - slotRawFloat(a))); break; case opExpRandRange : SetRaw(a, g->rgen->exprandrng(slotRawFloat(a), slotRawInt(b))); break; default : goto send_normal_2; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : if (IS_BINARY_BOOL_OP(opcode)) SetBool(a, opcode == opNE); else SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { switch (opcode) { case opAdd : SetObject(a, signal_add_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opSub : SetObject(a, signal_sub_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opMul : SetObject(a, signal_mul_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opIDiv : SetObject(a, signal_div_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opFDiv : SetObject(a, signal_div_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opEQ : SetFalse(a); break; case opNE : SetTrue(a); break; case opMin : SetObject(a, signal_min_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opMax : SetObject(a, signal_max_xf(g, slotRawObject(b), slotRawFloat(a))); break; case opRing1 : SetObject(a, signal_ring1_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opRing2 : SetObject(a, signal_ring2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opRing3 : SetObject(a, signal_ring3_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opRing4 : SetObject(a, signal_ring4_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opDifSqr : SetObject(a, signal_difsqr_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opSumSqr : SetObject(a, signal_sumsqr_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opSqrSum : SetObject(a, signal_sqrsum_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opSqrDif : SetObject(a, signal_sqrdif_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opAbsDif : SetObject(a, signal_absdif_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opThresh : SetObject(a, signal_thresh_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opAMClip : SetObject(a, signal_amclip_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opScaleNeg : SetObject(a, signal_scaleneg_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opClip2 : SetObject(a, signal_clip2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opFold2 : SetObject(a, signal_fold2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opWrap2 : SetObject(a, signal_wrap2_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opExcess : SetObject(a, signal_excess_fx(g, slotRawFloat(a), slotRawObject(b))); break; case opFirstArg : SetObject(a, slotRawObject(a)); break; default : goto send_normal_2; } } else goto send_normal_2; break; default : // double switch (opcode) { case opAdd : SetRaw(a, slotRawFloat(a) + slotRawFloat(b)); break; case opSub : SetRaw(a, slotRawFloat(a) - slotRawFloat(b)); break; case opMul : SetRaw(a, slotRawFloat(a) * slotRawFloat(b)); break; case opIDiv : SetInt(a, (long)floor(slotRawFloat(a) / slotRawFloat(b))); break; case opFDiv : SetRaw(a, slotRawFloat(a) / slotRawFloat(b)); break; case opMod : SetRaw(a, sc_mod(slotRawFloat(a), slotRawFloat(b))); break; case opEQ : SetBool(a, slotRawFloat(a) == slotRawFloat(b)); break; case opNE : SetBool(a, slotRawFloat(a) != slotRawFloat(b)); break; case opLT : SetBool(a, slotRawFloat(a) < slotRawFloat(b)); break; case opGT : SetBool(a, slotRawFloat(a) > slotRawFloat(b)); break; case opLE : SetBool(a, slotRawFloat(a) <= slotRawFloat(b)); break; case opGE : SetBool(a, slotRawFloat(a) >= slotRawFloat(b)); break; //case opIdentical : SetBool(a, slotRawFloat(a) == slotRawFloat(b)); break; //case opNotIdentical : SetBool(a, slotRawFloat(a) != slotRawFloat(b)); break; case opMin : SetRaw(a, sc_min(slotRawFloat(a), slotRawFloat(b))); break; case opMax : SetRaw(a, sc_max(slotRawFloat(a), slotRawFloat(b))); break; case opRound : SetRaw(a, sc_round(slotRawFloat(a), slotRawFloat(b))); break; case opRoundUp : SetRaw(a, sc_roundUp(slotRawFloat(a), slotRawFloat(b))); break; case opTrunc : SetRaw(a, sc_trunc(slotRawFloat(a), slotRawFloat(b))); break; case opAtan2 : SetRaw(a, atan2(slotRawFloat(a), slotRawFloat(b))); break; case opHypot : SetRaw(a, hypot(slotRawFloat(a), slotRawFloat(b))); break; case opHypotx : SetRaw(a, hypotx(slotRawFloat(a), slotRawFloat(b))); break; case opPow : SetRaw(a, pow(slotRawFloat(a), slotRawFloat(b))); break; case opRing1 : SetRaw(a, sc_ring1(slotRawFloat(a), slotRawFloat(b))); break; case opRing2 : SetRaw(a, sc_ring2(slotRawFloat(a), slotRawFloat(b))); break; case opRing3 : SetRaw(a, sc_ring3(slotRawFloat(a), slotRawFloat(b))); break; case opRing4 : SetRaw(a, sc_ring4(slotRawFloat(a), slotRawFloat(b))); break; case opDifSqr : SetRaw(a, sc_difsqr(slotRawFloat(a), slotRawFloat(b))); break; case opSumSqr : SetRaw(a, sc_sumsqr(slotRawFloat(a), slotRawFloat(b))); break; case opSqrSum : SetRaw(a, sc_sqrsum(slotRawFloat(a), slotRawFloat(b))); break; case opSqrDif : SetRaw(a, sc_sqrdif(slotRawFloat(a), slotRawFloat(b))); break; case opAbsDif : SetRaw(a, sc_abs(slotRawFloat(a) - slotRawFloat(b))); break; case opThresh : SetRaw(a, sc_thresh(slotRawFloat(a), slotRawFloat(b))); break; case opAMClip : SetRaw(a, sc_amclip(slotRawFloat(a), slotRawFloat(b))); break; case opScaleNeg : SetRaw(a, sc_scaleneg(slotRawFloat(a), slotRawFloat(b))); break; case opClip2 : SetRaw(a, sc_clip2(slotRawFloat(a), slotRawFloat(b))); break; case opFold2 : SetRaw(a, sc_fold2(slotRawFloat(a), slotRawFloat(b))); break; case opWrap2 : SetRaw(a, sc_wrap2(slotRawFloat(a), slotRawFloat(b))); break; case opExcess : SetRaw(a, sc_excess(slotRawFloat(a), slotRawFloat(b))); break; case opFirstArg : SetRaw(a, slotRawFloat(a)); break; case opRandRange : SetRaw(a, slotRawFloat(a) + g->rgen->frand() * (slotRawFloat(b) - slotRawFloat(a))); break; case opExpRandRange : SetRaw(a, g->rgen->exprandrng(slotRawFloat(a), slotRawFloat(b))); break; default : goto send_normal_2; } break; } } break; } g->sp = a; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (isPrimitive) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[opcode]; sendMessage(g, msg, numArgsPushed); return errNone; } SuperCollider-Source/lang/LangSource/PyrMathSupport.cpp000644 000765 000024 00000133506 12524671173 024345 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "MiscInlineMath.h" #include "SC_RGen.h" #include #include #if defined(__FreeBSD__) || defined(__NetBSD__) # include #endif float centsRatio[128]; float semitoneFreq[128]; /* host function : (move to separate file) */ void pyrmath_init_globs(); void pyrmath_init_globs() { int i; for (i=0; i<128; ++i) { semitoneFreq[i] = 440. * pow(2., (i - 69)/12.); centsRatio[i] = pow(2., i/(12. * 128.)); } } // 1/440 = 0.0022727272727 1/12 = 0.083333333333 #define SQRT2M1 0.41421356f double hypotx(double x, double y); double hypotx(double x, double y) { double minxy; x = fabs(x); y = fabs(y); minxy = sc_min(x,y); return x + y - SQRT2M1 * minxy; } unsigned short primeslist[NUMPRIMES] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, 65519, 65521 }; long nthPrime(int n) { if (n<0 || n>=NUMPRIMES) return 0; return primeslist[n]; } long findPrime(int n) { // binary search of primes table int i, p, lo = 0, hi = NUMPRIMES-1; while (hi>=lo) { i = (lo + hi) >> 1; p = nthPrime(i); if (n==p) return i; if (n=lo) { i = (lo + hi) >> 1; p = nthPrime(i); if (n==p) return i; if (n=lo) { i = (lo + hi) >> 1; p = nthPrime(i); if (n==p) return i; if (n #include #include "PredefinedSymbols.h" #include "PyrObjectProto.h" #include "SCBase.h" #define DEBUGMETHODS 0 #define METHODMETER 0 PyrMethod **gRowTable; PyrSlot keywordstack[MAXKEYSLOTS]; bool gKeywordError = true; extern bool gTraceInterpreter; long cvxUniqueMethods; extern int ivxIdentDict_array; void StoreToImmutableB(VMGlobals *g, PyrSlot *& sp, unsigned char *& ip); void initUniqueMethods() { PyrClass *dummyclass; cvxUniqueMethods = classVarOffset("Object", "uniqueMethods", &dummyclass); } HOT void sendMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed) { PyrMethod *meth = NULL; PyrMethodRaw *methraw; PyrSlot *recvrSlot, *sp; PyrClass *classobj; long index; PyrObject *obj; //postfl("->sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessageWithKeys"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = classOfSlot(recvrSlot); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; g->sp -= numArgsPushed - 1; sp = g->sp; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = classOfSlot(recvrSlot); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstand(g, selector, numArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethod(g, meth, numArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitive(g, meth, numArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; /* case methMultDispatchByClass : { index = methraw->specialIndex; if (index < numArgsPushed) { classobj = slotRawObject(sp + index)->classptr; selector = slotRawSymbol(&meth->selectors); goto lookup_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; case methMultDispatchByValue : { index = methraw->specialIndex; if (index < numArgsPushed) { index = arrayAtIdentityHashInPairs(array, b); meth = slotRawObject(&meth->selectors)->slots[index + 1].uom; goto meth_select_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; */ } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendSuperMessageWithKeys"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; //assert(isKindOfSlot(recvrSlot, classobj)); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstandWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethodWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; g->sp -= numArgsPushed - 1; sp = g->sp; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ numArgsPushed = keywordFixStack(g, meth, methraw, numArgsPushed, numKeyArgsPushed); numKeyArgsPushed = 0; selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitiveWithKeys(g, meth, numArgsPushed, numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendMessage\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "sendSuperMessage"); #endif recvrSlot = g->sp - numArgsPushed + 1; classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; //assert(isKindOfSlot(recvrSlot, classobj)); lookup_again: index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { doesNotUnderstand(g, selector, numArgsPushed); } else { methraw = METHRAW(meth); //postfl("methraw->methType %d\n", methraw->methType); switch (methraw->methType) { case methNormal : /* normal msg send */ executeMethod(g, meth, numArgsPushed); break; case methReturnSelf : /* return self */ g->sp -= numArgsPushed - 1; break; case methReturnLiteral : /* return literal */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &meth->selectors); /* in this case selectors is just a single value */ break; case methReturnArg : /* return an argument */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; // zero is index of the first argument if (index < numArgsPushed) { slotCopy(sp, sp + index); } else { slotCopy(sp, &slotRawObject(&meth->prototypeFrame)->slots[index]); } break; case methReturnInstVar : /* return inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; slotCopy(sp, &slotRawObject(recvrSlot)->slots[index]); break; case methAssignInstVar : /* assign inst var */ sp = g->sp -= numArgsPushed - 1; index = methraw->specialIndex; obj = slotRawObject(recvrSlot); if (obj->IsImmutable()) { StoreToImmutableB(g, sp, g->ip); } else { if (numArgsPushed >= 2) { slotCopy(&obj->slots[index], sp + 1); g->gc->GCWrite(obj, sp + 1); } else { SetNil(&obj->slots[index]); } slotCopy(sp, recvrSlot); } break; case methReturnClassVar : /* return class var */ sp = g->sp -= numArgsPushed - 1; slotCopy(sp, &g->classvars->slots[methraw->specialIndex]); break; case methAssignClassVar : /* assign class var */ sp = g->sp -= numArgsPushed - 1; if (numArgsPushed >= 2) { slotCopy(&g->classvars->slots[methraw->specialIndex], sp + 1); g->gc->GCWrite(g->classvars, sp + 1); } else { SetNil(&g->classvars->slots[methraw->specialIndex]); } slotCopy(sp, recvrSlot); break; case methRedirect : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); goto lookup_again; case methRedirectSuper : /* send a different selector to self, e.g. this.subclassResponsibility */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); classobj = slotRawSymbol(&slotRawClass(&meth->ownerclass)->superclass)->u.classobj; goto lookup_again; case methForwardInstVar : /* forward to an instance variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); index = methraw->specialIndex; slotCopy(recvrSlot, &slotRawObject(recvrSlot)->slots[index]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methForwardClassVar : /* forward to a class variable */ if (numArgsPushed < methraw->numargs) { // not enough args pushed /* push default arg values */ PyrSlot *pslot, *qslot; long m, mmax; pslot = g->sp; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0, mmax=methraw->numargs - numArgsPushed; mnumargs; g->sp += mmax; } selector = slotRawSymbol(&meth->selectors); slotCopy(recvrSlot, &g->classvars->slots[methraw->specialIndex]); classobj = classOfSlot(recvrSlot); goto lookup_again; case methPrimitive : /* primitive */ doPrimitive(g, meth, numArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif break; /* case methMultDispatchByClass : { index = methraw->specialIndex; if (index < numArgsPushed) { classobj = slotRawObject(sp + index)->classptr; selector = slotRawSymbol(&meth->selectors); goto lookup_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; case methMultDispatchByValue : { index = methraw->specialIndex; if (index < numArgsPushed) { index = arrayAtIdentityHashInPairs(array, b); meth = slotRawObject(&meth->selectors)->slots[index + 1].uom; goto meth_select_again; } else { doesNotUnderstand(g, selector, numArgsPushed); } } break; */ } } #if TAILCALLOPTIMIZE g->tailCall = 0; #endif #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "gc->SanityCheck(); #endif // move args up by one to make room for selector qslot = g->sp + 1; pslot = g->sp + 2; pend = pslot - numArgsPushed + 1; while (pslot > pend) *--pslot = *--qslot; selSlot = g->sp - numArgsPushed + 2; SetSymbol(selSlot, selector); g->sp++; recvrSlot = selSlot - 1; classobj = classOfSlot(recvrSlot); index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index; meth = gRowTable[index]; if (slotRawClass(&meth->ownerclass) == class_object) { // lookup instance specific method uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods]; if (isKindOfSlot(uniqueMethodSlot, class_identdict)) { arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, recvrSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; if (isKindOfSlot(slot, class_identdict)) { arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, selSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; slotCopy(selSlot, recvrSlot); slotCopy(recvrSlot, slot); blockValueWithKeys(g, numArgsPushed+1, numKeyArgsPushed); return; } } } } } } } } } executeMethodWithKeys(g, meth, numArgsPushed+1, numKeyArgsPushed); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } int blockValue(struct VMGlobals *g, int numArgsPushed); void doesNotUnderstand(VMGlobals *g, PyrSymbol *selector, long numArgsPushed) { PyrSlot *qslot, *pslot, *pend; long i, index; PyrSlot *uniqueMethodSlot, *arraySlot, *recvrSlot, *selSlot, *slot; PyrClass *classobj; PyrMethod *meth; PyrObject *array; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // move args up by one to make room for selector qslot = g->sp + 1; pslot = g->sp + 2; pend = pslot - numArgsPushed + 1; while (pslot > pend) *--pslot = *--qslot; selSlot = g->sp - numArgsPushed + 2; SetSymbol(selSlot, selector); g->sp++; recvrSlot = selSlot - 1; classobj = classOfSlot(recvrSlot); index = slotRawInt(&classobj->classIndex) + s_nocomprendo->u.index; meth = gRowTable[index]; if (slotRawClass(&meth->ownerclass) == class_object) { // lookup instance specific method uniqueMethodSlot = &g->classvars->slots[cvxUniqueMethods]; if (isKindOfSlot(uniqueMethodSlot, class_identdict)) { arraySlot = slotRawObject(uniqueMethodSlot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, recvrSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; if (isKindOfSlot(slot, class_identdict)) { arraySlot = slotRawObject(slot)->slots + ivxIdentDict_array; if ((IsObj(arraySlot) && (array = slotRawObject(arraySlot))->classptr == class_array)) { i = arrayAtIdentityHashInPairs(array, selSlot); if (i >= 0) { slot = array->slots + i; if (NotNil(slot)) { ++slot; slotCopy(selSlot, recvrSlot); slotCopy(recvrSlot, slot); blockValue(g, numArgsPushed+1); return; } } } } } } } } } executeMethod(g, meth, numArgsPushed+1); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } HOT void executeMethodWithKeys(VMGlobals *g, PyrMethod *meth, long allArgsPushed, long numKeyArgsPushed) { PyrMethodRaw *methraw; PyrFrame *frame; PyrFrame *caller; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrSlot *vars; PyrObject *proto; long i, j, m, mmax, numtemps, numargs, numArgsPushed; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "executeMethodWithKeys"); #endif #if DEBUGMETHODS if (gTraceInterpreter) { if (g->method) { postfl(" %s:%s -> %s:%s\n", slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } else { postfl(" top -> %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } } #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&meth->callMeter)++; } #endif #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 10; proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); numtemps = methraw->numtemps; numargs = methraw->numargs; caller = g->frame; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); //DumpStack(g, g->sp); //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetObject(&frame->context, frame); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, caller); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->method = meth; g->ip = slotRawInt8Array(&meth->code)->b - 1; g->frame = frame; g->block = (PyrBlock*)meth; g->sp -= allArgsPushed; qslot = g->sp; pslot = vars; if (numArgsPushed <= numargs) { /* not enough args pushed */ /* push all args to frame */ for (m=0,mmax=numArgsPushed; mslots + numArgsPushed - 1; for (m=0, mmax=numtemps - numArgsPushed; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ for (m=0,mmax=numargs; mgc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + numargs + 1, list); /* put extra args into list */ lslot = (list->slots - 1); // fixed and raw sizes are zero for (m=0,mmax=i; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs + 1; qslot = proto->slots + numargs; for (m=0,mmax=methraw->numvars; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs; qslot = proto->slots + numargs - 1; for (m=0,mmax=methraw->numvars; mposargs) { PyrSymbol **name0, **name; PyrSlot *key; name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1; key = g->sp + numArgsPushed + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j+1], &key[1]); goto found1; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } found1: ; } } slotCopy(&g->receiver, &vars[1]); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "gc->SanityCheck(); CallStackSanity(g, "executeMethod"); #endif #if DEBUGMETHODS if (gTraceInterpreter) { if (g->method) { postfl(" %s:%s -> %s:%s\n", slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } else { postfl(" top -> %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } } #endif #if METHODMETER if (gTraceInterpreter) { slotRawInt(&meth->callMeter)++; } #endif #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 20; proto = slotRawObject(&meth->prototypeFrame); methraw = METHRAW(meth); numtemps = methraw->numtemps; numargs = methraw->numargs; caller = g->frame; //postfl("executeMethod allArgsPushed %d numKeyArgsPushed %d\n", allArgsPushed, numKeyArgsPushed); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + proto->size; SetObject(&frame->method, meth); SetObject(&frame->homeContext, frame); SetObject(&frame->context, frame); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, caller); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->method = meth; g->ip = slotRawInt8Array(&meth->code)->b - 1; g->frame = frame; g->block = (PyrBlock*)meth; g->sp -= numArgsPushed; qslot = g->sp; pslot = vars; if (numArgsPushed <= numargs) { /* not enough args pushed */ /* push all args to frame */ for (m=0,mmax=numArgsPushed; mslots + numArgsPushed - 1; for (m=0, mmax=numtemps - numArgsPushed; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ for (m=0,mmax=numargs; mgc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + numargs + 1, list); /* put extra args into list */ lslot = (list->slots - 1); // fixed and raw sizes are zero for (m=0,mmax=i; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs + 1; qslot = proto->slots + numargs; for (m=0,mmax=methraw->numvars; mnumvars) { /* push default keyword and var values */ pslot = vars + numargs; qslot = proto->slots + numargs - 1; for (m=0,mmax=methraw->numvars; mreceiver, &vars[1]); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock\n"); //printf("->returnFromBlock\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock"); #endif curframe = g->frame; //again: returnFrame = slotRawFrame(&curframe->caller); if (returnFrame) { block = slotRawBlock(&curframe->method); blockraw = METHRAW(block); g->frame = returnFrame; g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip); g->block = slotRawBlock(&returnFrame->method); homeContext = slotRawFrame(&returnFrame->homeContext); meth = slotRawMethod(&homeContext->method); methraw = METHRAW(meth); slotCopy(&g->receiver, &homeContext->vars[0]); //?? g->method = meth; meth = slotRawMethod(&curframe->method); methraw = METHRAW(meth); if (!methraw->needsHeapContext) { g->gc->Free(curframe); } else { SetInt(&curframe->caller, 0); } } else { ////// this should never happen . error("return from Function at top of call stack.\n"); g->method = NULL; g->block = NULL; g->frame = NULL; g->sp = g->gc->Stack()->slots - 1; longjmp(g->escapeInterpreter, 1); } //if (gTraceInterpreter) postfl("<-returnFromBlock\n"); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); CallStackSanity(g, "returnFromBlock"); #endif } HOT void returnFromMethod(VMGlobals *g) { PyrFrame *returnFrame, *curframe, *homeContext; PyrMethod *meth; PyrMethodRaw *methraw; curframe = g->frame; //assert(slotRawFrame(&curframe->context) == NULL); /*if (gTraceInterpreter) { post("returnFromMethod %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name); post("tailcall %d\n", g->tailCall); }*/ #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif homeContext = slotRawFrame(&slotRawFrame(&curframe->context)->homeContext); if (homeContext == NULL) { null_return: #if TAILCALLOPTIMIZE if (g->tailCall) return; // do nothing. #endif /* static bool once = true; if (once || gTraceInterpreter) { once = false; post("return all the way out. sd %d\n", g->sp - g->gc->Stack()->slots); postfl("%s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name ); post("tailcall %d\n", g->tailCall); post("homeContext %p\n", homeContext); post("returnFrame %p\n", returnFrame); dumpObjectSlot(&homeContext->caller); DumpStack(g, g->sp); DumpBackTrace(g); } gTraceInterpreter = false; */ //if (IsNil(&homeContext->caller)) return; // do nothing. // return all the way out. PyrSlot *bottom = g->gc->Stack()->slots; slotCopy(bottom, g->sp); g->sp = bottom; // ??!! pop everybody g->method = NULL; g->block = NULL; g->frame = NULL; longjmp(g->escapeInterpreter, 2); } else { returnFrame = slotRawFrame(&homeContext->caller); if (returnFrame == NULL) goto null_return; // make sure returnFrame is a caller and find earliest stack frame { PyrFrame *tempFrame = curframe; while (tempFrame != returnFrame) { tempFrame = slotRawFrame(&tempFrame->caller); if (!tempFrame) { if (isKindOf((PyrObject*)g->thread, class_routine) && NotNil(&g->thread->parent)) { // not found, so yield to parent thread and continue searching. PyrSlot value; slotCopy(&value, g->sp); int numArgsPushed = 1; switchToThread(g, slotRawThread(&g->thread->parent), tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. g->sp -= numArgsPushed - 1; slotCopy(g->sp, &value); curframe = tempFrame = g->frame; } else { slotCopy(&g->sp[2], &g->sp[0]); slotCopy(g->sp, &g->receiver); g->sp++; SetObject(g->sp, g->method); g->sp++; sendMessage(g, getsym("outOfContextReturn"), 3); return; } } } } { PyrFrame *tempFrame = curframe; while (tempFrame != returnFrame) { meth = slotRawMethod(&tempFrame->method); methraw = METHRAW(meth); PyrFrame *nextFrame = slotRawFrame(&tempFrame->caller); if (!methraw->needsHeapContext) { SetInt(&tempFrame->caller, 0); } else { if (tempFrame != homeContext) SetInt(&tempFrame->caller, 0); } tempFrame = nextFrame; } } // return to it g->ip = (unsigned char *)slotRawPtr(&returnFrame->ip); g->frame = returnFrame; g->block = slotRawBlock(&returnFrame->method); homeContext = slotRawFrame(&returnFrame->homeContext); meth = slotRawMethod(&homeContext->method); methraw = METHRAW(meth); #if DEBUGMETHODS if (gTraceInterpreter) { postfl("%s:%s <- %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, slotRawSymbol(&slotRawClass(&g->method->ownerclass)->name)->name, slotRawSymbol(&g->method->name)->name ); } #endif g->method = meth; slotCopy(&g->receiver, &homeContext->vars[0]); } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } int keywordFixStack(VMGlobals *g, PyrMethod *meth, PyrMethodRaw *methraw, long allArgsPushed, long numKeyArgsPushed) { PyrSlot *pslot, *qslot; long i, j, m, diff, numArgsPushed, numArgsNeeded; if (numKeyArgsPushed) { // evacuate keyword args to separate area pslot = keywordstack + (numKeyArgsPushed<<1); qslot = g->sp + 1; for (m=0; msp - allArgsPushed + 1; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); numArgsNeeded = methraw->numargs; diff = numArgsNeeded - numArgsPushed; if (diff > 0) { // not enough args pslot = vars + numArgsPushed - 1; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0; mposargs) { PyrSymbol **name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1; PyrSlot *key = keywordstack; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j], &key[1]); goto found; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } found: ; } } g->sp += numArgsPushed - allArgsPushed; return numArgsPushed; } SuperCollider-Source/lang/LangSource/PyrMessage.h000644 000765 000024 00000003757 12321461511 023100 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRMESSAGE_H_ #define _PYRMESSAGE_H_ #include "PyrKernel.h" #define MAXKEYSLOTS 128 extern PyrSlot keywordstack[MAXKEYSLOTS]; extern bool gKeywordError; extern PyrMethod **gRowTable; void initUniqueMethods(); void sendMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed); void sendMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed); void sendSuperMessageWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed); void sendSuperMessage(VMGlobals *g, PyrSymbol *selector, long numArgsPushed); void doesNotUnderstandWithKeys(VMGlobals *g, PyrSymbol *selector, long numArgsPushed, long numKeyArgsPushed); void doesNotUnderstand(VMGlobals *g, PyrSymbol *selector, long numArgsPushed); void returnFromBlock(VMGlobals *g); void returnFromMethod(VMGlobals *g); void executeMethod(VMGlobals *g, PyrMethod *meth, long numArgsPushed); void executeMethodWithKeys(VMGlobals *g, PyrMethod *meth, long allArgsPushed, long numKeyArgsPushed); int keywordFixStack(VMGlobals *g, PyrMethod *meth, PyrMethodRaw *methraw, long allArgsPushed, long numKeyArgsPushed); #endif SuperCollider-Source/lang/LangSource/PyrObject.cpp000644 000765 000024 00000255042 12760322424 023257 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "GC.h" #include "PyrMessage.h" #include "PyrInterpreter.h" #include "PyrSymbolTable.h" #include "PyrObjectProto.h" #include "PyrKernelProto.h" #include "PyrLexer.h" #include "InitAlloc.h" #include "Hash.h" #include "SC_Constants.h" #include "SC_Alloca.h" #include "SC_Lock.h" #include #include #include #include #define BOOST_THREAD_VERSION 4 #define BOOST_THREAD_PROVIDES_EXECUTORS #include #include #include #ifdef _MSC_VER #include #endif #if 0 // not yet #include #endif PyrClass *gClassList = NULL; int gNumSelectors = 0; int gNumClasses = 0; int gNumClassVars = 0; int gFormatElemSize[NUMOBJFORMATS]; int gFormatElemCapc[NUMOBJFORMATS]; int gFormatElemTag[NUMOBJFORMATS]; PyrMethod *gNullMethod; // used to fill row table PyrClass* gTagClassTable[16]; PyrClass *class_object; PyrClass *class_dict; PyrClass *class_array; PyrClass *class_list, *class_method, *class_fundef, *class_frame, *class_class; PyrClass *class_symbol, *class_nil; PyrClass *class_boolean, *class_true, *class_false; PyrClass *class_int, *class_char, *class_float, *class_complex; PyrClass *class_rawptr; PyrClass *class_string; PyrClass *class_magnitude, *class_number, *class_collection, *class_ordered_collection; PyrClass *class_arrayed_collection; PyrClass *class_sequenceable_collection; PyrClass *class_simple_number; PyrClass *class_rawarray; PyrClass *class_signal; PyrClass *class_wavetable; PyrClass *class_floatarray; PyrClass *class_int8array; PyrClass *class_int16array; PyrClass *class_int32array; PyrClass *class_symbolarray; PyrClass *class_doublearray; PyrClass *class_func, *class_absfunc; PyrClass *class_stream; PyrClass *class_process; PyrClass *class_interpreter; PyrClass *class_thread; PyrClass *class_routine; PyrClass *class_finalizer; PyrClass *class_server_shm_interface; PyrSymbol *s_none; PyrSymbol *s_object; PyrSymbol *s_bag; PyrSymbol *s_set; PyrSymbol *s_identityset; PyrSymbol *s_dictionary; PyrSymbol *s_identitydictionary; PyrSymbol *s_linkedlist; PyrSymbol *s_sortedlist; PyrSymbol *s_array; PyrSymbol *s_list, *s_method, *s_fundef, *s_frame, *s_class; PyrSymbol *s_symbol, *s_nil; PyrSymbol *s_boolean, *s_true, *s_false; PyrSymbol *s_int, *s_char, *s_color, *s_float, *s_complex; PyrSymbol *s_rawptr, *s_objptr; PyrSymbol *s_string; PyrSymbol *s_magnitude, *s_number, *s_collection, *s_ordered_collection; PyrSymbol *s_arrayed_collection; PyrSymbol *s_sequenceable_collection; PyrSymbol *s_simple_number; PyrSymbol *s_signal; PyrSymbol *s_wavetable; PyrSymbol *s_rawarray; PyrSymbol *s_int8array; PyrSymbol *s_int16array; PyrSymbol *s_int32array; PyrSymbol *s_symbolarray; PyrSymbol *s_doublearray; PyrSymbol *s_floatarray; PyrSymbol *s_point; PyrSymbol *s_rect; PyrSymbol *s_func, *s_absfunc; PyrSymbol *s_stream; PyrSymbol *s_process; PyrSymbol *s_main; PyrSymbol *s_thread; PyrSymbol *s_routine; PyrSymbol *s_task; PyrSymbol *s_prstart; PyrSymbol *s_interpreter; PyrSymbol *s_finalizer; PyrSymbol *s_awake; PyrSymbol *s_appclock; PyrSymbol *s_systemclock; PyrSymbol *s_server_shm_interface; PyrSymbol *s_interpretCmdLine, *s_interpretPrintCmdLine; PyrSymbol *s_nocomprendo; PyrSymbol *s_curProcess, *s_curMethod, *s_curBlock, *s_curClosure, *s_curThread; //PyrSymbol *s_sampleRate; //PyrSymbol *s_audioClock, *s_logicalClock; PyrSymbol *s_run, *s_stop, *s_tick; PyrSymbol *s_startup; PyrSymbol *s_docmdline; PyrSymbol *s_audio; PyrSymbol *s_control; PyrSymbol *s_scalar; PyrSymbol *s_next; PyrSymbol *s_env; PyrSymbol *s_ugen, *s_outputproxy; PyrSymbol *s_new, *s_ref, *s_value, *s_at, *s_put; PyrSymbol *s_performList, *s_superPerformList; PyrSymbol *s_series, *s_copyseries, *s_putseries; PyrSymbol *s_envirGet, *s_envirPut; PyrSymbol *s_synth, *s_spawn, *s_environment, *s_event; PyrSymbol *s_hardwaresetup, *s_shutdown; PyrSymbol *s_linear, *s_exponential, *s_gate; PyrSymbol *s_super, *s_this; PyrSlot o_nil, o_true, o_false, o_end; PyrSlot o_pi, o_twopi; PyrSlot o_fhalf, o_fnegone, o_fzero, o_fone, o_ftwo, o_inf; PyrSlot o_negtwo, o_negone, o_zero, o_one, o_two; PyrSlot o_nullframe, o_none; PyrSlot o_emptyarray, o_onenilarray, o_argnamethis; void initSymbols() { s_new = getsym("new"); s_ref = getsym("Ref"); s_none = getsym("none"); s_object = getsym("Object"); s_this = getsym("this"); s_super = getsym("super"); s_dictionary = getsym("Dictionary"); s_bag = getsym("Bag"); s_set = getsym("Set"); s_identityset = getsym("IdentitySet"); s_identitydictionary = getsym("IdentityDictionary"); s_linkedlist = getsym("LinkedList"); s_sortedlist = getsym("SortedList"); s_array = getsym("Array"); s_list = getsym("List"); s_method = getsym("Method"); s_fundef = getsym("FunctionDef"); s_frame = getsym("Frame"); s_class = getsym("Class"); s_symbol = getsym("Symbol"); s_nil = getsym("Nil"); s_true = getsym("True"); s_false = getsym("False"); s_int = getsym("Integer"); s_float = getsym("Float"); s_char = getsym("Char"); s_color = getsym("Color"); s_rawptr = getsym("RawPointer"); s_objptr = getsym("ObjectPointer"); s_string = getsym("String"); s_magnitude = getsym("Magnitude"); s_number = getsym("Number"); s_simple_number = getsym("SimpleNumber"); s_collection = getsym("Collection"); //s_ordered_collection = getsym("OrderedCollection"); s_arrayed_collection = getsym("ArrayedCollection"); s_sequenceable_collection = getsym("SequenceableCollection"); s_boolean = getsym("Boolean"); s_signal = getsym("Signal"); s_wavetable = getsym("Wavetable"); //s_signalnode = getsym("SignalNode"); s_rawarray = getsym("RawArray"); s_int8array = getsym("Int8Array"); s_int16array = getsym("Int16Array"); s_int32array = getsym("Int32Array"); s_symbolarray = getsym("SymbolArray"); s_floatarray = getsym("FloatArray"); s_doublearray = getsym("DoubleArray"); s_complex = getsym("Complex"); s_point = getsym("Point"); s_rect = getsym("Rect"); s_absfunc = getsym("AbstractFunction"); s_func = getsym("Function"); s_stream = getsym("Stream"); s_process = getsym("Process"); s_main = getsym("Main"); s_thread = getsym("Thread"); s_routine = getsym("Routine"); s_task = getsym("Task"); s_prstart = getsym("prStart"); s_interpreter = getsym("Interpreter"); s_finalizer = getsym("Finalizer"); s_awake = getsym("awake"); s_appclock = getsym("AppClock"); s_systemclock = getsym("SystemClock"); s_server_shm_interface = getsym("ServerShmInterface"); s_linear = getsym("linear"); s_exponential = getsym("exponential"); s_gate = getsym("gate"); //s_dsp = getsym("DSP"); //s_dspsettings = getsym("DSPSettings"); s_synth = getsym("Synth"); s_spawn = getsym("BasicSpawn"); s_environment = getsym("Environment"); s_event = getsym("Event"); s_hardwaresetup = getsym("hardwareSetup"); s_shutdown = getsym("shutdown"); s_interpretCmdLine = getsym("interpretCmdLine"); s_interpretPrintCmdLine = getsym("interpretPrintCmdLine"); s_nocomprendo = getsym("doesNotUnderstand"); s_curProcess = getsym("thisProcess"); s_curThread = getsym("thisThread"); s_curMethod = getsym("thisMethod"); s_curBlock = getsym("thisFunctionDef"); s_curClosure = getsym("thisFunction"); //s_sampleRate = getsym("gSR"); //s_logicalClock = getsym("gTime"); //s_audioClock = getsym("gAudioTime"); s_audio = getsym("audio"); s_control = getsym("control"); s_scalar = getsym("scalar"); s_run = getsym("run"); s_stop = getsym("stop"); s_tick = getsym("tick"); s_startup = getsym("startup"); s_docmdline = getsym("doCmdLine"); s_next = getsym("next"); s_value = getsym("value"); s_performList = getsym("performList"); s_superPerformList = getsym("superPerformList"); s_at = getsym("at"); s_put = getsym("put"); s_series = getsym("prSimpleNumberSeries"); s_copyseries = getsym("copySeries"); s_putseries = getsym("putSeries"); s_ugen = getsym("UGen"); s_outputproxy = getsym("OutputProxy"); s_env = getsym("Env"); s_envirGet = getsym("envirGet"); s_envirPut = getsym("envirPut"); SetNil(&o_nil); SetFalse(&o_false); SetTrue(&o_true); SetFloat(&o_pi, pi); SetFloat(&o_twopi, twopi); SetFloat(&o_fhalf, .5); SetFloat(&o_fnegone, -1.); SetFloat(&o_fzero, 0.); SetFloat(&o_fone, 1.); SetFloat(&o_ftwo, 2.); SetInt(&o_negtwo, -2); SetInt(&o_negone, -1); SetInt(&o_zero, 0); SetInt(&o_one, 1); SetInt(&o_two, 2); SetSymbol(&o_none, s_none); SetFloat(&o_inf, std::numeric_limits::infinity()); slotCopy(&gSpecialValues[svNil], &o_nil); slotCopy(&gSpecialValues[svFalse], &o_false); slotCopy(&gSpecialValues[svTrue], &o_true); slotCopy(&gSpecialValues[svNegOne], &o_negone); slotCopy(&gSpecialValues[svZero], &o_zero); slotCopy(&gSpecialValues[svOne], &o_one); slotCopy(&gSpecialValues[svTwo], &o_two); slotCopy(&gSpecialValues[svFHalf], &o_fhalf); slotCopy(&gSpecialValues[svFNegOne], &o_fnegone); slotCopy(&gSpecialValues[svFZero], &o_fzero); slotCopy(&gSpecialValues[svFOne], &o_fone); slotCopy(&gSpecialValues[svFTwo], &o_ftwo); slotCopy(&gSpecialValues[svInf], &o_inf); gFormatElemSize[obj_notindexed] = sizeof(PyrSlot); gFormatElemSize[obj_slot ] = sizeof(PyrSlot); gFormatElemSize[obj_double] = sizeof(double); gFormatElemSize[obj_float ] = sizeof(float); gFormatElemSize[obj_int32 ] = sizeof(int32); gFormatElemSize[obj_int16 ] = sizeof(int16); gFormatElemSize[obj_int8 ] = sizeof(int8); gFormatElemSize[obj_char ] = sizeof(char); gFormatElemSize[obj_symbol ] = sizeof(PyrSymbol*); gFormatElemCapc[obj_notindexed] = sizeof(PyrSlot) / sizeof(PyrSlot); gFormatElemCapc[obj_slot ] = sizeof(PyrSlot) / sizeof(PyrSlot); gFormatElemCapc[obj_double] = sizeof(PyrSlot) / sizeof(double); gFormatElemCapc[obj_float ] = sizeof(PyrSlot) / sizeof(float); gFormatElemCapc[obj_int32 ] = sizeof(PyrSlot) / sizeof(int32); gFormatElemCapc[obj_int16 ] = sizeof(PyrSlot) / sizeof(int16); gFormatElemCapc[obj_int8 ] = sizeof(PyrSlot) / sizeof(int8); gFormatElemCapc[obj_char ] = sizeof(PyrSlot) / sizeof(char); gFormatElemCapc[obj_symbol] = sizeof(PyrSlot) / sizeof(PyrSymbol*); gFormatElemTag[obj_notindexed] = -1; gFormatElemTag[obj_slot ] = -1; gFormatElemTag[obj_double] = 0; gFormatElemTag[obj_float ] = 0; gFormatElemTag[obj_int32 ] = tagInt; gFormatElemTag[obj_int16 ] = tagInt; gFormatElemTag[obj_int8 ] = tagInt; gFormatElemTag[obj_char ] = tagChar; gFormatElemTag[obj_symbol] = tagSym; } const char *slotSymString(PyrSlot* slot) { switch (GetTag(slot)) { case tagObj : return slotRawSymbol(&slotRawObject(slot)->classptr->name)->name; case tagInt : return "Integer"; case tagChar : return "Char"; case tagSym : return slotRawSymbol(slot)->name; case tagNil : return "Nil"; case tagFalse : return "False"; case tagTrue : return "True"; default : return ""; } } PyrClass* newClassObj(PyrClass *classObjSuperClass, PyrSymbol* className, PyrSymbol* superClassName, int numInstVars, int numClassVars, int numConsts, int numInstMethods, int instFormat, int instFlags) { PyrClass* classobj, *superclassobj; PyrObject* array; PyrSymbolArray *symarray; int classFlags; /*{ int c; c = className->name[0]; if (!(c >= 'A' && c <= 'Z')) Debugger(); }*/ // pyrmalloc: // lifetime: kill upon recompiling library classobj = (PyrClass*)pyr_pool_runtime->Alloc(sizeof(PyrClass)); MEMFAIL(classobj); classobj->size = (sizeof(PyrClass) - sizeof(PyrObjectHdr))/sizeof(PyrSlot); classobj->prev = classobj->next = NULL; classobj->obj_flags = obj_immutable ; classobj->obj_format = obj_notindexed ; classobj->gc_color = obj_permanent ; classobj->obj_sizeclass = LOG2CEIL(classobj->size); classobj->classptr = classObjSuperClass; // append to the list of classes if (gClassList) SetObject(&classobj->nextclass, gClassList); else SetNil(&classobj->nextclass); gClassList = classobj; className->u.classobj = classobj; //postfl("> '%s' %d %d\n", className->name, className, classobj); SetSymbol(&classobj->name, className); if (superClassName) { SetSymbol(&classobj->superclass, superClassName); superclassobj = superClassName->u.classobj; } else { SetSymbol(&classobj->superclass, s_none); superclassobj = NULL; } SetInt(&classobj->subclasses, 0); // to be filled with subclasses later // in the meantime it is used as a tally of subclasses so that its allocation // size can be known if (numInstMethods) { array = newPyrArray(NULL, numInstMethods, obj_permanent | obj_immutable, false); SetObject(&classobj->methods, array); } else { SetNil(&classobj->methods); } if (numInstVars) { symarray = newPyrSymbolArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->instVarNames, symarray); array = newPyrArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->iprototype, array); nilSlots(array->slots, numInstVars); } else { SetNil(&classobj->instVarNames); SetNil(&classobj->iprototype); } if (numClassVars) { symarray = newPyrSymbolArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->classVarNames, symarray); array = newPyrArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->cprototype, array); nilSlots(array->slots, numClassVars); } else { SetNil(&classobj->classVarNames); SetNil(&classobj->cprototype); } if (numConsts) { symarray = newPyrSymbolArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constNames, symarray); array = newPyrArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constValues, array); nilSlots(array->slots, numConsts); } else { SetNil(&classobj->constNames); SetNil(&classobj->constValues); } classFlags = 0; if (instFormat != obj_notindexed) { classFlags |= classHasIndexableInstances; } SetInt(&classobj->instanceFormat, instFormat); SetInt(&classobj->instanceFlags, instFlags); SetInt(&classobj->classIndex, -1); SetInt(&classobj->classFlags, classFlags); SetInt(&classobj->maxSubclassIndex, 0); SetNil(&classobj->filenameSym); SetInt(&classobj->charPos, 0); SetInt(&classobj->classVarIndex, gNumClassVars); //if (numClassVars) post("%16s %4d %4d\n", className->name, gNumClassVars, numClassVars); gNumClassVars += numClassVars; return classobj; } void reallocClassObj(PyrClass* classobj, int numInstVars, int numClassVars, int numConsts, int numMethods, int instFormat, int instFlags) { PyrObject* array; PyrSymbolArray *symarray; PyrClass *superclassobj; freePyrSlot(&classobj->methods); freePyrSlot(&classobj->instVarNames); freePyrSlot(&classobj->classVarNames); freePyrSlot(&classobj->iprototype); freePyrSlot(&classobj->cprototype); freePyrSlot(&classobj->constNames); freePyrSlot(&classobj->constValues); if (numMethods) { array = newPyrArray(NULL, numMethods, obj_permanent | obj_immutable, false); SetObject(&classobj->methods, array); } else { SetNil(&classobj->methods); } if (numInstVars) { //post("reallocClassObj %s numInstVars %d\n", slotRawSymbol(&classobj->name)->name, numInstVars); symarray = newPyrSymbolArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->instVarNames, symarray); array = newPyrArray(NULL, numInstVars, obj_permanent | obj_immutable, false); SetObject(&classobj->iprototype, array); nilSlots(array->slots, numInstVars); } else { SetNil(&classobj->instVarNames); SetNil(&classobj->iprototype); } if (numClassVars) { //post("reallocClassObj %s numClassVars %d\n", slotRawSymbol(&classobj->name)->name, numClassVars); symarray = newPyrSymbolArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->classVarNames, symarray); nilSlots(array->slots, numClassVars); array = newPyrArray(NULL, numClassVars, obj_permanent | obj_immutable, false); SetObject(&classobj->cprototype, array); nilSlots(array->slots, numClassVars); } else { SetNil(&classobj->classVarNames); SetNil(&classobj->cprototype); } if (numConsts) { //post("reallocClassObj %s numConsts %d\n", slotRawSymbol(&classobj->name)->name, numConsts); symarray = newPyrSymbolArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constNames, symarray); array = newPyrArray(NULL, numConsts, obj_permanent | obj_immutable, false); SetObject(&classobj->constValues, array); nilSlots(array->slots, numConsts); } else { SetNil(&classobj->constNames); SetNil(&classobj->constValues); } superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; SetInt(&classobj->instanceFormat, instFormat); SetInt(&classobj->instanceFlags, instFlags); SetInt(&classobj->classIndex, -1); } void fixClassArrays(PyrClass *classobj); void fixClassArrays(PyrClass *classobj) { if (IsObj(&classobj->methods)) slotRawObject(&classobj->methods)->classptr = class_array; if (IsObj(&classobj->instVarNames)) slotRawObject(&classobj->instVarNames)->classptr = class_symbolarray; if (IsObj(&classobj->classVarNames)) slotRawObject(&classobj->classVarNames)->classptr = class_symbolarray; if (IsObj(&classobj->iprototype)) slotRawObject(&classobj->iprototype)->classptr = class_array; if (IsObj(&classobj->cprototype)) slotRawObject(&classobj->cprototype)->classptr = class_array; } int numInstVars(PyrClass* classobj) { int res; if (IsNil(&classobj->instVarNames)) res = 0; else res = slotRawObject(&classobj->instVarNames)->size; return res; } int numClassVars(PyrClass* classobj) { int res; if (IsNil(&classobj->classVarNames)) res = 0; else res = slotRawObject(&classobj->classVarNames)->size; return res; } void objAddIndexedSlotGrow(PyrSlot *arraySlot, PyrSlot *addSlot); void objAddIndexedSlotGrow(PyrSlot *arraySlot, PyrSlot *addSlot) { PyrObject *obj; if (IsNil(arraySlot)) { PyrObject *newobj = (PyrObject*)newPyrArray(NULL, 1, obj_permanent | obj_immutable, false); SetObject(arraySlot, newobj); obj = newobj; } else { obj = slotRawObject(arraySlot); if (obj->size >= ARRAYMAXINDEXSIZE(obj)) { //post("objAddIndexedSlotGrow\n"); PyrObject *newobj = (PyrObject*)newPyrArray(NULL, obj->size * 2, obj_permanent | obj_immutable, false); memcpy(newobj->slots, obj->slots, obj->size * sizeof(PyrSlot)); newobj->size = obj->size; SetObject(arraySlot, newobj); pyr_pool_runtime->Free((void*)obj); obj = newobj; } } slotCopy(&obj->slots[obj->size++], addSlot); } void addMethod(PyrClass *classobj, PyrMethod *method) { PyrSlot slot; SetObject(&slot, method); objAddIndexedSlotGrow(&classobj->methods, &slot); } PyrMethod* classFindDirectMethod(PyrClass* classobj, PyrSymbol *name) { PyrMethod *method; PyrSlot *methods; int i, numMethods; if (IsNil(&classobj->methods)) return NULL; methods = slotRawObject(&classobj->methods)->slots; numMethods = slotRawObject(&classobj->methods)->size; for (i=0; iname) == name) break; } if (i>=numMethods) method = NULL; return method; } int numSuperInstVars(PyrClass *superclassobj) { int superinstvars = 0; if (superclassobj) { if (IsObj(&superclassobj->iprototype)) { superinstvars = slotRawObject(&superclassobj->iprototype)->size; } } return superinstvars; } bool classFindInstVar(PyrClass* classobj, PyrSymbol *name, int *index) { PyrSymbolArray *ivnames; PyrSymbol *ivname; int i; if (NotNil(&classobj->instVarNames)) { ivnames = slotRawSymbolArray(&classobj->instVarNames); if (ivnames) { for (i=0; isize; ++i) { ivname = ivnames->symbols[i]; if (ivname == name) { //numsupervars = numSuperInstVars(slotRawSymbol(&classobj->superclass)->u.classobj); //*index = numsupervars + i; *index = i; return true; } } } } return false; } int instVarOffset(const char *classname, const char *instvarname) { PyrSymbol *instvarsymbol, *classsymbol; PyrClass* classobj; int index; char c; classsymbol = getsym(classname); instvarsymbol = getsym(instvarname); c = classname[0]; if (!(c >= 'A' && c <= 'Z')) return -1; classobj = classsymbol->u.classobj; if (!classobj) return -1; if (!classFindInstVar(classobj, instvarsymbol, &index)) return -1; return index; } int classVarOffset(const char *classname, const char *classvarname, PyrClass** classobj) { PyrSymbol *classvarsymbol, *classsymbol; int index; char c; classsymbol = getsym(classname); classvarsymbol = getsym(classvarname); c = classname[0]; if (!(c >= 'A' && c <= 'Z')) return -1; *classobj = classsymbol->u.classobj; if (!*classobj) return -1; if (!classFindClassVar(classobj, classvarsymbol, &index)) return -1; return index; } bool classFindClassVar(PyrClass** classobj, PyrSymbol *name, int *index) { PyrSymbolArray *cvnames; PyrSymbol *cvname; int i, j; char *classname; PyrClass* localclassobj = *classobj; // if this is a Metaclass then we need to search its normal Class for // the class vars classname = slotRawSymbol(&localclassobj->name)->name; if (strncmp(classname, "Meta_", 5) == 0) { localclassobj = getsym(classname+5)->u.classobj; } for (j=0; localclassobj; ++j) { if (NotNil(&localclassobj->classVarNames)) { cvnames = slotRawSymbolArray(&localclassobj->classVarNames); if (cvnames) { for (i=0; isize; ++i) { cvname = cvnames->symbols[i]; if (cvname == name) { *classobj = localclassobj; *index = i; return true; } } } } if (IsSym(&localclassobj->superclass)) { localclassobj = slotRawSymbol(&localclassobj->superclass)->u.classobj; } else { localclassobj = NULL; } } return false; } bool classFindConst(PyrClass** classobj, PyrSymbol *name, int *index) { PyrSymbolArray *knames; PyrSymbol *kname; int i, j; char *classname; PyrClass* localclassobj = *classobj; // if this is a Metaclass then we need to search its normal Class for // the class vars classname = slotRawSymbol(&localclassobj->name)->name; if (strncmp(classname, "Meta_", 5) == 0) { localclassobj = getsym(classname+5)->u.classobj; } for (j=0; localclassobj; ++j) { if (NotNil(&localclassobj->constNames)) { knames = slotRawSymbolArray(&localclassobj->constNames); if (knames) { for (i=0; isize; ++i) { kname = knames->symbols[i]; if (kname == name) { *classobj = localclassobj; *index = i; return true; } } } } if (IsSym(&localclassobj->superclass)) { localclassobj = slotRawSymbol(&localclassobj->superclass)->u.classobj; } else { localclassobj = NULL; } } return false; } struct compareByName { bool operator()(PyrClass * lhs, PyrClass * rhs) const { return strcmp(slotRawSymbol(&lhs->name)->name, slotRawSymbol(&rhs->name)->name) < 0; } }; template class pyr_pool_compile_allocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef pyr_pool_compile_allocator other; }; pyr_pool_compile_allocator(void) {} template pyr_pool_compile_allocator(pyr_pool_compile_allocator const &) {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type n, const void* hint = 0) { return (pointer)pyr_pool_compile->Alloc(n*sizeof(T)); } void deallocate(pointer p, size_type n) { pyr_pool_compile->Free(p); } void construct(pointer p, const T& val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } }; /* sort list of classes: * we fill a binary search tree * */ static PyrClass * sortClasses(PyrClass * aClassList) { typedef std::set > classSetType; classSetType classSet; PyrClass * insertHead = aClassList; do { assert(classSet.find(insertHead) == classSet.end()); classSet.insert(insertHead); insertHead = slotRawClass(&insertHead->nextclass); } while (insertHead); classSetType::iterator it = classSet.begin(); PyrClass * sortedClasses = *it; ++it; PyrClass * lastClass = sortedClasses; for (; it != classSet.end(); ++it) { PyrClass * current = *it; SetObject(&lastClass->nextclass, (PyrObject*)current); lastClass = current; } SetNil(&lastClass->nextclass); return sortedClasses; } void buildClassTree() { // after all classes are compiled this function builds the tree and // indexes the classes // count subclasses //postfl("count subclasses\n"); PyrClass *classobj = gClassList; while (classobj) { PyrClass * superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; if (superclassobj) { //postfl(" superclassobj %s\n", slotRawSymbol(&superclassobj->name)->name); SetRaw(&superclassobj->subclasses, slotRawInt(&superclassobj->subclasses) + 1); } classobj = slotRawClass(&classobj->nextclass); } // allocate subclass arrays //postfl("allocate subclass arrays\n"); classobj = gClassList; while (classobj) { int numSubclasses; numSubclasses = slotRawInt(&classobj->subclasses); //postfl(" %s %d\n", slotRawSymbol(&classobj->name)->name, numSubclasses); if (numSubclasses) { SetObject(&classobj->subclasses, (PyrObject*)newPyrArray(NULL, numSubclasses, obj_permanent | obj_immutable, false)); slotRawObject(&classobj->subclasses)->size = 0; } else { SetNil(&classobj->subclasses); } classobj = slotRawClass(&classobj->nextclass); } // fill in subclass arrays //postfl("fill in subclass arrays\n"); classobj = gClassList; while (classobj) { //postfl(" %s\n", slotRawSymbol(&classobj->name)->name); PyrClass *superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; if (superclassobj) { objAddIndexedObject(slotRawObject(&superclassobj->subclasses), (PyrObject*)classobj); //postfl(" superclassobj %s %d\n", slotRawSymbol(&superclassobj->name)->name, // slotRawObject(&superclassobj->subclasses)->size); } classobj = slotRawClass(&classobj->nextclass); } // alpha sort the classes via insertion sort gClassList = sortClasses(gClassList); } void indexClassTree(PyrClass *classobj, int numSuperMethods) { int i, numMethods; if (!classobj) return; SetInt(&classobj->classIndex, gNumClasses); gNumClasses ++; if (IsObj(&classobj->methods)) { PyrObject * methods = slotRawObject(&classobj->methods); numMethods = methods->size; } else numMethods = 0; numMethods = numSuperMethods + numMethods; if (IsObj(&classobj->subclasses)) { PyrObject * subclasses = slotRawObject(&classobj->subclasses); for (i=0; isize; ++i) indexClassTree(slotRawClass(&subclasses->slots[i]), numMethods); } SetInt(&classobj->maxSubclassIndex, gNumClasses - 1); } void findDiscrepancy(); void findDiscrepancy() { PyrClass *classobjA, *classobjB; classobjA = gClassList; while (classobjA) { classobjB = slotRawClass(&classobjA->nextclass);; while (classobjB) { if (slotRawSymbol(&classobjA->name) == slotRawSymbol(&classobjB->name)) { post("duplicate %s\n", slotRawSymbol(&classobjA->name)->name); } classobjB = slotRawClass(&classobjB->nextclass); } classobjA = slotRawClass(&classobjA->nextclass); } } static void indent(int n) { for (int i=0; iclassIndex)); indent(level); post("%s\n", slotRawSymbol(&classobj->name)->name); if (classobj == class_class) { indent(level+1); post(" [.. all metaclasses ..]\n"); } else { if (IsNil(&classobj->subclasses)) return; // FIXME: can we initialize subclasses with a NULL pointer? subclasses = slotRawObject(&classobj->subclasses); if (subclasses) { // determine if can put on one line bool oneline = subclasses->size <= 5; for (i=0; oneline && isize; ++i) { PyrClass *subclassobj = slotRawClass(&subclasses->slots[i]); if (IsObj(&subclassobj->subclasses)) // FIXME: shall we do a null-pointer check? oneline = false; } if (oneline) { indent(level+1); post("["); for (i=0; isize; ++i) { PyrClass *subclassobj = slotRawClass(&subclasses->slots[i]); post(" %s", slotRawSymbol(&subclassobj->name)->name); } post(" ]\n"); } else { indent(level); post("[\n"); for (i=0; isize; ++i) { postClassTree(slotRawClass(&subclasses->slots[i]), level+1); } indent(level); post("]\n"); } } } } void setSelectorFlags() { int i; PyrClass * classobj = gClassList; while (classobj) { if (IsObj(&classobj->methods)) { PyrObject *methods = slotRawObject(&classobj->methods); for (i=0; isize; ++i) { PyrMethod * method = slotRawMethod(&methods->slots[i]); slotRawSymbol(&method->name)->flags |= sym_Selector; //if (method->methType == methRedirect) { // post("rd: %3d %s:%s\n", k++, slotRawSymbol(&classobj->name)->name, // slotRawSymbol(&method->name)->name); //} } } classobj = slotRawClass(&classobj->nextclass); } // count selectors gNumSelectors = 0; SymbolTable* symbolTable = gMainVMGlobals->symbolTable; for (int i=0; iTableSize(); ++i) { PyrSymbol *sym = symbolTable->Get(i); if (sym && (sym->flags & sym_Selector)) { sym->u.index = gNumSelectors++; } } //post("gNumSelectors %d\n", gNumSelectors); } // the chunky stuff can be commented back in for implementing a better // compression scheme. The Q&D method works fine for my small class tree for now. typedef struct { PyrSymbol *selector; int minClassIndex; int maxClassIndex; int rowWidth; //int largestChunk; //int chunkOffset; int selectorIndex; int population; int rowOffset; } ColumnDescriptor; int compareColDescs(const void *va, const void *vb); int compareColDescs(const void *va, const void *vb) { ColumnDescriptor *a = (ColumnDescriptor*)va; ColumnDescriptor *b = (ColumnDescriptor*)vb; int diff; //diff = b->largestChunk - a->largestChunk; //if (diff != 0) return diff; diff = b->rowWidth - a->rowWidth; if (diff != 0) return diff; //diff = b->chunkOffset - a->chunkOffset; diff = b->minClassIndex - a->minClassIndex; return diff; } #define CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME 0 #if CHECK_METHOD_LOOKUP_TABLE_BUILD_TIME double elapsedTime(); #endif #ifdef _MSC_VER static size_t fillClassRows(const PyrClass *classobj, PyrMethod** bigTable); #else static size_t fillClassRows(const PyrClass *classobj, PyrMethod** bigTable, boost::basic_thread_pool & pool); #endif static void binsortClassRows(PyrMethod const ** bigTable, const ColumnDescriptor* sels, size_t numSelectors, size_t begin, size_t end) { // bin sort the class rows to the new ordering //post("reorder rows\n"); const int allocaThreshold = 16384; PyrMethod** temprow = (numSelectors < allocaThreshold) ? (PyrMethod**)alloca(numSelectors * sizeof(PyrMethod*)) : (PyrMethod**)malloc(numSelectors * sizeof(PyrMethod*)); for (int j=begin; j= allocaThreshold) free(temprow); } static ColumnDescriptor * prepareColumnTable(ColumnDescriptor * sels, int numSelectors) { // fill selector table //post("fill selector table\n"); SymbolTable* symbolTable = gMainVMGlobals->symbolTable; int selectorTableIndex = 0; for( int i : boost::irange(0, symbolTable->TableSize()) ) { PyrSymbol *sym = symbolTable->Get(i); if (sym && (sym->flags & sym_Selector)) sels[selectorTableIndex++].selector = sym; } assert( selectorTableIndex == numSelectors ); for (int i=0; iname); sels[i].minClassIndex = INT_MAX; sels[i].maxClassIndex = 0; //sels[i].largestChunk = 0; //sels[i].chunkOffset = 0; sels[i].selectorIndex = i; sels[i].population = 0; } return sels; } static void calcRowStats(PyrMethod const * const * bigTable, ColumnDescriptor * sels, int numClasses, int numSelectors, int begin, int end) { //chunkSize = 0; //chunkOffset = 0; for (int classIndex=0; classIndexownerclass.uoc; if (classIndex > sels[selectorIndex].maxClassIndex) sels[selectorIndex].maxClassIndex = classIndex; if (classIndex < sels[selectorIndex].minClassIndex) sels[selectorIndex].minClassIndex = classIndex; sels[selectorIndex].population ++; //if (chunkSize == 0) chunkOffset = j; //chunkSize++; //postfl(" %8s %3d %3d %3d %3d\n", slotRawSymbol(&classobj->name)->name, i, j, // chunkSize, slotRawInt(&classobj->classIndex)); //} else { //if (chunkSize > sels[i].largestChunk) { // sels[i].largestChunk = chunkSize; // sels[i].chunkOffset = chunkOffset; //} //chunkSize = 0; } } } for (int i=begin; i 0 ? hw_concurrency : 1; const int helperThreadCount = cpuCount > 1 ? cpuCount - 1 : 1; boost::basic_thread_pool pool( helperThreadCount ); // pyrmalloc: // lifetime: kill after compile bigTableSize = numSelectors * numClasses; //post("bigTableSize %d %d %d\n", bigTableSize, numSelectors, numClasses); ColumnDescriptor *sels = (ColumnDescriptor*)pyr_pool_compile->Alloc(numSelectors * sizeof(ColumnDescriptor)); MEMFAIL(sels); #ifdef _MSC_VER auto filledSelectorsFuture = std::async( std::launch::deferred, std::bind( &prepareColumnTable, sels, numSelectors ) ); #else auto filledSelectorsFuture = boost::async( pool, std::bind( &prepareColumnTable, sels, numSelectors ) ); #endif classes = (PyrClass**)pyr_pool_compile->Alloc(numClasses * sizeof(PyrClass*)); MEMFAIL(classes); auto fillClassIndices = [] (PyrClass** classes) { PyrClass *classobj = gClassList; while (classobj) { classes[slotRawInt(&classobj->classIndex)] = classobj; classobj = slotRawClass(&classobj->nextclass); } return classes; }; #ifdef _MSC_VER auto filledClassIndices = std::async( std::launch::deferred, fillClassIndices, classes); #else auto filledClassIndices = boost::async( pool, fillClassIndices, classes); #endif bigTable = (PyrMethod**)pyr_pool_compile->Alloc(bigTableSize * sizeof(PyrMethod*)); MEMFAIL(bigTable); #ifndef _MSC_VER pool.try_executing_one(); #endif filledClassIndices.wait(); #ifdef _MSC_VER size_t numentries = fillClassRows(class_object, bigTable); #else size_t numentries = fillClassRows(class_object, bigTable, pool); #endif post("\tnumentries = %lu / %d = %.2g\n", numentries, bigTableSize, (double)numentries/(double)bigTableSize); ColumnDescriptor * filledSelectors = filledSelectorsFuture.get(); #ifdef _MSC_VER std::vector< std::future > columnDescriptorsWithStats; #else std::vector< boost::future > columnDescriptorsWithStats; #endif size_t selectorsPerJob = numSelectors / cpuCount / 2; for( size_t beginSelectorIndex : boost::irange(selectorsPerJob, numSelectors, selectorsPerJob) ) { size_t endSelectorIndex = std::min( beginSelectorIndex + selectorsPerJob, numSelectors ); #ifdef _MSC_VER auto future = std::async( std::launch::deferred, calcRowStats, bigTable, filledSelectors, numClasses, numSelectors, beginSelectorIndex, endSelectorIndex ); #else auto future = boost::async( pool, calcRowStats, bigTable, filledSelectors, numClasses, numSelectors, beginSelectorIndex, endSelectorIndex ); #endif columnDescriptorsWithStats.push_back( std::move(future) ); } calcRowStats(bigTable, filledSelectors, numClasses, numSelectors, 0, std::min( selectorsPerJob, numSelectors) ); for( auto & future : columnDescriptorsWithStats ) { #ifdef _MSC_VER future.wait(); #else while( !future.is_ready() ) pool.schedule_one_or_yield(); #endif } //post("qsort\n"); // sort rows by largest chunk, then by width, then by chunk offset #if 0 // not yet __gnu_parallel::sort(sels, sels + numSelectors, [](ColumnDescriptor const & rhs, ColumnDescriptor const & lhs) { return compareColDescs(&rhs, &lhs) < 0; }); #else std::sort(sels, sels + numSelectors, [](ColumnDescriptor const & rhs, ColumnDescriptor const & lhs) { return compareColDescs(&rhs, &lhs) < 0; }); #endif // bin sort the class rows to the new ordering //post("reorder rows\n"); #ifdef _MSC_VER std::vector< std::future > binsortedClassRowFuture; #else std::vector< boost::future > binsortedClassRowFuture; #endif size_t classesPerJob = numClasses / cpuCount / 2; for( size_t beginClassIndex : boost::irange(classesPerJob, numClasses, classesPerJob) ) { size_t endClassIndex = std::min( beginClassIndex + classesPerJob, numClasses ); #ifdef _MSC_VER auto future = std::async( std::launch::deferred, binsortClassRows, (PyrMethod const **)bigTable, sels, numSelectors, beginClassIndex, endClassIndex ); #else auto future = boost::async( pool, binsortClassRows, (PyrMethod const **)bigTable, sels, numSelectors, beginClassIndex, endClassIndex ); #endif binsortedClassRowFuture.push_back( std::move(future) ); } binsortClassRows( (PyrMethod const **)bigTable, sels, numSelectors, 0, std::min( classesPerJob, numClasses) ); for( auto & future : binsortedClassRowFuture ) { #ifdef _MSC_VER future.wait(); #else while( !future.is_ready() ) pool.schedule_one_or_yield(); #endif } //post("calc row offsets %d\n", numSelectors); widthSum = 0; popSum = 0; freeIndex = 0; rowOffset = -1; for (int i=0; iu.index = rowOffset; //post("%3d %24s %3d %5d %5d\n", i, sels[i].selector->name, // sels[i].rowWidth, rowOffset, freeIndex); } //post("alloc row table %d\n", freeIndex); rowTableSize = (freeIndex + numClasses) * sizeof(PyrMethod*); gRowTable = (PyrMethod**)pyr_pool_runtime->Alloc(rowTableSize); MEMFAIL(gRowTable); // having the method ptr always be valid saves a branch in SendMessage() for (int i=0; iFree(classes); pyr_pool_compile->Free(bigTable); pyr_pool_compile->Free(sels); */ } #ifdef _MSC_VER static size_t fillClassRow(const PyrClass *classobj, PyrMethod** bigTable) #else static size_t fillClassRow(const PyrClass *classobj, PyrMethod** bigTable, boost::basic_thread_pool & pool) #endif { size_t count = 0; PyrMethod ** myrow = bigTable + slotRawInt(&classobj->classIndex) * gNumSelectors; PyrClass* superclassobj = slotRawSymbol(&classobj->superclass)->u.classobj; if (superclassobj) { PyrMethod ** superrow = bigTable + slotRawInt(&superclassobj->classIndex) * gNumSelectors; #pragma GCC ivdep for (int i = 0; i != gNumSelectors; ++i) { myrow[i] = superrow[i]; if (superrow[i]) ++count; } } else { memset(myrow, 0, gNumSelectors * sizeof(PyrMethod*)); } if (IsObj(&classobj->methods)) { PyrObject * methods = const_cast( slotRawObject(&classobj->methods) ); //postfl(" %d\n", methods->size); for (int i=0; isize; ++i) { PyrMethod* method = slotRawMethod(&methods->slots[i]); int selectorIndex = slotRawSymbol(&method->name)->u.index; if (myrow[selectorIndex] == 0) ++count; myrow[selectorIndex] = method; } } size_t result = count; if (IsObj(&classobj->subclasses)) { const PyrObject * subclasses = slotRawObject(&classobj->subclasses); int numSubclasses = subclasses->size; if( numSubclasses ) { #ifdef _MSC_VER if( numSubclasses <= 2 ) { for( int subClassIndex : boost::irange(0, numSubclasses) ) result += fillClassRow( slotRawClass(&subclasses->slots[subClassIndex]), bigTable); } else { typedef std::vector< std::future > VectorOfFutures; VectorOfFutures subclassResults; for( int subClassIndex : boost::irange(1, numSubclasses) ) { auto subclassResult = std::async(std::launch::deferred, fillClassRow, slotRawClass(&subclasses->slots[subClassIndex]), bigTable); subclassResults.emplace_back( std::move( subclassResult ) ); } result += fillClassRow( slotRawClass(&subclasses->slots[0]), bigTable); for( auto & subclassResult : subclassResults ) { result += subclassResult.get(); } } #else if( numSubclasses <= 2 ) { for( int subClassIndex : boost::irange(0, numSubclasses) ) result += fillClassRow( slotRawClass(&subclasses->slots[subClassIndex]), bigTable, pool ); } else { typedef std::vector< boost::future > VectorOfFutures; VectorOfFutures subclassResults; for( int subClassIndex : boost::irange(1, numSubclasses) ) { auto subclassResult = boost::async( pool, fillClassRow, slotRawClass(&subclasses->slots[subClassIndex]), bigTable, boost::ref(pool) ); subclassResults.emplace_back( std::move( subclassResult ) ); } result += fillClassRow( slotRawClass(&subclasses->slots[0]), bigTable, pool ); for( auto & subclassResult : subclassResults ) { while( !subclassResult.is_ready() ) pool.schedule_one_or_yield(); result += subclassResult.get(); } } #endif } } return result; } #ifdef _MSC_VER static size_t fillClassRows(const PyrClass *classobj, PyrMethod** bigTable) { return fillClassRow(classobj, bigTable); } #else static size_t fillClassRows(const PyrClass *classobj, PyrMethod** bigTable, boost::basic_thread_pool & pool) { return fillClassRow(classobj, bigTable, pool ); } #endif bool funcFindArg(PyrBlock* func, PyrSymbol *name, int *index) { int i; for (i=0; iargNames)->size; ++i) { if (slotRawSymbolArray(&func->argNames)->symbols[i] == name) { *index = i; return true; } } return false; } bool funcFindVar(PyrBlock* func, PyrSymbol *name, int *index) { int i; for (i=0; ivarNames)->size; ++i) { if (slotRawSymbolArray(&func->varNames)->symbols[i] == name) { *index = i; return true; } } return false; } PyrClass* makeIntrinsicClass(PyrSymbol *className, PyrSymbol *superClassName, int numInstVars, int numClassVars) { PyrClass *superClass = NULL; PyrClass *metaSuperClass = NULL; PyrSymbol *metaClassName = NULL; PyrSymbol *metaSuperClassName = NULL; PyrClass *classobj = NULL; PyrClass *metaclassobj = NULL; int superInstVars; //postfl("makeIntrinsicClass '%s'\n", className->name); if (superClassName) { superClass = superClassName->u.classobj; if (!superClass) { error("Can't find superclass '%s' of '%s'\n", superClassName->name, className->name); return NULL; } metaSuperClassName = getmetasym(superClassName->name); metaSuperClass = metaSuperClassName->u.classobj; superInstVars = numSuperInstVars(superClass); } else { // else it must be Object and so has no superclass metaSuperClassName = NULL; superInstVars = 0; } metaClassName = getmetasym(className->name); metaClassName->flags |= sym_MetaClass; metaclassobj = newClassObj( class_class, metaClassName, metaSuperClassName, classClassNumInstVars, 0, 0, 0, obj_notindexed, 0); SetInt(&metaclassobj->classFlags, slotRawInt(&metaclassobj->classFlags) | classIsIntrinsic); if (metaSuperClassName && classClassNumInstVars) { memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&metaSuperClass->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, slotRawSymbolArray(&metaSuperClass->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars; //dumpObject((PyrObject*)metaclassobj); } classobj = newClassObj(metaclassobj, className, superClassName, numInstVars + superInstVars, numClassVars, 0, 0, obj_notindexed, 0); SetInt(&classobj->classFlags, slotRawInt(&classobj->classFlags) | classIsIntrinsic); //postfl("%s:%s : %d\n", className->name, superClassName->name, superInstVars); if (superClass && superInstVars) { memcpy(slotRawObject(&classobj->iprototype)->slots, slotRawObject(&superClass->iprototype)->slots, sizeof(PyrSlot) * superInstVars); memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols, slotRawSymbolArray(&superClass->instVarNames)->symbols, sizeof(PyrSymbol*) * superInstVars); slotRawObject(&classobj->iprototype)->size = superInstVars; slotRawObject(&classobj->instVarNames)->size = superInstVars; } return classobj; } void addIntrinsicVar(PyrClass *classobj, const char *varName, PyrSlot *slot) { //postfl("%s %s %d\n", slotRawSymbol(&classobj->name)->name, varName, // slotRawObject(&classobj->instVarNames)->size); objAddIndexedSymbol(slotRawSymbolArray(&classobj->instVarNames), getsym(varName)); objAddIndexedSlot(slotRawObject(&classobj->iprototype), slot); } void addIntrinsicClassVar(PyrClass *classobj, const char *varName, PyrSlot *slot); void addIntrinsicClassVar(PyrClass *classobj, const char *varName, PyrSlot *slot) { //postfl("%s %s %d\n", slotRawSymbol(&classobj->name)->name, varName, // slotRawObject(&classobj->instVarNames)->size); objAddIndexedSymbol(slotRawSymbolArray(&classobj->classVarNames), getsym(varName)); objAddIndexedSlot(slotRawObject(&classobj->cprototype), slot); } void initClasses() { PyrClass *class_object_meta; PyrMethodRaw *methraw; // BOOTSTRAP THE OBJECT HIERARCHY gNumClassVars = 0; gClassList = NULL; gNullMethod = newPyrMethod(); SetSymbol(&gNullMethod->name, (PyrSymbol*)NULL); methraw = METHRAW(gNullMethod); methraw->methType = methNormal; // build intrinsic classes class_class = NULL; class_object = makeIntrinsicClass(s_object, 0, 0, 4); class_class = makeIntrinsicClass(s_class, s_object, classClassNumInstVars, 1); // now fix class_class ptrs that were just previously installed erroneously class_object->classptr->classptr = class_class; class_class->classptr->classptr = class_class; class_object_meta = class_object->classptr; class_object_meta->superclass = class_class->name; addIntrinsicClassVar(class_object, "dependantsDictionary", &o_nil); addIntrinsicClassVar(class_object, "currentEnvironment", &o_nil); addIntrinsicClassVar(class_object, "topEnvironment", &o_nil); addIntrinsicClassVar(class_object, "uniqueMethods", &o_nil); // declare varNames for Class addIntrinsicVar(class_class, "name", &o_nil); addIntrinsicVar(class_class, "nextclass", &o_nil); addIntrinsicVar(class_class, "superclass", &o_nil); addIntrinsicVar(class_class, "subclasses", &o_nil); addIntrinsicVar(class_class, "methods", &o_nil); addIntrinsicVar(class_class, "instVarNames", &o_nil); addIntrinsicVar(class_class, "classVarNames", &o_nil); addIntrinsicVar(class_class, "iprototype", &o_nil); addIntrinsicVar(class_class, "cprototype", &o_nil); addIntrinsicVar(class_class, "constNames", &o_nil); addIntrinsicVar(class_class, "constValues", &o_nil); addIntrinsicVar(class_class, "instanceFormat", &o_nil); addIntrinsicVar(class_class, "instanceFlags", &o_zero); addIntrinsicVar(class_class, "classIndex", &o_zero); addIntrinsicVar(class_class, "classFlags", &o_zero); addIntrinsicVar(class_class, "maxSubclassIndex", &o_zero); addIntrinsicVar(class_class, "filenameSymbol", &o_nil); addIntrinsicVar(class_class, "charPos", &o_zero); addIntrinsicVar(class_class, "classVarIndex", &o_zero); addIntrinsicClassVar(class_class, "classesInited", &o_nil); // class_object_meta's inst var names need to be copied from class_class // because class_class didn't exist when it was created memcpy(slotRawObject(&class_object_meta->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&class_object_meta->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); memcpy(slotRawObject(&class_class->classptr->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&class_class->classptr->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); // OK the next thing I need is arrays.. class_collection = makeIntrinsicClass(s_collection, s_object, 0, 0); class_sequenceable_collection = makeIntrinsicClass(s_sequenceable_collection, s_collection, 0, 0); class_arrayed_collection = makeIntrinsicClass(s_arrayed_collection, s_sequenceable_collection, 0, 0); class_array = makeIntrinsicClass(s_array, s_arrayed_collection, 0, 0); SetInt(&class_array->instanceFormat, obj_slot); SetInt(&class_array->classFlags, slotRawInt(&class_array->classFlags) | classHasIndexableInstances); // now fix array classptrs in already created classes fixClassArrays(class_class); fixClassArrays(class_class->classptr); fixClassArrays(class_object_meta); fixClassArrays(class_collection); fixClassArrays(class_sequenceable_collection); fixClassArrays(class_arrayed_collection); fixClassArrays(class_array); class_fundef = makeIntrinsicClass(s_fundef, s_object, 10, 0); // declare varNames for Block addIntrinsicVar(class_fundef, "raw1", &o_nil); addIntrinsicVar(class_fundef, "raw2", &o_nil); addIntrinsicVar(class_fundef, "code", &o_nil); addIntrinsicVar(class_fundef, "selectors", &o_nil); addIntrinsicVar(class_fundef, "constants", &o_nil); addIntrinsicVar(class_fundef, "prototypeFrame", &o_nil); addIntrinsicVar(class_fundef, "context", &o_nil); addIntrinsicVar(class_fundef, "argNames", &o_nil); addIntrinsicVar(class_fundef, "varNames", &o_nil); addIntrinsicVar(class_fundef, "sourceCode", &o_nil); class_method = makeIntrinsicClass(s_method, s_fundef, 5, 0); addIntrinsicVar(class_method, "ownerClass", &o_nil); addIntrinsicVar(class_method, "name", &o_nil); addIntrinsicVar(class_method, "primitiveName", &o_nil); addIntrinsicVar(class_method, "filenameSymbol", &o_nil); addIntrinsicVar(class_method, "charPos", &o_zero); //addIntrinsicVar(class_method, "byteMeter", &o_zero); //addIntrinsicVar(class_method, "callMeter", &o_zero); class_frame = makeIntrinsicClass(s_frame, s_object, 0, 0); SetInt(&class_frame->classFlags, slotRawInt(&class_frame->classFlags) | classHasIndexableInstances); //addIntrinsicVar(class_frame, "method", &o_nil); //addIntrinsicVar(class_frame, "caller", &o_nil); //addIntrinsicVar(class_frame, "context", &o_nil); //addIntrinsicVar(class_frame, "homeContext", &o_nil); //addIntrinsicVar(class_frame, "ip", &o_nil); class_process = makeIntrinsicClass(s_process, s_object, 6, 0); addIntrinsicVar(class_process, "classVars", &o_nil); addIntrinsicVar(class_process, "interpreter", &o_nil); addIntrinsicVar(class_process, "curThread", &o_nil); addIntrinsicVar(class_process, "mainThread", &o_nil); addIntrinsicVar(class_process, "schedulerQueue", &o_nil); addIntrinsicVar(class_process, "nowExecutingPath", &o_nil); class_interpreter = makeIntrinsicClass(s_interpreter, s_object, 29, 0); addIntrinsicVar(class_interpreter, "cmdLine", &o_nil); addIntrinsicVar(class_interpreter, "context", &o_nil); for (int i=0; i<26; ++i) { char name[2]; name[0] = 'a' + i; name[1] = 0; addIntrinsicVar(class_interpreter, name, &o_nil); } addIntrinsicVar(class_interpreter, "codeDump", &o_nil); addIntrinsicVar(class_interpreter, "preProcessor", &o_nil); class_absfunc = makeIntrinsicClass(s_absfunc, s_object, 0, 0); class_stream = makeIntrinsicClass(s_stream, s_absfunc, 0, 0); class_thread = makeIntrinsicClass(s_thread, s_stream, 27, 0); addIntrinsicVar(class_thread, "state", &o_nil); addIntrinsicVar(class_thread, "func", &o_nil); addIntrinsicVar(class_thread, "stack", &o_nil); addIntrinsicVar(class_thread, "method", &o_nil); addIntrinsicVar(class_thread, "block", &o_nil); addIntrinsicVar(class_thread, "frame", &o_nil); addIntrinsicVar(class_thread, "ip", &o_zero); addIntrinsicVar(class_thread, "sp", &o_zero); addIntrinsicVar(class_thread, "numpop", &o_zero); addIntrinsicVar(class_thread, "receiver", &o_nil); addIntrinsicVar(class_thread, "numArgsPushed", &o_zero); addIntrinsicVar(class_thread, "parent", &o_nil); addIntrinsicVar(class_thread, "terminalValue", &o_nil); addIntrinsicVar(class_thread, "primitiveError", &o_zero); addIntrinsicVar(class_thread, "primitiveIndex", &o_zero); addIntrinsicVar(class_thread, "randData", &o_zero); addIntrinsicVar(class_thread, "beats", &o_fzero); addIntrinsicVar(class_thread, "seconds", &o_fzero); addIntrinsicVar(class_thread, "clock", &o_nil); addIntrinsicVar(class_thread, "nextBeat", &o_nil); addIntrinsicVar(class_thread, "endBeat", &o_nil); addIntrinsicVar(class_thread, "endValue", &o_nil); addIntrinsicVar(class_thread, "environment", &o_nil); addIntrinsicVar(class_thread, "exceptionHandler", &o_nil); addIntrinsicVar(class_thread, "threadPlayer", &o_nil); addIntrinsicVar(class_thread, "executingPath", &o_nil); addIntrinsicVar(class_thread, "oldExecutingPath", &o_nil); class_finalizer = makeIntrinsicClass(s_finalizer, s_object, 2, 0); addIntrinsicVar(class_finalizer, "cFunction", &o_nil); addIntrinsicVar(class_finalizer, "object", &o_nil); class_routine = makeIntrinsicClass(s_routine, s_thread, 0, 0); class_symbol = makeIntrinsicClass(s_symbol, s_object, 0, 0); class_nil = makeIntrinsicClass(s_nil, s_object, 0, 0); class_boolean = makeIntrinsicClass(s_boolean, s_object, 0, 0); class_true = makeIntrinsicClass(s_true, s_boolean, 0, 0); class_false = makeIntrinsicClass(s_false, s_boolean, 0, 0); class_magnitude = makeIntrinsicClass(s_magnitude, s_object, 0, 0); class_char = makeIntrinsicClass(s_char, s_magnitude, 0, 0); class_number = makeIntrinsicClass(s_number, s_magnitude, 0, 0); class_simple_number = makeIntrinsicClass(s_simple_number, s_number, 0, 0); class_int = makeIntrinsicClass(s_int, s_simple_number, 0, 0); class_float = makeIntrinsicClass(s_float, s_simple_number, 0, 0); class_rawptr = makeIntrinsicClass(s_rawptr, s_object, 0, 0); /* class_complex = makeIntrinsicClass(s_complex, s_number, 2, 0); addIntrinsicVar(class_complex, "real", &o_nil); addIntrinsicVar(class_complex, "imag", &o_nil); */ class_rawarray = makeIntrinsicClass(s_rawarray, s_arrayed_collection, 0, 0); //SetInt(&class_rawarray->instanceFormat, obj_int8); //slotRawInt(&class_rawarray->classFlags) |= classHasIndexableInstances; class_int8array = makeIntrinsicClass(s_int8array, s_rawarray, 0, 0); SetInt(&class_int8array->instanceFormat, obj_int8); SetInt(&class_int8array->classFlags, slotRawInt(&class_int8array->classFlags) | classHasIndexableInstances); class_int16array = makeIntrinsicClass(s_int16array, s_rawarray, 0, 0); SetInt(&class_int16array->instanceFormat, obj_int16); SetInt(&class_int16array->classFlags, slotRawInt(&class_int16array->classFlags) | classHasIndexableInstances); class_int32array = makeIntrinsicClass(s_int32array, s_rawarray, 0, 0); SetInt(&class_int32array->instanceFormat, obj_int32); SetInt(&class_int32array->classFlags, slotRawInt(&class_int32array->classFlags) | classHasIndexableInstances); class_symbolarray = makeIntrinsicClass(s_symbolarray, s_rawarray, 0, 0); SetInt(&class_symbolarray->instanceFormat, obj_symbol); SetInt(&class_symbolarray->classFlags, slotRawInt(&class_symbolarray->classFlags) | classHasIndexableInstances); class_string = makeIntrinsicClass(s_string, s_rawarray, 0, 1); addIntrinsicClassVar(class_string, "unixCmdActions", &o_nil); SetInt(&class_string->instanceFormat, obj_char); SetInt(&class_string->classFlags, slotRawInt(&class_string->classFlags) | classHasIndexableInstances); class_floatarray = makeIntrinsicClass(s_floatarray, s_rawarray, 0, 0); SetInt(&class_floatarray->instanceFormat, obj_float); SetInt(&class_floatarray->classFlags, slotRawInt(&class_floatarray->classFlags) | classHasIndexableInstances); class_signal = makeIntrinsicClass(s_signal, s_floatarray, 0, 0); SetInt(&class_signal->instanceFormat, obj_float); SetInt(&class_signal->classFlags, slotRawInt(&class_signal->classFlags) | classHasIndexableInstances); class_wavetable = makeIntrinsicClass(s_wavetable, s_floatarray, 0, 0); SetInt(&class_wavetable->instanceFormat, obj_float); SetInt(&class_wavetable->classFlags, slotRawInt(&class_wavetable->classFlags) | classHasIndexableInstances); //addIntrinsicVar(class_signal, "rate", &o_nil); class_doublearray = makeIntrinsicClass(s_doublearray, s_rawarray, 0, 0); SetInt(&class_doublearray->instanceFormat, obj_double); SetInt(&class_doublearray->classFlags, slotRawInt(&class_doublearray->classFlags) | classHasIndexableInstances); class_list = makeIntrinsicClass(s_list, s_sequenceable_collection, 1, 0); addIntrinsicVar(class_list, "array", &o_nil); //addIntrinsicVar(class_list, "size", &o_zero); class_func = makeIntrinsicClass(s_func, s_absfunc, 2, 0); addIntrinsicVar(class_func, "def", &o_nil); addIntrinsicVar(class_func, "context", &o_nil); class_server_shm_interface = makeIntrinsicClass(s_server_shm_interface, s_object, 2, 0); addIntrinsicVar(class_server_shm_interface, "ptr", &o_nil); addIntrinsicVar(class_server_shm_interface, "finalizer", &o_nil); gTagClassTable[ 0] = NULL; gTagClassTable[ 1] = NULL; gTagClassTable[ 2] = class_int; gTagClassTable[ 3] = class_symbol; gTagClassTable[ 4] = class_char; gTagClassTable[ 5] = class_nil; gTagClassTable[ 6] = class_false; gTagClassTable[ 7] = class_true; gTagClassTable[ 8] = class_rawptr; gTagClassTable[ 9] = class_float; gTagClassTable[10] = class_float; gTagClassTable[11] = class_float; gTagClassTable[12] = class_float; SetObject(&o_emptyarray, newPyrArray(NULL, 0, obj_permanent | obj_immutable, false)); SetObject(&o_onenilarray, newPyrArray(NULL, 1, obj_permanent | obj_immutable, false)); slotRawObject(&o_onenilarray)->size = 1; SetNil(slotRawObject(&o_onenilarray)->slots); SetObject(&o_argnamethis, newPyrSymbolArray(NULL, 1, obj_permanent | obj_immutable, false)); slotRawSymbolArray(&o_argnamethis)->size = 1; slotRawSymbolArray(&o_argnamethis)->symbols[0] = s_this; /* post("array %p '%s'\n", class_array, class_array->name.us->name); post("o_emptyarray %p '%s'\n", slotRawObject(&o_emptyarray)->classptr, slotRawObject(&o_emptyarray)->classptr->name.us->name); post("o_argnamethis %p '%s'\n", slotRawObject(&o_argnamethis)->classptr, slotRawObject(&o_argnamethis)->classptr->name.us->name); post("o_onenilarray %p '%s'\n", slotRawObject(&o_onenilarray)->classptr, slotRawObject(&o_onenilarray)->classptr->name.us->name); dumpObjectSlot(&o_emptyarray); dumpObjectSlot(&o_argnamethis); dumpObjectSlot(&o_onenilarray); */ } PyrObject* instantiateObject(class PyrGC *gc, PyrClass* classobj, int size, bool fill, bool runGC) { PyrObject *newobj, *proto; int numbytes, format, flags; format = slotRawInt(&classobj->instanceFormat); flags = slotRawInt(&classobj->instanceFlags); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { // create an indexable object numbytes = size * gFormatElemSize[format]; newobj = gc->New(numbytes, flags, format, runGC); if (fill) { newobj->size = size; if (format == obj_slot) { nilSlots(newobj->slots, size); } else { memset(newobj->slots, format == obj_char ? ' ' : 0, size * gFormatElemSize[format]); } } else { newobj->size = 0; } } else { if (IsObj(&classobj->iprototype)) { proto = slotRawObject(&classobj->iprototype); size = proto->size; numbytes = size * sizeof(PyrSlot); newobj = gc->New(numbytes, flags, format, runGC); newobj->size = size; if (size) { memcpy(newobj->slots, proto->slots, numbytes); } } else { numbytes = 0; newobj = gc->New(numbytes, flags, format, runGC); newobj->size = 0; } } newobj->classptr = classobj; return newobj; } PyrObject* instantiateObjectLight(class PyrGC *gc, PyrClass* classobj, int size, bool runGC); PyrObject* instantiateObjectLight(class PyrGC *gc, PyrClass* classobj, int size, bool runGC) { PyrObject *newobj, *proto; int numbytes, format, flags; format = slotRawInt(&classobj->instanceFormat); flags = slotRawInt(&classobj->instanceFlags); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { numbytes = size * gFormatElemSize[format]; } else { if (IsObj(&classobj->iprototype)) { proto = slotRawObject(&classobj->iprototype); size = proto->size; numbytes = size * sizeof(PyrSlot); } else { size = 0; numbytes = 0; } } newobj = gc->New(numbytes, flags, format, runGC); newobj->size = size; newobj->classptr = classobj; return newobj; } PyrObject* copyObject(class PyrGC *gc, PyrObject *inobj, bool runGC) { PyrObject *newobj; // copies are neither immutable not permanent int flags = ~(obj_immutable) & inobj->obj_flags; flags = ~(obj_permanent) & flags; int elemsize = gFormatElemSize[inobj->obj_format]; int numbytes = inobj->size * elemsize; newobj = gc->New(numbytes, flags, inobj->obj_format, runGC); newobj->size = inobj->size; newobj->classptr = inobj->classptr; memcpy(newobj->slots, inobj->slots, inobj->size * elemsize); return newobj; } PyrObject* copyObjectRange(class PyrGC *gc, PyrObject *inobj, int start, int end, bool runGC) { PyrObject *newobj; if (start < 0) start = 0; if (end >= inobj->size) end = inobj->size - 1; int length = end - start + 1; if (length < 0) length = 0; int elemsize = gFormatElemSize[inobj->obj_format]; int numbytes = length * elemsize; // copies are neither immutable not permanent int flags = ~(obj_immutable) & inobj->obj_flags; flags = ~(obj_permanent) & flags; newobj = gc->New(numbytes, flags, inobj->obj_format, runGC); newobj->size = length; newobj->classptr = inobj->classptr; if (length > 0) { memcpy(newobj->slots, (char*)(inobj->slots) + start * elemsize, length * elemsize); } return newobj; } void dumpObject(PyrObject *obj) { char str[256]; PyrClass *classobj; int i; if (obj == NULL) { postfl("NULL object pointer\n"); return; } classobj = obj->classptr; if (isKindOf(obj, class_class)) { post("class %s (%p) {\n", slotRawSymbol(&((PyrClass*)obj)->name)->name, obj); } else { //post("Instance of %s (%p) {\n", slotRawSymbol(&classobj->name)->name, obj); post("Instance of %s { (%p, gc=%02X, fmt=%02X, flg=%02X, set=%02X)\n", slotRawSymbol(&classobj->name)->name, obj, obj->gc_color, obj->obj_format, obj->obj_flags, obj->obj_sizeclass); } //flushPostBuf(); if (obj->obj_format == obj_notindexed) { post(" instance variables [%d]\n", obj->size); for (i=0; isize; ++i) { slotString(obj->slots + i, str); post(" %s : %s\n", slotRawSymbolArray(&classobj->instVarNames)->symbols[i]->name, str); } } else { int maxsize; post(" indexed slots [%d]\n", obj->size); maxsize = sc_min(32, obj->size); switch (obj->obj_format) { case obj_slot : for (i=0; islots + i, str); post(" %3d : %s\n", i, str); } break; case obj_double : for (i=0; islots[i])); } break; case obj_float : for (i=0; islots))[i]; post(" %3d : %g\n", i, val); } break; case obj_int32 : for (i=0; islots))[i]; post(" %3d : %d\n", i, val); } break; case obj_int16 : for (i=0; islots))[i]; post(" %3d : %d\n", i, val); } break; case obj_int8 : for (i=0; islots))[i]; post(" %3d : %4d %4u 0x%02X\n", i, val, val&255, val&255); } break; case obj_char : for (i=0; islots))[i]; post(" %3d : %c\n", i, val); } break; case obj_symbol : for (i=0; islots))[i]; post(" %3d : '%s'\n", i, sym->name); } break; default : post("unknown obj_format %X\n", obj->obj_format); } if (obj->size > maxsize) { post(" ...\n"); } } post("}\n"); } void dumpBadObject(PyrObject *obj) { char str[128]; PyrClass *classobj; int i; if (obj == NULL) { postfl("NULL object pointer\n"); return; } classobj = obj->classptr; if (isKindOf(obj, class_class)) { postfl("class %s (%p) {\n", slotRawSymbol(&((PyrClass*)obj)->name)->name, obj); } else { //postfl("Instance of %s (%p) {\n", slotRawSymbol(&classobj->name)->name, obj); postfl("Instance of %s { (%p, gc=%02X, fmt=%02X, flg=%02X, set=%02X)\n", slotRawSymbol(&classobj->name)->name, obj, obj->gc_color, obj->obj_format, obj->obj_flags, obj->obj_sizeclass); } if (obj->obj_format == obj_notindexed) { postfl(" instance variables [%d]\n", obj->size); for (i=0; isize; ++i) { slotString(obj->slots + i, str); postfl(" %s : %s\n", slotRawSymbolArray(&classobj->instVarNames)->symbols[i]->name, str); } } else { int maxsize; postfl(" indexed slots [%d]\n", obj->size); maxsize = obj->size; maxsize = sc_min(32, maxsize); switch (obj->obj_format) { case obj_slot : for (i=0; islots + i, str); postfl(" %3d : %s\n", i, str); } break; case obj_double : for (i=0; islots[i])); } break; case obj_float : for (i=0; islots))[i]; postfl(" %3d : %g\n", i, val); } break; case obj_int32 : for (i=0; islots))[i]; postfl(" %3d : %d\n", i, val); } break; case obj_int16 : for (i=0; islots))[i]; postfl(" %3d : %d\n", i, val); } break; case obj_int8 : for (i=0; islots))[i]; postfl(" %3d : %4d %4u 0x%02X\n", i, val, val&255, val&255); } break; case obj_char : for (i=0; islots))[i]; postfl(" %3d : %c\n", i, val); } break; case obj_symbol : for (i=0; islots))[i]; post(" %3d : '%s'\n", i, sym->name); } break; default : postfl("unknown obj_format %X\n", obj->obj_format); } if (obj->size > maxsize) { postfl(" ...\n"); } } postfl("}\n"); } void dumpObjectSlot(PyrSlot *slot) { if (IsObj(slot)) { dumpObject(slotRawObject(slot)); } else { dumpPyrSlot(slot); } } void dumpSlotOneWord(const char *tagstr, PyrSlot *slot) { char str[256]; slotOneWord(slot, str); post("%s %s\n", tagstr, str); } void CallStackSanity(VMGlobals *g, const char *tagstr); void CallStackSanity(VMGlobals *g, const char *tagstr) { PyrFrame *frame; frame = g->frame; while (frame) { if (FrameSanity(frame, tagstr)) { DumpBackTrace(g); //Debugger(); break; } frame = slotRawFrame(&frame->caller); } } bool FrameSanity(PyrFrame *frame, const char *tagstr); bool FrameSanity(PyrFrame *frame, const char *tagstr) { bool failed = false; if (frame==NULL) return false; if (NotObj(&frame->method)) { postfl("Frame %p method tag wrong %p\n", frame, GetTag(&frame->method)); failed = true; //} else if (!isKindOf((PyrObject*)slotRawObject(&frame->method)->classptr, class_fundef)) { } else if (slotRawObject(&frame->method)->classptr != class_method && slotRawObject(&frame->method)->classptr != class_fundef) { postfl("Frame %p method class wrong %p\n", frame, slotRawObject(&frame->method)->classptr); failed = true; //if (slotRawObject(&frame->method)->classptr->classptr == class_class) { postfl("class: '%s'\n", slotRawSymbol(&slotRawObject(&frame->method)->classptr->name)->name); ///} else { // postfl("not even a class\n"); //} } else if (NotObj(&slotRawBlock(&frame->method)->code)) { postfl("Method %p code tag wrong %p\n", slotRawBlock(&frame->method), GetTag(&slotRawBlock(&frame->method)->code)); failed = true; } else if (slotRawObject(&slotRawBlock(&frame->method)->code)->classptr != class_int8array) { postfl("Code %p class wrong %p\n", slotRawObject(&slotRawBlock(&frame->method)->code), slotRawObject(&slotRawBlock(&frame->method)->code)->classptr); postfl("class: '%s'\n", slotRawSymbol(&slotRawObject(&slotRawBlock(&frame->method)->code)->classptr->name)->name); failed = true; } /* if (frame->caller.utag != tagHFrame && frame->caller.utag != tagNil) { postfl("Frame %p caller tag wrong %p\n", frame, frame->caller.utag); failed = true; } if (frame->context.utag != tagHFrame && frame->context.utag != tagNil) { postfl("Frame %p context tag wrong %p\n", frame, frame->context.utag); failed = true; } if (frame->homeContext.utag != tagHFrame && frame->homeContext.utag != tagNil) { postfl("Frame %p homeContext tag wrong %p\n", frame, frame->homeContext.utag); failed = true; } */ if (!IsPtr(&frame->ip)) { postfl("Frame %p ip tag wrong %p\n", frame, GetTag(&frame->ip)); failed = true; } return failed; } void DumpFrame(PyrFrame *frame) { char str[256]; int i, numargs; PyrMethod *meth; PyrMethodRaw *methraw; if (FrameSanity(frame, "DumpFrame")) { post("FRAME CORRUPTED\n"); return; } slotOneWord(&frame->method, str); //slotString(&frame->method, str); meth = slotRawMethod(&frame->method); methraw = METHRAW(meth); if (methraw->numtemps) { post("\t%s %p\n", str, frame); numargs = methraw->numargs + methraw->varargs; for (i=0; inumtemps; ++i) { slotOneWord(frame->vars + i, str); //slotString(frame->vars + i, str); if (i < numargs) { post("\t\targ %s = %s\n", slotRawSymbolArray(&meth->argNames)->symbols[i]->name, str); } else { post("\t\tvar %s = %s\n", slotRawSymbolArray(&meth->varNames)->symbols[i - numargs]->name, str); } } } else { post("\t%s (no arguments or variables)\n", str); } } void dumpByteCodes(PyrBlock *theBlock); void DumpDetailedFrame(PyrFrame *frame); void DumpDetailedFrame(PyrFrame *frame) { char mstr[256]; char str[256]; int i, numargs; PyrMethod *meth; PyrMethodRaw *methraw; if (FrameSanity(frame, "DumpDetailedFrame")) { post("FRAME CORRUPTED\n"); return; } slotOneWord(&frame->method, mstr); //slotString(&frame->method, str); meth = slotRawMethod(&frame->method); methraw = METHRAW(meth); if (methraw->numtemps) { post("\t%s\n", mstr); numargs = methraw->numargs + methraw->varargs; for (i=0; inumtemps; ++i) { slotOneWord(frame->vars + i, str); //slotString(frame->vars + i, str); if (i < numargs) { post("\t\targ %s = %s\n", slotRawSymbolArray(&meth->argNames)->symbols[i]->name, str); } else { post("\t\tvar %s = %s\n", slotRawSymbolArray(&meth->varNames)->symbols[i - numargs]->name, str); } } } else { post("\t%s (no arguments or variables)\n", mstr); } post("\t....%s details:\n", mstr); post("\t\tneedsHeapContext = %d\n", methraw->needsHeapContext); post("\t\tnumtemps = %d\n", methraw->numtemps); post("\t\tpopSize = %d\n", methraw->popSize); slotString(&frame->method, str); post("\t\tmethod = %s\n", str); slotString(&frame->caller, str); post("\t\tcaller = %s\n", str); slotString(&frame->context, str); post("\t\tcontext = %s\n", str); slotString(&frame->homeContext, str); post("\t\thomeCtx = %s\n", str); slotString(&frame->ip, str); post("\t\tip = %s\n", str); if (IsPtr(&frame->ip)) { post("ipoffset = %d\n", (char*)slotRawPtr(&frame->ip) - (char*)slotRawInt8Array(&meth->code)->b); dumpByteCodes(meth); } } bool respondsTo(PyrSlot *slot, PyrSymbol *selector) { PyrClass *classobj; PyrMethod *meth; int index; classobj = classOfSlot(slot); index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; return slotRawSymbol(&meth->name) == selector; } PyrMethod* methodLookup(PyrSlot *slot, PyrSymbol *selector); PyrMethod* methodLookup(PyrSlot *slot, PyrSymbol *selector) { PyrClass *classobj; PyrMethod *meth; int index; classobj = classOfSlot(slot); index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; return meth; } bool isSubclassOf(PyrClass *classobj, PyrClass *testclass) { while (classobj) { if (classobj == testclass) { return true; } classobj = slotRawSymbol(&classobj->superclass)->u.classobj; } return false; } /*bool isKindOf(PyrObjectHdr *obj, PyrClass *testclass) { int objClassIndex = slotRawInt(&obj->classptr->classIndex); return objClassIndex >= slotRawInt(&testclass->classIndex) && objClassIndex <= slotRawInt(&testclass->maxSubclassIndex); }*/ bool objAddIndexedSlot(PyrObject *obj, PyrSlot *slot) { if (obj->size < ARRAYMAXINDEXSIZE(obj)) { slotCopy(&obj->slots[obj->size++], slot); return true; } else { return false; } } bool objAddIndexedSymbol(PyrSymbolArray *obj, PyrSymbol *symbol) { if (obj->size < MAXINDEXSIZE((PyrObject*)obj)) { obj->symbols[obj->size++] = symbol; return true; } else { return false; } } bool objAddIndexedObject(PyrObject *obj, PyrObject *obj2) { if (obj->size < ARRAYMAXINDEXSIZE(obj)) { SetObject(obj->slots + obj->size, obj2); obj->size++; return true; } else { return false; } } void fillSlots(PyrSlot* slot, int size, PyrSlot* fillslot) { for (int i = 0; i != size; ++i) slotCopy(&slot[i], fillslot); } void nilSlots(PyrSlot* slot, int size) { fillSlots(slot, size, &o_nil); } void zeroSlots(PyrSlot* slot, int size) { PyrSlot zero; SetTagRaw(&zero, 0); SetRaw(&zero, 0.0); fillSlots(slot, size, &zero); } PyrObject* newPyrObject(class PyrGC *gc, size_t inNumBytes, int inFlags, int inFormat, bool inRunGC) { return gc->New(inNumBytes, inFlags, inFormat, inRunGC); } PyrObject* newPyrArray(class PyrGC *gc, int size, int flags, bool runGC) { PyrObject* array; int numbytes = size * sizeof(PyrSlot); if (!gc) array = PyrGC::NewPermanent(numbytes, flags, obj_slot); else array = gc->New(numbytes, flags, obj_slot, runGC); array->classptr = class_array; return array; } PyrSymbolArray* newPyrSymbolArray(class PyrGC *gc, int size, int flags, bool runGC) { PyrSymbolArray* array; int numbytes = size * sizeof(PyrSymbol*); if (!gc) array = (PyrSymbolArray*)PyrGC::NewPermanent(numbytes, flags, obj_symbol); else array = (PyrSymbolArray*)gc->New(numbytes, flags, obj_symbol, runGC); array->classptr = class_symbolarray; return array; } PyrInt8Array* newPyrInt8Array(class PyrGC *gc, int size, int flags, bool runGC) { PyrInt8Array* array; if (!gc) array = (PyrInt8Array*)PyrGC::NewPermanent(size, flags, obj_int8); else array = (PyrInt8Array*)gc->New(size, flags, obj_int8, runGC); array->classptr = class_int8array; return array; } PyrInt32Array* newPyrInt32Array(class PyrGC *gc, int size, int flags, bool runGC) { PyrInt32Array* array; int numbytes = size * sizeof(int32); if (!gc) array = (PyrInt32Array*)PyrGC::NewPermanent(numbytes, flags, obj_int32); else array = (PyrInt32Array*)gc->New(numbytes, flags, obj_int32, runGC); array->classptr = class_int32array; return array; } PyrDoubleArray* newPyrDoubleArray(class PyrGC *gc, int size, int flags, bool runGC) { PyrDoubleArray* array; int numbytes = size * sizeof(double); if (!gc) array = (PyrDoubleArray*)PyrGC::NewPermanent(numbytes, flags, obj_double); else array = (PyrDoubleArray*)gc->New(size, flags, obj_double, runGC); array->classptr = class_doublearray; return array; } PyrString* newPyrString(class PyrGC *gc, const char *s, int flags, bool runGC) { PyrString* string; int length = strlen(s); if (!gc) string = (PyrString*)PyrGC::NewPermanent(length, flags, obj_char); else string = (PyrString*)gc->New(length, flags, obj_char, runGC); string->classptr = class_string; string->size = length; memcpy(string->s, s, length); return string; } PyrString* newPyrStringN(class PyrGC *gc, int length, int flags, bool runGC) { PyrString* string; if (!gc) string = (PyrString*)PyrGC::NewPermanent(length, flags, obj_char); else string = (PyrString*)gc->New(length, flags, obj_char, runGC); string->classptr = class_string; string->size = length; // filled with garbage! return string; } PyrBlock* newPyrBlock(int flags) { PyrBlock* block; PyrMethodRaw *methraw; int32 numbytes = sizeof(PyrBlock) - sizeof(PyrObjectHdr); int32 numSlots = numbytes / sizeof(PyrSlot); if (!compilingCmdLine) block = (PyrBlock*)PyrGC::NewPermanent(numbytes, flags, obj_notindexed); else block = (PyrBlock*)gMainVMGlobals->gc->New(numbytes, flags, obj_notindexed, false); block->classptr = class_fundef; block->size = numSlots; // clear out raw area methraw = METHRAW(block); methraw->specialIndex = 0; methraw->methType = methBlock; methraw->needsHeapContext = 0; methraw->frameSize = 0; methraw->varargs = 0; methraw->numargs = 0; methraw->numvars = 0; methraw->numtemps = 0; methraw->popSize = 0; nilSlots(&block->rawData1, numSlots); return block; } SCLANG_DLLEXPORT_C struct VMGlobals* scGlobals() { return gMainVMGlobals; } PyrMethod* initPyrMethod(PyrMethod* method) { int32 numbytes = sizeof(PyrMethod) - sizeof(PyrObjectHdr); int32 numSlots = numbytes / sizeof(PyrSlot); method->classptr = class_method; method->size = 0; method->size = numSlots; SetFloat(&method->rawData1, 0.0); SetFloat(&method->rawData2, 0.0); nilSlots(&method->code, numSlots-2); //slotCopy(&method->byteMeter, &o_zero); //slotCopy(&method->callMeter, &o_zero); //post("<- newPyrMethod %p %p\n", method, methraw); return method; } PyrMethod* newPyrMethod() { int32 numbytes = sizeof(PyrMethod) - sizeof(PyrObjectHdr); PyrMethod* method = (PyrMethod*)PyrGC::NewPermanent(numbytes, obj_permanent | obj_immutable, obj_notindexed); return initPyrMethod(method); } void freePyrSlot(PyrSlot *slot) { if (IsObj(slot)) { PyrObject *obj = slotRawObject(slot); if (obj && obj->IsPermanent()) { // don't deallocate these if (obj != slotRawObject(&o_emptyarray) && obj != slotRawObject(&o_onenilarray) && obj != slotRawObject(&o_argnamethis)) pyr_pool_runtime->Free((void*)obj); SetNil(slot); } } } void freePyrObject(PyrObject *obj) { if (obj->IsPermanent()) { pyr_pool_runtime->Free((void*)obj); } } int getIndexedInt(PyrObject *obj, int index, int *value) { PyrSlot *slot; int err = errNone; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : slot = obj->slots + index; if (IsFloat(slot)) { *value = (int)slotRawFloat(slot); } else if (IsInt(slot)) { *value = slotRawInt(slot); } else { err = errWrongType; } break; case obj_double : *value = (int)((double*)(obj->slots))[index]; break; case obj_float : *value = (int)((float*)(obj->slots))[index]; break; case obj_int32 : *value = ((int32*)(obj->slots))[index]; break; case obj_int16 : *value = ((int16*)(obj->slots))[index]; break; case obj_int8 : *value = ((int8*)(obj->slots))[index]; break; default : err = errWrongType; } return err; } int getIndexedFloat(PyrObject *obj, int index, float *value) { PyrSlot *slot; int err = errNone; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : slot = obj->slots + index; if (IsFloat(slot)) { *value = slotRawFloat(slot); } else if (IsInt(slot)) { *value = slotRawInt(slot); } else { err = errWrongType; } break; case obj_double : *value = ((double*)(obj->slots))[index]; break; case obj_float : *value = ((float*)(obj->slots))[index]; break; case obj_int32 : *value = ((int32*)(obj->slots))[index]; break; case obj_int16 : *value = ((int16*)(obj->slots))[index]; break; case obj_int8 : *value = ((int8*)(obj->slots))[index]; break; default : err = errWrongType; } return err; } int getIndexedDouble(PyrObject *obj, int index, double *value) { PyrSlot *slot; int err = errNone; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : slot = obj->slots + index; if (IsFloat(slot)) { *value = slotRawFloat(slot); } else if (IsInt(slot)) { *value = slotRawInt(slot); } else { err = errWrongType; } break; case obj_double : *value = ((double*)(obj->slots))[index]; break; case obj_float : *value = ((float*)(obj->slots))[index]; break; case obj_int32 : *value = ((int32*)(obj->slots))[index]; break; case obj_int16 : *value = ((int16*)(obj->slots))[index]; break; case obj_int8 : *value = ((int8*)(obj->slots))[index]; break; default : err = errWrongType; } return err; } void getIndexedSlot(PyrObject *obj, PyrSlot *a, int index) { // postfl("getIndexedSlot %s %X %d\n", slotRawSymbol(&obj->classptr->name)->name, // obj, index); switch (obj->obj_format) { case obj_slot : slotCopy(a, &obj->slots[index]); break; case obj_double : SetFloat(a, ((double*)(obj->slots))[index]); break; case obj_float : SetFloat(a, ((float*)(obj->slots))[index]); break; case obj_int32 : SetInt(a, ((int32*)(obj->slots))[index]); break; case obj_int16 : SetInt(a, ((int16*)(obj->slots))[index]); break; case obj_int8 : SetInt(a, ((int8*)(obj->slots))[index]); break; case obj_symbol : SetSymbol(a, (PyrSymbol*)((int**)(obj->slots))[index]); break; case obj_char : SetChar(a, ((unsigned char*)(obj->slots))[index]); break; } } int putIndexedSlot(VMGlobals *g, PyrObject *obj, PyrSlot *c, int index) { PyrSlot *slot; switch (obj->obj_format) { case obj_slot : if (obj->IsImmutable()) return errImmutableObject; slot = obj->slots + index; slotCopy(slot, c); g->gc->GCWrite(obj, slot); break; case obj_double : if (NotFloat(c)) { if (NotInt(c)) return errWrongType; else { ((double*)(obj->slots))[index] = slotRawInt(c); } } else ((double*)(obj->slots))[index] = slotRawFloat(c); break; case obj_float : if (NotFloat(c)) { if (NotInt(c)) return errWrongType; else { ((float*)(obj->slots))[index] = slotRawInt(c); } } else ((float*)(obj->slots))[index] = slotRawFloat(c); break; case obj_int32 : if (NotInt(c)) return errWrongType; ((int32*)(obj->slots))[index] = slotRawInt(c); break; case obj_int16 : if (NotInt(c)) return errWrongType; ((int16*)(obj->slots))[index] = slotRawInt(c); break; case obj_int8 : if (NotInt(c)) return errWrongType; ((int8*)(obj->slots))[index] = slotRawInt(c); break; case obj_symbol : if (NotSym(c)) return errWrongType; ((PyrSymbol**)(obj->slots))[index] = slotRawSymbol(c); break; case obj_char : if (NotChar(c)) return errWrongType; ((unsigned char*)(obj->slots))[index] = slotRawChar(c); break; } return errNone; } int putIndexedFloat(PyrObject *obj, double val, int index) { PyrSlot *slot; switch (obj->obj_format) { case obj_slot : if (obj->IsImmutable()) return errImmutableObject; slot = obj->slots + index; SetFloat(slot, val); break; case obj_double : ((double*)(obj->slots))[index] = val; break; case obj_float : ((float*)(obj->slots))[index] = (float)val; break; case obj_int32 : ((int32*)(obj->slots))[index] = (int32)val; break; case obj_int16 : ((int16*)(obj->slots))[index] = (int16)val; break; case obj_int8 : ((int8*)(obj->slots))[index] = (int8)val; break; } return errNone; } static int hashPtr(void* ptr) { int32 hashed_part = int32((size_t)ptr&0xffffffff); return Hash(hashed_part); } int calcHash(PyrSlot *a); int calcHash(PyrSlot *a) { int hash; switch (GetTag(a)) { case tagObj : hash = hashPtr(slotRawObject(a)); break; case tagInt : hash = Hash(slotRawInt(a)); break; case tagChar : hash = Hash(slotRawChar(a) & 255); break; case tagSym : hash = slotRawSymbol(a)->hash; break; case tagNil : hash = 0xA5A5A5A5; break; case tagFalse : hash = 0x55AA55AA; break; case tagTrue : hash = 0x69696969; break; case tagPtr : hash = hashPtr(slotRawPtr(a)); break; default : // hash for a double union { int32 i[2]; double d; } u; u.d = slotRawFloat(a); hash = Hash(u.i[0] + Hash(u.i[1])); } return hash; } void InstallFinalizer(VMGlobals* g, PyrObject *inObj, int slotIndex, ObjFuncPtr inFunc) { PyrObject *finalizer = g->gc->NewFinalizer(inFunc, inObj, false); SetObject(inObj->slots + slotIndex, finalizer); g->gc->GCWriteNew(inObj, finalizer); // we know finalizer is white so we can use GCWriteNew } SuperCollider-Source/lang/LangSource/PyrObject.h000644 000765 000024 00000021122 12321461511 022704 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* PyrObject represents the structure of all SC Objects. */ #ifndef _PYROBJECT_H_ #define _PYROBJECT_H_ #include "PyrSlot.h" /* special gc colors */ enum { obj_permanent = 1, // sent to gc->New as a flag obj_gcmarker = 2 // gc treadmill marker }; /* obj flag fields */ enum { obj_inaccessible = 4, obj_immutable = 16, obj_marked = 128 }; /* format types : */ enum { obj_notindexed, obj_slot, obj_double, obj_float, obj_int32, obj_int16, obj_int8, obj_char, obj_symbol, NUMOBJFORMATS }; /* PyrObjectHdr : object header fields prev, next : pointers in the GC treadmill classptr : pointer to the object's class size : number of slots or indexable elements. obj_format : what kind of data this object holds obj_sizeclass : power of two size class of the object obj_flags : immutable : set if object may not be updated. finalize : set if object requires finalization. marked : used by garbage collector debug sanity check. may be used by primitives but must be cleared before exiting primitive. gc_color : GC color : black, grey, white, free, permanent scratch1 : undefined value. may be used within primitives as a temporary scratch value. */ struct PyrObjectHdr { struct PyrObjectHdr *prev, *next; struct PyrClass *classptr; int size; unsigned char obj_format; unsigned char obj_sizeclass; unsigned char obj_flags; unsigned char gc_color; int scratch1; int SizeClass() { return obj_sizeclass; } void SetMark() { obj_flags |= obj_marked; } void ClearMark() { obj_flags &= ~obj_marked; } bool IsMarked() const { return obj_flags & obj_marked; } bool IsPermanent() const { return gc_color == obj_permanent; } bool IsImmutable() const { return obj_flags & obj_immutable; } bool IsMutable() const { return !IsImmutable(); } }; struct PyrObject : public PyrObjectHdr { PyrSlot slots[1]; }; struct PyrList : public PyrObjectHdr { PyrSlot array; }; struct PyrDoubleArray : public PyrObjectHdr { double d[1]; }; struct PyrFloatArray : public PyrObjectHdr { float f[1]; }; struct PyrInt32Array : public PyrObjectHdr { uint32 i[1]; }; struct PyrInt16Array : public PyrObjectHdr { uint16 i[1]; }; struct PyrInt8Array : public PyrObjectHdr { uint8 b[1]; }; struct PyrString : public PyrObjectHdr { char s[1]; }; struct PyrSymbolArray : public PyrObjectHdr { PyrSymbol* symbols[1]; }; extern struct PyrClass *class_object; extern struct PyrClass *class_array; extern struct PyrClass *class_list, *class_method, *class_fundef, *class_frame, *class_class; extern struct PyrClass *class_symbol, *class_nil; extern struct PyrClass *class_boolean, *class_true, *class_false; extern struct PyrClass *class_int, *class_char, *class_float, *class_complex; extern struct PyrClass *class_rawptr; extern struct PyrClass *class_string; extern struct PyrClass *class_magnitude, *class_number, *class_collection; extern struct PyrClass *class_sequenceable_collection; extern struct PyrClass *class_arrayed_collection; extern struct PyrClass *class_simple_number; extern struct PyrClass *class_signal; extern struct PyrClass *class_wavetable; extern struct PyrClass *class_rawarray; extern struct PyrClass *class_int8array; extern struct PyrClass *class_int16array; extern struct PyrClass *class_int32array; extern struct PyrClass *class_symbolarray; extern struct PyrClass *class_floatarray; extern struct PyrClass *class_doublearray; extern struct PyrClass *class_func, *class_absfunc; extern struct PyrClass *class_stream; extern struct PyrClass *class_process; extern struct PyrClass *class_interpreter; extern struct PyrClass *class_thread; extern struct PyrClass *class_routine; extern struct PyrClass *class_finalizer; extern struct PyrClass *class_server_shm_interface; extern PyrSymbol *s_none; extern PyrSymbol *s_object; extern PyrSymbol *s_bag; extern PyrSymbol *s_set; extern PyrSymbol *s_identityset; extern PyrSymbol *s_dictionary; extern PyrSymbol *s_identitydictionary; extern PyrSymbol *s_linkedlist; extern PyrSymbol *s_sortedlist; extern PyrSymbol *s_array; extern PyrSymbol *s_list, *s_method, *s_fundef, *s_frame, *s_class; extern PyrSymbol *s_symbol, *s_nil; extern PyrSymbol *s_boolean, *s_true, *s_false; extern PyrSymbol *s_int, *s_char, *s_color, *s_float, *s_complex; extern PyrSymbol *s_rawptr, *s_objptr; extern PyrSymbol *s_string; extern PyrSymbol *s_magnitude, *s_number, *s_collection; extern PyrSymbol *s_ordered_collection; extern PyrSymbol *s_sequenceable_collection; extern PyrSymbol *s_arrayed_collection; extern PyrSymbol *s_simple_number; extern PyrSymbol *s_signal; extern PyrSymbol *s_wavetable; extern PyrSymbol *s_int8array; extern PyrSymbol *s_int16array; extern PyrSymbol *s_int32array; extern PyrSymbol *s_symbolarray; extern PyrSymbol *s_floatarray; extern PyrSymbol *s_doublearray; extern PyrSymbol *s_point; extern PyrSymbol *s_rect; extern PyrSymbol *s_stream; extern PyrSymbol *s_process; extern PyrSymbol *s_main; extern PyrSymbol *s_thread; extern PyrSymbol *s_routine; extern PyrSymbol *s_linear, *s_exponential, *s_gate; extern PyrSymbol *s_env; extern PyrSymbol *s_audio, *s_control, *s_scalar; extern PyrSymbol *s_run, *s_stop, *s_tick; extern PyrSymbol *s_next; extern PyrSymbol *s_at; extern PyrSymbol *s_put; extern PyrSymbol *s_series, *s_copyseries, *s_putseries; extern PyrSymbol *s_value; extern PyrSymbol *s_performList; extern PyrSymbol *s_superPerformList; extern PyrSymbol *s_ugen, *s_outputproxy; extern PyrSymbol *s_new, *s_ref; extern PyrSymbol *s_synth, *s_spawn, *s_environment, *s_event; extern PyrSymbol *s_interpreter; extern PyrSymbol *s_finalizer; extern PyrSymbol *s_awake; extern PyrSymbol *s_appclock; extern PyrSymbol *s_systemclock; extern PyrSymbol *s_server_shm_interface; extern PyrSymbol *s_interpretCmdLine, *s_interpretPrintCmdLine; extern int gFormatElemSize[NUMOBJFORMATS]; extern int gFormatElemCapc[NUMOBJFORMATS]; extern int gFormatElemTag[NUMOBJFORMATS]; void dumpObject(PyrObject *obj); void dumpObjectSlot(PyrSlot *slot); bool respondsTo(PyrSlot *slot, PyrSymbol *selector); bool isSubclassOf(struct PyrClass *classobj, struct PyrClass *testclass); extern struct PyrClass* gTagClassTable[16]; inline struct PyrClass* classOfSlot(PyrSlot *slot) { PyrClass *classobj; int tag; if (IsFloat(slot)) classobj = class_float; else if ((tag = GetTag(slot) & 0xF) == 1) classobj = slotRawObject(slot)->classptr; else classobj = gTagClassTable[tag]; return classobj; } typedef int (*ObjFuncPtr)(struct VMGlobals*, struct PyrObject*); void stringFromPyrString(PyrString *obj, char *str, int maxlength); void pstringFromPyrString(PyrString *obj, unsigned char *str, int maxlength); int instVarOffset(const char *classname, const char *instvarname); int classVarOffset(const char *classname, const char *classvarname, PyrClass** classobj); void fillSlots(PyrSlot* slot, int size, PyrSlot* fillslot); void nilSlots(PyrSlot* slot, int size); void zeroSlots(PyrSlot* slot, int size); int calcHash(PyrSlot *a); int getIndexedFloat(struct PyrObject *obj, int index, float *value); int getIndexedDouble(struct PyrObject *obj, int index, double *value); inline int getIndexedVal(struct PyrObject *obj, int index, float *value) { return getIndexedFloat(obj, index, value); } inline int getIndexedVal(struct PyrObject *obj, int index, double *value) { return getIndexedDouble(obj, index, value); } void getIndexedSlot(struct PyrObject *obj, PyrSlot *a, int index); int putIndexedSlot(struct VMGlobals *g, struct PyrObject *obj, PyrSlot *c, int index); int putIndexedFloat(PyrObject *obj, double val, int index); inline long ARRAYMAXINDEXSIZE(PyrObjectHdr* obj) { return (1L << obj->obj_sizeclass); } inline long MAXINDEXSIZE(PyrObjectHdr* obj) { return ((1L << obj->obj_sizeclass) * gFormatElemCapc[ obj->obj_format ]); } void InstallFinalizer(VMGlobals* g, PyrObject *inObj, int slotIndex, ObjFuncPtr inFunc); ///// #endif SuperCollider-Source/lang/LangSource/PyrObjectProto.h000644 000765 000024 00000002654 12321461511 023741 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYROBJPROTO_H_ #define _PYROBJPROTO_H_ #include "PyrObject.h" void initSymbols(); void initClasses(); void buildClassTree(); void freePyrSlot(PyrSlot *slot); void freePyrObject(PyrObject* obj); bool objAddIndexedSlot(PyrObject *obj, PyrSlot *slot); bool objAddIndexedSymbol(PyrSymbolArray *obj, PyrSymbol *symbol); bool objAddIndexedObject(PyrObject *obj, PyrObject *obj2); void CallStackSanity(struct VMGlobals *g, const char * tagstr); bool FrameSanity(struct PyrFrame *frame, const char* tagstr); void dumpBadObject(PyrObject *obj); void initRawRegistry(); #endif SuperCollider-Source/lang/LangSource/PyrParseNode.cpp000644 000765 000024 00000423546 12756531745 023754 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "PyrParseNode.h" #include "PyrLexer.h" #include "PyrKernel.h" #include "PyrListPrim.h" #include "PyrSymbolTable.h" #include "Opcodes.h" #include "PyrKernelProto.h" #include "PyrObjectProto.h" #include "GC.h" #include #include #include #include #include #include "InitAlloc.h" #include "PredefinedSymbols.h" #include "SimpleStack.h" #include "PyrPrimitive.h" #include "SC_Win32Utils.h" AdvancingAllocPool gParseNodePool; PyrSymbol *gSpecialUnarySelectors[opNumUnarySelectors]; PyrSymbol *gSpecialBinarySelectors[opNumBinarySelectors]; PyrSymbol *gSpecialSelectors[opmNumSpecialSelectors]; PyrSymbol* gSpecialClasses[op_NumSpecialClasses]; PyrSlot gSpecialValues[svNumSpecialValues]; PyrParseNode* gRootParseNode; intptr_t gParserResult; int conjureConstantIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot); void compilePushConstant(PyrParseNode* node, PyrSlot *slot); PyrClass *gCurrentClass = NULL; PyrClass *gCurrentMetaClass = NULL; PyrClass *gCompilingClass = NULL; PyrMethod *gCompilingMethod = NULL; PyrBlock *gCompilingBlock = NULL; PyrBlock *gPartiallyAppliedFunction = NULL; bool gIsTailCodeBranch = false; bool gTailIsMethodReturn = false; int gFunctionHighestExternalRef = 1; bool gFunctionCantBeClosed = true; #if TAILCALLOPTIMIZE bool gGenerateTailCallByteCodes = true; #else bool gGenerateTailCallByteCodes = false; #endif long gInliningLevel; int compileErrors = 0; int numOverwrites = 0; std::string overwriteMsg; extern bool compilingCmdLine; extern int errLineOffset, errCharPosOffset; bool gPostInlineWarnings = false; const char* nodename[] = { "ClassNode", "ClassExtNode", "MethodNode", "BlockNode", "SlotNode", /* variable declarations */ "VarListNode", "VarDefNode", "DynDictNode", "DynListNode", "LitListNode", "LitDictNode", "StaticVarListNode", "InstVarListNode", "PoolVarListNode", "ArgListNode", "SlotDefNode", /* selectors */ "LiteralNode", /* code */ "PushLitNode", "PushNameNode", "PushKeyArgNode", "CallNode", "BinopCallNode", "DropNode", "AssignNode", "MultiAssignNode", "MultiAssignVarListNode", "SetterNode", "CurryArgNode", "ReturnNode", "BlockReturnNode" }; void compileTail() { if (gGenerateTailCallByteCodes && gIsTailCodeBranch) { //if (gCompilingClass && gCompilingMethod) post("tail call %s:%s ismethod %d\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, gTailIsMethodReturn); if (gTailIsMethodReturn) compileByte(255); else compileByte(176); } } PyrGC* compileGC(); PyrGC* compileGC() { return gCompilingVMGlobals ? gCompilingVMGlobals->gc : 0; } void initParser() { compileErrors = 0; numOverwrites = 0; overwriteMsg.clear(); } void finiParser() { } void initParseNodes() { } void initParserPool() { //postfl("initPool gParseNodePool pyr_pool_compile\n"); gParseNodePool.Init(pyr_pool_compile, 32000, 32000, 2000); } void freeParserPool() { //postfl("freePool gParseNodePool pyr_pool_compile\n"); gParseNodePool.FreeAll(); } PyrParseNode::PyrParseNode(int inClassNo) { mClassno = inClassNo; mNext = 0; mTail = this; mCharno = ::charno; mLineno = ::lineno; mParens = 0; } void compileNodeList(PyrParseNode *node, bool onTailBranch) { PyrSlot dummy; //postfl("->compileNodeList\n"); for (; node; node = node->mNext) { //postfl("-->compileNodeList %p\n", node); COMPILENODE(node, &dummy, onTailBranch); //postfl("<--compileNodeList %p\n", node); } //postfl("<-compileNodeList\n"); } void nodePostErrorLine(PyrParseNode* node) { postErrorLine(node->mLineno, linestarts[node->mLineno], node->mCharno); } PyrPushNameNode* newPyrPushNameNode(PyrSlotNode *slotNode) { slotNode->mClassno = pn_PushNameNode; return (PyrPushNameNode*)slotNode; } void compilePushVar(PyrParseNode *node, PyrSymbol *varName) { int level, index, vindex, varType; PyrBlock *tempfunc; PyrClass *classobj; //postfl("compilePushVar\n"); classobj = gCompilingClass; if (varName->name[0] >= 'A' && varName->name[0] <= 'Z') { if (compilingCmdLine && varName->u.classobj == NULL) { error("Class not defined.\n"); nodePostErrorLine(node); compileErrors++; } else { if (findSpecialClassName(varName, &index)) { compileOpcode(opExtended, opPushSpecialValue); // special op for pushing a class compileByte(index); } else { PyrSlot slot; SetSymbol(&slot, varName); index = conjureLiteralSlotIndex(node, gCompilingBlock, &slot); compileOpcode(opExtended, opExtended); // special op for pushing a class compileByte(index); } } } else if (varName == s_this || varName == s_super) { gFunctionCantBeClosed = true; compileOpcode(opPushSpecialValue, opsvSelf); } else if (varName == s_true) { compileOpcode(opPushSpecialValue, opsvTrue); } else if (varName == s_false) { compileOpcode(opPushSpecialValue, opsvFalse); } else if (varName == s_nil) { compileOpcode(opPushSpecialValue, opsvNil); } else if (findVarName(gCompilingBlock, &classobj, varName, &varType, &level, &index, &tempfunc)) { switch (varType) { case varInst : compileOpcode(opPushInstVar, index); break; case varClass : { index += slotRawInt(&classobj->classVarIndex); if (index < 4096) { compileByte((opPushClassVar<<4) | ((index >> 8) & 15)); compileByte(index & 255); } else { compileByte(opPushClassVar); compileByte((index >> 8) & 255); compileByte(index & 255); } } break; case varConst : { PyrSlot *slot = slotRawObject(&classobj->constValues)->slots + index; compilePushConstant(node, slot); } break; case varTemp : vindex = index; if (level == 0) { compileOpcode(opPushTempZeroVar, vindex); } else if (level < 8) { compileOpcode(opPushTempVar, level); compileByte(vindex); } else { compileByte(opPushTempVar); compileByte(level); compileByte(vindex); } break; case varPseudo : compileOpcode(opExtended, opSpecialOpcode); compileByte(index); break; } } else { error("Variable '%s' not defined.\n", varName->name); nodePostErrorLine(node); compileErrors++; //Debugger(); } } PyrCurryArgNode* newPyrCurryArgNode() { PyrCurryArgNode* node = ALLOCNODE(PyrCurryArgNode); return node; } void PyrCurryArgNode::compile(PyrSlot *result) { if (gPartiallyAppliedFunction) { compileOpcode(opPushTempZeroVar, mArgNum); } else { error("found _ argument outside of a call.\n"); nodePostErrorLine((PyrParseNode*)this); compileErrors++; } } PyrSlotNode* newPyrSlotNode(PyrSlot *slot) { PyrSlotNode* node = ALLOCNODE(PyrSlotNode); node->mSlot = *slot; return node; } void PyrSlotNode::compile(PyrSlot *result) { if (mClassno == pn_LiteralNode) compileLiteral(result); else if (mClassno == pn_PushLitNode) compilePushLit(result); else if (mClassno == pn_PushNameNode) compilePushVar((PyrParseNode*)this, slotRawSymbol(&mSlot)); else { error("compilePyrSlotNode: shouldn't get here.\n"); dumpObjectSlot(&mSlot); nodePostErrorLine((PyrParseNode*)this); compileErrors++; //Debugger(); } } PyrClassExtNode* newPyrClassExtNode(PyrSlotNode* className, PyrMethodNode* methods) { PyrClassExtNode* node = ALLOCNODE(PyrClassExtNode); node->mClassName = className; node->mMethods = methods; return node; } void PyrClassExtNode::compile(PyrSlot *result) { PyrClass *classobj = slotRawSymbol(&mClassName->mSlot)->u.classobj; if (!classobj) { char extPath[1024]; asRelativePath(gCompilingFileSym->name, extPath); error("Class extension for nonexistent class '%s'\n In file:'%s'\n", slotRawSymbol(&mClassName->mSlot)->name, extPath ); return; } gCurrentClass = classobj; gCurrentMetaClass = classobj->classptr; compileExtNodeMethods(this); } void compileExtNodeMethods(PyrClassExtNode* node) { PyrMethodNode *method; method = node->mMethods; for (; method; method = (PyrMethodNode*)method->mNext) { PyrSlot dummy; //post("compile ext %s:%s\n", method->mExtension = true; compilePyrMethodNode(method, &dummy); } gCompilingMethod = NULL; gCompilingBlock = NULL; gPartiallyAppliedFunction = NULL; gInliningLevel = 0; } PyrClassNode* newPyrClassNode(PyrSlotNode* className, PyrSlotNode* superClassName, PyrVarListNode* varlists, PyrMethodNode* methods, PyrSlotNode* indexType) { PyrClassNode* node = ALLOCNODE(PyrClassNode); node->mClassName = className; node->mIndexType = indexType; node->mSuperClassName = superClassName; node->mVarlists = varlists; node->mMethods = methods; node->mVarTally[varInst] = 0; node->mVarTally[varClass] = 0; node->mVarTally[varTemp] = 0; node->mVarTally[varConst] = 0; //node->mVarTally[varPool] = 0; return node; } bool compareVarDefs(PyrClassNode* node, PyrClass* classobj) { int numinstvars, numclassvars; int i, xinst, xclass; PyrVarListNode* varlist; PyrVarDefNode *vardef; PyrParseNode *errnode; PyrSymbol **varNames; bool isIntrinsic; isIntrinsic = slotRawInt(&classobj->classFlags) & classIsIntrinsic; numinstvars = numInstVars(classobj); numclassvars = numClassVars(classobj); if (numinstvars == node->mVarTally[varInst] + node->mNumSuperInstVars && numclassvars == node->mVarTally[varClass]) { xclass = 0; xinst = node->mNumSuperInstVars; varlist = node->mVarlists; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { int type = varlist->mFlags; if (type == varInst) { vardef = varlist->mVarDefs; varNames = slotRawSymbolArray(&classobj->instVarNames)->symbols; for (i=0; vardef; vardef = (PyrVarDefNode*)vardef->mNext, xinst++, ++i) { if (slotRawSymbol(&vardef->mVarName->mSlot) != varNames[xinst]) { errnode = (PyrParseNode*)vardef; //post("A %s %d %d %d\n", vardef->mVarName->slotRawSymbol(&mSlot)->name, // vardef->mVarName->slotRawSymbol(&mSlot), varNames[xinst].us, xinst); //post("A %s %s %d\n", vardef->mVarName->slotRawSymbol(&mSlot)->name, // varNames[xinst].us->name, xinst); goto differExit; } } } else if (type == varClass) { vardef = varlist->mVarDefs; varNames = slotRawSymbolArray(&classobj->classVarNames)->symbols; for (i=0; vardef && xclass < numclassvars; vardef = (PyrVarDefNode*)vardef->mNext, xclass++, ++i) { if (slotRawSymbol(&vardef->mVarName->mSlot) != varNames[xclass]) { errnode = (PyrParseNode*)vardef; //post("B %d %d %d\n", vardef->mVarName->slotRawSymbol(&mSlot), varNames[xclass].us, xclass); goto differExit; } } } } } else { //post("C %d %d %d %d %d\n", numinstvars, node->mVarTally[varInst], node->mNumSuperInstVars, // numclassvars, node->mVarTally[varClass]); errnode = (node->mVarlists ? (PyrParseNode*)node->mVarlists : (PyrParseNode*)node->mClassName); goto differExit; } return false; differExit: if (isIntrinsic) { error("You may not change variable definitions of intrinsic classes.\n"); nodePostErrorLine(errnode); compileErrors++; } return true; } void countClassVarDefs(PyrClassNode* node, int *numClassMethods, int *numInstMethods) { PyrVarListNode* varlist; PyrVarDefNode *vardef; //*numClassMethods = 0; //*numInstMethods = 0; node->mVarTally[varInst] = 0; node->mVarTally[varClass] = 0; node->mVarTally[varTemp] = 0; node->mVarTally[varConst] = 0; // count number of variables of each type varlist = node->mVarlists; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { int type = varlist->mFlags; vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { node->mVarTally[type]++; if (type == varClass) { if (vardef->mFlags & rwReadOnly) { *numClassMethods = *numClassMethods + 1; } if (vardef->mFlags & rwWriteOnly) { *numClassMethods = *numClassMethods + 1; } } else if (type == varInst) { if (vardef->mFlags & rwReadOnly) { *numInstMethods = *numInstMethods + 1; } if (vardef->mFlags & rwWriteOnly) { *numInstMethods = *numInstMethods + 1; } } } } } void countNodeMethods(PyrClassNode* node, int *numClassMethods, int *numInstMethods) { // count methods PyrMethodNode *method; //*numClassMethods = 0; //*numInstMethods = 0; method = node->mMethods; for (; method; method = (PyrMethodNode*)method->mNext) { if (method->mIsClassMethod) *numClassMethods = *numClassMethods + 1; else *numInstMethods = *numInstMethods + 1; } } void compileNodeMethods(PyrClassNode* node) { PyrMethodNode *method; method = node->mMethods; for (; method; method = (PyrMethodNode*)method->mNext) { PyrSlot dummy; method->mExtension = false; compilePyrMethodNode(method, &dummy); } gCompilingMethod = NULL; gCompilingBlock = NULL; gPartiallyAppliedFunction = NULL; gInliningLevel = 0; } PyrClass* getNodeSuperclass(PyrClassNode *node) { PyrClass *superclassobj = NULL; // postfl("getNodeSuperclass node %d\n", node); // postfl("getNodeSuperclass node->mSuperClassName %d\n", node->mSuperClassName); // postfl("getNodeSuperclass node->mSuperClassName->mSlot.utag %d\n", // node->mSuperClassName->mSlot.utag); if (node->mSuperClassName && IsSym(&node->mSuperClassName->mSlot)) { superclassobj = slotRawSymbol(&node->mSuperClassName->mSlot)->u.classobj; if (superclassobj == NULL) { error("Cannot find superclass '%s' for class '%s'\n", slotSymString(&node->mSuperClassName->mSlot), slotSymString(&node->mClassName->mSlot)); nodePostErrorLine((PyrParseNode*)node->mSuperClassName); superclassobj = (PyrClass*)-1; compileErrors++; } } else { if (slotRawSymbol(&node->mClassName->mSlot) != s_object) { superclassobj = class_object; } // else this is object and there is no superclass } return superclassobj; } void fillClassPrototypes(PyrClassNode *node, PyrClass *classobj, PyrClass *superclassobj) { PyrVarListNode* varlist; PyrVarDefNode *vardef; PyrSlot *islot, *cslot, *kslot; PyrSymbol **inameslot, **cnameslot, **knameslot; PyrClass *metaclassobj; PyrMethod *method; PyrMethodRaw *methraw; int instVarIndex, classVarIndex; // copy superclass's prototype to here if (superclassobj && NotNil(&superclassobj->iprototype) && slotRawObject(&superclassobj->iprototype)->size) { memcpy(slotRawObject(&classobj->iprototype)->slots, slotRawObject(&superclassobj->iprototype)->slots, sizeof(PyrSlot)* slotRawObject(&superclassobj->iprototype)->size); //slotRawObject(&classobj->iprototype)->size = slotRawObject(&superclassobj->iprototype)->size; slotRawObject(&classobj->iprototype)->size = node->mNumSuperInstVars; memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols, slotRawSymbolArray(&superclassobj->instVarNames)->symbols, sizeof(PyrSymbol*)* slotRawObject(&superclassobj->instVarNames)->size); //slotRawObject(&classobj->instVarNames)->size = slotRawObject(&superclassobj->iprototype)->size; slotRawObject(&classobj->instVarNames)->size = node->mNumSuperInstVars; } // fill the class' own part of prototypes metaclassobj = classobj->classptr; varlist = node->mVarlists; if (NotNil(&classobj->iprototype)) { islot = slotRawObject(&classobj->iprototype)->slots + node->mNumSuperInstVars; } if (NotNil(&classobj->cprototype)) { cslot = slotRawObject(&classobj->cprototype)->slots; } if (NotNil(&classobj->constValues)) { kslot = slotRawObject(&classobj->constValues)->slots; } if (NotNil(&classobj->instVarNames)) { inameslot = slotRawSymbolArray(&classobj->instVarNames)->symbols + node->mNumSuperInstVars; } if (NotNil(&classobj->classVarNames)) { cnameslot = slotRawSymbolArray(&classobj->classVarNames)->symbols; } if (NotNil(&classobj->constNames)) { knameslot = slotRawSymbolArray(&classobj->constNames)->symbols; } instVarIndex = node->mNumSuperInstVars; classVarIndex = 0; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { int type = varlist->mFlags; switch (type) { case varInst : vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { PyrSlot litslot; compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot); *islot++ = litslot; slotRawObject(&classobj->iprototype)->size++; *inameslot++ = slotRawSymbol(&vardef->mVarName->mSlot); slotRawSymbolArray(&classobj->instVarNames)->size++; if (vardef->mFlags & rwReadOnly) { // create getter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 1; methraw->numvars = 0; methraw->posargs = 1; methraw->varargs = 0; methraw->numtemps = 1; methraw->popSize = 0; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, classobj); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); slotCopy(&method->name, &vardef->mVarName->mSlot); methraw->methType = methReturnInstVar; methraw->specialIndex = instVarIndex; addMethod(classobj, method); } if (vardef->mFlags & rwWriteOnly) { char setterName[256]; PyrSymbol *setterSym; sprintf(setterName, "%s_", slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore = strcpy(setterName, slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore[0] = '_'; //underscore[1] = 0; setterSym = getsym(setterName); // create setter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 2; methraw->numvars = 0; methraw->posargs = 2; methraw->varargs = 0; methraw->numtemps = 2; methraw->popSize = 1; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, classobj); SetSymbol(&method->name, setterSym); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methAssignInstVar; methraw->specialIndex = instVarIndex; addMethod(classobj, method); } instVarIndex++; } break; case varClass : vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { PyrSlot litslot; compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot); *cslot++ = litslot; slotRawObject(&classobj->cprototype)->size++; *cnameslot++ = slotRawSymbol(&vardef->mVarName->mSlot); slotRawSymbolArray(&classobj->classVarNames)->size++; if (vardef->mFlags & rwReadOnly) { // create getter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 1; methraw->numvars = 0; methraw->posargs = 1; methraw->varargs = 0; methraw->numtemps = 1; methraw->popSize = 0; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, metaclassobj); slotCopy(&method->name, &vardef->mVarName->mSlot); SetSymbol(&method->selectors, slotRawSymbol(&classobj->name)); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methReturnClassVar; methraw->specialIndex = classVarIndex + slotRawInt(&classobj->classVarIndex); addMethod(metaclassobj, method); } if (vardef->mFlags & rwWriteOnly) { char setterName[256]; PyrSymbol *setterSym; sprintf(setterName, "%s_", slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore = strcpy(setterName, slotRawSymbol(&vardef->mVarName->mSlot)->name); //underscore[0] = '_'; //underscore[1] = 0; setterSym = getsym(setterName); // create setter method method = newPyrMethod(); methraw = METHRAW(method); methraw->numargs = 2; methraw->numvars = 0; methraw->posargs = 2; methraw->varargs = 0; methraw->numtemps = 2; methraw->popSize = 1; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, metaclassobj); SetSymbol(&method->name, setterSym); SetSymbol(&method->selectors, slotRawSymbol(&classobj->name)); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methAssignClassVar; methraw->specialIndex = classVarIndex + slotRawInt(&classobj->classVarIndex); addMethod(metaclassobj, method); } classVarIndex++; } break; case varConst : vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { PyrSlot litslot; compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot); *kslot++ = litslot; slotRawObject(&classobj->constValues)->size++; *knameslot++ = slotRawSymbol(&vardef->mVarName->mSlot); slotRawSymbolArray(&classobj->constNames)->size++; if (vardef->mFlags & rwReadOnly) { // create getter method method = newPyrMethod(); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; methraw->numargs = 1; methraw->numvars = 0; methraw->posargs = 1; methraw->varargs = 0; methraw->numtemps = 1; methraw->popSize = 0; SetNil(&method->contextDef); SetNil(&method->varNames); SetObject(&method->ownerclass, metaclassobj); slotCopy(&method->name, &vardef->mVarName->mSlot); if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset); methraw->methType = methReturnLiteral; slotCopy(&method->selectors, &litslot); addMethod(metaclassobj, method); } } break; } } } int getIndexType(PyrClassNode *classnode) { PyrSlotNode *node; int res; node = classnode->mIndexType; if (node == NULL) res = obj_notindexed; else { char *name; name = slotRawSymbol(&node->mSlot)->name; if (strcmp(name, "slot") == 0) res = obj_slot; else if (strcmp(name, "double") == 0) res = obj_double; else if (strcmp(name, "float") == 0) res = obj_float; else if (strcmp(name, "int32") == 0) res = obj_int32; else if (strcmp(name, "int16") == 0) res = obj_int16; else if (strcmp(name, "int8") == 0) res = obj_int8; else if (strcmp(name, "char") == 0) res = obj_char; else if (strcmp(name, "symbol") == 0) res = obj_symbol; else { error("Illegal indexed type. Must be one of:\n" " slot, double, float, int8, int16, int32, char\n"); res = obj_slot; compileErrors++; } } return res; } void PyrClassNode::compile(PyrSlot *result) { PyrClass *classobj, *superclassobj, *metaclassobj; int numClassMethods, numInstMethods; bool isIntrinsic; bool varsDiffer, superclassesDiffer, indexTypesDiffer; bool shouldRecompileSubclasses = false; int indexType; // find num instvars in superclass //postfl("class '%s'\n", slotRawSymbol(&mClassName->mSlot)->name); superclassobj = getNodeSuperclass(this); indexType = getIndexType(this); //postfl("%s %d\n", slotRawSymbol(&mClassName->mSlot)->name, indexType); if ((size_t)superclassobj == -1) { // redundant error message removed: //error("Can't find superclass of '%s'\n", slotRawSymbol(&mClassName->mSlot)->name); //nodePostErrorLine(node); return; // can't find superclass } mNumSuperInstVars = numSuperInstVars(superclassobj); numClassMethods = 0; numInstMethods = 0; countClassVarDefs(this, &numClassMethods, &numInstMethods); //postfl("accessor methods %d %d\n", numClassMethods, numInstMethods); countNodeMethods(this, &numClassMethods, &numInstMethods); //postfl("total methods %d %d\n", numClassMethods, numInstMethods); // get or make a class object // see if it already exists classobj = slotRawSymbol(&mClassName->mSlot)->u.classobj; if (classobj) { // deal with intrinsic classes or other classes being recompiled here. // recompile of subclasses not necessary if inst and class vars are // unchanged. metaclassobj = (PyrClass*)classobj->classptr; isIntrinsic = slotRawInt(&classobj->classFlags) & classIsIntrinsic; varsDiffer = compareVarDefs(this, classobj); if (varsDiffer) { if (isIntrinsic) { //error("Class '%s' declaration doesn't match intrinsic definition.\n", // slotRawSymbol(&mClassName->mSlot)->name); return; } else { shouldRecompileSubclasses = true; } } superclassesDiffer = superclassobj != slotRawSymbol(&classobj->superclass)->u.classobj; indexTypesDiffer = indexType != slotRawInt(&classobj->instanceFormat); //postfl("%d %d %d\n", indexType, slotRawInt(&classobj->instanceFormat)); //if (varsDiffer || superclassesDiffer || indexTypesDiffer) { if (varsDiffer || superclassesDiffer || indexTypesDiffer) { if (isIntrinsic) { if (superclassesDiffer) { error("Superclass of '%s' does not match intrinsic definition.\n", slotRawSymbol(&mClassName->mSlot)->name); nodePostErrorLine((PyrParseNode*)(mSuperClassName ? mSuperClassName : mClassName)); compileErrors++; } if (indexTypesDiffer) { error("Index type of '%s' does not match intrinsic definition.\n", slotRawSymbol(&mClassName->mSlot)->name); nodePostErrorLine((indexType ? (PyrParseNode*)mIndexType : (PyrParseNode*)mClassName)); compileErrors++; } error("Class '%s' declaration doesn't match intrinsic definition.\n", slotRawSymbol(&mClassName->mSlot)->name); return; } else { shouldRecompileSubclasses = true; } } // reallocate fields in the class object reallocClassObj(metaclassobj, classClassNumInstVars, 0, 0, numClassMethods, indexType, 0); //postfl("^3 %d %d\n", metaclassobj, class_class); //postfl("^4 %d %d\n", slotRawObject(&metaclassobj->iprototype), slotRawObject(&class_class->iprototype)); memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; slotRawSymbolArray(&metaclassobj->instVarNames)->size = classClassNumInstVars; reallocClassObj(classobj, mVarTally[varInst] + mNumSuperInstVars, mVarTally[varClass], mVarTally[varConst], numInstMethods, indexType, 0); } else { PyrSymbol *superClassName, *metaClassName, *metaSuperClassName; superClassName = superclassobj ? slotRawSymbol(&superclassobj->name) : NULL; metaClassName = getmetasym(slotRawSymbol(&mClassName->mSlot)->name); metaClassName->flags |= sym_MetaClass; metaSuperClassName = superClassName ? getmetasym(superClassName->name) : NULL; metaclassobj = newClassObj(class_class, metaClassName, metaSuperClassName, classClassNumInstVars, 0, 0, numClassMethods, indexType, 0); // test //postfl("^1 %d %d\n", metaclassobj, class_class); //postfl("^2 %d %d\n", slotRawObject(&metaclassobj->iprototype), slotRawObject(&class_class->iprototype)); memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots, sizeof(PyrSlot) * classClassNumInstVars); memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols, slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars); slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars; slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars; // end test classobj = newClassObj(metaclassobj, slotRawSymbol(&mClassName->mSlot), superClassName, mVarTally[varInst] + mNumSuperInstVars, mVarTally[varClass], mVarTally[varConst], numInstMethods, indexType, 0); } gCurrentClass = classobj; gCurrentMetaClass = metaclassobj; if (gCompilingFileSym) { SetSymbol(&classobj->filenameSym, gCompilingFileSym); SetInt(&classobj->charPos, linestarts[mClassName->mLineno] + errCharPosOffset); SetSymbol(&metaclassobj->filenameSym, gCompilingFileSym); SetInt(&metaclassobj->charPos, linestarts[mClassName->mLineno] + errCharPosOffset); } else { SetNil(&classobj->filenameSym); SetNil(&metaclassobj->filenameSym); } // fill inst and class prototypes fillClassPrototypes(this, classobj, superclassobj); // compile methods compileNodeMethods(this); // recompileSubclasses if (shouldRecompileSubclasses) { recompileSubclasses(classobj); } } void recompileSubclasses(PyrClass* classobj) { } #if 0 void catVarLists(PyrVarListNode *varlist); void catVarLists(PyrVarListNode *varlist) { PyrVarListNode *prevvarlist; PyrVarDefNode *vardef, *lastvardef; if (varlist) { // find end of this list vardef = varlist->mVarDefs; for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { lastvardef = vardef; } prevvarlist = varlist; varlist = (PyrVarListNode*)varlist->mNext; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { vardef = varlist->mVarDefs; if (lastvardef) { lastvardef->mNext = (PyrParseNode*)vardef; } else { prevvarlist->mVarDefs = vardef; } // find end of this list for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) { lastvardef = vardef; } } } } #else void catVarLists(PyrVarListNode *varlist); void catVarLists(PyrVarListNode *varlist) { PyrVarListNode *prevvarlist; PyrVarDefNode *vardef, *lastvardef; if (varlist) { // find end of this list vardef = varlist->mVarDefs; lastvardef = (PyrVarDefNode*)vardef->mTail; prevvarlist = varlist; varlist = (PyrVarListNode*)varlist->mNext; for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) { vardef = varlist->mVarDefs; lastvardef->mNext = (PyrParseNode*)vardef; // find end of this list lastvardef = (PyrVarDefNode*)vardef->mTail; } } } #endif PyrMethodNode* newPyrMethodNode(PyrSlotNode* methodName, PyrSlotNode* primitiveName, PyrArgListNode* arglist, PyrVarListNode *varlist, PyrParseNode* body, int isClassMethod) { PyrMethodNode* node = ALLOCNODE(PyrMethodNode); node->mMethodName = methodName; node->mPrimitiveName = primitiveName; node->mArglist = arglist; catVarLists(varlist); node->mVarlist = varlist; node->mBody = body; node->mIsClassMethod = isClassMethod; return node; } enum { push_Normal, push_AllArgs, push_AllButFirstArg, push_AllButFirstArg2 }; int checkPushAllArgs(PyrParseNode *actualArg, int numArgs); int checkPushAllArgs(PyrParseNode *actualArg, int numArgs) { PyrBlock *block; PyrPushNameNode *nameNode; block = gCompilingBlock; int i; //if (strcmp("ar", slotRawSymbol(&gCompilingMethod->name)->name)==0) Debugger(); if (actualArg->mClassno != pn_PushNameNode) { if (numArgs < 3) { return push_Normal; } actualArg = actualArg->mNext; for (i=1; imClassno != pn_PushNameNode) { return push_Normal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) { return push_Normal; } actualArg = actualArg->mNext; } return push_AllButFirstArg; } else { for (i=0; imClassno != pn_PushNameNode) { return push_Normal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) { return push_Normal; } actualArg = actualArg->mNext; } return push_AllArgs; } } int checkPushAllButFirstTwoArgs(PyrParseNode *actualArg, int numArgs); int checkPushAllButFirstTwoArgs(PyrParseNode *actualArg, int numArgs) { PyrBlock *block; PyrPushNameNode *nameNode; block = gCompilingBlock; int i; if (numArgs >= 2) { actualArg = actualArg->mNext; actualArg = actualArg->mNext; for (i=1; imClassno != pn_PushNameNode) { return push_Normal; } nameNode = (PyrPushNameNode*)actualArg; /*if (slotRawSymbol(&gCompilingClass->name) == s_ugen) { post("check meth %s %d '%s' '%s'\n", slotRawSymbol(&gCompilingMethod->name)->name, i, slotRawSymbol(&nameNode->mSlot)->name, block->argNames.uosym->symbols[i]->name); }*/ if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) { return push_Normal; } actualArg = actualArg->mNext; } return push_AllButFirstArg2; } return push_Normal; } int compareCallArgs(PyrMethodNode* node, PyrCallNode *cnode, int *varIndex, PyrClass **specialClass) { int i, numFormalArgs, numActualArgs; int special, varType, varLevel; PyrParseNode *actualArg; PyrVarDefNode *formalArg; PyrPushNameNode *nameNode; // fail if has a rest arg .. too much trouble? if (node->mArglist && node->mArglist->mRest) { return methNormal; } // check first actual arg is 'this' actualArg = cnode->mArglist; if (actualArg->mClassno != pn_PushNameNode) { return methNormal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) == s_this) { special = methRedirect; } else if (slotRawSymbol(&nameNode->mSlot) == s_super) { special = methRedirectSuper; } else { bool varFound; PyrClass *classobj; classobj = gCompilingClass; varFound = findVarName(gCompilingBlock, &classobj, slotRawSymbol(&nameNode->mSlot), &varType, &varLevel, varIndex, NULL); if (!varFound ) return methNormal; if (varType == varInst) special = methForwardInstVar; else if (varType == varClass) { special = methForwardClassVar; *varIndex += slotRawInt(&classobj->classVarIndex); *specialClass = classobj; } else return methNormal; } actualArg = actualArg->mNext; numActualArgs = nodeListLength((PyrParseNode*)cnode->mArglist); if (!node->mArglist) { numFormalArgs = 1; if (numActualArgs != numFormalArgs) { return methNormal; } } else { numFormalArgs = 1 + nodeListLength((PyrParseNode*)node->mArglist->mVarDefs); if (numActualArgs != numFormalArgs) { return methNormal; } formalArg = node->mArglist->mVarDefs; for (i=0; imClassno != pn_PushNameNode) { return methNormal; } nameNode = (PyrPushNameNode*)actualArg; if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbol(&formalArg->mVarName->mSlot)) { return methNormal; } formalArg = (PyrVarDefNode*)formalArg->mNext; actualArg = actualArg->mNext; } } /* if (special == methForwardInstVar) { postfl("methForwardInstVar %s:%s formal %d actual %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs); } if (special == methForwardClassVar) { postfl("methForwardClassVar %s:%s formal %d actual %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs); } if (special == methRedirectSuper) { postfl("methRedirectSuper %s:%s formal %d actual %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs); } */ // if (special == methTempDelegate) { // postfl("methTempDelegate %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); // } return special; } void installByteCodes(PyrBlock *block) { PyrInt8Array *byteArray; long length, flags; ByteCodes byteCodes; byteCodes = getByteCodes(); if (byteCodes) { length = byteCodeLength(byteCodes); if (length) { flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; byteArray = newPyrInt8Array(compileGC(), length, flags, false); copyByteCodes(byteArray->b, byteCodes); byteArray->size = length; freeByteCodes(byteCodes); SetObject(&block->code, byteArray); } else { error("installByteCodes: zero length byte codes\n"); } } else { error("installByteCodes: NULL byte codes\n"); } } PyrMethod* initPyrMethod(PyrMethod* method); void compilePyrMethodNode(PyrMethodNode *node, PyrSlot *result) { node->compile(result); } void PyrMethodNode::compile(PyrSlot *result) { PyrMethod *method, *oldmethod; PyrMethodRaw *methraw; int i, j, numArgs, numVars, methType, funcVarArgs, firstKeyIndex; int index, numSlots, numArgNames; bool hasPrimitive = false; bool hasVarExprs = false; PyrVarDefNode *vardef; PyrObject *proto; PyrSymbolArray *argNames, *varNames; SetTailBranch branch(false); //postfl("->method '%s'\n", slotRawSymbol(&mMethodName->mSlot)->name); gCompilingClass = mIsClassMethod ? gCurrentMetaClass : gCurrentClass; oldmethod = classFindDirectMethod(gCompilingClass, slotRawSymbol(&mMethodName->mSlot)); if (oldmethod && !mExtension) { error("Method %s:%s already defined.\n", slotRawSymbol(&slotRawClass(&oldmethod->ownerclass)->name)->name, slotRawSymbol(&oldmethod->name)->name); nodePostErrorLine((PyrParseNode*)mMethodName); compileErrors++; return; } if (oldmethod) { ++numOverwrites; // accumulate overwrite message onto the string buffer overwriteMsg .append(slotRawSymbol(&slotRawClass(&oldmethod->ownerclass)->name)->name) .append(":") .append(slotRawSymbol(&oldmethod->name)->name) .append("\t") .append(gCompilingFileSym->name) .append("\t") .append(slotRawSymbol(&oldmethod->filenameSym)->name) .append("\n"); method = oldmethod; freePyrSlot(&method->code); freePyrSlot(&method->selectors); freePyrSlot(&method->prototypeFrame); freePyrSlot(&method->argNames); freePyrSlot(&method->varNames); initPyrMethod(method); } else { method = newPyrMethod(); } SetObject(&method->ownerclass, gCompilingClass); methraw = METHRAW(method); methraw->unused1 = 0; methraw->unused2 = 0; //postfl("method %p raw %p\n", method, methraw); method->contextDef = o_nil; method->name = mMethodName->mSlot; if (gCompilingFileSym) SetSymbol(&method->filenameSym, gCompilingFileSym); SetInt(&method->charPos, linestarts[mMethodName->mLineno] + errCharPosOffset); if (mPrimitiveName) { hasPrimitive = true; method->primitiveName = mPrimitiveName->mSlot; methraw->specialIndex = slotRawSymbol(&mPrimitiveName->mSlot)->u.index; } gCompilingBlock = (PyrBlock*)method; gCompilingMethod = (PyrMethod*)method; gPartiallyAppliedFunction = NULL; gInliningLevel = 0; methraw->needsHeapContext = 0; methraw->varargs = funcVarArgs = (mArglist && mArglist->mRest) ? 1 : 0; numArgs = mArglist ? nodeListLength((PyrParseNode*)mArglist->mVarDefs) + 1 : 1; numVars = mVarlist ? nodeListLength((PyrParseNode*)mVarlist->mVarDefs) : 0; numSlots = numArgs + funcVarArgs + numVars; methraw->frameSize = (numSlots + FRAMESIZE) * sizeof(PyrSlot); methraw->numargs = numArgs; methraw->numvars = numVars; methraw->posargs = numArgs + funcVarArgs; methraw->numtemps = numSlots; methraw->popSize = numSlots - 1; firstKeyIndex = numArgs + funcVarArgs; numArgNames = methraw->posargs; if (numSlots == 1) { slotCopy(&method->argNames, &o_argnamethis); slotCopy(&method->prototypeFrame, &o_onenilarray); } else { argNames = newPyrSymbolArray(NULL, numArgNames, obj_permanent | obj_immutable, false); argNames->size = numArgNames; SetObject(&method->argNames, argNames); proto = newPyrArray(NULL, numSlots, obj_permanent | obj_immutable, false); proto->size = numSlots; SetObject(&method->prototypeFrame, proto); // declare args slotRawSymbolArray(&method->argNames)->symbols[0] = s_this; if (mArglist) { PyrSymbol **methargs; methargs = slotRawSymbolArray(&method->argNames)->symbols; vardef = mArglist->mVarDefs; for (i=1; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in arglist methargs[i] = slotRawSymbol(varslot); //postfl("defarg %d '%s'\n", i, slotRawSymbol(slot)->name); /*if (slotRawSymbol(varslot)->name[0] == 'a' && slotRawSymbol(varslot)->name[1] == 'r' && slotRawSymbol(varslot)->name[2] == 'g') { post("%d %s:%s '%s'\n", i, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, slotRawSymbol(varslot)->name); }*/ } if (funcVarArgs) { PyrSlot *varslot; varslot = &mArglist->mRest->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in arglist methargs[i] = slotRawSymbol(varslot); //postfl("defrest '%s'\n", slotRawSymbol(slot)->name); } } // fill prototype args if (NotNil(&method->prototypeFrame)) { SetNil(&slotRawObject(&method->prototypeFrame)->slots[0]); } if (mArglist) { vardef = mArglist->mVarDefs; for (i=1; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&method->prototypeFrame)->slots + i; //compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litval); if (vardef->hasExpr(&litval)) hasVarExprs = true; *slot = litval; } if (funcVarArgs) { slotCopy(&slotRawObject(&method->prototypeFrame)->slots[numArgs], &o_emptyarray); } } } if (numVars) { varNames = newPyrSymbolArray(NULL, numVars, obj_permanent | obj_immutable, false); varNames->size = numVars; SetObject(&method->varNames, varNames); } else { SetNil(&method->varNames); } // declare vars if (mVarlist) { PyrSymbol **methargs, **methvars; methargs = slotRawSymbolArray(&method->argNames)->symbols; methvars = slotRawSymbolArray(&method->varNames)->symbols; vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // already declared as var? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in mVarlist methvars[i] = slotRawSymbol(varslot); //postfl("defvar %d '%s'\n", i, slotRawSymbol(slot)->name); } } if (mVarlist) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&method->prototypeFrame)->slots + i + numArgs + funcVarArgs; if (vardef->hasExpr(&litval)) hasVarExprs = true; //compilePyrLiteralNode(vardef->mDefVal, &litval); *slot = litval; } } methType = methNormal; if (hasVarExprs) { methType = methNormal; } else if (hasPrimitive) { methType = methPrimitive; /* if (getPrimitiveNumArgs(methraw->specialIndex) != numArgs) { post("warning: number of arguments for method %s:%s does not match primitive %s. %d vs %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, getPrimitiveName(methraw->specialIndex)->name, numArgs, getPrimitiveNumArgs(methraw->specialIndex)); } */ } else if (slotRawSymbol(&gCompilingMethod->name) == s_nocomprendo) { methType = methNormal; } else { int bodyType = mBody->mClassno; if (bodyType == pn_ReturnNode) { PyrReturnNode *rnode; PyrParseNode *xnode; int rtype; PyrSlot rslot; rnode = (PyrReturnNode*)mBody; xnode = (PyrParseNode*)rnode->mExpr; if (xnode) { rtype = xnode->mClassno; if (rtype == pn_PushLitNode) { // return literal ? compilePyrLiteralNode((PyrLiteralNode*)xnode, &rslot); if (IsObj(&rslot) && slotRawObject(&rslot)->classptr == class_fundef) { methType = methNormal; } else { methType = methReturnLiteral; method->selectors = rslot; } } else if (rtype == pn_PushNameNode) { PyrSlot *rslot; rslot = &((PyrPushNameNode*)xnode)->mSlot; if (slotRawSymbol(rslot) == s_this) { // return this methType = methReturnSelf; } else { if (funcFindArg((PyrBlock*)method, slotRawSymbol(rslot), &index)) { // return arg ? // eliminate the case where its an ellipsis or keyword argument if (index < methraw->numargs) { methType = methReturnArg; methraw->specialIndex = index; // when you change sp to sp - 1 //methraw->specialIndex = index - 1; } } else if (classFindInstVar(gCompilingClass, slotRawSymbol(rslot), &index)) { // return inst var methType = methReturnInstVar; methraw->specialIndex = index; } } } else if (rtype == pn_CallNode) { // need to do this for binary opcodes too.. int specialIndex; PyrCallNode *cnode; PyrClass *specialClass = 0; cnode = (PyrCallNode*)xnode; methType = compareCallArgs(this, cnode, &specialIndex, &specialClass); if (methType != methNormal) { methraw->specialIndex = specialIndex; method->selectors = cnode->mSelector->mSlot; if (specialClass) method->constants = specialClass->name; } } } else { methType = methReturnSelf; } } else if (bodyType == pn_AssignNode && numArgs == 2) { // assign inst var ? PyrAssignNode *anode; //post("methAssignInstVar 1 %s:%s\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); anode = (PyrAssignNode*)mBody; if (anode->mNext && anode->mNext->mClassno == pn_ReturnNode && ((PyrReturnNode*)anode->mNext)->mExpr == NULL) { //post("methAssignInstVar 2 %s:%s\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); if (classFindInstVar(gCompilingClass, slotRawSymbol(&anode->mVarName->mSlot), &index)) { methType = methAssignInstVar; methraw->specialIndex = index; //post("methAssignInstVar 3 %s:%s\n", // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); } } } } methraw->methType = methType; // set primitive // optimize common cases if (methType == methNormal || methType == methPrimitive) { PyrSlot dummy; PyrSymbol *name; // compile body initByteCodes(); if (gCompilingClass == class_int) { // handle some special cases name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmDo]) { compileByte(143); compileByte(0); compileByte(143); compileByte(1); } else if (name == gSpecialSelectors[opmReverseDo]) { compileByte(143); compileByte(2); compileByte(143); compileByte(3); compileByte(143); compileByte(4); } else if (name == gSpecialSelectors[opmFor]) { compileByte(143); compileByte(5); compileByte(143); compileByte(6); compileByte(143); compileByte(16); } else if (name == gSpecialSelectors[opmForBy]) { compileByte(143); compileByte(7); compileByte(143); compileByte(8); compileByte(143); compileByte(9); } else goto compile_body; } else if (gCompilingClass == class_arrayed_collection) { name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmDo]) { compileByte(143); compileByte(10); compileByte(143); compileByte(1); } else if (name == gSpecialSelectors[opmReverseDo]) { compileByte(143); compileByte(11); compileByte(143); compileByte(12); compileByte(143); compileByte(4); } else goto compile_body; } else if (slotRawSymbol(&gCompilingClass->name) == s_dictionary) { name = slotRawSymbol(&method->name); if (name == getsym("keysValuesArrayDo")) { compileByte(143); compileByte(13); compileByte(143); compileByte(14); } else goto compile_body; } else if (gCompilingClass == class_number) { name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmForSeries]) { compileByte(143); compileByte(29); compileByte(143); compileByte(30); compileByte(143); compileByte(31); } else goto compile_body; } else if (gCompilingClass == class_float) { // handle some special cases name = slotRawSymbol(&method->name); if (name == gSpecialSelectors[opmDo]) { compileByte(143); compileByte(17); compileByte(143); compileByte(18); } else if (name == gSpecialSelectors[opmReverseDo]) { compileByte(143); compileByte(19); compileByte(143); compileByte(20); compileByte(143); compileByte(21); } else goto compile_body; } else { compile_body: SetTailIsMethodReturn mr(false); if (mArglist) { vardef = mArglist->mVarDefs; for (i=1; imNext) { vardef->compileArg(&dummy); } } if (mVarlist) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { vardef->compile(&dummy); } } COMPILENODE(mBody, &dummy, true); } installByteCodes((PyrBlock*)method); } if (!oldmethod) { addMethod(gCompilingClass, method); } gCompilingMethod = NULL; gCompilingBlock = NULL; gPartiallyAppliedFunction = NULL; //postfl("<-method '%s'\n", slotRawSymbol(&mMethodName->mSlot)->name); } PyrArgListNode* newPyrArgListNode(PyrVarDefNode* varDefs, PyrSlotNode* rest) { PyrArgListNode* node = ALLOCNODE(PyrArgListNode); node->mVarDefs = varDefs; node->mRest = rest; return node; } void PyrArgListNode::compile(PyrSlot *result) { error("compilePyrArgListNode: shouldn't get here.\n"); compileErrors++; } PyrVarListNode* newPyrVarListNode(PyrVarDefNode* vardefs, int flags) { PyrVarListNode* node = ALLOCNODE(PyrVarListNode); node->mVarDefs = vardefs; node->mFlags = flags; return node; } void PyrVarListNode::compile(PyrSlot *result) { error("compilePyrVarListNode: shouldn't get here.\n"); compileErrors++; } PyrVarDefNode* newPyrVarDefNode(PyrSlotNode* varName, PyrParseNode* defVal, int flags) { PyrVarDefNode* node = ALLOCNODE(PyrVarDefNode); node->mVarName = varName; node->mDefVal = defVal; node->mFlags = flags; node->mDrop = true; return node; } bool PyrVarDefNode::hasExpr(PyrSlot *result) { if (result) SetNil(result); if (!mDefVal) return false; if (mDefVal->mClassno != pn_PushLitNode && mDefVal->mClassno != pn_LiteralNode) { //post("hasExpr A %s:%s %s %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, mVarName->slotRawSymbol(&mSlot)->name, mDefVal->mClassno); return true; } PyrPushLitNode *node = (PyrPushLitNode*)mDefVal; if (IsPtr(&node->mSlot)) { PyrParseNode* litnode = (PyrParseNode*)slotRawPtr(&node->mSlot); if (litnode) { if (litnode->mClassno == pn_BlockNode) { //post("hasExpr B %s:%s %s %d\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name, mVarName->slotRawSymbol(&mSlot)->name, node->mClassno); return true; } else { if (result) node->compileLiteral(result); } } } else if (result) *result = node->mSlot; if (node->mParens) return true; return false; } void PyrVarDefNode::compile(PyrSlot *result) { if (hasExpr(NULL)) { COMPILENODE(mDefVal, result, false); compileAssignVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot), mDrop); } //error("compilePyrVarDefNode: shouldn't get here.\n"); //compileErrors++; } void PyrVarDefNode::compileArg(PyrSlot *result) { if (hasExpr(NULL)) { ByteCodes trueByteCodes; compilePushVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot)); mDrop = false; trueByteCodes = compileBodyWithGoto(this, 0, true); int jumplen = byteCodeLength(trueByteCodes); compileByte(143); // special opcodes compileByte(26); compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(trueByteCodes); compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean } //error("compilePyrVarDefNode: shouldn't get here.\n"); //compileErrors++; } PyrCallNode* newPyrCallNode(PyrSlotNode* selector, PyrParseNode* arglist, PyrParseNode* keyarglist, PyrParseNode* blocklist) { PyrCallNode* node = ALLOCNODE(PyrCallNode); node->mSelector = selector; arglist = linkNextNode(arglist, blocklist); node->mArglist = arglist; node->mKeyarglist = keyarglist; return node; } int PyrCallNode::isPartialApplication() { int sum = 0; PyrParseNode* argnode = mArglist; for (; argnode; argnode = argnode->mNext) { if (argnode->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)argnode)->mArgNum = sum; sum ++; } } PyrParseNode* keynode = mKeyarglist; for (; keynode; keynode = keynode->mNext) { if (keynode->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)keynode)->mArgNum = sum; sum ++; } } return sum; } void PyrCallNodeBase::compilePartialApplication(int numCurryArgs, PyrSlot *result) { // create a function // compile the call ByteCodes savedBytes = saveByteCodeArray(); int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; PyrBlock* block = newPyrBlock(flags); PyrSlot blockSlot; SetObject(&blockSlot, block); int prevFunctionHighestExternalRef = gFunctionHighestExternalRef; bool prevFunctionCantBeClosed = gFunctionCantBeClosed; gFunctionHighestExternalRef = 0; gFunctionCantBeClosed = false; PyrClass* prevClass = gCompilingClass; PyrBlock* prevBlock = gCompilingBlock; gCompilingBlock = block; PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction; gPartiallyAppliedFunction = block; PyrMethodRaw* methraw = METHRAW(block); methraw->unused1 = 0; methraw->unused2 = 0; methraw->needsHeapContext = 0; SetObject(&block->contextDef, prevBlock); //// methraw->varargs = 0; methraw->frameSize = (numCurryArgs + FRAMESIZE) * sizeof(PyrSlot); PyrObject* proto = newPyrArray(compileGC(), numCurryArgs, flags, false); proto->size = numCurryArgs; SetObject(&block->prototypeFrame, proto); PyrSymbolArray* argNames = newPyrSymbolArray(compileGC(), numCurryArgs, flags, false); argNames->size = numCurryArgs; SetObject(&block->argNames, argNames); SetNil(&block->varNames); methraw->numargs = numCurryArgs; methraw->numvars = 0; methraw->posargs = numCurryArgs; methraw->numtemps = numCurryArgs; methraw->popSize = numCurryArgs; methraw->methType = methBlock; { PyrSymbol* s_empty = getsym("_"); PyrSymbol **blockargs = slotRawSymbolArray(&block->argNames)->symbols; for (int i=0; islots + i); } } initByteCodes(); { SetTailBranch branch(true); SetTailIsMethodReturn mr(false); PyrSlot body; compileCall(&body); } compileOpcode(opSpecialOpcode, opcFunctionReturn); installByteCodes(block); gCompilingBlock = prevBlock; gPartiallyAppliedFunction = prevPartiallyAppliedFunction; restoreByteCodeArray(savedBytes); int index = conjureLiteralSlotIndex(this, gCompilingBlock, &blockSlot); compileOpcode(opExtended, opPushLiteral); compileByte(index); if (!gFunctionCantBeClosed && gFunctionHighestExternalRef == 0) { SetNil(&block->contextDef); } else { METHRAW(prevBlock)->needsHeapContext = 1; } gCompilingBlock = prevBlock; gCompilingClass = prevClass; gPartiallyAppliedFunction = prevPartiallyAppliedFunction; gFunctionCantBeClosed = gFunctionCantBeClosed || prevFunctionCantBeClosed; gFunctionHighestExternalRef = sc_max(gFunctionHighestExternalRef - 1, prevFunctionHighestExternalRef); } void PyrCallNodeBase::compile(PyrSlot *result) { int numCurryArgs = isPartialApplication(); if (numCurryArgs) { compilePartialApplication(numCurryArgs, result); } else { compileCall(result); } } bool isSeries(PyrParseNode* node, PyrParseNode** args) { if (node->mClassno != pn_CallNode) return false; PyrCallNode *callnode = (PyrCallNode*)node; if (slotRawSymbol(&callnode->mSelector->mSlot) != s_series) return false; if (callnode->mKeyarglist) return false; *args = callnode->mArglist; return true; } void PyrCallNode::compileCall(PyrSlot *result) { int index, selType; PyrSlot dummy; bool varFound; PyrParseNode *argnode2; //postfl("compilePyrCallNode\n"); PyrParseNode* argnode = mArglist; PyrParseNode* keynode = mKeyarglist; int numArgs = nodeListLength(argnode); int numKeyArgs = nodeListLength(keynode); int isSuper = isSuperObjNode(argnode); int numBlockArgs = METHRAW(gCompilingBlock)->numargs; slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called; index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, slotRawSymbol(&mSelector->mSlot), &selType); if (numKeyArgs > 0 || (numArgs > 15 && !(selType == selSwitch || selType == selCase))) { for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } for (; keynode; keynode = keynode->mNext) { COMPILENODE(keynode, &dummy, false); } if (isSuper) { compileTail(); compileByte(opSendSuper); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); } else { switch (selType) { case selNormal : compileTail(); compileByte(opSendMsg); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); break; case selSpecial : compileTail(); compileByte(opSendSpecialMsg); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); break; case selUnary : case selBinary : index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot); // fall through default: compileTail(); compileByte(opSendMsg); compileByte(numArgs + 2*numKeyArgs); compileByte(numKeyArgs); compileByte(index); break; } } } else if (isSuper) { if (numArgs == 1) { // pushes this as well, don't compile arg gFunctionCantBeClosed = true; compileTail(); compileOpcode(opSendSuper, numArgs); compileByte(index); } else { for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSuper, numArgs); compileByte(index); } } else { PyrSymbol *varname; if (argnode->mClassno == pn_PushNameNode) { varname = slotRawSymbol(&((PyrPushNameNode*)argnode)->mSlot); } else { varname = NULL; } if (varname == s_this) { gFunctionCantBeClosed = true; } switch (selType) { case selNormal : if (numArgs == 1 && varname == s_this) { compileTail(); compileOpcode(opSendMsg, 0); compileByte(index); //} else if (numArgs>1 && numArgs == numBlockArgs) { } else if (numArgs>1 && numArgs == numBlockArgs) { // try for multiple push optimization int code; code = checkPushAllArgs(argnode, numArgs); if (code == push_Normal) goto normal; else if (code == push_AllArgs) { compileTail(); compileByte(137); // push all args, send msg compileByte(index); //post("137 pushAllArgs %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else if (code == push_AllButFirstArg) { COMPILENODE(argnode, &dummy, false); compileTail(); compileByte(138); // push all but first arg, send msg compileByte(index); //post("138 pushAllButFirstArg %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto normal; } else if (numArgs>2 && numArgs == numBlockArgs+1) { int code; code = checkPushAllButFirstTwoArgs(argnode, numBlockArgs); if (code == push_Normal) goto normal; else if (code == push_AllButFirstArg2) { COMPILENODE(argnode, &dummy, false); COMPILENODE(argnode->mNext, &dummy, false); compileTail(); compileByte(141); // one arg pushed, push all but first arg, send msg compileByte(index); //post("141 pushAllButFirstArg2 %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto normal; } else { normal: for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); } break; case selSpecial : if (numArgs == 1) { if (varname == s_this) { compileTail(); compileOpcode(opSendSpecialMsg, 0); compileByte(index); } else if (varname) { PyrClass *classobj; PyrBlock *tempFunc; int varType, varLevel, varIndex; classobj = gCompilingClass; varFound = findVarName(gCompilingBlock, &classobj, varname, &varType, &varLevel, &varIndex, &tempFunc); if (varFound && varType == varInst) { //post("136 pushInstVar(sp) %s:%s '%s' %d %d\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name, varname->name, varIndex, index); compileTail(); compileByte(136); compileByte(varIndex); compileByte(index); } else goto special; } else goto special; } else if (index == opmDo && isSeries(argnode, &argnode)) { index = opmForSeries; mArglist = linkNextNode(argnode, mArglist->mNext); numArgs = nodeListLength(mArglist); goto special; } else if (numArgs>1 && numArgs == numBlockArgs) { //} else if (numArgs>1 && numArgs == numBlockArgs) { // try for multiple push optimization int code; code = checkPushAllArgs(argnode, numArgs); if (code == push_Normal) goto special; else if (code == push_AllArgs) { compileTail(); compileByte(139); // push all args, send special msg compileByte(index); //post("139 pushAllArgs(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else if (code == push_AllButFirstArg) { COMPILENODE(argnode, &dummy, false); compileTail(); compileByte(140); // push all but first arg, send special msg compileByte(index); //post("140 pushAllButFirstArg(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto special; } else if (numArgs>2 && numArgs == numBlockArgs+1) { int code; code = checkPushAllButFirstTwoArgs(argnode, numBlockArgs); if (code == push_Normal) goto special; else if (code == push_AllButFirstArg2) { COMPILENODE(argnode, &dummy, false); COMPILENODE(argnode->mNext, &dummy, false); compileTail(); compileByte(142); // one arg pushed, push all but first arg, send msg compileByte(index); //post("142 pushAllButFirstArg2(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, // slotRawSymbol(&gCompilingMethod->name)->name); } else goto special; } else { int i; special: for (i=0; argnode; argnode = argnode->mNext,i++) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(index); } break; case selUnary : if (numArgs != 1) { index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot); goto defaultCase; } for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialUnaryArithMsg, index); break; case selBinary : if (numArgs != 2) { index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot); goto defaultCase; } //for (; argnode; argnode = argnode->mNext) { // COMPILENODE(argnode, &dummy, false); //} argnode2 = argnode->mNext; if (index == opAdd && argnode2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)argnode2)->mSlot) && slotRawInt(&((PyrPushLitNode*)argnode2)->mSlot) == 1) { COMPILENODE(argnode, &dummy, false); compileOpcode(opPushSpecialValue, opsvPlusOne); } else if (index == opSub && argnode2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)argnode2)->mSlot) && slotRawInt(&((PyrPushLitNode*)argnode2)->mSlot) == 1) { COMPILENODE(argnode, &dummy, false); compileOpcode(opPushSpecialValue, opsvMinusOne); } else { COMPILENODE(argnode, &dummy, false); COMPILENODE(argnode->mNext, &dummy, false); compileTail(); compileOpcode(opSendSpecialBinaryArithMsg, index); } break; case selIf : compileAnyIfMsg(this); break; case selCase : compileCaseMsg(this); break; case selSwitch : compileSwitchMsg(this); break; case selWhile : compileWhileMsg(this); break; case selLoop : compileLoopMsg(this); break; case selAnd : if (numArgs == 2) compileAndMsg(argnode, argnode->mNext); else goto special; break; case selOr : if (numArgs == 2) compileOrMsg(argnode, argnode->mNext); else goto special; break; case selQuestionMark : if (numArgs == 2) compileQMsg(argnode, argnode->mNext); break; case selDoubleQuestionMark : if (numArgs == 2) compileQQMsg(argnode, argnode->mNext); break; case selExclamationQuestionMark : if (numArgs == 2) compileXQMsg(argnode, argnode->mNext); break; default : defaultCase: if (numArgs == 1 && varname == s_this) { compileTail(); compileOpcode(opSendMsg, 0); compileByte(index); } else { for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); } break; } } } ByteCodes compileSubExpression(PyrPushLitNode* litnode, bool onTailBranch) { return compileSubExpressionWithGoto(litnode, 0, onTailBranch); } ByteCodes compileSubExpressionWithGoto(PyrPushLitNode* litnode, int branchLen, bool onTailBranch) { PyrBlockNode *bnode = (PyrBlockNode*)slotRawPtr(&litnode->mSlot); return compileBodyWithGoto(bnode->mBody, branchLen, onTailBranch); } ByteCodes compileBodyWithGoto(PyrParseNode* body, int branchLen, bool onTailBranch) { ByteCodes currentByteCodes, subExprByteCodes; PyrSlot dummy; PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction; gPartiallyAppliedFunction = NULL; currentByteCodes = saveByteCodeArray(); COMPILENODE(body, &dummy, onTailBranch); if (branchLen) { if (!byteCodeLength(gCompilingByteCodes)) { compileOpcode(opPushSpecialValue, opsvNil); // push nil } compileJump(opcJumpFwd, branchLen); } subExprByteCodes = getByteCodes(); restoreByteCodeArray(currentByteCodes); gPartiallyAppliedFunction = prevPartiallyAppliedFunction; return subExprByteCodes; } #if 0 ByteCodes compileDefaultValue(int litIndex, int realExprLen) { ByteCodes currentByteCodes, defaultByteCodes; currentByteCodes = saveByteCodeArray(); compileOpcode(opPushSpecialValue, litIndex); compileJump(realExprLen, unconditionalJump); defaultByteCodes = getByteCodes(); restoreByteCodeArray(currentByteCodes); return (defaultByteCodes); } #endif bool isAnInlineableBlock(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; PyrBlockNode *bnode; anode = (PyrPushLitNode*)node; if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) { if (bnode->mArglist || bnode->mVarlist) { if (gPostInlineWarnings) { post("WARNING: FunctionDef contains variable declarations and so" " will not be inlined.\n"); if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist); else nodePostErrorLine((PyrParseNode*)bnode->mVarlist); } } else res = true; } } return res; } bool isAnInlineableAtomicLiteralBlock(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; PyrBlockNode *bnode; anode = (PyrPushLitNode*)node; if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) { if (bnode->mArglist || bnode->mVarlist) { if (gPostInlineWarnings) { post("WARNING: FunctionDef contains variable declarations and so" " will not be inlined.\n"); if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist); else nodePostErrorLine((PyrParseNode*)bnode->mVarlist); } } else { if (bnode->mBody->mClassno == pn_DropNode && ((PyrDropNode*)bnode->mBody)->mExpr2->mClassno == pn_BlockReturnNode) res = isAtomicLiteral(((PyrDropNode*)bnode->mBody)->mExpr1); else res = false; } } } return res; } bool isAtomicLiteral(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; anode = (PyrPushLitNode*)node; if (NotObj(&anode->mSlot) && !IsPtr(&anode->mSlot)) res = true; } return res; } bool isWhileTrue(PyrParseNode *node) { bool res = false; if (node->mClassno == pn_PushLitNode) { PyrPushLitNode *anode; PyrBlockNode *bnode; anode = (PyrPushLitNode*)node; if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) { if (bnode->mArglist || bnode->mVarlist) { /* post("WARNING: FunctionDef contains variable declarations and so" " will not be inlined.\n"); if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist); else nodePostErrorLine((PyrParseNode*)bnode->mVarlist); */ } else { if (bnode->mBody->mClassno == pn_PushLitNode && IsTrue(&((PyrPushLitNode*)bnode->mBody)->mSlot)) { res = true; } } } else if (IsTrue(&anode->mSlot)) { res = true; } } return res; } void compileAndMsg(PyrParseNode* arg1, PyrParseNode* arg2) { PyrSlot dummy; ByteCodes trueByteCodes; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); compileJump(opcJumpIfFalsePushFalse, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmAnd); } } void compileOrMsg(PyrParseNode* arg1, PyrParseNode* arg2) { PyrSlot dummy; ByteCodes falseByteCodes; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { falseByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); compileJump(opcJumpIfTruePushTrue, byteCodeLength(falseByteCodes)); compileAndFreeByteCodes(falseByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmOr); } } void compileQMsg(PyrParseNode* arg1, PyrParseNode* arg2) { // question mark. PyrSlot dummy; COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); compileByte(143); // special opcodes compileByte(22); // ?? } void compileQQMsg(PyrParseNode* arg1, PyrParseNode* arg2) { // double question mark. ?? {|obj| ^if (this.notNil, this, func) } PyrSlot dummy; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { ByteCodes nilByteCodes; nilByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); int jumplen = byteCodeLength(nilByteCodes); compileByte(143); // special opcodes compileByte(23); // ?? compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(nilByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmDoubleQuestionMark); } } void compileXQMsg(PyrParseNode* arg1, PyrParseNode* arg2) { // double question mark. !? {|obj| ^if (this.isNil, this, func) } PyrSlot dummy; COMPILENODE(arg1, &dummy, false); if (isAnInlineableBlock(arg2)) { ByteCodes nilByteCodes; nilByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); int jumplen = byteCodeLength(nilByteCodes); compileByte(143); // special opcodes compileByte(27); // !? compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(nilByteCodes); } else { COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, 2); compileByte(opmExclamationQuestionMark); } } void compileAnyIfMsg(PyrCallNodeBase2* node) { PyrParseNode* arg1 = node->mArglist; if (arg1->mClassno == pn_CallNode) { PyrCallNode* callNode = (PyrCallNode*)arg1; int numCallArgs = nodeListLength(callNode->mArglist); int numCallKeyArgs = nodeListLength(callNode->mKeyarglist); if (numCallArgs == 1 && numCallKeyArgs == 0) { if (slotRawSymbol(&callNode->mSelector->mSlot) == gSpecialUnarySelectors[opIsNil]) { compileIfNilMsg(node, true); return; } else if (slotRawSymbol(&callNode->mSelector->mSlot) == gSpecialUnarySelectors[opNotNil]) { compileIfNilMsg(node, false); return; } } } compileIfMsg(node); } void compileIfMsg(PyrCallNodeBase2* node) { PyrSlot dummy; ByteCodes trueByteCodes, falseByteCodes; int numArgs = nodeListLength(node->mArglist); PyrParseNode* arg1 = node->mArglist; PyrParseNode *arg2, *arg3; if (numArgs == 2) { arg2 = arg1->mNext; if (isAnInlineableBlock(arg2)) { COMPILENODE(arg1, &dummy, false); trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); if (byteCodeLength(trueByteCodes)) { compileJump(opcJumpIfFalsePushNil, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else goto unoptimized; } else if (numArgs == 3) { arg2 = arg1->mNext; arg3 = arg2->mNext; if (isAnInlineableBlock(arg2) && isAnInlineableBlock(arg3)) { COMPILENODE(arg1, &dummy, false); falseByteCodes = compileSubExpression((PyrPushLitNode*)arg3, true); trueByteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)arg2, byteCodeLength(falseByteCodes), true); if (byteCodeLength(falseByteCodes)) { compileJump(opcJumpIfFalse, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); compileAndFreeByteCodes(falseByteCodes); } else if (byteCodeLength(trueByteCodes)) { compileJump(opcJumpIfFalsePushNil, byteCodeLength(trueByteCodes)); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else goto unoptimized; } else { unoptimized: for (; arg1; arg1 = arg1->mNext) { COMPILENODE(arg1, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } void compileIfNilMsg(PyrCallNodeBase2* node, bool flag) { PyrSlot dummy; ByteCodes trueByteCodes, falseByteCodes; PyrParseNode *arg2, *arg3; int numArgs = nodeListLength(node->mArglist); PyrParseNode* arg1 = node->mArglist; if (numArgs < 2) { COMPILENODE(arg1, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } else if (numArgs == 2) { arg2 = arg1->mNext; if (isAnInlineableBlock(arg2)) { PyrCallNode* callNode = (PyrCallNode*)arg1; COMPILENODE(callNode->mArglist, &dummy, false); trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true); int jumplen = byteCodeLength(trueByteCodes); if (jumplen) { compileByte(143); // special opcodes compileByte(flag ? 26 : 27); compileByte((jumplen >> 8) & 0xFF); compileByte(jumplen & 0xFF); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the value compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } else if (numArgs == 3) { arg2 = arg1->mNext; arg3 = arg2->mNext; if (isAnInlineableBlock(arg2) && isAnInlineableBlock(arg3)) { PyrCallNode* callNode = (PyrCallNode*)arg1; COMPILENODE(callNode->mArglist, &dummy, false); falseByteCodes = compileSubExpression((PyrPushLitNode*)arg3, true); int falseLen = byteCodeLength(falseByteCodes); trueByteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)arg2, falseLen, true); int trueLen = byteCodeLength(trueByteCodes); if (falseLen) { compileByte(143); // special opcodes compileByte(flag ? 24 : 25); compileByte((trueLen >> 8) & 0xFF); compileByte(trueLen & 0xFF); compileAndFreeByteCodes(trueByteCodes); compileAndFreeByteCodes(falseByteCodes); } else if (trueLen) { compileByte(143); // special opcodes compileByte(flag ? 26 : 27); compileByte((trueLen >> 8) & 0xFF); compileByte(trueLen & 0xFF); compileAndFreeByteCodes(trueByteCodes); } else { compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean compileOpcode(opPushSpecialValue, opsvNil); // push nil } } else { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } else { for (; arg1; arg1 = arg1->mNext) { COMPILENODE(arg1, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmIf); } } PyrParseNode* reverseNodeList(PyrParseNode** list) { PyrParseNode* temp1 = *list; PyrParseNode* temp2 = NULL; PyrParseNode* temp3 = NULL; while (temp1) { *list = temp1; temp2 = temp1->mNext; temp1->mNext = temp3; temp3 = temp1; temp1 = temp2; } return *list; } PyrCallNode* buildCase(PyrParseNode *arg1) { // transform case statement into nested if statements. //int numArgs = nodeListLength(arg1); //post("->buildCase %d\n", numArgs); PyrParseNode *arg2 = arg1->mNext; PyrPushLitNode *litnode = (PyrPushLitNode*)arg1; PyrBlockNode *bnode = (PyrBlockNode*)slotRawPtr(&litnode->mSlot); PyrParseNode *bbody = bnode->mBody; if (bbody->mClassno == pn_DropNode) { PyrDropNode* dropNode = (PyrDropNode*)bbody; if (dropNode->mExpr2->mClassno == pn_BlockReturnNode) { arg1 = dropNode->mExpr1; } else { arg1 = dropNode; } } else { arg1 = bbody; } arg1->mNext = arg2; PyrParseNode *arg3 = 0; if (arg2) { arg3 = arg2->mNext; if (arg3) { PyrParseNode *arg4 = arg3->mNext; if (arg4) { arg3 = buildCase(arg3); PyrBlockNode* bnode = newPyrBlockNode(NULL, NULL, arg3, false); arg3 = newPyrPushLitNode(NULL, bnode); arg2->mNext = arg3; arg3->mNext = NULL; arg1->mTail = arg3; } } else { arg1->mTail = arg2; } } else { arg1->mTail = arg1; } /* post("arg1->mNext %p arg2 %p\n", arg1->mNext, arg2); if (arg2) { post("arg2->mNext %p arg3 %p\n", arg2->mNext, arg3); post("isAnInlineableBlock arg2 %d\n", isAnInlineableBlock(arg2)); } if (arg3) { post("isAnInlineableBlock arg3 %d\n", isAnInlineableBlock(arg3)); post("arg3->mNext %p\n", arg3->mNext); } DUMPNODE(arg1, 0); */ PyrSlot selector; SetSymbol(&selector, gSpecialSelectors[opmIf]); PyrSlotNode* selectorNode = newPyrSlotNode(&selector); PyrCallNode *callNode = newPyrCallNode(selectorNode, arg1, NULL, NULL); //post("<-buildCase %d\n", numArgs); return callNode; } void compileCaseMsg(PyrCallNodeBase2* node) { PyrParseNode *argnode = node->mArglist; bool canInline = true; for (; argnode; argnode = argnode->mNext) { if (!isAnInlineableBlock(argnode)) { canInline = false; break; } } PyrSlot dummy; if (canInline) { PyrCallNode* callNode = buildCase(node->mArglist); callNode->compile(&dummy); } else { int numArgs = 0; argnode = node->mArglist; for (; argnode; argnode = argnode->mNext, ++numArgs) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmCase); } } void compileSwitchMsg(PyrCallNode* node) { PyrSlot dummy; bool canInline = true; int numArgs; { PyrParseNode *argnode = node->mArglist; numArgs = nodeListLength(argnode); if (numArgs <= 2) { error("Missing argument in switch statement"); nodePostErrorLine(node); compileErrors++; }; argnode = argnode->mNext; // skip first arg. PyrParseNode* nextargnode = 0; for (; argnode; argnode = nextargnode) { nextargnode = argnode->mNext; if (nextargnode != NULL) { if (!isAtomicLiteral(argnode) && !isAnInlineableAtomicLiteralBlock(argnode)) { canInline = false; break; } if (!isAnInlineableBlock(nextargnode)) { canInline = false; break; } nextargnode = nextargnode->mNext; } else { if (!isAnInlineableBlock(argnode)) { canInline = false; } break; } } } if (canInline) { PyrParseNode *argnode = node->mArglist; int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; int arraySize = NEXTPOWEROFTWO(numArgs * 2); PyrObject* array = newPyrArray(compileGC(), arraySize, flags, false); array->size = arraySize; nilSlots(array->slots, arraySize); PyrSlot slot; SetObject(&slot, array); COMPILENODE(argnode, &dummy, false); compilePushConstant(node, &slot); compileByte(143); // lookup slot in dictionary and jump to offset. compileByte(28); argnode = argnode->mNext; // skip first arg. PyrParseNode* nextargnode = 0; int absoluteOffset = byteCodeLength(gCompilingByteCodes); int offset = 0; int lastOffset = 0; for (; argnode; argnode = nextargnode) { nextargnode = argnode->mNext; if (nextargnode != NULL) { ByteCodes byteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)nextargnode, 0x6666, true); PyrSlot *key; PyrSlot value; SetInt(&value, offset); PyrPushLitNode* keyargnode = (PyrPushLitNode*)argnode; if (isAtomicLiteral(argnode)) { key = &keyargnode->mSlot; } else { PyrBlockNode *bnode = (PyrBlockNode*)slotRawPtr(&keyargnode->mSlot); PyrDropNode *dropnode = (PyrDropNode*)bnode->mBody; PyrPushLitNode* litnode = (PyrPushLitNode*)dropnode->mExpr1; key = &litnode->mSlot; } int index = arrayAtIdentityHashInPairs(array, key); PyrSlot *slot = array->slots + index; slotCopy(slot, key); SetInt(slot+1, offset); if (byteCodes) { offset += byteCodeLength(byteCodes); compileAndFreeByteCodes(byteCodes); } else { compileOpcode(opPushSpecialValue, opsvNil); offset += 1; } nextargnode = nextargnode->mNext; if (nextargnode == NULL) { compileOpcode(opPushSpecialValue, opsvNil); lastOffset = offset; offset += 1; } } else { ByteCodes byteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)argnode, 0, true); lastOffset = offset; if (byteCodes) { offset += byteCodeLength(byteCodes); compileAndFreeByteCodes(byteCodes); } else { compileOpcode(opPushSpecialValue, opsvNil); lastOffset = offset; offset += 1; } } } Byte *bytes = gCompilingByteCodes->bytes + absoluteOffset; PyrSlot *slots = array->slots; { int jumplen = offset - lastOffset; bytes[lastOffset-2] = (jumplen >> 8) & 255; bytes[lastOffset-1] = jumplen & 255; } for (int i=0; i> 8) & 255; bytes[offsetToHere-1] = jumplen & 255; } } } } else { PyrParseNode *argnode = node->mArglist; for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmSwitch); } } void compileWhileMsg(PyrCallNodeBase2* node) { int numArgs; PyrParseNode *argnode; PyrSlot dummy; ByteCodes whileByteCodes, exprByteCodes; int whileByteCodeLen, exprByteCodeLen; numArgs = nodeListLength(node->mArglist); if (numArgs == 1 && isAnInlineableBlock(node->mArglist)) { whileByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false); whileByteCodeLen = byteCodeLength(whileByteCodes); compileAndFreeByteCodes(whileByteCodes); exprByteCodeLen = 1; compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3); // opcJumpBak does a drop.. compileOpcode(opPushSpecialValue, opsvNil); compileJump(opcJumpBak, exprByteCodeLen + whileByteCodeLen + 4); } else if (numArgs == 2 && isWhileTrue(node->mArglist) && isAnInlineableBlock(node->mArglist->mNext)) { exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist->mNext, false); exprByteCodeLen = byteCodeLength(exprByteCodes); compileAndFreeByteCodes(exprByteCodes); compileJump(opcJumpBak, exprByteCodeLen + 1); } else if (numArgs == 2 && isAnInlineableBlock(node->mArglist) && isAnInlineableBlock(node->mArglist->mNext)) { whileByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false); exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist->mNext, false); whileByteCodeLen = byteCodeLength(whileByteCodes); compileAndFreeByteCodes(whileByteCodes); if (exprByteCodes) { exprByteCodeLen = byteCodeLength(exprByteCodes); compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3); compileAndFreeByteCodes(exprByteCodes); } else { exprByteCodeLen = 1; compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3); // opcJumpBak does a drop.. compileOpcode(opPushSpecialValue, opsvNil); } compileJump(opcJumpBak, exprByteCodeLen + whileByteCodeLen + 4); } else { argnode = node->mArglist; for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmWhile); } } void compileLoopMsg(PyrCallNodeBase2* node) { int numArgs; PyrParseNode *argnode; PyrSlot dummy; ByteCodes exprByteCodes; int exprByteCodeLen; numArgs = nodeListLength(node->mArglist); if (numArgs == 1 && isAnInlineableBlock(node->mArglist)) { exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false); exprByteCodeLen = byteCodeLength(exprByteCodes); compileAndFreeByteCodes(exprByteCodes); compileJump(opcJumpBak, exprByteCodeLen + 1); } else { argnode = node->mArglist; for (; argnode; argnode = argnode->mNext) { COMPILENODE(argnode, &dummy, false); } compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(opmLoop); } } PyrBinopCallNode* newPyrBinopCallNode(PyrSlotNode* selector, PyrParseNode* arg1, PyrParseNode* arg2, PyrParseNode* arg3) { PyrBinopCallNode* node = ALLOCNODE(PyrBinopCallNode); node->mSelector = selector; node->mArglist = arg1; arg1->mNext = arg2; arg2->mNext = arg3; return node; } int PyrBinopCallNode::isPartialApplication() { int sum = 0; PyrParseNode* argnode = mArglist; for (; argnode; argnode = argnode->mNext) { if (argnode->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)argnode)->mArgNum = sum; sum ++; } } return sum; } void PyrBinopCallNode::compileCall(PyrSlot *result) { int index, selType, isSuper, numArgs; PyrSlot dummy; PyrParseNode *arg1 = mArglist; PyrParseNode *arg2 = arg1->mNext; PyrParseNode *arg3 = arg2->mNext; //postfl("compilePyrBinopCallNode\n"); isSuper = isSuperObjNode(arg1); slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called; index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, slotRawSymbol(&mSelector->mSlot), &selType); numArgs = arg3 ? 3 : 2; if (isSuper) { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendSuper, numArgs); compileByte(index); } else { switch (selType) { case selNormal : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); break; case selSpecial : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendSpecialMsg, numArgs); compileByte(index); break; case selUnary : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); if (arg3) compileOpcode(opSpecialOpcode, opcDrop); // drop third argument compileOpcode(opSpecialOpcode, opcDrop); // drop second argument compileOpcode(opSendSpecialUnaryArithMsg, index); break; case selBinary : if (arg3) { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSpecialOpcode, opcSpecialBinaryOpWithAdverb); compileByte(index); } else if (index == opAdd && arg2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)arg2)->mSlot) && slotRawInt(&((PyrPushLitNode*)arg2)->mSlot) == 1) { COMPILENODE(arg1, &dummy, false); compileOpcode(opPushSpecialValue, opsvPlusOne); } else if (index == opSub && arg2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)arg2)->mSlot) && slotRawInt(&((PyrPushLitNode*)arg2)->mSlot) == 1) { COMPILENODE(arg1, &dummy, false); compileTail(); compileOpcode(opPushSpecialValue, opsvMinusOne); } else { COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); compileTail(); compileOpcode(opSendSpecialBinaryArithMsg, index); } break; case selIf : compileAnyIfMsg(this); break; case selCase : compileCaseMsg(this); break; case selWhile : compileWhileMsg(this); break; case selLoop : compileLoopMsg(this); break; case selAnd : compileAndMsg(arg1, arg2); break; case selOr : compileOrMsg(arg1, arg2); break; case selQuestionMark : compileQMsg(arg1, arg2); break; case selDoubleQuestionMark : compileQQMsg(arg1, arg2); break; case selExclamationQuestionMark : compileXQMsg(arg1, arg2); break; default : COMPILENODE(arg1, &dummy, false); COMPILENODE(arg2, &dummy, false); if (arg3) COMPILENODE(arg3, &dummy, false); compileTail(); compileOpcode(opSendMsg, numArgs); compileByte(index); break; } } } PyrPushKeyArgNode* newPyrPushKeyArgNode(PyrSlotNode* selector, PyrParseNode* expr) { PyrPushKeyArgNode* node = ALLOCNODE(PyrPushKeyArgNode); node->mSelector = selector; node->mExpr = expr; return node; } void PyrPushKeyArgNode::compile(PyrSlot *result) { PyrSlot dummy; //postfl("->compilePyrPushKeyArgNode\n"); compilePushConstant((PyrParseNode*)this, &mSelector->mSlot); COMPILENODE(mExpr, &dummy, false); } PyrDropNode* newPyrDropNode(PyrParseNode* expr1, PyrParseNode* expr2) { PyrDropNode* node = ALLOCNODE(PyrDropNode); node->mExpr1 = expr1; node->mExpr2 = expr2; return node; } void PyrDropNode::compile(PyrSlot *result) { //postfl("->compilePyrDropNode\n"); PyrSlot dummy; // eliminate as many drops as possible if (!mExpr2) { post("DROP EXPR2 NULL\n"); COMPILENODE(mExpr1, &dummy, true); } else if (mExpr2->mClassno == pn_BlockReturnNode) { // no drop before a block return COMPILENODE(mExpr1, &dummy, true); } else if (mExpr1 && mExpr1->mClassno == pn_AssignNode) { // let the store do the drop ((PyrAssignNode*)mExpr1)->mDrop = 1; COMPILENODE(mExpr1, &dummy, false); COMPILENODE(mExpr2, &dummy, true); } else if (mExpr1 && mExpr1->mClassno == pn_DropNode) { PyrDropNode *znode; // let the store do the drop, a bit more complex. // find the ultimate expression in the left subtree before the drop. znode = (PyrDropNode*)mExpr1; while (znode->mExpr2 && znode->mExpr2->mClassno == pn_DropNode) { znode = (PyrDropNode*)znode->mExpr2; } if (znode->mExpr2->mClassno == pn_AssignNode) { ((PyrAssignNode*)znode->mExpr2)->mDrop = 1; COMPILENODE(mExpr1, &dummy, false); COMPILENODE(mExpr2, &dummy, true); } else { COMPILENODE(mExpr1, &dummy, false); compileOpcode(opSpecialOpcode, opcDrop); COMPILENODE(mExpr2, &dummy, true); } } else { COMPILENODE(mExpr1, &dummy, false); compileOpcode(opSpecialOpcode, opcDrop); COMPILENODE(mExpr2, &dummy, true); } //postfl("<-compilePyrDropNode\n"); } PyrPushLitNode* newPyrPushLitNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj) { PyrPushLitNode* node; if (literalSlot) { node = literalSlot; node->mClassno = pn_PushLitNode; } else { node = ALLOCSLOTNODE(PyrSlotNode, pn_PushLitNode); SetPtr(&node->mSlot, (PyrObject*)literalObj); } return node; } void compilePushConstant(PyrParseNode* node, PyrSlot *slot) { int index = conjureConstantIndex(node, gCompilingBlock, slot); if (index < (1<<4)) { compileByte((opPushLiteral << 4) | index); } else if (index < (1<<8)) { compileByte(40); compileByte(index & 0xFF); } else if (index < (1<<16)) { compileByte(41); compileByte((index >> 8) & 0xFF); compileByte(index & 0xFF); } else if (index < (1<<24)) { compileByte(42); compileByte((index >> 16) & 0xFF); compileByte((index >> 8) & 0xFF); compileByte(index & 0xFF); } else { compileByte(43); compileByte((index >> 24) & 0xFF); compileByte((index >> 16) & 0xFF); compileByte((index >> 8) & 0xFF); compileByte(index & 0xFF); } } void compilePushInt(int value) { //postfl("compilePushInt\n"); if (value >= -1 && value <= 2) { compileOpcode(opPushSpecialValue, opsvZero + value); } else{ //printf("int %d\n", value); if (value >= -(1<<7) && value <= ((1<<7)-1)) { compileByte(44); compileByte(value & 0xFF); } else if (value >= -(1<<15) && value <= ((1<<15)-1)) { compileByte(45); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); } else if (value >= -(1<<23) && value <= ((1<<23)-1)) { compileByte(46); compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); } else { compileByte(47); compileByte((value >> 24) & 0xFF); compileByte((value >> 16) & 0xFF); compileByte((value >> 8) & 0xFF); compileByte(value & 0xFF); } } } void PyrSlotNode::compilePushLit(PyrSlot *result) { int index; PyrSlot slot; ByteCodes savedBytes; //postfl("compilePyrPushLitNode\n"); if (IsPtr(&mSlot)) { PyrParseNode *literalObj = (PyrParseNode*)slotRawPtr(&mSlot); //index = conjureLiteralObjIndex(gCompilingBlock, literalObj); if (literalObj->mClassno == pn_BlockNode) { savedBytes = saveByteCodeArray(); COMPILENODE(literalObj, &slot, false); restoreByteCodeArray(savedBytes); index = conjureLiteralSlotIndex(literalObj, gCompilingBlock, &slot); compileOpcode(opExtended, opPushLiteral); compileByte(index); PyrBlock *block = slotRawBlock(&slot); if (NotNil(&block->contextDef)) { METHRAW(gCompilingBlock)->needsHeapContext = 1; } } else { COMPILENODE(literalObj, &slot, false); compilePushConstant((PyrParseNode*)literalObj, &slot); } } else { slot = mSlot; if (IsInt(&slot)) { compilePushInt(slotRawInt(&slot)); } else if (SlotEq(&slot, &o_nil)) { compileOpcode(opPushSpecialValue, opsvNil); } else if (SlotEq(&slot, &o_true)) { compileOpcode(opPushSpecialValue, opsvTrue); } else if (SlotEq(&slot, &o_false)) { compileOpcode(opPushSpecialValue, opsvFalse); } else if (SlotEq(&slot, &o_fhalf)) { compileOpcode(opPushSpecialValue, opsvFHalf); } else if (SlotEq(&slot, &o_fnegone)) { compileOpcode(opPushSpecialValue, opsvFNegOne); } else if (SlotEq(&slot, &o_fzero)) { compileOpcode(opPushSpecialValue, opsvFZero); } else if (SlotEq(&slot, &o_fone)) { compileOpcode(opPushSpecialValue, opsvFOne); } else if (SlotEq(&slot, &o_ftwo)) { compileOpcode(opPushSpecialValue, opsvFTwo); } else if (SlotEq(&slot, &o_inf)) { compileOpcode(opPushSpecialValue, opsvInf); } else if (IsFloat(&slot)) { compilePushConstant((PyrParseNode*)this, &slot); } else if (IsSym(&slot)) { compilePushConstant((PyrParseNode*)this, &slot); } else { compilePushConstant((PyrParseNode*)this, &slot); } } } PyrLiteralNode* newPyrLiteralNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj) { PyrLiteralNode* node; if (literalSlot) { node = literalSlot; node->mClassno = pn_LiteralNode; } else { node = ALLOCSLOTNODE(PyrSlotNode, pn_LiteralNode); SetPtr(&node->mSlot, (PyrObject*)literalObj); } return node; } void compilePyrLiteralNode(PyrLiteralNode *node, PyrSlot *result) { if (!node) { SetNil(result); } else { node->compileLiteral(result); } } void PyrSlotNode::compileLiteral(PyrSlot *result) { ByteCodes savedBytes; if (IsPtr(&mSlot)) { PyrParseNode* literalObj = (PyrParseNode*)slotRawPtr(&mSlot); if (literalObj->mClassno == pn_BlockNode) { savedBytes = saveByteCodeArray(); COMPILENODE(literalObj, result, false); restoreByteCodeArray(savedBytes); PyrBlock *block = slotRawBlock(result); if (NotNil(&block->contextDef)) { METHRAW(gCompilingBlock)->needsHeapContext = 1; } } else { COMPILENODE(literalObj, result, false); } } else { *(PyrSlot*)result = mSlot; } } PyrReturnNode* newPyrReturnNode(PyrParseNode* expr) { PyrReturnNode* node = ALLOCNODE(PyrReturnNode); node->mExpr = expr; return node; } void PyrReturnNode::compile(PyrSlot *result) { PyrPushLitNode *lit; PyrSlot dummy; //post("->compilePyrReturnNode\n"); gFunctionCantBeClosed = true; if (!mExpr) { compileOpcode(opSpecialOpcode, opcReturnSelf); } else if (mExpr->mClassno == pn_PushLitNode) { lit = (PyrPushLitNode*)mExpr; if (IsSym(&(lit->mSlot)) && slotRawSymbol(&lit->mSlot) == s_this) { compileOpcode(opSpecialOpcode, opcReturnSelf); } else if (IsNil(&lit->mSlot)) { compileOpcode(opSpecialOpcode, opcReturnNil); } else if (IsTrue(&lit->mSlot)) { compileOpcode(opSpecialOpcode, opcReturnTrue); } else if (IsFalse(&lit->mSlot)) { compileOpcode(opSpecialOpcode, opcReturnFalse); } else { COMPILENODE(lit, &dummy, false); compileOpcode(opSpecialOpcode, opcReturn); } } else { SetTailBranch branch(true); SetTailIsMethodReturn mr(true); COMPILENODE(mExpr, &dummy, true); compileOpcode(opSpecialOpcode, opcReturn); } //post("<-compilePyrReturnNode\n"); } PyrBlockReturnNode* newPyrBlockReturnNode() { PyrBlockReturnNode* node = ALLOCNODE(PyrBlockReturnNode); return node; } void PyrBlockReturnNode::compile(PyrSlot *result) { //postfl("compilePyrBlockReturnNode\n"); //compileOpcode(opSpecialOpcode, opcFunctionReturn); } PyrAssignNode* newPyrAssignNode(PyrSlotNode* varName, PyrParseNode* expr, int flags) { PyrAssignNode* node = ALLOCNODE(PyrAssignNode); node->mVarName = varName; node->mExpr = expr; node->mDrop = 0; return node; } PyrSetterNode* newPyrSetterNode(PyrSlotNode* selector, PyrParseNode* expr1, PyrParseNode* expr2) { PyrSetterNode* node = ALLOCNODE(PyrSetterNode); node->mSelector = selector; node->mExpr1 = expr1; node->mExpr2 = expr2; return node; } PyrMultiAssignNode* newPyrMultiAssignNode(PyrMultiAssignVarListNode* varList, PyrParseNode* expr, int flags) { PyrMultiAssignNode* node = ALLOCNODE(PyrMultiAssignNode); node->mVarList = varList; node->mExpr = expr; node->mDrop = 0; return node; } PyrMultiAssignVarListNode* newPyrMultiAssignVarListNode(PyrSlotNode* varNames, PyrSlotNode* rest) { PyrMultiAssignVarListNode* node = ALLOCNODE(PyrMultiAssignVarListNode); node->mVarNames = varNames; node->mRest = rest; return node; } void compileAssignVar(PyrParseNode* node, PyrSymbol* varName, bool drop) { int level, index, vindex, varType; PyrBlock *tempfunc; PyrClass *classobj; //postfl("compileAssignVar\n"); classobj = gCompilingClass; if (varName == s_this || varName == s_super || varName == s_curProcess || varName == s_curThread || varName == s_curMethod || varName == s_curBlock || varName == s_curClosure) { error("You may not assign to '%s'.", varName->name); nodePostErrorLine(node); compileErrors++; } else if (varName->name[0] >= 'A' && varName->name[0] <= 'Z') { // actually this shouldn't even parse, so you won't get here. error("You may not assign to a class name."); nodePostErrorLine(node); compileErrors++; } else if (findVarName(gCompilingBlock, &classobj, varName, &varType, &level, &index, &tempfunc)) { switch (varType) { case varInst : if (drop) { if (index <= 15) { compileByte((opStoreInstVar<<4) | index); } else { compileByte(opStoreInstVar); compileByte(index); compileByte((opSpecialOpcode<<4) | opcDrop); } } else { compileByte(opStoreInstVar); compileByte(index); } break; case varClass : { index += slotRawInt(&classobj->classVarIndex); if (drop) { if (index < 4096) { compileByte((opStoreClassVar<<4) | ((index>>8) & 15)); compileByte(index & 255); } else { compileByte(opStoreClassVar); assert(false); vindex = 0; compileByte(vindex); // FIXME: vindex is not initalized!!!! compileByte(index); compileByte((opSpecialOpcode<<4) | opcDrop); } } else { compileByte(opStoreClassVar); compileByte((index >> 8) & 255); compileByte(index & 255); } } break; case varConst : { error("You may not assign to a constant."); nodePostErrorLine(node); compileErrors++; } break; case varTemp : //compileOpcode(opStoreTempVar, level); //compileByte(index); if (drop) { if (index <= 15 && level < 8) { compileByte((opStoreTempVar<<4) | level); compileByte(index); } else { compileByte(opStoreTempVar); compileByte(level); compileByte(index); compileByte((opSpecialOpcode<<4) | opcDrop); } } else { compileByte(opStoreTempVar); compileByte(level); compileByte(index); } break; } } else { error("Variable '%s' not defined.\n", varName->name); nodePostErrorLine(node); compileErrors++; //Debugger(); } } void PyrAssignNode::compile(PyrSlot* result) { PyrSlot dummy; //postfl("compilePyrAssignNode\n"); COMPILENODE(mExpr, &dummy, false); compileAssignVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot), mDrop); } int PyrSetterNode::isPartialApplication() { int sum = 0; if (mExpr1->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)mExpr1)->mArgNum = sum; sum ++; } if (mExpr2->mClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)mExpr2)->mArgNum = sum; sum ++; } return sum; } void PyrSetterNode::compileCall(PyrSlot* result) { int index, selType, isSuper; PyrSlot dummy; char setterName[128]; PyrSymbol *setterSym; //postfl("compilePyrSetterNode\n"); if (nodeListLength(mExpr1) > 1) { error("Setter method called with too many arguments.\n"); nodePostErrorLine(mExpr1); compileErrors++; } else { COMPILENODE(mExpr1, &dummy, false); COMPILENODE(mExpr2, &dummy, false); //postfl("compilePyrCallNode\n"); isSuper = isSuperObjNode(mExpr1); sprintf(setterName, "%s_", slotRawSymbol(&mSelector->mSlot)->name); setterSym = getsym(setterName); slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called; index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, setterSym, &selType); if (isSuper) { compileTail(); compileOpcode(opSendSuper, 2); compileByte(index); } else { compileTail(); compileOpcode(opSendMsg, 2); compileByte(index); } } } void PyrMultiAssignNode::compile(PyrSlot* result) { PyrSlot dummy; //postfl("compilePyrMultiAssignNode\n"); COMPILENODE(mExpr, &dummy, false); COMPILENODE(mVarList, &dummy, false); } void PyrMultiAssignVarListNode::compile(PyrSlot* result) { int i, numAssigns; PyrSlotNode *varname; //postfl("compilePyrMultiAssignVarListNode\n"); numAssigns = nodeListLength((PyrParseNode*)mVarNames); varname = mVarNames; for (i=0; imNext) { compileOpcode(opSpecialOpcode, opcDup); compilePushInt(i); compileOpcode(opSendSpecialMsg, 2); compileByte(opmAt); compileAssignVar((PyrParseNode*)varname, slotRawSymbol(&varname->mSlot), 1); //compileOpcode(opSpecialOpcode, opcDrop); } if (mRest) { compileOpcode(opSpecialOpcode, opcDup); compilePushInt(i); compileOpcode(opSendSpecialMsg, 2); compileByte(opmCopyToEnd); compileAssignVar((PyrParseNode*)mRest, slotRawSymbol(&mRest->mSlot), 1); //compileOpcode(opSpecialOpcode, opcDrop); } } PyrDynDictNode* newPyrDynDictNode(PyrParseNode *elems) { PyrDynDictNode* node; //if (compilingCmdLine) post("newPyrDynDictNode\n"); node = ALLOCNODE(PyrDynDictNode); node->mElems = elems; return node; } int PyrDynDictNode::isPartialApplication() { int sum = 0; int numItems = nodeListLength(mElems); PyrParseNode* inode = mElems; for (int i=0; imClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)inode)->mArgNum = sum; sum ++; } inode = (PyrParseNode*)inode->mNext; } return sum; } void PyrDynDictNode::compileCall(PyrSlot* result) { int i, numItems; PyrParseNode *inode; PyrSlot dummy; //postfl("compilePyrDynDictNode\n"); numItems = nodeListLength(mElems) >> 1; compilePushVar((PyrParseNode*)this, s_event); compilePushInt(numItems); compileByte(110); // push nil for proto compileByte(110); // push nil for parent compileByte(108); // push true for know compileOpcode(opSendSpecialMsg, 5); compileByte(opmNew); inode = mElems; for (i=0; isize); COMPILENODE(inode, &dummy, false); inode = (PyrParseNode*)inode->mNext; COMPILENODE(inode, &dummy, false); inode = (PyrParseNode*)inode->mNext; compileOpcode(opSendSpecialMsg, 3); compileByte(opmPut); } } PyrDynListNode* newPyrDynListNode(PyrParseNode *classname, PyrParseNode *elems) { PyrDynListNode* node; //if (compilingCmdLine) post("newPyrDynListNode\n"); node = ALLOCNODE(PyrDynListNode); node->mClassname = classname; node->mElems = elems; return node; } int PyrDynListNode::isPartialApplication() { int sum = 0; int numItems = nodeListLength(mElems); PyrParseNode* inode = mElems; for (int i=0; imClassno == pn_CurryArgNode) { ((PyrCurryArgNode*)inode)->mArgNum = sum; sum ++; } inode = (PyrParseNode*)inode->mNext; } return sum; } void PyrDynListNode::compileCall(PyrSlot* result) { int i, numItems; PyrParseNode *inode; PyrSlot dummy; //postfl("compilePyrDynListNode\n"); numItems = nodeListLength(mElems); if (mClassname) { compilePushVar((PyrParseNode*)this, slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot)); } else { compilePushVar((PyrParseNode*)this, s_array); } //compileOpcode(opExtended, opPushSpecialValue); //compileByte(op_class_list); compilePushInt(numItems); compileOpcode(opSendSpecialMsg, 2); compileByte(opmNew); inode = mElems; for (i=0; imNext) { //if (compilingCmdLine) post("+ %d %d\n", i, gCompilingByteCodes->size); COMPILENODE(inode, &dummy, false); compileOpcode(opSendSpecialMsg, 2); compileByte(opmAdd); } } PyrLitListNode* newPyrLitListNode(PyrParseNode *classname, PyrParseNode *elems) { PyrLitListNode* node = ALLOCNODE(PyrLitListNode); node->mClassname = classname; node->mElems = elems; return node; } void PyrLitListNode::compile(PyrSlot* result) { PyrSlot *resultSlot; PyrSlot itemSlot; PyrObject *array; PyrParseNode *inode; int i, numItems, flags; //postfl("->compilePyrLitListNode\n"); if (mClassname && slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot) != s_array) { error("Only Array is supported as literal type.\n"); post("Compiling as an Array.\n"); } resultSlot = (PyrSlot*)result; numItems = mElems ? nodeListLength(mElems) : 0; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; array = newPyrArray(compileGC(), numItems, flags, false); inode = mElems; for (i=0; imNext) { COMPILENODE(inode, &itemSlot, false); array->slots[i] = itemSlot; } array->size = numItems; SetObject(resultSlot, array); //postfl("<-compilePyrLitListNode\n"); } PyrLitDictNode* newPyrLitDictNode(PyrParseNode *elems) { PyrLitDictNode* node = ALLOCNODE(PyrLitDictNode); node->mElems = elems; return node; } int litDictPut(PyrObject *dict, PyrSlot *key, PyrSlot *value); int litDictPut(PyrObject *dict, PyrSlot *key, PyrSlot *value) { #if 0 PyrSlot *slot, *newslot; int i, index, size; PyrObject *array; bool knows = IsTrue(dict->slots + ivxIdentDict_know); if (knows && IsSym(key)) { if (slotRawSymbol(key) == s_parent) { slotCopy(&dict->slots[ivxIdentDict_parent], value); return errNone; } if (slotRawSymbol(key) == s_proto) { slotCopy(&dict->slots[ivxIdentDict_proto], value); return errNone; } } array = slotRawObject(&dict->slots[ivxIdentDict_array]); if (!isKindOf((PyrObject*)array, class_array)) return errFailed; index = arrayAtIdentityHashInPairs(array, key); slot = array->slots + index; slotCopy(&slot[1], value); if (IsNil(slot)) { slotCopy(slot, key); } #endif return errNone; } void PyrLitDictNode::dump(int level) { } void PyrLitDictNode::compile(PyrSlot* result) { #if 0 PyrSlot *resultSlot; PyrSlot itemSlot; PyrObject *array; PyrParseNode *inode; int i, numItems, flags; //postfl("->compilePyrLitDictNode\n"); if (mClassname && slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot) != s_array) { error("Only Array is supported as literal type.\n"); post("Compiling as an Array.\n"); } resultSlot = (PyrSlot*)result; numItems = mElems ? nodeListLength(mElems) : 0; int numSlots = NEXTPOWEROFTWO(numItems*2); PyrObject *obj = instantiateObject(g->gc, class_event->u.classobj, 0, true, false); PyrSlot *slots = obj->slots; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; array = newPyrArray(compileGC(), numSlots, flags, false); nilSlots(array->slots, numSlots); inode = mElems; for (i=0; imNext) { COMPILENODE(inode, &itemSlot, false); array->slots[i] = itemSlot; } array->size = numItems; SetObject(resultSlot, array); //postfl("<-compilePyrLitListNode\n"); #endif } extern LongStack closedFuncCharNo; extern int lastClosedFuncCharNo; PyrBlockNode* newPyrBlockNode(PyrArgListNode *arglist, PyrVarListNode *varlist, PyrParseNode *body, bool isTopLevel) { PyrBlockNode* node = ALLOCNODE(PyrBlockNode); node->mArglist = arglist; catVarLists(varlist); node->mVarlist = varlist; node->mBody = body; node->mIsTopLevel = isTopLevel; node->mBeginCharNo = lastClosedFuncCharNo; return node; } void PyrBlockNode::compile(PyrSlot* slotResult) { PyrBlock *block, *prevBlock; PyrMethodRaw *methraw; int i, j, numArgs, numVars, funcVarArgs; int numSlots, numArgNames, flags; PyrVarDefNode *vardef; PyrObject *proto; PyrSymbolArray *argNames, *varNames; PyrSlot dummy; bool hasVarExprs = false; //postfl("->block\n"); // create a new block object flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; block = newPyrBlock(flags); SetObject(slotResult, block); int prevFunctionHighestExternalRef = gFunctionHighestExternalRef; bool prevFunctionCantBeClosed = gFunctionCantBeClosed; gFunctionHighestExternalRef = 0; gFunctionCantBeClosed = false; prevBlock = gCompilingBlock; PyrClass* prevClass = gCompilingClass; gCompilingBlock = block; PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction; gPartiallyAppliedFunction = NULL; methraw = METHRAW(block); methraw->unused1 = 0; methraw->unused2 = 0; int endCharNo = linestarts[mLineno] + mCharno; int stringLength = endCharNo - mBeginCharNo; int lastChar = text[mBeginCharNo + stringLength - 1]; if (lastChar == 0) stringLength--; methraw->needsHeapContext = 0; if (mIsTopLevel) { gCompilingClass = class_interpreter; SetNil(&block->contextDef); } else { SetObject(&block->contextDef, prevBlock); } methraw->varargs = funcVarArgs = (mArglist && mArglist->mRest) ? 1 : 0; numArgs = mArglist ? nodeListLength((PyrParseNode*)mArglist->mVarDefs) : 0; numVars = mVarlist ? nodeListLength((PyrParseNode*)mVarlist->mVarDefs) : 0; if(numArgs > 255) { error("Too many arguments in function definition (> 255)\n"); nodePostErrorLine((PyrParseNode*)mArglist->mVarDefs); compileErrors++; } if(numArgs > 255) { error("Too many arguments in function definition (> 255).\n"); nodePostErrorLine((PyrParseNode*)mArglist->mVarDefs); compileErrors++; } numSlots = numArgs + funcVarArgs + numVars; methraw->frameSize = (numSlots + FRAMESIZE) * sizeof(PyrSlot); if (numSlots) { proto = newPyrArray(compileGC(), numSlots, flags, false); proto->size = numSlots; SetObject(&block->prototypeFrame, proto); } else { SetNil(&block->prototypeFrame); } numArgNames = numArgs + funcVarArgs; if (numArgNames) { argNames = newPyrSymbolArray(compileGC(), numArgNames, flags, false); argNames->size = numArgNames; SetObject(&block->argNames, argNames); } else { SetNil(&block->argNames); } if (numVars) { varNames = newPyrSymbolArray(compileGC(), numVars, flags, false); varNames->size = numVars; SetObject(&block->varNames, varNames); } else { SetNil(&block->varNames); } methraw->numargs = numArgs; methraw->numvars = numVars; methraw->posargs = numArgs + funcVarArgs; methraw->numtemps = numSlots; methraw->popSize = numSlots; // declare args if (numArgs) { PyrSymbol **blockargs; blockargs = slotRawSymbolArray(&block->argNames)->symbols; vardef = mArglist->mVarDefs; for (i=0; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in mArglist blockargs[i] = slotRawSymbol(varslot); //postfl("defarg %d '%s'\n", i, slotRawSymbol(slot)->name); } } if (funcVarArgs) { PyrSlot *varslot; PyrSymbol **blockargs; blockargs = slotRawSymbolArray(&block->argNames)->symbols; varslot = &mArglist->mRest->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in mArglist blockargs[numArgs] = slotRawSymbol(varslot); //postfl("defrest '%s'\n", slotRawSymbol(slot)->name); } // declare vars if (numVars) { PyrSymbol **blockargs, **blockvars; blockargs = slotRawSymbolArray(&block->argNames)->symbols; blockvars = slotRawSymbolArray(&block->varNames)->symbols; vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *varslot; varslot = &vardef->mVarName->mSlot; // already declared as arg? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // already declared as var? for (j=0; jname, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); nodePostErrorLine((PyrParseNode*)vardef); compileErrors++; } } // put it in varlist blockvars[i] = slotRawSymbol(varslot); //postfl("defvar %d '%s'\n", i, slotRawSymbol(slot)->name); } } if (numArgs) { vardef = mArglist->mVarDefs; for (i=0; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&block->prototypeFrame)->slots + i; if (vardef->hasExpr(&litval)) hasVarExprs = true; //compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litval); *slot = litval; } } if (funcVarArgs) { //SetNil(&slotRawObject(&block->prototypeFrame)->slots[numArgs]); slotCopy(&slotRawObject(&block->prototypeFrame)->slots[numArgs], &o_emptyarray); } if (numVars) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { PyrSlot *slot, litval; slot = slotRawObject(&block->prototypeFrame)->slots + i + numArgs + funcVarArgs; if (vardef->hasExpr(&litval)) hasVarExprs = true; //compilePyrLiteralNode(vardef->mDefVal, &litval); *slot = litval; } } methraw->methType = methBlock; // compile body initByteCodes(); { SetTailBranch branch(true); /*if (compilingCmdLine) { post("block %d\n", gIsTailCodeBranch); DUMPNODE(mBody, 0); }*/ SetTailIsMethodReturn mr(false); if (hasVarExprs) { if (mArglist) { vardef = mArglist->mVarDefs; for (i=0; imNext) { vardef->compileArg(&dummy); } } if (mVarlist) { vardef = mVarlist->mVarDefs; for (i=0; imNext) { vardef->compile(&dummy); } } } if (mBody->mClassno == pn_BlockReturnNode) { compileOpcode(opPushSpecialValue, opsvNil); } else { COMPILENODE(mBody, &dummy, true); } } compileOpcode(opSpecialOpcode, opcFunctionReturn); installByteCodes(block); if ((!gFunctionCantBeClosed && gFunctionHighestExternalRef == 0) || mIsTopLevel) { SetNil(&block->contextDef); PyrString* string = newPyrStringN(compileGC(), stringLength, flags, false); memcpy(string->s, text+mBeginCharNo, stringLength); SetObject(&block->sourceCode, string); //static int totalLength = 0, totalStrings = 0; //totalLength += stringLength; //totalStrings++; //post("cf %4d %4d %6d %s:%s \n", totalStrings, stringLength, totalLength, slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); } gCompilingBlock = prevBlock; gCompilingClass = prevClass; gPartiallyAppliedFunction = prevPartiallyAppliedFunction; gFunctionCantBeClosed = gFunctionCantBeClosed || prevFunctionCantBeClosed; gFunctionHighestExternalRef = sc_max(gFunctionHighestExternalRef - 1, prevFunctionHighestExternalRef); } PyrParseNode* linkNextNode(PyrParseNode* a, PyrParseNode* b) { if (a == NULL) return b; if (b) { a->mTail->mNext = b; a->mTail = b->mTail; } return a; } PyrParseNode* linkAfterHead(PyrParseNode* a, PyrParseNode* b) { b->mNext = a->mNext; if (!a->mNext) a->mTail = b; a->mNext = b; return a; } bool isSuperObjNode(PyrParseNode *node) { return node->mClassno == pn_PushNameNode && slotRawSymbol(&((PyrPushNameNode*)node)->mSlot) == s_super; } bool isThisObjNode(PyrParseNode *node) { return node->mClassno == pn_PushNameNode && slotRawSymbol(&((PyrPushNameNode*)node)->mSlot) == s_this; } int nodeListLength(PyrParseNode *node) { int length = 0; for (; node; node=node->mNext) length++; return length; } int conjureSelectorIndex(PyrParseNode *node, PyrBlock* func, bool isSuper, PyrSymbol *selector, int *selType) { int i; PyrObject *selectors; PyrSlot *slot; int newsize, flags; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; if (!isSuper) { if (selector == gSpecialSelectors[opmIf]) { *selType = selIf; return opmIf; } else if (selector == gSpecialSelectors[opmWhile]) { *selType = selWhile; return opmWhile; } else if (selector == gSpecialSelectors[opmAnd]) { *selType = selAnd; return opmAnd; } else if (selector == gSpecialSelectors[opmOr]) { *selType = selOr; return opmOr; } else if (selector == gSpecialSelectors[opmCase]) { *selType = selCase; return opmCase; } else if (selector == gSpecialSelectors[opmSwitch]) { *selType = selSwitch; return opmSwitch; } else if (selector == gSpecialSelectors[opmLoop]) { *selType = selLoop; return opmLoop; } else if (selector == gSpecialSelectors[opmQuestionMark]) { *selType = selQuestionMark; return opmAnd; } else if (selector == gSpecialSelectors[opmDoubleQuestionMark]) { *selType = selDoubleQuestionMark; return opmAnd; } else if (selector == gSpecialSelectors[opmExclamationQuestionMark]) { *selType = selExclamationQuestionMark; return opmAnd; } for (i=0; iselectors)) { selectors = slotRawObject(&func->selectors); for (i=0; isize; ++i) { if (IsSym(&selectors->slots[i]) && slotRawSymbol(&selectors->slots[i]) == selector) { *selType = selNormal; return i; } } } else { selectors = (PyrObject*)newPyrArray(compileGC(), 2, flags, false); SetObject(&func->selectors, selectors); } // otherwise add it to the selectors table if (selectors->size+1 >= 256) { error("Selector table too big: too many classes, method selectors or function definitions in this function. Simplify the function.\n"); post("Next selector was: %s\n", selector->name); nodePostErrorLine(node); compileErrors++; return 0; } if (selectors->size+1 > ARRAYMAXINDEXSIZE(selectors)) { // resize literal table newsize = ARRAYMAXINDEXSIZE(selectors) * 2; SetRaw(&func->selectors, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false)); memcpy(slotRawObject(&func->selectors)->slots, selectors->slots, selectors->size * sizeof(PyrSlot)); slotRawObject(&func->selectors)->size = selectors->size; freePyrObject(selectors); selectors = slotRawObject(&func->selectors); } slot = selectors->slots + selectors->size++; SetSymbol(slot, selector); *selType = selNormal; return selectors->size-1; } int conjureLiteralSlotIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot) { int i; PyrObject *selectors; PyrSlot *slot2; int newsize, flags; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; // lookup slot in selectors table if (IsObj(&func->selectors)) { selectors = slotRawObject(&func->selectors); /*if (selectors->classptr != class_array) { post("compiling %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name); post("selectors is a '%s'\n", selectors->classptr->name.us->name); dumpObjectSlot(slot); Debugger(); }*/ for (i=0; isize; ++i) if (SlotEq(&selectors->slots[i], slot)) return i; } else { selectors = (PyrObject*)newPyrArray(compileGC(), 4, flags, false); SetObject(&func->selectors, selectors); } // otherwise add it to the selectors table if (selectors->size+1 >= 256) { error("Selector table too big: too many classes, method selectors or function definitions in this function. Simplify the function.\n"); post("Next literal was:\n"); dumpPyrSlot(slot); nodePostErrorLine(node); compileErrors++; return 0; } if (selectors->size+1 > ARRAYMAXINDEXSIZE(selectors)) { // resize literal table newsize = ARRAYMAXINDEXSIZE(selectors) * 2; // resize literal table SetRaw(&func->selectors, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false)); memcpy(slotRawObject(&func->selectors)->slots, selectors->slots, selectors->size * sizeof(PyrSlot)); slotRawObject(&func->selectors)->size = selectors->size; freePyrObject(selectors); selectors = slotRawObject(&func->selectors); } slot2 = selectors->slots + selectors->size++; slotCopy(slot2, slot); return selectors->size-1; } int conjureConstantIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot) { int i; PyrObject *constants; int newsize, flags; flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable; // lookup slot in constants table if (IsObj(&func->constants)) { constants = slotRawObject(&func->constants); for (i=0; isize; ++i) if (SlotEq(&constants->slots[i], slot)) return i; } else { constants = (PyrObject*)newPyrArray(compileGC(), 4, flags, false); SetObject(&func->constants, constants); } // otherwise add it to the constants table if (constants->size+1 > ARRAYMAXINDEXSIZE(constants)) { // resize literal table newsize = ARRAYMAXINDEXSIZE(constants) * 2; // resize literal table SetRaw(&func->constants, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false)); memcpy(slotRawObject(&func->constants)->slots, constants->slots, constants->size * sizeof(PyrSlot)); slotRawObject(&func->constants)->size = constants->size; freePyrObject((PyrObject*)constants); constants = slotRawObject(&func->constants); } slotCopy(&constants->slots[constants->size++], slot); return constants->size-1; } bool findVarName(PyrBlock* func, PyrClass **classobj, PyrSymbol *name, int *varType, int *level, int *index, PyrBlock** tempfunc) { int i, j, k; int numargs; PyrSymbol *argname, *varname; PyrMethodRaw *methraw; //postfl("->findVarName %s\n", name->name); // find var in enclosing blocks, instance, class if (name == s_super) { gFunctionCantBeClosed = true; name = s_this; } if (name->name[0] >= 'A' && name->name[0] <= 'Z') return false; for (j=0; func; func = slotRawBlock(&func->contextDef), ++j) { methraw = METHRAW(func); numargs = methraw->posargs; for (i=0; iargNames)->symbols[i]; //postfl(" %d %d arg '%s' '%s'\n", j, i, argname->name, name->name); if (argname == name) { *level = j; *index = i; *varType = varTemp; if (tempfunc) *tempfunc = func; if (j > gFunctionHighestExternalRef) gFunctionHighestExternalRef = j; return true; } } for (i=0, k=numargs; inumvars; ++i,++k) { varname = slotRawSymbolArray(&func->varNames)->symbols[i]; //postfl(" %d %d %d var '%s' '%s'\n", j, i, k, varname->name, name->name); if (varname == name) { *level = j; *index = k; *varType = varTemp; if (tempfunc) *tempfunc = func; if (j > gFunctionHighestExternalRef) gFunctionHighestExternalRef = j; return true; } } } if (classFindInstVar(*classobj, name, index)) { *level = 0; *varType = varInst; if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true; return true; } if (classFindClassVar(classobj, name, index)) { *varType = varClass; if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true; return true; } if (classFindConst(classobj, name, index)) { *varType = varConst; //if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true; return true; } if (name == s_curProcess) { *varType = varPseudo; *index = opgProcess; return true; } if (name == s_curThread) { *varType = varPseudo; *index = opgThread; return true; } if (name == s_curMethod) { *varType = varPseudo; *index = opgMethod; return true; } if (name == s_curBlock) { *varType = varPseudo; *index = opgFunctionDef; return true; } if (name == s_curClosure) { *varType = varPseudo; *index = opgFunction; return true; } return false; } extern PyrSymbol *s_env; void initSpecialClasses() { gSpecialClasses[op_class_object] = s_object; gSpecialClasses[op_class_symbol] = s_symbol; gSpecialClasses[op_class_nil] = s_nil; gSpecialClasses[op_class_boolean] = s_boolean; gSpecialClasses[op_class_true] = s_true; gSpecialClasses[op_class_false] = s_false; gSpecialClasses[op_class_magnitude] = s_magnitude; gSpecialClasses[op_class_char] = s_char; gSpecialClasses[op_class_number] = s_number; gSpecialClasses[op_class_complex] = s_complex; gSpecialClasses[op_class_simple_number] = s_simple_number; gSpecialClasses[op_class_int] = s_int; gSpecialClasses[op_class_float] = s_float; gSpecialClasses[op_class_method] = s_method; gSpecialClasses[op_class_fundef] = s_fundef; gSpecialClasses[op_class_stream] = s_stream; gSpecialClasses[op_class_func] = s_func; gSpecialClasses[op_class_frame] = s_frame; gSpecialClasses[op_class_process] = s_process; gSpecialClasses[op_class_main] = s_main; gSpecialClasses[op_class_class] = s_class; gSpecialClasses[op_class_string] = s_string; gSpecialClasses[op_class_collection] = s_collection; gSpecialClasses[op_class_sequenceable_collection] = s_sequenceable_collection; gSpecialClasses[op_class_arrayed_collection] = s_arrayed_collection; gSpecialClasses[op_class_array] = s_array; gSpecialClasses[op_class_int8array] = s_int8array; gSpecialClasses[op_class_int16array] = s_int16array; gSpecialClasses[op_class_int32array] = s_int32array; gSpecialClasses[op_class_floatarray] = s_floatarray; gSpecialClasses[op_class_signal] = s_signal; gSpecialClasses[op_class_doublearray] = s_doublearray; gSpecialClasses[op_class_symbolarray] = s_symbolarray; gSpecialClasses[op_class_list] = s_list; gSpecialClasses[op_class_linkedlist] = s_linkedlist; gSpecialClasses[op_class_bag] = s_bag; gSpecialClasses[op_class_set] = s_set; gSpecialClasses[op_class_identityset] = s_identityset; gSpecialClasses[op_class_dictionary] = s_dictionary; gSpecialClasses[op_class_identitydictionary] = s_identitydictionary; gSpecialClasses[op_class_sortedlist] = s_sortedlist; gSpecialClasses[op_class_synth] = s_synth; gSpecialClasses[op_class_ref] = s_ref; gSpecialClasses[op_class_environment] = s_environment; gSpecialClasses[op_class_event] = s_event; gSpecialClasses[op_class_wavetable] = s_wavetable; gSpecialClasses[op_class_env] = s_env; gSpecialClasses[op_class_routine] = s_routine; gSpecialClasses[op_class_color] = s_color; gSpecialClasses[op_class_rect] = s_rect; //Infinitum, Point, Rect, ?? } void initSpecialSelectors() { PyrSymbol **sel; long i; sel = gSpecialUnarySelectors; sel[opNeg] = getsym("neg"); sel[opRecip] = getsym("reciprocal"); sel[opNot] = getsym("not"); sel[opIsNil] = getsym("isNil"); sel[opNotNil] = getsym("notNil"); sel[opBitNot] = getsym("bitNot"); sel[opAbs] = getsym("abs"); sel[opAsFloat] = getsym("asFloat"); sel[opAsInt] = getsym("asInt"); sel[opCeil] = getsym("ceil"); //5 sel[opFloor] = getsym("floor"); sel[opFrac] = getsym("frac"); sel[opSign] = getsym("sign"); sel[opSquared] = getsym("squared"); sel[opCubed] = getsym("cubed"); //10 sel[opSqrt] = getsym("sqrt"); sel[opExp] = getsym("exp"); sel[opMIDICPS] = getsym("midicps"); sel[opCPSMIDI] = getsym("cpsmidi"); sel[opMIDIRatio] = getsym("midiratio"); sel[opRatioMIDI] = getsym("ratiomidi"); sel[opAmpDb] = getsym("ampdb"); //15 sel[opDbAmp] = getsym("dbamp"); sel[opOctCPS] = getsym("octcps"); sel[opCPSOct] = getsym("cpsoct"); sel[opLog] = getsym("log"); sel[opLog2] = getsym("log2"); //20 sel[opLog10] = getsym("log10"); sel[opSin] = getsym("sin"); sel[opCos] = getsym("cos"); sel[opTan] = getsym("tan"); sel[opArcSin] = getsym("asin"); //25 sel[opArcCos] = getsym("acos"); sel[opArcTan] = getsym("atan"); sel[opSinH] = getsym("sinh"); sel[opCosH] = getsym("cosh"); sel[opTanH] = getsym("tanh"); //30 sel[opRand] = getsym("rand"); sel[opRand2] = getsym("rand2"); sel[opLinRand] = getsym("linrand"); sel[opBiLinRand] = getsym("bilinrand"); sel[opSum3Rand] = getsym("sum3rand"); /* sel[opExpRand] = getsym("exprand"); sel[opBiExpRand] = getsym("biexprand"); sel[opGammaRand] = getsym("gammarand"); sel[opGaussRand] = getsym("gaussrand"); sel[opPoiRand] = getsym("poirand"); */ sel[opDistort] = getsym("distort"); sel[opSoftClip] = getsym("softclip"); sel[opCoin] = getsym("coin"); sel[opRectWindow] = getsym("rectWindow"); sel[opHanWindow] = getsym("hanWindow"); sel[opWelchWindow] = getsym("welWindow"); sel[opTriWindow] = getsym("triWindow"); sel[opSCurve] = getsym("scurve"); sel[opRamp] = getsym("ramp"); sel[opDigitValue] = getsym("digitValue"); sel[opSilence] = getsym("silence"); sel[opThru] = getsym("thru"); sel = gSpecialBinarySelectors; sel[opAdd] = getsym("+"); sel[opSub] = getsym("-"); sel[opMul] = getsym("*"); sel[opFDiv] = getsym("/"); sel[opIDiv] = getsym("div"); sel[opMod] = getsym("mod"); sel[opEQ] = getsym("=="); sel[opNE] = getsym("!="); sel[opLT] = getsym("<"); sel[opGT] = getsym(">"); sel[opLE] = getsym("<="); sel[opGE] = getsym(">="); //sel[opIdentical] = getsym("==="); //sel[opNotIdentical] = getsym("!=="); sel[opMin] = getsym("min"); sel[opMax] = getsym("max"); sel[opBitAnd] = getsym("bitAnd"); sel[opBitOr] = getsym("bitOr"); sel[opBitXor] = getsym("bitXor"); sel[opLCM] = getsym("lcm"); sel[opGCD] = getsym("gcd"); sel[opRound] = getsym("round"); sel[opRoundUp] = getsym("roundUp"); sel[opTrunc] = getsym("trunc"); sel[opAtan2] = getsym("atan2"); sel[opHypot] = getsym("hypot"); sel[opHypotx] = getsym("hypotApx"); sel[opPow] = getsym("pow"); sel[opShiftLeft] = getsym("leftShift"); sel[opShiftRight] = getsym("rightShift"); sel[opUnsignedShift] = getsym("unsignedRightShift"); sel[opFill] = getsym("fill"); sel[opRing1] = getsym("ring1"); // a * (b + 1) == a * b + a sel[opRing2] = getsym("ring2"); // a * b + a + b sel[opRing3] = getsym("ring3"); // a*a*b sel[opRing4] = getsym("ring4"); // a*a*b - a*b*b sel[opDifSqr] = getsym("difsqr"); // a*a - b*b sel[opSumSqr] = getsym("sumsqr"); // a*a + b*b sel[opSqrSum] = getsym("sqrsum"); // (a + b)^2 sel[opSqrDif] = getsym("sqrdif"); // (a - b)^2 sel[opAbsDif] = getsym("absdif"); // sel[opThresh] = getsym("thresh"); // sel[opAMClip] = getsym("amclip"); // sel[opScaleNeg] = getsym("scaleneg"); // sel[opClip2] = getsym("clip2"); sel[opFold2] = getsym("fold2"); sel[opWrap2] = getsym("wrap2"); sel[opExcess] = getsym("excess"); sel[opFirstArg] = getsym("firstArg"); sel[opRandRange] = getsym("rrand"); sel[opExpRandRange] = getsym("exprand"); sel = gSpecialSelectors; sel[opmNew] = getsym("new"); sel[opmNewClear] = getsym("newClear"); sel[opmNewCopyArgs] = getsym("newCopyArgs"); sel[opmInit] = getsym("init"); sel[opmAt] = getsym("at"); sel[opmPut] = getsym("put"); sel[opmNext] = getsym("next"); sel[opmReset] = getsym("reset"); sel[opmValue] = getsym("value"); sel[opmCopyToEnd] = getsym("copyToEnd"); // used by multiple assignment //sel[opmIsNil] = getsym("isNil"); //sel[opmNotNil] = getsym("notNil"); sel[opmSize] = getsym("size"); sel[opmClass] = getsym("class"); sel[opmIf] = getsym("if"); sel[opmWhile] = getsym("while"); sel[opmFor] = getsym("for"); sel[opmAnd] = getsym("and"); sel[opmOr] = getsym("or"); sel[opmCase] = getsym("case"); sel[opmSwitch] = getsym("switch"); sel[opmIdentical] = getsym("==="); sel[opmNotIdentical] = getsym("!=="); sel[opmPrint] = getsym("print"); sel[opmAdd] = getsym("add"); sel[opmRemove] = getsym("remove"); sel[opmIndexOf] = getsym("indexOf"); sel[opmWrapAt] = getsym("wrapAt"); sel[opmClipAt] = getsym("clipAt"); sel[opmFoldAt] = getsym("foldAt"); sel[opmWrapPut] = getsym("wrapPut"); sel[opmClipPut] = getsym("clipPut"); sel[opmFoldPut] = getsym("foldPut"); sel[opmDo] = getsym("do"); sel[opmCollect] = getsym("collect"); sel[opmSelect] = getsym("select"); sel[opmReject] = getsym("reject"); sel[opmAny] = getsym("any"); sel[opmEvery] = getsym("every"); sel[opmFind] = getsym("find"); sel[opmChoose] = getsym("choose"); sel[opmValueList] = getsym("valueList"); sel[opmAddFirst] = getsym("addFirst"); sel[opmPrimitiveFailed] = getsym("primitiveFailed"); sel[opmSubclassResponsibility] = getsym("subclassResponsibility"); sel[opmShouldNotImplement] = getsym("shouldNotImplement"); sel[opmDoesNotUnderstand] = getsym("doesNotUnderstand"); // not really needed sel[opmNotYetImplemented] = getsym("notYetImplemented"); sel[opmAtSign] = getsym("@"); sel[opmWrapAtSign] = getsym("@@"); sel[opmClipAtSign] = getsym("|@|"); sel[opmFoldAtSign] = getsym("@|@"); sel[opmMultiNew] = getsym("multiNew"); // UGens sel[opmMultiNewList] = getsym("multiNewList"); // UGens sel[opmAR] = getsym("ar"); // UGens sel[opmKR] = getsym("kr"); // UGens sel[opmIR] = getsym("ir"); // UGens sel[opmEnvirGet] = getsym("envirGet"); sel[opmEnvirPut] = getsym("envirPut"); sel[opmHalt] = getsym("halt"); sel[opmForBy] = getsym("forBy"); sel[opmForSeries] = getsym("forSeries"); sel[opmReverseDo] = getsym("reverseDo"); sel[opmLoop] = getsym("loop"); sel[opmNonBooleanError] = getsym("mustBeBoolean"); sel[opmCopy] = getsym("copy"); sel[opmPerformList] = getsym("performList"); sel[opmIsKindOf] = getsym("isKindOf"); sel[opmPostln] = getsym("postln"); sel[opmAsString] = getsym("asString"); sel[opmPlusPlus] = getsym("++"); sel[opmLTLT] = getsym("<<"); sel[opmQuestionMark] = getsym("?"); sel[opmDoubleQuestionMark] = getsym("??"); sel[opmExclamationQuestionMark] = getsym("!?"); sel[opmYield] = getsym("yield"); sel[opmName] = getsym("name"); sel[opmMulAdd] = getsym("madd"); sel[opmSeries] = getsym("series"); for (i=0; ispecialIndex = i; } for (i=0; ispecialIndex = i; } } bool findSpecialClassName(PyrSymbol *className, int *index) { int i; for (i=0; idump(level); } while (false); struct PyrParseNode { PyrParseNode(int classno); virtual ~PyrParseNode() {} virtual void compile(PyrSlot *result) = 0; virtual void dump(int level) = 0; struct PyrParseNode *mNext; struct PyrParseNode *mTail; int mLineno; int mCharno; unsigned char mClassno; unsigned char mParens; }; struct PyrSlotNode : public PyrParseNode { PyrSlotNode() : PyrParseNode(pn_SlotNode) {} PyrSlotNode(int classno) : PyrParseNode(classno) {} virtual ~PyrSlotNode() {} virtual void compile(PyrSlot *result); virtual void compileLiteral(PyrSlot *result); virtual void compilePushLit(PyrSlot *result); virtual void dump(int level); virtual void dumpLiteral(int level); virtual void dumpPushLit(int level); PyrSlot mSlot; }; typedef PyrSlotNode PyrLiteralNode; typedef PyrSlotNode PyrPushLitNode; typedef PyrSlotNode PyrPushNameNode; struct PyrCurryArgNode : public PyrParseNode { PyrCurryArgNode() : PyrParseNode(pn_CurryArgNode), mArgNum(-1) {} virtual ~PyrCurryArgNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); int mArgNum; } ; struct PyrClassExtNode : public PyrParseNode { PyrClassExtNode() : PyrParseNode(pn_ClassExtNode) {} virtual ~PyrClassExtNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrSlotNode* mClassName; struct PyrMethodNode *mMethods; } ; struct PyrClassNode : public PyrParseNode { PyrClassNode() : PyrParseNode(pn_ClassNode) {} virtual ~PyrClassNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrSlotNode* mClassName; struct PyrSlotNode* mSuperClassName; struct PyrSlotNode* mIndexType; struct PyrVarListNode *mVarlists; struct PyrMethodNode *mMethods; int mVarTally[4]; int mNumSuperInstVars; } ; struct PyrMethodNode : public PyrParseNode { PyrMethodNode() : PyrParseNode(pn_MethodNode) {} virtual ~PyrMethodNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrSlotNode* mMethodName; struct PyrSlotNode* mPrimitiveName; struct PyrArgListNode *mArglist; struct PyrVarListNode *mVarlist; struct PyrParseNode *mBody; int mIsClassMethod; // is class method? bool mExtension; } ; struct PyrVarListNode : public PyrParseNode { PyrVarListNode() : PyrParseNode(pn_VarListNode) {} virtual ~PyrVarListNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrVarDefNode *mVarDefs; int mFlags; } ; struct PyrVarDefNode : public PyrParseNode { PyrVarDefNode() : PyrParseNode(pn_VarDefNode) {} virtual ~PyrVarDefNode() {} virtual void compile(PyrSlot *result); virtual void compileArg(PyrSlot *result); virtual void dump(int level); bool hasExpr(PyrSlot *result); struct PyrSlotNode* mVarName; PyrParseNode* mDefVal; int mFlags; bool mDrop; } ; struct PyrCallNodeBase : public PyrParseNode { PyrCallNodeBase(int classno) : PyrParseNode(classno) {} virtual ~PyrCallNodeBase() {} virtual void compile(PyrSlot *result); virtual void compilePartialApplication(int numCurryArgs, PyrSlot *result); virtual void compileCall(PyrSlot *result)=0; virtual int isPartialApplication()=0; }; struct PyrCallNodeBase2 : public PyrCallNodeBase { PyrCallNodeBase2(int classno) : PyrCallNodeBase(classno) {} virtual ~PyrCallNodeBase2() {} struct PyrSlotNode* mSelector; struct PyrParseNode *mArglist; struct PyrParseNode *mKeyarglist; bool mTailCall; } ; struct PyrCallNode : public PyrCallNodeBase2 { PyrCallNode() : PyrCallNodeBase2(pn_CallNode) {} virtual ~PyrCallNode() {} virtual void compileCall(PyrSlot *result); virtual void dump(int level); virtual int isPartialApplication(); } ; struct PyrBinopCallNode : public PyrCallNodeBase2 { PyrBinopCallNode() : PyrCallNodeBase2(pn_BinopCallNode) {} virtual ~PyrBinopCallNode() {} virtual void compileCall(PyrSlot *result); virtual void dump(int level); virtual int isPartialApplication(); } ; struct PyrSetterNode : public PyrCallNodeBase { PyrSetterNode() : PyrCallNodeBase(pn_SetterNode) {} virtual ~PyrSetterNode() {} virtual void compileCall(PyrSlot *result); virtual void dump(int level); virtual int isPartialApplication(); struct PyrSlotNode* mSelector; struct PyrParseNode *mExpr1; struct PyrParseNode *mExpr2; int mFlags; // is a var def ? } ; struct PyrDynListNode : public PyrCallNodeBase { PyrDynListNode() : PyrCallNodeBase(pn_DynListNode) {} virtual ~PyrDynListNode() {} virtual void compileCall(PyrSlot *result); virtual void dump(int level); virtual int isPartialApplication(); struct PyrParseNode *mClassname; struct PyrParseNode *mElems; } ; struct PyrDynDictNode : public PyrCallNodeBase { PyrDynDictNode() : PyrCallNodeBase(pn_DynDictNode) {} virtual ~PyrDynDictNode() {} virtual void compileCall(PyrSlot *result); virtual void dump(int level); virtual int isPartialApplication(); struct PyrParseNode *mElems; } ; struct PyrDropNode : public PyrParseNode { PyrDropNode() : PyrParseNode(pn_DropNode) {} virtual ~PyrDropNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrParseNode *mExpr1; struct PyrParseNode *mExpr2; } ; struct PyrPushKeyArgNode : public PyrParseNode { PyrPushKeyArgNode() : PyrParseNode(pn_PushKeyArgNode) {} virtual ~PyrPushKeyArgNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrSlotNode* mSelector; struct PyrParseNode *mExpr; } ; struct PyrReturnNode : public PyrParseNode { PyrReturnNode() : PyrParseNode(pn_ReturnNode) {} virtual ~PyrReturnNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrParseNode *mExpr; // if null, return self } ; struct PyrBlockReturnNode : public PyrParseNode { PyrBlockReturnNode() : PyrParseNode(pn_BlockReturnNode) {} virtual ~PyrBlockReturnNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrParseNode *mExpr; // if null, return self } ; struct PyrAssignNode : public PyrParseNode { PyrAssignNode() : PyrParseNode(pn_AssignNode) {} virtual ~PyrAssignNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrSlotNode* mVarName; struct PyrParseNode *mExpr; bool mDrop; // allow drop } ; struct PyrMultiAssignNode : public PyrParseNode { PyrMultiAssignNode() : PyrParseNode(pn_MultiAssignNode) {} virtual ~PyrMultiAssignNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrMultiAssignVarListNode *mVarList; struct PyrParseNode *mExpr; bool mDrop; // allow drop } ; struct PyrMultiAssignVarListNode : public PyrParseNode { PyrMultiAssignVarListNode() : PyrParseNode(pn_MultiAssignVarListNode) {} virtual ~PyrMultiAssignVarListNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrSlotNode *mVarNames; struct PyrSlotNode *mRest; } ; struct PyrBlockNode : public PyrParseNode { PyrBlockNode() : PyrParseNode(pn_BlockNode) {} virtual ~PyrBlockNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrArgListNode *mArglist; struct PyrVarListNode *mVarlist; struct PyrParseNode *mBody; bool mIsTopLevel; int mBeginCharNo; }; struct PyrArgListNode : public PyrParseNode { PyrArgListNode() : PyrParseNode(pn_ArgListNode) {} virtual ~PyrArgListNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrVarDefNode *mVarDefs; struct PyrSlotNode *mRest; } ; struct PyrLitListNode : public PyrParseNode { PyrLitListNode() : PyrParseNode(pn_LitListNode) {} virtual ~PyrLitListNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrParseNode *mClassname; struct PyrParseNode *mElems; } ; struct PyrLitDictNode : public PyrParseNode { PyrLitDictNode() : PyrParseNode(pn_LitDictNode) {} virtual ~PyrLitDictNode() {} virtual void compile(PyrSlot *result); virtual void dump(int level); struct PyrParseNode *mElems; } ; extern PyrParseNode* gRootParseNode; extern intptr_t gParserResult; extern bool gIsTailCodeBranch; extern bool gTailIsMethodReturn; extern bool compilingCmdLine; extern const char* nodename[]; void compileNode(PyrParseNode* node, PyrSlot *result, bool onTailBranch); class SetTailBranch { bool mSave; public: SetTailBranch(bool inValue) { mSave = gIsTailCodeBranch; gIsTailCodeBranch = inValue; } ~SetTailBranch() { gIsTailCodeBranch = mSave; } }; class SetTailIsMethodReturn { bool mSave; public: SetTailIsMethodReturn(bool inValue) { mSave = gTailIsMethodReturn; gTailIsMethodReturn = inValue; } ~SetTailIsMethodReturn() { gTailIsMethodReturn = mSave; } }; inline void compileNode(PyrParseNode* node, PyrSlot *result, bool onTailBranch) { SetTailBranch branch(gIsTailCodeBranch && onTailBranch); /*if (compilingCmdLine) { printf("stb %14s %d %d\n", nodename[node->mClassno], onTailBranch, gIsTailCodeBranch); }*/ node->compile(result); } void initParseNodes(); PyrSlotNode* newPyrSlotNode(PyrSlot *slot); PyrCurryArgNode* newPyrCurryArgNode(); PyrClassNode* newPyrClassNode(PyrSlotNode* className, PyrSlotNode* superClassName, PyrVarListNode* varlists, PyrMethodNode* methods, PyrSlotNode* indexType); PyrClassExtNode* newPyrClassExtNode(PyrSlotNode* className, PyrMethodNode* methods); PyrMethodNode* newPyrMethodNode(PyrSlotNode* methodName, PyrSlotNode* primitiveName, PyrArgListNode* arglist, PyrVarListNode *varlist, PyrParseNode* body, int isClassMethod); PyrArgListNode* newPyrArgListNode(PyrVarDefNode* varDefs, PyrSlotNode* rest); PyrVarListNode* newPyrVarListNode(PyrVarDefNode* vardefs, int flags); PyrVarDefNode* newPyrVarDefNode(PyrSlotNode* varName, PyrParseNode* defVal, int flags); PyrCallNode* newPyrCallNode(PyrSlotNode* selector, PyrParseNode* arglist, PyrParseNode* keyarglist, PyrParseNode* blocklist); PyrBinopCallNode* newPyrBinopCallNode(PyrSlotNode* selector, PyrParseNode* arg1, PyrParseNode* arg2, PyrParseNode* arg3); PyrDropNode* newPyrDropNode(PyrParseNode* expr1, PyrParseNode* expr2); PyrPushKeyArgNode* newPyrPushKeyArgNode(PyrSlotNode* selector, PyrParseNode* expr); PyrPushLitNode* newPyrPushLitNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj); PyrLiteralNode* newPyrLiteralNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj); PyrReturnNode* newPyrReturnNode(PyrParseNode* expr); PyrBlockReturnNode* newPyrBlockReturnNode(); PyrAssignNode* newPyrAssignNode(PyrSlotNode* varName, PyrParseNode* expr, int flags); PyrSetterNode* newPyrSetterNode(PyrSlotNode* varName, PyrParseNode* expr1, PyrParseNode* expr2); PyrMultiAssignNode* newPyrMultiAssignNode(PyrMultiAssignVarListNode* varList, PyrParseNode* expr, int flags); PyrPushNameNode* newPyrPushNameNode(PyrSlotNode *slotNode); PyrDynDictNode* newPyrDynDictNode(PyrParseNode *elems); PyrDynListNode* newPyrDynListNode(PyrParseNode *classname, PyrParseNode *elems); PyrLitListNode* newPyrLitListNode(PyrParseNode *classname, PyrParseNode *elems); PyrLitDictNode* newPyrLitDictNode(PyrParseNode *elems); PyrMultiAssignVarListNode* newPyrMultiAssignVarListNode(PyrSlotNode* varNames, PyrSlotNode* rest); PyrBlockNode* newPyrBlockNode(PyrArgListNode *arglist, PyrVarListNode *varlist, PyrParseNode *body, bool isTopLevel); void compilePyrMethodNode(PyrMethodNode* node, PyrSlot *result); void compilePyrLiteralNode(PyrLiteralNode* node, PyrSlot *result); PyrClass* getNodeSuperclass(PyrClassNode *node); void countNodeMethods(PyrClassNode* node, int *numClassMethods, int *numInstMethods); void compileExtNodeMethods(PyrClassExtNode* node); void countVarDefs(PyrClassNode* node); bool compareVarDefs(PyrClassNode* node, PyrClass* classobj); void recompileSubclasses(PyrClass* classobj); void compileNodeMethods(PyrClassNode* node); void fillClassPrototypes(PyrClassNode *node, PyrClass *classobj, PyrClass *superclassobj); int nodeListLength(PyrParseNode *node); bool isSuperObjNode(PyrParseNode *node); bool isThisObjNode(PyrParseNode *node); int conjureSelectorIndex(PyrParseNode *node, PyrBlock* func, bool isSuper, PyrSymbol *selector, int *selType); int conjureLiteralSlotIndex(PyrParseNode *node, PyrBlock* func, PyrSlot *slot); bool findVarName(PyrBlock* func, PyrClass **classobj, PyrSymbol *name, int *varType, int *level, int *index, PyrBlock** tempfunc); void countClassVarDefs(PyrClassNode* node, int *numClassMethods, int *numInstMethods); void compileNodeList(PyrParseNode *node, bool onTailBranch); void dumpNodeList(PyrParseNode *node); int compareCallArgs(PyrMethodNode* node, PyrCallNode *cnode, int *varIndex, PyrClass *specialClass); bool findSpecialClassName(PyrSymbol *className, int *index); int getIndexType(PyrClassNode *classnode); void compileAnyIfMsg(PyrCallNodeBase2* node); void compileIfMsg(PyrCallNodeBase2* node); void compileIfNilMsg(PyrCallNodeBase2* node, bool flag); void compileCaseMsg(PyrCallNodeBase2* node); void compileWhileMsg(PyrCallNodeBase2* node); void compileLoopMsg(PyrCallNodeBase2* node); void compileAndMsg(PyrParseNode* arg1, PyrParseNode* arg2); void compileOrMsg(PyrParseNode* arg1, PyrParseNode* arg2); void compileQMsg(PyrParseNode* arg1, PyrParseNode* arg2); void compileQQMsg(PyrParseNode* arg1, PyrParseNode* arg2); void compileXQMsg(PyrParseNode* arg1, PyrParseNode* arg2); void compileSwitchMsg(PyrCallNode* node); void compilePushInt(int value); void compileAssignVar(PyrParseNode *node, PyrSymbol* varName, bool drop); void compilePushVar(PyrParseNode *node, PyrSymbol *varName); bool isAnInlineableBlock(PyrParseNode *node); bool isAnInlineableAtomicLiteralBlock(PyrParseNode *node); bool isAtomicLiteral(PyrParseNode *node); bool isWhileTrue(PyrParseNode *node); void installByteCodes(PyrBlock *block); ByteCodes compileSubExpression(PyrPushLitNode* litnode, bool onTailBranch); ByteCodes compileSubExpressionWithGoto(PyrPushLitNode* litnode, int branchLen, bool onTailBranch); ByteCodes compileBodyWithGoto(PyrParseNode* body, int branchLen, bool onTailBranch); //ByteCodes compileDefaultValue(int litIndex, int realExprLen); void initParser(); void finiParser(); void initParserPool(); void freeParserPool(); void initSpecialSelectors(); void initSpecialClasses(); void nodePostErrorLine(PyrParseNode* node); PyrParseNode* linkNextNode(PyrParseNode* a, PyrParseNode* b); PyrParseNode* linkAfterHead(PyrParseNode* a, PyrParseNode* b); extern int compileErrors; extern int numOverwrites; extern std::string overwriteMsg; extern intptr_t zzval; extern PyrSymbol *ps_newlist; extern PyrSymbol *gSpecialUnarySelectors[opNumUnarySelectors]; extern PyrSymbol *gSpecialBinarySelectors[opNumBinarySelectors]; extern PyrSymbol *gSpecialSelectors[opmNumSpecialSelectors]; extern PyrSymbol* gSpecialClasses[op_NumSpecialClasses]; extern PyrClass *gCurrentClass; extern PyrClass *gCurrentMetaClass; extern PyrClass *gCompilingClass; extern PyrMethod *gCompilingMethod; extern PyrBlock *gCompilingBlock; /* compiling "inlining" of special arithmetic opcodes. inlining of IF, WHILE, AND, OR */ #define YYSTYPE intptr_t #endif SuperCollider-Source/lang/LangSource/PyrPrimitive.h000644 000765 000024 00000003017 12321461511 023451 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Functions for defining language primitives. */ #ifndef _PYRPRIMITIVE_H_ #define _PYRPRIMITIVE_H_ #include "PyrSlot.h" typedef int (*PrimitiveHandler)(struct VMGlobals *g, int numArgsPushed); typedef int (*PrimitiveWithKeysHandler)(struct VMGlobals *g, int numArgsPushed, int numKeyArgsPushed); int nextPrimitiveIndex(); int definePrimitive(int base, int index, const char *name, PrimitiveHandler handler, int numArgs, int varArgs); int definePrimitiveWithKeys(int base, int index, const char *name, PrimitiveHandler handler, PrimitiveWithKeysHandler keyhandler, int numArgs, int varArgs); int getPrimitiveNumArgs(int index); PyrSymbol* getPrimitiveName(int index); #endif SuperCollider-Source/lang/LangSource/PyrPrimitiveProto.h000644 000765 000024 00000006736 12450771573 024527 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRPRIMITIVEPROTO_H_ #define _PYRPRIMITIVEPROTO_H_ #include "PyrPrimitive.h" int basicNew(VMGlobals *g, int numArgsPushed); int basicNewClear(VMGlobals *g, int numArgsPushed); int basicSwap(VMGlobals *g, int numArgsPushed); int instVarAt(VMGlobals *g, int numArgsPushed); int instVarPut(VMGlobals *g, int numArgsPushed); int instVarSize(VMGlobals *g, int numArgsPushed); int objectHash(VMGlobals *g, int numArgsPushed); int objectClass(VMGlobals *g, int numArgsPushed); int blockValue(VMGlobals *g, int numArgsPushed); int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed); int blockValueArray(VMGlobals *g, int numArgsPushed); int blockSpawn(VMGlobals *g, int numArgsPushed); int objectIsKindOf(VMGlobals *g, int numArgsPushed); int objectIsMemberOf(VMGlobals *g, int numArgsPushed); int objectDump(VMGlobals *g, int numArgsPushed); int haltInterpreter(VMGlobals *g, int numArgsPushed); int objectIdentical(VMGlobals *g, int numArgsPushed); int objectNotIdentical(VMGlobals *g, int numArgsPushed); int objectPerform(VMGlobals *g, int numArgsPushed); int objectPerformList(VMGlobals *g, int numArgsPushed); int objectPerformSelList(VMGlobals *g, int numArgsPushed); int undefinedPrimitive(VMGlobals *g, int numArgsPushed); int prObjectString(VMGlobals *g, int numArgsPushed); int prClassString(VMGlobals *g, int numArgsPushed); int prSymbolString(VMGlobals *g, int numArgsPushed); int prSymbolClass(VMGlobals *g, int numArgsPushed); int prPostString(VMGlobals *g, int numArgsPushed); int prPostLine(VMGlobals *g, int numArgsPushed); int prFlushPostBuf(VMGlobals *g, int numArgsPushed); int prPrimitiveError(VMGlobals *g, int numArgsPushed); int prPrimitiveErrorString(VMGlobals *g, int numArgsPushed); int prDumpStack(VMGlobals *g, int numArgsPushed); int prDebugger(VMGlobals *g, int numArgsPushed); int prPrimName(VMGlobals *g, int numArgsPushed); int prObjectShallowCopy(VMGlobals *g, int numArgsPushed); int prObjectCopyRange(VMGlobals *g, int numArgsPushed); int prObjectPointsTo(VMGlobals *g, int numArgsPushed); int prObjectRespondsTo(VMGlobals *g, int numArgsPushed); int prCompileString(VMGlobals *g, int numArgsPushed); int prDumpBackTrace(VMGlobals *g, int numArgsPushed); int prDumpByteCodes(VMGlobals *g, int numArgsPushed); int prAllClasses(VMGlobals *g, int numArgsPushed); int prPostClassTree(VMGlobals *g, int numArgsPushed); void initPrimitiveTable(); void growPrimitiveTable(int newsize); void initPrimitives(); void deinitPrimitives(); void doPrimitive(VMGlobals* g, struct PyrMethod* meth, int numArgsPushed); void doPrimitiveWithKeys(VMGlobals* g, struct PyrMethod* meth, int allArgsPushed, int numKeysPushed); #endif SuperCollider-Source/lang/LangSource/PyrSched.h000644 000765 000024 00000004442 12756531745 022555 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRSCHED_H_ #define _PYRSCHED_H_ #include "VMGlobals.h" #include "SC_Export.h" #include "SC_Lock.h" #include extern timed_mutex gLangMutex; double elapsedTime(); double monotonicClockTime(); int64 OSCTime(); int64 ElapsedTimeToOSC(double elapsed); double OSCToElapsedTime(int64 oscTime); bool addheap(VMGlobals *g, PyrObject *heap, double schedtime, PyrSlot *task); bool lookheap(PyrObject *heap, double *schedtime, PyrSlot *task) ; bool getheap(VMGlobals *g, PyrObject *heap, double *schedtime, PyrSlot *task) ; void offsetheap(VMGlobals *g, PyrObject *heap, double offset) ; void dumpheap(PyrObject *heap); const double kSecondsToOSC = 4294967296.; // pow(2,32)/1 const double kMicrosToOSC = 4294.967296; // pow(2,32)/1e6 const double kNanosToOSC = 4.294967296; // pow(2,32)/1e9 const double kOSCtoSecs = 2.328306436538696e-10; // 1/pow(2,32) const double kOSCtoNanos = 0.2328306436538696; // 1e9/pow(2,32) // lock language, // if shouldBeRunning == false, return EINTR // if language has been locked, return 0 inline int lockLanguageOrQuit(bool shouldBeRunning) { bool locked = gLangMutex.try_lock(); if (locked) { if (shouldBeRunning == false) { gLangMutex.unlock(); return EINTR; } } else { for (;;) { locked = gLangMutex.try_lock_for(std::chrono::seconds(1)); if (shouldBeRunning == false) { if (locked) gLangMutex.unlock(); return EINTR; } if (locked) return 0; } } return 0; } #endif SuperCollider-Source/lang/LangSource/PyrSignal.cpp000644 000765 000024 00000103101 12321461511 023244 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* compound formulas : amclip out = B<=0 ? 0 : A*B; // two quadrant amplitude modulation ring1 out = A*(B+1) = A*B + A; // amplitude modulation of a by b. ring2 out = A*B + A + B; // ring modulation plus both original signals ring3 out = A*A*B; // ring modulation variant ring4 out = A*A*B - A*B*B; // ring modulation variant difsqr out = A*A - B*B; // difference of squares sumsqr out = A*A + B*B; // sum of squares sqrdif out = (A - B)^2 // square of the difference = a^2 + b^2 - 2ab sqrsum out = (A + B)^2 // square of the sum = a^2 + b^2 + 2ab */ #include #include #include #include "PyrSignal.h" #include "PyrKernel.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "SCBase.h" #include "InitAlloc.h" float gSlopeFactor[32]; long gWrapMask[32]; float *sineCycle; float *invSineCycle; float *pmSineCycle; float *gFracTable; double phaseToSineIndex; double sineIndexToPhase; void signal_init_globs() { int i; double phaseoffset, d, pmf; long sz, sz2; /* setup slopes and wrap masks */ for (i=0; i<32; ++i) { long length = 1L<Alloc((SINESIZE+1) * sizeof(float)); MEMFAIL(sineCycle); invSineCycle = (float*)pyr_pool_runtime->Alloc((SINESIZE+1) * sizeof(float)); MEMFAIL(invSineCycle); pmSineCycle = (float*)pyr_pool_runtime->Alloc((SINESIZE+1) * sizeof(float)); MEMFAIL(pmSineCycle); //gFracTable = (float*)pyr_pool_runtime->Alloc(FRACTABLESIZE * sizeof(float)); //MEMFAIL(gFracTable); sineIndexToPhase = 2. * 3.1415926535897932384626433832795 / SINESIZE; phaseToSineIndex = 1. / sineIndexToPhase; phaseoffset = sineIndexToPhase * 0.5; pmf = (1L << 29) / twopi; for (i=0; i<=SINESIZE; ++i) { double phase; phase = i * sineIndexToPhase; sineCycle[i] = d = sin(phase); invSineCycle[i] = 1. / d; pmSineCycle[i] = d * pmf; } // fix 1/0 values to a special large number invSineCycle[0] = invSineCycle[SINESIZE/2] = invSineCycle[SINESIZE] = VERY_BIG_FLOAT; sz = SINESIZE; sz2 = sz>>1; for (i=1; i<=8; ++i) { //for (i=1; i<=0; ++i) { //ie. none //postfl("%d %f %f\n", i, invSineCycle[i], sineCycle[i]); invSineCycle[i] = invSineCycle[sz-i] = VERY_BIG_FLOAT; invSineCycle[sz2-i] = invSineCycle[sz2+i] = VERY_BIG_FLOAT; } /*fracscale = 1./FRACTABLESIZE; for (i=0; igc->New(numbytes, 0, obj_float, true); if (signal) { signal->classptr = class_signal; signal->size = size; } // note: signal is filled with garbage return signal; } /*PyrObject* newPyrSignalFrom(VMGlobals *g, PyrObject* inSignal, long size) { PyrObject *signal; double *pslot, *qslot, *endptr; long set, m, mmax; long numbytes = size * sizeof(float); signal = (PyrObject*)g->gc->New(numbytes, 0, obj_float, true); signal->classptr = inSignal->classptr; signal->size = size; return signal; } */ PyrObject* signal_fill(PyrObject *outSignal, float inValue) { float *out = (float*)(outSignal->slots) - 1; UNROLL_CODE(outSignal->size, out, *++out = inValue;); return outSignal; } PyrObject* signal_scale(PyrObject *outSignal, float inValue) { if (inValue != 1.f) { float *out = (float*)(outSignal->slots) - 1; UNROLL_CODE(outSignal->size, out, *++out *= inValue;) } return outSignal; } PyrObject* signal_offset(PyrObject *outSignal, float inValue) { if (inValue != 0.f) { float *out = (float*)(outSignal->slots) - 1; UNROLL_CODE(outSignal->size, out, *++out += inValue;) } return outSignal; } PyrObject* signal_add_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP1(+); } PyrObject* signal_mul_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP1(*); } PyrObject* signal_sub_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( *++c = *++a - *++b; ); } PyrObject* signal_ring1_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; *++c = *a * *++b + *a; ); } PyrObject* signal_ring2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a * *b + *a + *b; ); } PyrObject* signal_ring3_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; *++c = *a * *a * *++b; ); } PyrObject* signal_ring4_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a * *a * *b - *a * *b * *b; ); } PyrObject* signal_thresh_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a < *b ? 0.f : *a; ); } PyrObject* signal_amclip_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *b <= 0.f ? 0.f : *a * *b; ); } PyrObject* signal_div_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( *++c = *++a / *++b; ); } PyrObject* signal_difsqr_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *c = *a * *a - *b * *b; ); } PyrObject* signal_sumsqr_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *c = *a * *a + *b * *b; ); } PyrObject* signal_sqrsum_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { float z; BINOP_LOOP2( z = *++a + *++b; *++c = z * z; ); } PyrObject* signal_sqrdif_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { float z; BINOP_LOOP2( z = *++a - *++b; *++c = z * z; ); } PyrObject* signal_absdif_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( *++c = fabs(*++a - *++b); ); } PyrObject* signal_add_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 0.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = *++a + inb;) } return outc; } PyrObject* signal_sub_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 0.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = *++a - inb;) } return outc; } PyrObject* signal_mul_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 1.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = *++a * inb;) } return outc; } PyrObject* signal_ring1_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = *a * inb + *a;) return outc; } PyrObject* signal_ring2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = *a * inb + *a + inb;) return outc; } PyrObject* signal_ring3_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a * inb;) return outc; } PyrObject* signal_ring4_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float inb2 = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a * inb + *a * inb2;) return outc; } PyrObject* signal_thresh_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float inb2 = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a < inb2 ? 0.f : *a;) return outc; } PyrObject* signal_amclip_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *res; PyrObject *outc = newPyrSignal(g, ina->size); if (inb <= 0.f) res = signal_fill(outc, 0.f); else res = signal_scale(outc, inb); return res; } PyrObject* signal_div_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); if (inb == 1.f) { float *a = (float*)(ina->slots); memcpy((float*)(outc->slots), a, ina->size * sizeof(float)); } else { float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; inb = 1.f/inb; UNROLL_CODE(outc->size, c, *++c = *++a * inb;) } return outc; } PyrObject* signal_difsqr_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; inb = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a - inb;) return outc; } PyrObject* signal_sumsqr_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; inb = inb * inb; UNROLL_CODE(outc->size, c, ++a; *++c = *a * *a + inb;) return outc; } PyrObject* signal_sqrsum_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float temp; UNROLL_CODE(outc->size, c, ++a; temp = *a + inb; *++c = temp * temp;) return outc; } PyrObject* signal_sqrdif_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; float temp; UNROLL_CODE(outc->size, c, ++a; temp = *a - inb; *++c = temp * temp;) return outc; } PyrObject* signal_absdif_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++a; *++c = fabs(*a - inb); ) return outc; } PyrObject* signal_ring1_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = ina * *++b + ina;) return outc; } PyrObject* signal_ring2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; *++c = ina * *b + ina + *b;) return outc; } PyrObject* signal_ring3_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; float ina2 = ina * ina; UNROLL_CODE(outc->size, c, *++c = ina2 * *++b;) return outc; } PyrObject* signal_ring4_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; float ina2 = ina * ina; UNROLL_CODE(outc->size, c, ++b; *++c = ina2 * *b - ina * *b * *b;) return outc; } PyrObject* signal_thresh_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = ina < *b ? 0.f : ina;) return outc; } PyrObject* signal_amclip_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = *b <= 0.f ? 0.f : ina * *b;) return outc; } PyrObject* signal_sub_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = ina - *++b;) return outc; } PyrObject* signal_div_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, *++c = ina / *++b;) return outc; } PyrObject* signal_difsqr_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; ina = ina * ina; UNROLL_CODE(outc->size, c, ++b; *++c = ina - *b * *b;) return outc; } PyrObject* signal_sumsqr_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; ina = ina * ina; UNROLL_CODE(outc->size, c, ++b; *++c = ina + *b * *b;) return outc; } PyrObject* signal_sqrsum_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float temp; float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; temp = ina + *b; *++c = temp * temp;) return outc; } PyrObject* signal_sqrdif_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float temp; float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; temp = ina - *b; *++c = temp * temp;) return outc; } PyrObject* signal_absdif_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL_CODE(outc->size, c, ++b; *++c = fabs(ina - *b);) return outc; } PyrObject* signal_min_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a < *b ? *a : *b; ); } PyrObject* signal_max_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a > *b ? *a : *b; ); } PyrObject* signal_scaleneg_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a < 0.f ? *a * *b : *a; ); } PyrObject* signal_clip2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a > *b ? *b : (*a < -*b ? -*b : *a); ); } PyrObject* signal_fold2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = sc_fold(*a, -*b, *b); ); } PyrObject* signal_wrap2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = sc_wrap(*a, -*b, *b); ); } PyrObject* signal_excess_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { BINOP_LOOP2( ++a; ++b; *++c = *a > *b ? *a - *b : (*a < -*b ? *a + *b : 0.f); ); } bool signal_equal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { float *a = (float*)(ina->slots) - 1; float *b = (float*)(inb->slots) - 1; float *endptr = a + ina->size; if (ina->size != inb->size) return false; if (slotRawSymbol(&ina->slots[ kSignalRate ]) != slotRawSymbol(&inb->slots[ kSignalRate ])) return false; while (a < endptr) { if (*a++ != *b++) return false; } return true; } PyrObject* signal_min_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a < inb ? *a : inb;) return outc; } PyrObject* signal_max_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a > inb ? *a : inb;) return outc; } PyrObject* signal_scaleneg_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a < 0.f ? *a * inb : *a;) return outc; } PyrObject* signal_clip2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a > inb ? inb : (*a < -inb ? -inb : *a);) return outc; } PyrObject* signal_fold2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = sc_fold(*a, -inb, inb);) return outc; } PyrObject* signal_wrap2_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = sc_wrap(*a, -inb, inb);) return outc; } PyrObject* signal_excess_xf(VMGlobals *g, PyrObject* ina, float inb) { PyrObject *outc = newPyrSignal(g, ina->size); float *a = (float*)(ina->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++a; *++c = *a > inb ? *a - inb : (*a < -inb ? *a + inb : 0.f);) return outc; } PyrObject* signal_scaleneg_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; if (ina < 0.f) { UNROLL1_CODE(outc->size, c, *++c = ina * *++b;); } else { UNROLL1_CODE(outc->size, c, *++c = ina;); } return outc; } PyrObject* signal_clip2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = ina > *b ? *b : (ina < -*b ? -*b : ina);) return outc; } PyrObject* signal_fold2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = sc_fold(ina, -*b, *b);) return outc; } PyrObject* signal_wrap2_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = sc_wrap(ina, -*b, *b);) return outc; } PyrObject* signal_excess_fx(VMGlobals *g, float ina, PyrObject* inb) { PyrObject *outc = newPyrSignal(g, inb->size); float *b = (float*)(inb->slots) - 1; float *c = (float*)(outc->slots) - 1; UNROLL1_CODE(outc->size, c, ++b; *++c = ina > *b ? ina - *b : (ina < -*b ? ina + *b : 0.f);) return outc; } PyrObject* signal_invert(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, *++out = -*++in;) return outc; } PyrObject* signal_recip(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, *++out = 1.f / *++in;) return outc; } PyrObject* signal_squared(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, ++in; *++out = *in * *in;) return outc; } PyrObject* signal_cubed(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, ++in; *++out = *in * *in * *in;) return outc; } // PowerPC has a fast fabs instruction PyrObject* signal_abs(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL_CODE(inPyrSignal->size, out, *++out = fabs(*++in);) return outc; } float signal_findpeak(PyrObject *inPyrSignal) { float *out = (float*)(inPyrSignal->slots) - 1; float peak = 0.f; float z; UNROLL1_CODE(inPyrSignal->size, out, ++out; z = fabs(*out); peak = z>peak ? z : peak;) return peak; } PyrObject* signal_normalize_transfer_fn(PyrObject *inPyrSignal) { float *out, scale, offset, x, maxval; long length, halflength; maxval = 0.0; out = (float*)(inPyrSignal->slots) - 1; length = inPyrSignal->size; halflength = length >> 1; offset = (out[halflength-1] + out[halflength]) * 0.5; UNROLL1_CODE(inPyrSignal->size, out, ++out; x = *out - offset; x = (x < 0.) ? -x : x; if (x > maxval) maxval = x; ); if (maxval) { out = (float*)(inPyrSignal->slots) - 1; scale = 1.0 / maxval; UNROLL1_CODE(inPyrSignal->size, out, ++out; *out = (*out - offset) * scale; ); } return inPyrSignal; } float signal_integral(PyrObject *inPyrSignal) { float *out = (float*)(inPyrSignal->slots) - 1; float sum = 0.f; UNROLL1_CODE(inPyrSignal->size, out, sum += *++out;) return sum; } PyrObject* signal_sign(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, ++in; *++out = *in < 0.f ? -1.f : (*in > 0.f ? 1.f : 0.f);) return outc; } PyrObject* signal_negative(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = *++in < 0.f ? 1.f : 0.f;) return outc; } PyrObject* signal_positive(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = *++in >= 0.f ? 1.f : 0.f;) return outc; } PyrObject* signal_strictly_positive(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = *++in > 0.f ? 1.f : 0.f;) return outc; } PyrObject* signal_nyqring(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; switch (inPyrSignal->size & 3) { while (out < endptr) { *++out = -*++in; case 3 : *++out = *++in; case 2 : *++out = -*++in; case 1 : *++out = *++in; case 0 : ; } } return outc; } PyrObject* signal_clip_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { ++in; *++out = *in < lo ? lo : (*in > hi ? hi : *in); } return outc; } PyrObject* signal_clip_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc) { PyrObject *outd; float *a, *b, *c, *d, *endptr; long minsize = sc_min(ina->size, inb->size); minsize = sc_min(minsize, inc->size); outd = newPyrSignal(g, minsize); a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - 1; c = (float*)(inc->slots) - 1; d = (float*)(outd->slots) - 1; endptr = a + minsize; UNROLL1_CODE(outd->size, d, ++a; ++b; ++c; *++d = *a < *b ? *b : (*a > *c ? *c : *a);); return outd; } /// WRAP AND FOLD ARE STILL INCORRECT ! PyrObject* signal_wrap_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi) { float *out = (float*)(inPyrSignal->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { ++out; *out = sc_wrap(*out, lo, hi); } return inPyrSignal; } PyrObject* signal_wrap_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc) { PyrObject *outd; float *a, *b, *c, *d, *endptr; long minsize = sc_min(ina->size, inb->size); minsize = sc_min(minsize, inc->size); outd = newPyrSignal(g, minsize); a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - 1; c = (float*)(inc->slots) - 1; d = (float*)(outd->slots) - 1; endptr = d + outd->size; while (d < endptr) { a++; b++; c++; d++; ++d; *d = sc_wrap(*a, *b, *c); } return outd; } PyrObject* signal_fold_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi) { float *out = (float*)(inPyrSignal->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { ++out; *out = sc_fold(*out, lo, hi); } return inPyrSignal; } PyrObject* signal_fold_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc) { PyrObject *outd; float *a, *b, *c, *d, *endptr; long minsize = sc_min(ina->size, inb->size); minsize = sc_min(minsize, inc->size); outd = newPyrSignal(g, minsize); a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - 1; c = (float*)(inc->slots) - 1; d = (float*)(outd->slots) - 1; endptr = d + outd->size; while (d < endptr) { a++; b++; c++; d++; *d = sc_fold(*a, *b, *c); } return outd; } PyrObject* signal_log(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = log(*++in);) return outc; } PyrObject* signal_log2(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sc_log2(*++in);) return outc; } PyrObject* signal_log10(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = log10(*++in);) return outc; } PyrObject* signal_sin(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sin(*++in);) return outc; } PyrObject* signal_cos(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = cos(*++in);) return outc; } PyrObject* signal_tan(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = tan(*++in);) return outc; } PyrObject* signal_sinh(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sinh(*++in);) return outc; } PyrObject* signal_cosh(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = cosh(*++in);) return outc; } PyrObject* signal_tanh(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = tanh(*++in);) return outc; } PyrObject* signal_tanh_ds(PyrObject *inPyrSignal) { float *out = (float*)(inPyrSignal->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, ++out; *out = tanh(*out);) return inPyrSignal; } PyrObject* signal_asin(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = asin(*++in);) return outc; } PyrObject* signal_acos(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = acos(*++in);) return outc; } PyrObject* signal_atan(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = atan(*++in);) return outc; } PyrObject* signal_exp(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = exp(*++in);) return outc; } PyrObject* signal_sqrt(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; UNROLL1_CODE(inPyrSignal->size, out, *++out = sqrt(*++in);) return outc; } PyrObject* signal_distort(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { float z = *++in; if (z < 0.f) *++out = z/(1.f - z); else *++out = z/(1.f + z); } return outc; } PyrObject* signal_softclip(VMGlobals *g, PyrObject *inPyrSignal) { float *in = (float*)(inPyrSignal->slots) - 1; PyrObject *outc = newPyrSignal(g, inPyrSignal->size); float *out = (float*)(outc->slots) - 1; float *endptr = out + inPyrSignal->size; while (out < endptr) { float z = *++in; if (z < -0.5f) *++out = (-z - .25f)/z; else if (z > 0.5f) *++out = (z - .25f)/z; else *++out = z; } return outc; } PyrObject* signal_rotate(VMGlobals *g, PyrObject* ina, int rot) { long i, j; PyrObject *outc = newPyrSignal(g, ina->size); float *a0 = (float*)(ina->slots) - 1; // float *a = a0 + sc_mod(rot, ina->size); float *a = a0 + sc_mod(0 - rot, ina->size); float *aend = a0 + ina->size; float *c = (float*)(outc->slots) - 1; long nsmps = outc->size; for (i=0,j=rot; i= aend) a = a0; } return outc; } PyrObject* signal_reverse_range(PyrObject* ina, long start, long end) { long size = ina->size; long size2; long i; start = sc_max(0, start); end = sc_min(end + 1, size); size = end - start; size2 = size>>1; float *a = (float*)(ina->slots) - 1 + start; // float *b = (float*)(ina->slots) - 1 + end; float *b = (float*)(ina->slots) + end; float temp; for (i=0; isize; long i; float z, scale, maxlevel; float *a0, *a; start = sc_max(0, start); end = sc_min(end + 1, size); size = end - start; a0 = (float*)(ina->slots) - 1 + start; a = a0; maxlevel = 0.f; for (i=0; i maxlevel) maxlevel = z; } a = a0; if (maxlevel != 0.f) { scale = 1./maxlevel; for (i=0; isize; long i; float z; start = sc_max(0, start); end = sc_min(end, size); size = end - start + 1; float *a = (float*)(ina->slots) - 1 + start; for (i=0; isize; long i; float z, level, slope; start = sc_max(0, start); end = sc_min(end + 1, size); size = end - start; float *a = (float*)(ina->slots) - 1 + start; slope = (lvl1 - lvl0) / size; level = lvl0; for (i=0; i 0) { a = (float*)(ina->slots) + index - 1; b = (float*)(inb->slots) - 1; len = sc_min(inb->size, ina->size - index); } else { a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - index - 1; len = sc_min(ina->size, inb->size + index); } UNROLL_CODE(len, a, *++a += *++b;); return ina; } PyrObject* signal_overwrite(VMGlobals *g, PyrObject* ina, PyrObject* inb, long index) { float *a, *b; long len; if (index > 0) { a = (float*)(ina->slots) + index - 1; b = (float*)(inb->slots) - 1; len = sc_min(inb->size, ina->size - index); } else { a = (float*)(ina->slots) - 1; b = (float*)(inb->slots) - index - 1; len = sc_min(ina->size, inb->size + index); } UNROLL_CODE(len, a, *++a = *++b;); return ina; } SuperCollider-Source/lang/LangSource/PyrSignal.h000644 000765 000024 00000041145 12321461511 022722 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PYR_SIGNAL_H #define PYR_SIGNAL_H #include "PyrObject.h" #include "GC.h" #define UNROLL 1 enum { kSignalRate = 0, // index of rate slot kSignalNextNode }; #define FSINESIZE 8192. #define SINESIZE 8192 #define SINEMASK 8191 #define VERY_BIG_FLOAT (1.e10) extern float *sineCycle; extern float *invSineCycle; extern float *pmSineCycle; extern double phaseToSineIndex; extern double sineIndexToPhase; //#define FRACTABLESIZE 4096 //#define FRACMASK 0x3FFC //extern float *gFracTable; PyrObject* newPyrSignal(VMGlobals *g, long size); #define UNROLL8_CODE(size,var,stmt) \ { int tempi, tempend; \ tempend = size>>3; \ for (tempi=0; tempi>2; \ for (tempi=0; tempi>2; \ for (tempi=0; tempislots) - 1; \ b = (float*)(inb->slots) - 1; \ size = sc_min(ina->size, inb->size); \ outc = newPyrSignal(g, size); \ c = (float*)(outc->slots) - 1; \ endptr = c + size; \ switch (size & 3) { \ while (c < endptr) { \ *++c = *++a OP *++b; \ case 3 : *++c = *++a OP *++b; \ case 2 : *++c = *++a OP *++b; \ case 1 : *++c = *++a OP *++b; \ case 0 : ; \ } \ } \ return outc; \ #define BINOP_LOOP2(STMT1) \ float *a, *b, *c, *endptr; \ PyrObject *outc; \ long size; \ a = (float*)(ina->slots) - 1; \ b = (float*)(inb->slots) - 1; \ size = sc_min(ina->size, inb->size); \ outc = newPyrSignal(g, size); \ c = (float*)(outc->slots) - 1; \ endptr = c + size; \ switch (size & 3) { \ while (c < endptr) { \ STMT1; \ case 3 :STMT1; \ case 2 :STMT1; \ case 1 :STMT1; \ case 0 : ; \ } \ } \ return outc; \ #endif /* compound formulas : amclip out = B<=0 ? 0 : A*B; // two quadrant amplitude modulation ring1 out = A*(B+1) = A*B + A; // amplitude modulation of a by b. ring2 out = A*B + A + B; // ring modulation plus both original signals ring3 out = A*A*B; // ring modulation variant ring4 out = A*A*B - A*B*B; // ring modulation variant difsqr out = A*A - B*B; // difference of squares sumsqr out = A*A + B*B; // sum of squares sqrdif out = (A - B)^2 // square of the difference = a^2 + b^2 - 2ab sqrsum out = (A + B)^2 // square of the sum = a^2 + b^2 + 2ab */ void signal_init_globs(); PyrObject* signal_fill(PyrObject *outSignal, float inValue); PyrObject* signal_scale(PyrObject *outSignal, float inValue); PyrObject* signal_offset(PyrObject *outSignal, float inValue); PyrObject* signal_scale_offset(PyrObject *outSignal, float mul, float add); PyrObject* signal_mix(PyrObject* ina, PyrObject* inb, float start, float end, float slopeFactor); PyrObject* signal_add_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_sub_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_mul_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_mul_ds_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_add_ds_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_sub_ds_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_ring1_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_ring2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_ring3_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_ring4_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_thresh_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_amclip_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_div_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_difsqr_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_sumsqr_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_sqrsum_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_sqrdif_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_add_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_sub_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_mul_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_ring1_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_ring2_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_ring3_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_ring4_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_thresh_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_amclip_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_div_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_difsqr_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_sumsqr_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_sqrsum_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_sqrdif_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_ring1_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_ring2_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_ring3_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_ring4_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_thresh_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_amclip_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_sub_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_div_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_difsqr_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_sumsqr_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_sqrsum_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_sqrdif_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_min_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_max_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_min_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_max_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_invert(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_recip(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_squared(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_cubed(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_abs(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_sign(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_negative(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_positive(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_strictly_positive(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_nyqring(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_clip_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi); PyrObject* signal_clip_f_ds(PyrObject *inPyrSignal, float lo, float hi); PyrObject* signal_clip_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc); PyrObject* signal_wrap_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi); PyrObject* signal_wrap_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc); PyrObject* signal_fold_f(VMGlobals *g, PyrObject *inPyrSignal, float lo, float hi); PyrObject* signal_fold_x(VMGlobals *g, PyrObject *ina, PyrObject *inb, PyrObject *inc); PyrObject* signal_log(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_log2(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_log10(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_sin(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_cos(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_tan(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_sinh(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_cosh(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_tanh(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_asin(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_acos(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_atan(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_exp(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_sqrt(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_distort(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_distortneg(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_softclip(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_softclipneg(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_fsin(VMGlobals *g, PyrObject *inPyrSignal); PyrObject* signal_poly3(VMGlobals *g, PyrObject *inPyrSignal, float a, float b, float c); PyrObject* signal_poly3r(VMGlobals *g, PyrObject *inPyrSignal, float a1, float a2, float b1, float b2, float c1, float c2, float slopeFactor); PyrObject* signal_integrate(VMGlobals *g, PyrObject *inPyrSignal, float *ioSum); PyrObject* signal_leakdc(VMGlobals *g, PyrObject *inPyrSignal, float *ioDC, float leakFactor); PyrObject* signal_ampflw1(VMGlobals *g, PyrObject *inPyrSignal, float *ioAmp, float leak1); PyrObject* signal_ampflw2(VMGlobals *g, PyrObject *inPyrSignal, float *ioAmp, float leak1); PyrObject* signal_differentiate(VMGlobals *g, PyrObject *inPyrSignal, float *ioPrev); PyrObject* signal_rotate(VMGlobals *g, PyrObject* ina, int rot); PyrObject* signal_reverse_ds(PyrObject* ina); PyrObject* signal_cat(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_insert(VMGlobals *g, PyrObject* ina, PyrObject* inb, long index); PyrObject* signal_overdub(VMGlobals *g, PyrObject* ina, PyrObject* inb, long index); PyrObject* signal_overwrite(VMGlobals *g, PyrObject* ina, PyrObject* inb, long index); PyrObject* signal_cat3(VMGlobals *g, PyrObject* ina, PyrObject* inb, PyrObject* inc); PyrObject* signal_linen(VMGlobals *g, PyrObject* ina, long atk, long dcy, float amp); PyrObject* signal_linen2(VMGlobals *g, PyrObject* ina, long atk, long dcy, float amp, float midamp); PyrObject* signal_writesplice(VMGlobals *g, PyrObject* outc, PyrObject* ina, PyrObject* inb, long indexc, long indexa, long indexb, long fadelen, float midamp); PyrObject* signal_splice(VMGlobals *g, PyrObject* ina, PyrObject* inb, long indexa, long indexb, long fadelen, float midamp); PyrObject* signal_invert_ds(PyrObject *inPyrSignal); PyrObject* signal_recip_ds(PyrObject *inPyrSignal); PyrObject* signal_squared_ds(PyrObject *inPyrSignal); PyrObject* signal_cubed_ds(PyrObject *inPyrSignal); PyrObject* signal_abs_ds(PyrObject *inPyrSignal); PyrObject* signal_sign_ds(PyrObject *inPyrSignal); PyrObject* signal_negative_ds(PyrObject *inPyrSignal); PyrObject* signal_positive_ds(PyrObject *inPyrSignal); PyrObject* signal_strictly_positive_ds(PyrObject *inPyrSignal); PyrObject* signal_nyqring_ds(PyrObject *inPyrSignal); PyrObject* signal_clipneg_ds(PyrObject *inPyrSignal); PyrObject* signal_distort_ds(PyrObject *inPyrSignal); PyrObject* signal_distortneg_ds(PyrObject *inPyrSignal); PyrObject* signal_softclip_ds(PyrObject *inPyrSignal); PyrObject* signal_softclipneg_ds(PyrObject *inPyrSignal); PyrObject* signal_fsin_ds(PyrObject *inPyrSignal); PyrObject* signal_log_ds(PyrObject *inPyrSignal); PyrObject* signal_log2_ds(PyrObject *inPyrSignal); PyrObject* signal_log10_ds(PyrObject *inPyrSignal); PyrObject* signal_sin_ds(PyrObject *inPyrSignal); PyrObject* signal_cos_ds(PyrObject *inPyrSignal); PyrObject* signal_tan_ds(PyrObject *inPyrSignal); PyrObject* signal_sinh_ds(PyrObject *inPyrSignal); PyrObject* signal_cosh_ds(PyrObject *inPyrSignal); PyrObject* signal_tanh_ds(PyrObject *inPyrSignal); PyrObject* signal_asin_ds(PyrObject *inPyrSignal); PyrObject* signal_acos_ds(PyrObject *inPyrSignal); PyrObject* signal_atan_ds(PyrObject *inPyrSignal); PyrObject* signal_exp_ds(PyrObject *inPyrSignal); PyrObject* signal_sqrt_ds(PyrObject *inPyrSignal); float signal_findpeak(PyrObject *inPyrSignal); PyrObject* signal_normalize(PyrObject *inPyrSignal); PyrObject* signal_normalize_transfer_fn(PyrObject *inPyrSignal); float signal_integral(PyrObject *inPyrSignal); PyrObject* signal_combself(VMGlobals *g, PyrObject* ina, long rot); PyrObject* signal_bilinen(VMGlobals *g, PyrObject* ina, long atk, long dcy, float amp, float midamp); PyrObject* signal_lace2(VMGlobals *g, PyrObject* ina, PyrObject* inb); void signal_unlace2(VMGlobals *g, PyrObject* ina, PyrObject** outb, PyrObject** outc); void signal_convolve(VMGlobals *g, PyrObject* ina, PyrObject* ir, PyrObject* previn, long *ppos); PyrObject* signal_thumbnail(VMGlobals *g, PyrObject* ina, long startpos, long length, int binsize); PyrObject* signal_scaleneg_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_scaleneg_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_scaleneg_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_clip2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_clip2_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_clip2_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_fold2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_fold2_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_fold2_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_wrap2_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_wrap2_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_wrap2_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_excess_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); PyrObject* signal_excess_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_excess_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_absdif_fx(VMGlobals *g, float ina, PyrObject* inb); PyrObject* signal_absdif_xf(VMGlobals *g, PyrObject* ina, float inb); PyrObject* signal_absdif_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); bool signal_equal_xf(VMGlobals *g, PyrObject* ina, float inb); bool signal_equal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb); void signal_get_bounds(PyrObject* ina, float *ominval, float *omaxval); void signal_smooth_ds(PyrObject* inPyrSignal); void signal_hanning_ds(PyrObject* inPyrSignal); void signal_welch_ds(PyrObject* inPyrSignal); void signal_parzen_ds(PyrObject* inPyrSignal); PyrObject* signal_normalize_range(PyrObject* ina, long start, long end); PyrObject* signal_zero_range(PyrObject* ina, long start, long end); PyrObject* signal_invert_range(PyrObject* ina, long start, long end); PyrObject* signal_reverse_range(PyrObject* ina, long start, long end); PyrObject* signal_fade_in(PyrObject* ina, long start, long end); PyrObject* signal_fade_out(PyrObject* ina, long start, long end); PyrObject* signal_abs_range(PyrObject* ina, long start, long end); PyrObject* signal_squared_range(PyrObject* ina, long start, long end); PyrObject* signal_cubed_range(PyrObject* ina, long start, long end); PyrObject* signal_distort_range(PyrObject* ina, long start, long end); PyrObject* signal_fade_range(PyrObject* ina, long start, long end, float lvl0, float lvl1); #endif // PYR_SIGNAL_H SuperCollider-Source/lang/LangSource/PyrSlot.h000644 000765 000024 00000004557 12756531745 022457 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* PyrSlot is a value holder for SC variables. A PyrSlot is an 8-byte value which is either a double precision float or a 32-bit tag plus a 32-bit value. */ #ifndef _PYRSLOT_H_ #define _PYRSLOT_H_ #if ( __SIZEOF_POINTER__ == 8 ) || defined(__x86_64__) || defined(_M_X64) || defined(__LP64__) || defined(_WIN64) #include "PyrSlot64.h" #elif ( __SIZEOF_POINTER__ == 4 ) || defined(__i386__) || defined(_M_IX86) || defined(__ILP32__) || defined(_WIN32) || defined(__ppc__) || defined(__arm__) #include "PyrSlot32.h" #else #error "no PyrSlot imlementation for this platform" #endif extern PyrSlot o_nil, o_true, o_false, o_inf; extern PyrSlot o_pi, o_twopi; extern PyrSlot o_fhalf, o_fnegone, o_fzero, o_fone, o_ftwo; extern PyrSlot o_negtwo, o_negone, o_zero, o_one, o_two; extern PyrSlot o_emptyarray, o_onenilarray, o_argnamethis; extern PyrSymbol *s_object; // "Object" extern PyrSymbol *s_this; // "this" extern PyrSymbol *s_super; // "super" void dumpPyrSlot(PyrSlot* slot); void slotString(PyrSlot *slot, char *str); void slotOneWord(PyrSlot *slot, char *str); bool postString(PyrSlot *slot, char *str); const char *slotSymString(PyrSlot* slot); int asCompileString(PyrSlot *slot, char *str); int slotIntVal(PyrSlot* slot, int *value); int slotFloatVal(PyrSlot* slot, float *value); int slotDoubleVal(PyrSlot *slot, double *value); int slotStrVal(PyrSlot *slot, char *str, int maxlen); int slotStrLen(PyrSlot *slot); int slotPStrVal(PyrSlot *slot, unsigned char *str); int slotSymbolVal(PyrSlot *slot, PyrSymbol **symbol); #endif SuperCollider-Source/lang/LangSource/PyrSlot32.h000644 000765 000024 00000023620 12756531745 022614 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* PyrSlot is a value holder for SC variables. A PyrSlot is an 8-byte value which is either a double precision float or a 32-bit tag plus a 32-bit value. */ #ifndef _PYRSLOT32_H_ #define _PYRSLOT32_H_ #include "SC_Endian.h" #include "SC_Types.h" #include "PyrErrors.h" #include #include struct PyrSymbol; /* Pyrite slots are the size of an 8 byte double. If the upper bits indicate that the double is a 'Not-A-Number' then the upper 32 bits are used as a tag to indicate one of a number of other types whose data is in the lower 32 bits. */ /* some DSPs like the TIC32 do not support 8 byte doubles */ /* on such CPUs, set DOUBLESLOTS to zero */ #define DOUBLESLOTS 1 /* use the high order bits of an IEEE double NaN as a tag */ enum { tagObj = 0x7FF90001, tagInt = 0x7FF90002, tagSym = 0x7FF90003, tagChar = 0x7FF90004, tagNil = 0x7FF90005, // nil, false, and true are indicated by the tag alone. tagFalse = 0x7FF90006, // the lower 32 bits are zero. tagTrue = 0x7FF90007, tagPtr = 0x7FF90008, /* anything else is a double */ tagUnused = 0x7FF9000D #if !DOUBLESLOTS ,tagFloat = 0x7FF9000F /* used only to initialized 4 byte float tags, never compared with */ #endif }; typedef union pyrslot { double f; struct { #if BYTE_ORDER == BIG_ENDIAN int tag; #endif // BIG_ENDIAN union { int c; /* char */ int i; float f; void *ptr; struct PyrObject *o; PyrSymbol *s; struct PyrMethod *om; struct PyrBlock *oblk; struct PyrClass *oc; struct PyrFrame *of; struct PyrList *ol; struct PyrString *os; struct PyrInt8Array *ob; struct PyrDoubleArray *od; struct PyrSymbolArray *osym; struct PyrProcess *op; struct PyrThread *ot; struct PyrInterpreter *oi; } u; #if BYTE_ORDER == LITTLE_ENDIAN // need to swap on intel int tag; #endif // LITTLE_ENDIAN } s; } PyrSlot; /* these are some defines to make accessing the structure less verbose. obviously it polutes the namespace of identifiers beginning with 'u'. */ #define utag s.tag //int #define ui s.u.i //PyrObject #define uo s.u.o //PyrSymbol #define us s.u.s #define uc s.u.c #define uoc s.u.oc #define uof s.u.of #define uol s.u.ol #define uod s.u.od #define uob s.u.ob #define uop s.u.op #define uoi s.u.oi #define uod s.u.od //string #define uos s.u.os #define uot s.u.ot //method #define uom s.u.om //symbol array #define uosym s.u.osym #define uoblk s.u.oblk #define uptr s.u.ptr #if DOUBLESLOTS #define uf f #else #define uf s.u.f #endif /* Note that on the PowerPC, the fastest way to copy a slot is to copy the double field, not the struct. */ inline int GetTag(const PyrSlot* slot) { return slot->utag; } /* some macros for setting values of slots */ inline void SetInt(PyrSlot* slot, int val) { (slot)->utag = tagInt; (slot)->ui = (val); } inline void SetObject(PyrSlot* slot, struct PyrObjectHdr* val) { (slot)->utag = tagObj; (slot)->uo = (PyrObject*)(val); } inline void SetSymbol(PyrSlot* slot, PyrSymbol *val) { (slot)->utag = tagSym; (slot)->us = (val); } inline void SetChar(PyrSlot* slot, char val) { (slot)->utag = tagChar; (slot)->uc = (val); } inline void SetPtr(PyrSlot* slot, void* val) { (slot)->utag = tagPtr; (slot)->uptr = (void*)(val); } inline void SetObjectOrNil(PyrSlot* slot, PyrObject* val) { if (val) { (slot)->utag = tagObj; (slot)->uo = (val); } else { (slot)->utag = tagNil; (slot)->ui = 0; } } inline void SetTrue(PyrSlot* slot) { (slot)->utag = tagTrue; (slot)->ui = 0; } inline void SetFalse(PyrSlot* slot) { (slot)->utag = tagFalse; (slot)->ui = 0; } inline void SetBool(PyrSlot* slot, bool test) { (slot)->utag = ((test) ? tagTrue : tagFalse); (slot)->ui = 0; } inline void SetNil(PyrSlot* slot) { (slot)->utag = tagNil; (slot)->ui = 0; } #if DOUBLESLOTS inline void SetFloat(PyrSlot* slot, double val) { (slot)->uf = (val); } #else inline void SetFloat(PyrSlot* slot, double val) { (slot)->utag = s_float; (slot)->uf = (val); } #endif inline bool IsObj(const PyrSlot* slot) { return ((slot)->utag == tagObj); } inline bool NotObj(const PyrSlot* slot) { return ((slot)->utag != tagObj); } inline bool IsNil(const PyrSlot* slot) { return ((slot)->utag == tagNil); } inline bool NotNil(const PyrSlot* slot) { return ((slot)->utag != tagNil); } inline bool IsFalse(const PyrSlot* slot) { return ((slot)->utag == tagFalse); } inline bool IsTrue(const PyrSlot* slot) { return ((slot)->utag == tagTrue); } inline bool SlotEq(PyrSlot* a, PyrSlot* b) { return ((a)->ui == (b)->ui && (a)->utag == (b)->utag); } inline bool IsSym(const PyrSlot* slot) { return ((slot)->utag == tagSym); } inline bool NotSym(const PyrSlot* slot) { return ((slot)->utag != tagSym); } inline bool IsChar(const PyrSlot* slot) { return ((slot)->utag == tagChar); } inline bool NotChar(const PyrSlot* slot) { return ((slot)->utag != tagChar); } inline bool IsInt(const PyrSlot* slot) { return ((slot)->utag == tagInt); } inline bool NotInt(const PyrSlot* slot) { return ((slot)->utag != tagInt); } inline bool IsFloatTag(int tag) { return ((tag & 0xFFFFFFF0) != 0x7FF90000); } inline bool IsFloat(const PyrSlot* slot) { return (((slot)->utag & 0xFFFFFFF0) != 0x7FF90000); } inline bool NotFloat(const PyrSlot* slot) { return (((slot)->utag & 0xFFFFFFF0) == 0x7FF90000); } inline bool IsPtr(const PyrSlot* slot) { return ((slot)->utag == tagPtr); } inline bool NotPtr(const PyrSlot* slot) { return ((slot)->utag != tagPtr); } inline void SetRawChar(PyrSlot* slot, int val) { assert(IsChar(slot)); slot->uc = val; } inline void SetRaw(PyrSlot* slot, int val) { assert(IsInt(slot)); slot->ui = val; } inline void SetRaw(PyrSlot* slot, long val) { assert(IsInt(slot)); slot->ui = val; } inline void SetRaw(PyrSlot* slot, PyrObject * val) { assert(IsObj(slot)); slot->uo = val; } inline void SetRaw(PyrSlot* slot, PyrSymbol * val) { assert(IsSym(slot)); slot->us = val; } inline void SetRaw(PyrSlot* slot, void * val) { assert(IsPtr(slot)); slot->uptr = val; } inline void SetRaw(PyrSlot* slot, double val) { assert(IsFloat(slot)); SetFloat(slot, val); } inline void SetTagRaw(PyrSlot* slot, int tag) { slot->utag = tag; } template inline int slotVal(PyrSlot * slot, numeric_type *value) { if (IsFloat(slot)) { *value = static_cast(slot->uf); return errNone; } else if (IsInt(slot)) { *value = static_cast(slot->ui); return errNone; } return errWrongType; } inline int slotFloatVal(PyrSlot *slot, float *value) { return slotVal(slot, value); } inline int slotIntVal(PyrSlot *slot, int *value) { return slotVal(slot, value); } inline int slotDoubleVal(PyrSlot *slot, double *value) { return slotVal(slot, value); } inline int slotSymbolVal(PyrSlot *slot, PyrSymbol **symbol) { if (!IsSym(slot)) return errWrongType; *symbol = slot->us; return errNone; } inline void* slotRawPtr(PyrSlot *slot) { assert(IsPtr(slot) || (slot->s.u.ptr == NULL && IsNil(slot))); return slot->s.u.ptr; } inline PyrBlock* slotRawBlock(PyrSlot *slot) { return slot->s.u.oblk; } inline PyrSymbolArray* slotRawSymbolArray(PyrSlot *slot) { return slot->s.u.osym; } inline PyrDoubleArray* slotRawDoubleArray(PyrSlot *slot) { return slot->s.u.od; } inline PyrInt8Array* slotRawInt8Array(PyrSlot *slot) { return slot->s.u.ob; } inline PyrMethod* slotRawMethod(PyrSlot *slot) { return slot->s.u.om; } inline const PyrMethod* slotRawMethod(const PyrSlot *slot) { return slot->s.u.om; } inline PyrThread* slotRawThread(PyrSlot *slot) { return slot->s.u.ot; } inline PyrString* slotRawString(PyrSlot *slot) { return slot->s.u.os; } inline PyrList* slotRawList(PyrSlot *slot) { return slot->s.u.ol; } inline PyrFrame* slotRawFrame(PyrSlot *slot) { return slot->s.u.of; } inline PyrClass* slotRawClass(PyrSlot *slot) { return slot->s.u.oc; } inline const PyrClass* slotRawClass(const PyrSlot *slot) { return slot->s.u.oc; } inline PyrInterpreter* slotRawInterpreter(PyrSlot *slot) { return slot->s.u.oi; } inline PyrSymbol* slotRawSymbol(PyrSlot *slot) { assert(IsSym(slot)); return slot->s.u.s; } inline const PyrSymbol* slotRawSymbol(const PyrSlot *slot) { return slot->s.u.s; } inline int slotRawChar(const PyrSlot *slot) { assert(IsChar(slot)); return slot->s.u.c; } inline int slotRawInt(const PyrSlot *slot) { assert(IsInt(slot)); return slot->s.u.i; } inline double slotRawFloat(const PyrSlot *slot) { assert(IsFloat(slot)); return slot->uf; } inline PyrObject* slotRawObject(PyrSlot *slot) { assert(IsObj(slot)); return slot->s.u.o; } inline const PyrObject* slotRawObject(const PyrSlot *slot) { assert(IsObj(slot)); return slot->s.u.o; } inline void slotCopy(PyrSlot *dst, const PyrSlot *src) { double *dstp = (double*)dst; double *srcp = (double*)src; *dstp = *srcp; } inline void slotCopy(PyrSlot *dst, const PyrSlot *src, int num) { double *dstp = (double*)dst - 1; double *srcp = (double*)src - 1; for (int i=0;i #include struct PyrSymbol; enum { tagNotInitialized, // uninitialized slots have a tag of 0 tagObj, tagInt, tagSym, tagChar, tagNil, // nil, false, and true are indicated by the tag alone. tagFalse, tagTrue, tagPtr, /* anything else is a double */ tagFloat, tagUnused, }; typedef struct pyrslot { long tag; union { int64 c; /* char */ int64 i; double f; void *ptr; struct PyrObject *o; PyrSymbol *s; struct PyrMethod *om; struct PyrBlock *oblk; struct PyrClass *oc; struct PyrFrame *of; struct PyrList *ol; struct PyrString *os; struct PyrInt8Array *ob; struct PyrDoubleArray *od; struct PyrSymbolArray *osym; struct PyrProcess *op; struct PyrThread *ot; struct PyrInterpreter *oi; } u; } PyrSlot; /* tag setter function */ inline int GetTag(const PyrSlot* slot) { return slot->tag; } /* tag checking functions */ inline bool IsObj(const PyrSlot* slot) { return slot->tag == tagObj; } inline bool NotObj(const PyrSlot* slot) { return slot->tag != tagObj; } inline bool IsNil(const PyrSlot* slot) { return slot->tag == tagNil; } inline bool NotNil(const PyrSlot* slot) { return slot->tag != tagNil; } inline bool IsFalse(const PyrSlot* slot) { return slot->tag == tagFalse; } inline bool IsTrue(const PyrSlot* slot) { return slot->tag == tagTrue; } inline bool IsSym(const PyrSlot* slot) { return slot->tag == tagSym; } inline bool NotSym(const PyrSlot* slot) { return slot->tag != tagSym; } inline bool IsChar(const PyrSlot* slot) { return slot->tag == tagChar; } inline bool NotChar(const PyrSlot* slot) { return slot->tag != tagChar; } inline bool IsInt(const PyrSlot* slot) { return slot->tag == tagInt; } inline bool NotInt(const PyrSlot* slot) { return slot->tag != tagInt; } inline bool IsFloat(const PyrSlot* slot) { return slot->tag == tagFloat; } inline bool NotFloat(const PyrSlot* slot) { return slot->tag != tagFloat; } inline bool IsPtr(const PyrSlot* slot) { return slot->tag == tagPtr; } inline bool NotPtr(const PyrSlot* slot) { return slot->tag != tagPtr; } /* setter functions */ inline void SetInt(PyrSlot* slot, int val) { slot->tag = tagInt; slot->u.i = val; } inline void SetObject(PyrSlot* slot, struct PyrObjectHdr* val) { slot->tag = tagObj; slot->u.o = (struct PyrObject*)(val); } inline void SetSymbol(PyrSlot* slot, PyrSymbol *val) { slot->tag = tagSym; slot->u.s = val; } inline void SetChar(PyrSlot* slot, char val) { slot->tag = tagChar; slot->u.c = val; } inline void SetPtr(PyrSlot* slot, void* val) { slot->tag = tagPtr; slot->u.ptr = (void*)val; } inline void SetObjectOrNil(PyrSlot* slot, struct PyrObject* val) { if (val) { slot->tag = tagObj; slot->u.o = val; } else { slot->tag = tagNil; slot->u.i = 0; } } inline void SetTrue(PyrSlot* slot) { slot->tag = tagTrue; slot->u.i = 0; } inline void SetFalse(PyrSlot* slot) { slot->tag = tagFalse; slot->u.i = 0; } inline void SetBool(PyrSlot* slot, bool test) { slot->tag = (test ? tagTrue : tagFalse); slot->u.i = 0; } inline void SetNil(PyrSlot* slot) { slot->tag = tagNil; slot->u.i = 0; } inline void SetFloat(PyrSlot* slot, double val) { slot->tag = tagFloat; slot->u.f = val; } /* raw setter functions, no typecheck */ inline void SetRawChar(PyrSlot* slot, int val) { assert(IsChar(slot)); slot->u.c = val; } inline void SetRaw(PyrSlot* slot, int val) { assert(IsInt(slot)); slot->u.i = val; } inline void SetRaw(PyrSlot* slot, long val) { assert(IsInt(slot)); slot->u.i = val; } inline void SetRaw(PyrSlot* slot, PyrObject * val) { assert(IsObj(slot)); slot->u.o = val; } inline void SetRaw(PyrSlot* slot, PyrSymbol * val) { assert(IsSym(slot)); slot->u.s = val; } inline void SetRaw(PyrSlot* slot, void * val) { assert(IsPtr(slot)); slot->u.ptr = val; } inline void SetRaw(PyrSlot* slot, double val) { assert(IsFloat(slot)); slot->u.f = val; } inline void SetTagRaw(PyrSlot* slot, int tag) { slot->tag = tag; } /* slot comparison */ inline bool SlotEq(PyrSlot* a, PyrSlot* b) { return (a->tag == b->tag) && (a->u.i == b->u.i); } /* extract numeric value */ template inline int slotVal(PyrSlot * slot, numeric_type *value) { if (IsFloat(slot)) { *value = static_cast(slot->u.f); return errNone; } else if (IsInt(slot)) { *value = static_cast(slot->u.i); return errNone; } return errWrongType; } inline int slotFloatVal(PyrSlot *slot, float *value) { return slotVal(slot, value); } inline int slotIntVal(PyrSlot *slot, int *value) { return slotVal(slot, value); } inline int slotDoubleVal(PyrSlot *slot, double *value) { return slotVal(slot, value); } /* get symbol */ inline int slotSymbolVal(PyrSlot *slot, PyrSymbol **symbol) { if (!IsSym(slot)) return errWrongType; *symbol = slot->u.s; return errNone; } /* raw access functions */ inline void* slotRawPtr(PyrSlot *slot) { assert(IsPtr(slot) || (slot->u.ptr == NULL && IsNil(slot))); return slot->u.ptr; } inline PyrBlock* slotRawBlock(PyrSlot *slot) { return slot->u.oblk; } inline PyrSymbolArray* slotRawSymbolArray(PyrSlot *slot) { return slot->u.osym; } inline PyrDoubleArray* slotRawDoubleArray(PyrSlot *slot) { return slot->u.od; } inline PyrInt8Array* slotRawInt8Array(PyrSlot *slot) { return slot->u.ob; } inline PyrMethod* slotRawMethod(PyrSlot *slot) { return slot->u.om; } inline const PyrMethod* slotRawMethod(const PyrSlot *slot) { return slot->u.om; } inline PyrThread* slotRawThread(PyrSlot *slot) { return slot->u.ot; } inline PyrString* slotRawString(PyrSlot *slot) { return slot->u.os; } inline PyrList* slotRawList(PyrSlot *slot) { return slot->u.ol; } inline PyrFrame* slotRawFrame(PyrSlot *slot) { return slot->u.of; } inline PyrClass* slotRawClass(PyrSlot *slot) { return slot->u.oc; } inline const PyrClass* slotRawClass(const PyrSlot *slot) { return slot->u.oc; } inline PyrInterpreter* slotRawInterpreter(PyrSlot *slot) { return slot->u.oi; } inline PyrSymbol* slotRawSymbol(PyrSlot *slot) { return slot->u.s; } inline const PyrSymbol* slotRawSymbol(const PyrSlot *slot) { return slot->u.s; } inline int slotRawChar(const PyrSlot *slot) { return slot->u.c; } inline int slotRawInt(const PyrSlot *slot) { assert(IsInt(slot)); return slot->u.i; } inline double slotRawFloat(const PyrSlot *slot) { assert(IsFloat(slot)); return slot->u.f; } inline PyrObject* slotRawObject(PyrSlot *slot) { assert(IsObj(slot)); return slot->u.o; } inline const PyrObject* slotRawObject(const PyrSlot *slot) { assert(IsObj(slot)); return slot->u.o; } /* slot copy functions */ inline void slotCopy(PyrSlot *dst, const PyrSlot *src) { *dst = *src; } inline void slotCopy(PyrSlot *dst, const PyrSlot *src, int num) { for (int i=0; i #include #include "InitAlloc.h" #include "VMGlobals.h" #include "Hash.h" SCLANG_DLLEXPORT_C PyrSymbol* getsym(const char *name) { PyrSymbol* symbol = gMainVMGlobals->symbolTable->Make(name); if (!symbol) { fprintf(stderr, "getsym failed '%s'\n", name); exit(-1); } return symbol; } SCLANG_DLLEXPORT_C PyrSymbol* getmetasym(const char *name) { char str[256]; strcpy(str, "Meta_"); strncat(str, name, 250); return getsym(str); } SCLANG_DLLEXPORT_C PyrSymbol* findsym(const char *name) { PyrSymbol* symbol = gMainVMGlobals->symbolTable->Find(name); return symbol; } SymbolSpace::SymbolSpace(AllocPool *inPool) { mPool = inPool; mStringPool.Init(inPool, STRINGCHUNK, STRINGCHUNK, STRINGCHUNK/5); mSymbolPool.Init(inPool, SYMBOLCHUNK, SYMBOLCHUNK, SYMBOLCHUNK/5); } PyrSymbol* SymbolSpace::NewSymbol(const char *inName, int inHash, int inLength) { PyrSymbol *sym; sym = (PyrSymbol*)mSymbolPool.Alloc(sizeof(PyrSymbol)); MEMFAIL(sym); sym->name = (char*)mStringPool.Alloc(inLength+1); MEMFAIL(sym->name); strcpy(sym->name, inName); sym->hash = inHash; sym->length = inLength; sym->specialIndex = -1; sym->flags = 0; if (inName[0] >= 'A' && inName[0] <= 'Z') sym->flags |= sym_Class; if (inLength > 1 && inName[0] == '_') sym->flags |= sym_Primitive; if (inLength > 1 && inName[inLength-1] == '_') sym->flags |= sym_Setter; sym->u.index = 0; sym->classdep = NULL; return sym; } SymbolTable::SymbolTable(AllocPool *inPool, int inSize) : mPool(inPool), mSpace(inPool), mMaxItems(inSize) { assert(ISPOWEROFTWO(inSize)); AllocTable(); } void SymbolTable::CopyFrom(SymbolTable& inTable) { MakeEmpty(); Rehash(inTable.mTable, inTable.mMaxItems); } int SymbolTable::StrHash(const char *inName, size_t *outLength) { return Hash(inName, outLength); } PyrSymbol* SymbolTable::Find(const char *inName) { size_t length; int hash = StrHash(inName, &length); return Find(inName, hash); } PyrSymbol* SymbolTable::Find(const char *inName, int inHash) { int index = inHash & mMask; PyrSymbol* sym = mTable[index]; while (sym && (sym->hash != inHash || strcmp(inName, sym->name)!=0)) { index = (index+1) & mMask; sym = mTable[index]; } return sym; } void SymbolTable::Add(PyrSymbol* inSymbol) { if (mNumItems + 1 > (mMaxItems>>1)) Grow(); int index = inSymbol->hash & mMask; PyrSymbol *testSymbol = mTable[index]; while (testSymbol && testSymbol != inSymbol) { index = (index + 1) & mMask; testSymbol = mTable[index]; } if (!testSymbol) { // if it is not already in the table. mTable[index] = inSymbol; mNumItems ++ ; } } PyrSymbol* SymbolTable::MakeNew(const char *inName, int inHash, int inLength) { PyrSymbol* symbol = mSpace.NewSymbol(inName, inHash, inLength); Add(symbol); return symbol; } PyrSymbol* SymbolTable::Make(const char *inName) { size_t length; int hash = StrHash(inName, &length); PyrSymbol* symbol = Find(inName, hash); if (!symbol) symbol = MakeNew(inName, hash, length); return symbol; } void SymbolTable::MakeEmpty() { int size = mMaxItems * sizeof(PyrSymbol*); memset(mTable, 0, size); mNumItems = 0 ; } void SymbolTable::AllocTable() { int size = mMaxItems * sizeof(PyrSymbol*); mTable = (PyrSymbol**)mPool->Alloc(size); MEMFAIL(mTable); MakeEmpty(); mMask = mMaxItems - 1; } void SymbolTable::Rehash(PyrSymbol** inTable, int inSize) { // rehash all entries from inTable into the new table for (int i=0; iFree(oldtable); } void SymbolTable::CheckSymbols() { for (int i=0; iu.index == 0) { int c; c = symbol->name[0]; if (c == '_') { post("WARNING: Primitive '%s' used but not bound\n", symbol->name); } else if (c >= 'A' && c <= 'Z') { post("WARNING: Symbol '%s' used but not defined as a Class\n", symbol->name); } else if ((symbol->flags & sym_Called) && !(symbol->flags & sym_Selector)) { post("WARNING: Method '%s' called but not defined\n", symbol->name); } } } } SuperCollider-Source/lang/LangSource/PyrSymbolTable.h000644 000765 000024 00000004307 12524671173 023735 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SymbolTable_ #define _SymbolTable_ #include "PyrSymbol.h" #include "AdvancingAllocPool.h" #include "SC_Export.h" #define STRINGCHUNK 32000 #define SYMBOLCHUNK 32000 SCLANG_DLLEXPORT_C PyrSymbol* getsym(const char *name); SCLANG_DLLEXPORT_C PyrSymbol* findsym(const char *name); class SymbolSpace { public: SymbolSpace(AllocPool *inPool); PyrSymbol* NewSymbol(const char *inName, int inHash, int inLength); private: AllocPool *mPool; AdvancingAllocPool mStringPool; AdvancingAllocPool mSymbolPool; }; class SymbolTable { public: SymbolTable(AllocPool *inPool, int inSize); void CopyFrom(SymbolTable& inTable); int NumItems() { return mNumItems; } int TableSize() { return mMaxItems; } PyrSymbol* Get(int inIndex) { return mTable[inIndex]; } void CheckSymbols(); private: friend PyrSymbol* getsym(const char *name); friend PyrSymbol* findsym(const char *name); PyrSymbol* Find(const char *inName); PyrSymbol* Make(const char *inName); PyrSymbol* MakeNew(const char *inName, int inHash, int inLength); int StrHash(const char *inName, size_t *outLength); void AllocTable(); void Grow(); PyrSymbol* Find(const char *inName, int inHash); void Add(PyrSymbol* inSymbol); void Rehash(PyrSymbol** inTable, int inSize); void MakeEmpty(); AllocPool *mPool; SymbolSpace mSpace; PyrSymbol **mTable; int mNumItems, mMaxItems, mMask; }; #endif SuperCollider-Source/lang/LangSource/SC_LanguageClient.cpp000644 000765 000024 00000024471 12756531745 024642 0ustar00crucialstaff000000 000000 /* Abstract interpreter interface. Copyright (c) 2003 2004 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_LanguageClient.h" #include "SC_LanguageConfig.hpp" #include "SC_Lock.h" #include #include #include #ifdef _WIN32 # include # include # define snprintf _snprintf # ifndef PATH_MAX # define PATH_MAX _MAX_PATH # endif #else # include #endif #include "PyrObject.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrSched.h" #include "GC.h" #include "VMGlobals.h" #include "SC_DirUtils.h" #include "SCBase.h" #include "SC_StringBuffer.h" void closeAllGUIScreens(); void initGUI(); void initGUIPrimitives(); extern PyrString* newPyrStringN(class PyrGC *gc, long length, long flags, long collect); // ===================================================================== // SC_LanguageClient // ===================================================================== SC_LanguageClient* gInstance = 0; SC_Lock gInstanceMutex; class HiddenLanguageClient { public: HiddenLanguageClient(): mPostFile(0), mScratch(0), mRunning(false) {} std::string mName; FILE* mPostFile; SC_StringBuffer mScratch; bool mRunning; }; SC_LanguageClient::SC_LanguageClient(const char* name) { mHiddenClient = new HiddenLanguageClient; lockInstance(); if (gInstance) { unlockInstance(); fprintf(stderr, "SC_LanguageClient already running\n"); abort(); } mHiddenClient->mName = name; gInstance = this; unlockInstance(); } SC_LanguageClient::~SC_LanguageClient() { lockInstance(); gInstance = 0; unlockInstance(); } void SC_LanguageClient::initRuntime(const Options& opt) { // start virtual machine if (!mHiddenClient->mRunning) { #ifdef __linux__ char deprecatedSupportDirectory[PATH_MAX]; sc_GetUserHomeDirectory(deprecatedSupportDirectory, PATH_MAX); sc_AppendToPath(deprecatedSupportDirectory, PATH_MAX, "share/SuperCollider"); if (sc_DirectoryExists(deprecatedSupportDirectory)) { char supportDirectory[PATH_MAX]; sc_GetUserAppSupportDirectory(supportDirectory, PATH_MAX); postfl("WARNING: Deprecated support directory detected: %s\n" "Extensions and other contents in this directory will not be available until you move them to the new support directory:\n" "%s\n" "Quarks will need to be reinstalled due to broken symbolic links.\n\n", deprecatedSupportDirectory, supportDirectory); } #endif mHiddenClient->mRunning = true; if (opt.mRuntimeDir) { int err = chdir(opt.mRuntimeDir); if (err) error("Cannot change to runtime directory: %s", strerror(errno)); } pyr_init_mem_pools(opt.mMemSpace, opt.mMemGrow); init_OSC(opt.mPort); schedInit(); onInitRuntime(); } } void SC_LanguageClient::shutdownRuntime() { schedCleanup(); cleanup_OSC(); } void SC_LanguageClient::compileLibrary(bool standalone) { ::compileLibrary(standalone); } extern void shutdownLibrary(); void SC_LanguageClient::shutdownLibrary() { ::shutdownLibrary(); flush(); } void SC_LanguageClient::recompileLibrary(bool standalone) { compileLibrary(standalone); } void SC_LanguageClient::setCmdLine(const char* buf, size_t size) { if (isLibraryCompiled()) { lock(); if (isLibraryCompiled()) { VMGlobals *g = gMainVMGlobals; PyrString* strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, buf, size); SetObject(&slotRawInterpreter(&g->process->interpreter)->cmdLine, strobj); g->gc->GCWriteNew(slotRawObject(&g->process->interpreter), strobj); // we know strobj is white so we can use GCWriteNew } unlock(); } } void SC_LanguageClient::setCmdLine(const char* str) { setCmdLine(str, strlen(str)); } void SC_LanguageClient::setCmdLinef(const char* fmt, ...) { SC_StringBuffer & scratch = mHiddenClient->mScratch; va_list ap; va_start(ap, fmt); scratch.reset(); scratch.vappendf(fmt, ap); va_end(ap); setCmdLine(scratch.getData()); } void SC_LanguageClient::runLibrary(PyrSymbol* symbol) { lock(); ::runLibrary(symbol); unlock(); } void SC_LanguageClient::runLibrary(const char* methodName) { lock(); ::runLibrary(getsym(methodName)); unlock(); } void SC_LanguageClient::executeFile(const char* fileName) { std::string escaped_file_name(fileName); int i = 0; while (i < escaped_file_name.size()) { if (escaped_file_name[i] == '\\') escaped_file_name.insert(++i, 1, '\\'); ++i; } setCmdLinef("thisProcess.interpreter.executeFile(\"%s\")", escaped_file_name.c_str()); runLibrary(s_interpretCmdLine); } void SC_LanguageClient::snprintMemArg(char* dst, size_t size, int arg) { int rem = arg; int mod = 0; const char* modstr = ""; while (((rem % 1024) == 0) && (mod < 4)) { rem /= 1024; mod++; } switch (mod) { case 0: modstr = ""; break; case 1: modstr = "k"; break; case 2: modstr = "m"; break; case 3: modstr = "g"; break; default: rem = arg; modstr = ""; break; } snprintf(dst, size, "%d%s", rem, modstr); } bool SC_LanguageClient::parseMemArg(const char* arg, int* res) { long value, factor = 1; char* endPtr = 0; if (*arg == '\0') return false; value = strtol(arg, &endPtr, 0); char spec = *endPtr++; if (spec != '\0') { if (*endPtr != '\0') // trailing characters return false; switch (spec) { case 'k': factor = 1024; break; case 'm': factor = 1024 * 1024; break; default: // invalid mem spec return false; } } *res = value * factor; return true; } bool SC_LanguageClient::parsePortArg(const char* arg, int* res) { long value; char* endPtr; if (*arg == '\0') return false; value = strtol(arg, &endPtr, 0); if ((*endPtr != '\0') || (value < 0) || (value > 65535)) return false; *res = value; return true; } void SC_LanguageClient::tick() { if (trylock()) { if (isLibraryCompiled()) { ::runLibrary(s_tick); } unlock(); } flush(); } bool SC_LanguageClient::tickLocked( double * nextTime ) { if (isLibraryCompiled()) { ::runLibrary(s_tick); } return slotDoubleVal( &gMainVMGlobals->result, nextTime ) == errNone; } void SC_LanguageClient::onInitRuntime() { } void SC_LanguageClient::onLibraryStartup() { } void SC_LanguageClient::onLibraryShutdown() { } void SC_LanguageClient::onInterpStartup() { } // runLibrary methods void SC_LanguageClient::interpretCmdLine() { runLibrary(s_interpretCmdLine); } void SC_LanguageClient::interpretPrintCmdLine() { runLibrary(s_interpretPrintCmdLine); } void SC_LanguageClient::runMain() { runLibrary(s_run); } void SC_LanguageClient::stopMain() { runLibrary(s_stop); } // locks void SC_LanguageClient::lock() { gLangMutex.lock(); } bool SC_LanguageClient::trylock() { return gLangMutex.try_lock(); } void SC_LanguageClient::unlock() { gLangMutex.unlock(); } SC_LanguageClient* SC_LanguageClient::instance() { return gInstance; } void SC_LanguageClient::lockInstance() { gInstanceMutex.lock(); } void SC_LanguageClient::unlockInstance() { gInstanceMutex.unlock(); } extern bool compiledOK; const char* SC_LanguageClient::getName() const { return mHiddenClient->mName.c_str(); } FILE* SC_LanguageClient::getPostFile() { return mHiddenClient->mPostFile; } void SC_LanguageClient::setPostFile(FILE* file) { mHiddenClient->mPostFile = file; } bool SC_LanguageClient::isLibraryCompiled() { return compiledOK; } int SC_LanguageClient::run(int argc, char **argv) { throw std::runtime_error("SC_LanguageClient::run only supported on terminal client"); } // ===================================================================== // library functions // ===================================================================== void setPostFile(FILE* file) { SC_LanguageClient::instance()->setPostFile(file); } int vpost(const char *fmt, va_list ap) { char buf[512]; int n = vsnprintf(buf, sizeof(buf), fmt, ap); if (n > 0) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postText(buf, sc_min(n, sizeof(buf) - 1)); SC_LanguageClient::unlockInstance(); } return 0; } void post(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vpost(fmt, ap); } void postfl(const char *fmt, ...) { char buf[512]; va_list ap; va_start(ap, fmt); int n = vsnprintf(buf, sizeof(buf), fmt, ap); if (n > 0) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postFlush(buf, sc_min(n, sizeof(buf) - 1)); SC_LanguageClient::unlockInstance(); } } void postText(const char *str, long len) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postFlush(str, len); SC_LanguageClient::unlockInstance(); } void postChar(char c) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postFlush(&c, sizeof(char)); SC_LanguageClient::unlockInstance(); } void error(const char *fmt, ...) { char buf[512]; va_list ap; va_start(ap, fmt); int n = vsnprintf(buf, sizeof(buf), fmt, ap); if (n > 0) { SC_LanguageClient *client = SC_LanguageClient::lockedInstance(); if (client) client->postError(buf, sc_min(n, sizeof(buf) - 1)); SC_LanguageClient::unlockInstance(); } } void flushPostBuf(void) { SC_LanguageClient::instance()->flush(); } void closeAllGUIScreens() { SC_LanguageClient::instance()->onLibraryShutdown(); } void initGUI() { SC_LanguageClient::instance()->onInterpStartup(); } void initGUIPrimitives() { SC_LanguageClient::instance()->onLibraryStartup(); } long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2); long scMIDIout(int port, int len, int statushi, int chan, int data1, int data2) { return 0; } // EOF SuperCollider-Source/lang/LangSource/SC_LanguageConfig.cpp000644 000765 000024 00000020234 12524671173 024613 0ustar00crucialstaff000000 000000 /* * Copyright 2003 Maurizio Umberto Puxeddu * Copyright 2011 Jakob Leben * * This file is part of SuperCollider. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * */ #include "SC_LanguageConfig.hpp" #include "SCBase.h" #include "SC_DirUtils.h" #include #include #include #include #include #include #ifdef _WIN32 # include "SC_Win32Utils.h" #else # include # include # include #endif #include #include #include "yaml-cpp/yaml.h" using namespace std; SC_LanguageConfig *gLanguageConfig = 0; string SC_LanguageConfig::gConfigFile; static bool findPath( SC_LanguageConfig::DirVector & vec, const char * path, bool addIfMissing) { char standardPath[PATH_MAX]; sc_StandardizePath(path, standardPath); for ( SC_LanguageConfig::DirVector::iterator it = vec.begin(); it != vec.end(); ++it) { typedef boost::filesystem::path Path; Path stdPath(standardPath), thisPath(it->c_str()); stdPath = stdPath / "."; thisPath = thisPath / "."; if (boost::filesystem::absolute(stdPath) == boost::filesystem::absolute(thisPath)) return true; } if (addIfMissing) vec.push_back(string(standardPath)); return false; } SC_LanguageConfig::SC_LanguageConfig(bool optStandalone) { char classLibraryDir[MAXPATHLEN]; char systemExtensionDir[MAXPATHLEN]; char userExtensionDir[MAXPATHLEN]; if( !optStandalone ) { sc_GetResourceDirectory(classLibraryDir, MAXPATHLEN-32); sc_AppendToPath(classLibraryDir, MAXPATHLEN, "SCClassLibrary"); findPath(mDefaultClassLibraryDirectories, classLibraryDir, true); } if ( !( sc_IsStandAlone() || optStandalone ) ) { sc_GetSystemExtensionDirectory(systemExtensionDir, MAXPATHLEN); findPath(mDefaultClassLibraryDirectories, systemExtensionDir, true); sc_GetUserExtensionDirectory(userExtensionDir, MAXPATHLEN); findPath(mDefaultClassLibraryDirectories, userExtensionDir, true); } } void SC_LanguageConfig::postExcludedDirectories(void) { DirVector &vec = mExcludedDirectories; DirVector::iterator it; for (it=vec.begin(); it!=vec.end(); ++it) { post("\texcluding dir: '%s'\n", it->c_str()); } } bool SC_LanguageConfig::forEachIncludedDirectory(bool (*func)(const char *, int)) { for (DirVector::iterator it=mDefaultClassLibraryDirectories.begin(); it!=mDefaultClassLibraryDirectories.end(); ++it) { if (!pathIsExcluded(it->c_str())) { if (!func(it->c_str(), 0)) return false; } } for (DirVector::iterator it=mIncludedDirectories.begin(); it!=mIncludedDirectories.end(); ++it) { if (!pathIsExcluded(it->c_str())) { if (!func(it->c_str(), 0)) return false; } } return true; } bool SC_LanguageConfig::pathIsExcluded(const char *path) { return findPath(mExcludedDirectories, path, false); } void SC_LanguageConfig::addIncludedDirectory(const char *path) { if (path == 0) return; findPath(mIncludedDirectories, path, true); } void SC_LanguageConfig::addExcludedDirectory(const char *path) { if (path == 0) return; findPath(mExcludedDirectories, path, true); } void SC_LanguageConfig::removeIncludedDirectory(const char *path) { char standardPath[PATH_MAX]; sc_StandardizePath(path, standardPath); string str(standardPath); DirVector::iterator end = std::remove(mIncludedDirectories.begin(), mIncludedDirectories.end(), str); mIncludedDirectories.erase(end, mIncludedDirectories.end()); } void SC_LanguageConfig::removeExcludedDirectory(const char *path) { string str(path); DirVector::iterator end = std::remove(mExcludedDirectories.begin(), mExcludedDirectories.end(), str); mExcludedDirectories.erase(end, mExcludedDirectories.end()); } const char* SC_LanguageConfig::getCurrentConfigPath() { return gConfigFile.c_str(); } extern bool gPostInlineWarnings; bool SC_LanguageConfig::readLibraryConfigYAML(const char* fileName, bool standalone) { freeLibraryConfig(); gLanguageConfig = new SC_LanguageConfig(standalone); using namespace YAML; try { std::ifstream fin(fileName); Parser parser(fin); Node doc; while(parser.GetNextDocument(doc)) { const Node * includePaths = doc.FindValue("includePaths"); if (includePaths && includePaths->Type() == NodeType::Sequence) { for (Iterator it = includePaths->begin(); it != includePaths->end(); ++it) { Node const & pathNode = *it; if (pathNode.Type() != NodeType::Scalar) continue; string path; pathNode.GetScalar(path); gLanguageConfig->addIncludedDirectory(path.c_str()); } } const Node * excludePaths = doc.FindValue("excludePaths"); if (excludePaths && excludePaths->Type() == NodeType::Sequence) { for (Iterator it = excludePaths->begin(); it != excludePaths->end(); ++it) { Node const & pathNode = *it; if (pathNode.Type() != NodeType::Scalar) continue; string path; pathNode.GetScalar(path); gLanguageConfig->addExcludedDirectory(path.c_str()); } } const Node * inlineWarnings = doc.FindValue("postInlineWarnings"); if (inlineWarnings) { try { gPostInlineWarnings = inlineWarnings->to(); } catch(...) { postfl("Warning: Cannot parse config file entry \"postInlineWarnings\"\n"); } } } return true; } catch (std::exception & e) { postfl("Exception when parsing YAML config file: %s\n", e.what()); freeLibraryConfig(); return false; } } bool SC_LanguageConfig::writeLibraryConfigYAML(const char* fileName) { using namespace YAML; Emitter out; out.SetIndent(4); out.SetMapFormat(Block); out.SetSeqFormat(Block); out.SetBoolFormat(TrueFalseBool); out << BeginMap; out << Key << "includePaths"; out << Value << BeginSeq; for (DirVector::iterator it = gLanguageConfig->mIncludedDirectories.begin(); it != gLanguageConfig->mIncludedDirectories.end(); ++it) out << *it; out << EndSeq; out << Key << "excludePaths"; out << Value << BeginSeq; for (DirVector::iterator it = gLanguageConfig->mExcludedDirectories.begin(); it != gLanguageConfig->mExcludedDirectories.end(); ++it) out << *it; out << EndSeq; out << Key << "postInlineWarnings"; out << Value << gPostInlineWarnings; out << EndMap; ofstream fout(fileName); fout << out.c_str(); return true; } bool SC_LanguageConfig::defaultLibraryConfig(bool standalone) { freeLibraryConfig(); gLanguageConfig = new SC_LanguageConfig(standalone); return true; } static bool file_exists(const char * fileName) { FILE * fp = fopen(fileName, "r"); if (fp) fclose(fp); return fp != NULL; } static bool file_exists(std::string const & fileName) { return file_exists(fileName.c_str()); } bool SC_LanguageConfig::readLibraryConfig(bool standalone) { bool configured = false; if (!gConfigFile.empty() && file_exists(gConfigFile)) { configured = readLibraryConfigYAML(gConfigFile.c_str(), standalone); if (configured) return true; } if( !standalone ) { char config_dir[PATH_MAX]; sc_GetUserConfigDirectory(config_dir, PATH_MAX); std::string user_yaml_config_file = std::string(config_dir) + SC_PATH_DELIMITER + "sclang_conf.yaml"; if (file_exists(user_yaml_config_file)) configured = readLibraryConfigYAML(user_yaml_config_file.c_str(), standalone); if (!configured) { char global_yaml_config_file[] = "/etc/sclang_conf.yaml"; if (file_exists(global_yaml_config_file)) configured = readLibraryConfigYAML(global_yaml_config_file, standalone); } if (configured) return true; } SC_LanguageConfig::defaultLibraryConfig(standalone); return false; } void SC_LanguageConfig::freeLibraryConfig() { if (gLanguageConfig) { delete gLanguageConfig; gLanguageConfig = 0; } } SuperCollider-Source/lang/LangSource/SC_LanguageConfig.hpp000644 000765 000024 00000004373 12524671173 024626 0ustar00crucialstaff000000 000000 /* * Copyright 2003 Maurizio Umberto Puxeddu * Copyright 2011 Jakob Leben * * This file is part of SuperCollider. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 * USA * */ #ifndef SC_LANGUAGECONFIG_HPP_INCLUDED #define SC_LANGUAGECONFIG_HPP_INCLUDED #include #include class SC_LanguageConfig { public: typedef std::vector DirVector; SC_LanguageConfig(bool standalone); const DirVector& includedDirectories() { return mIncludedDirectories; } const DirVector& excludedDirectories() { return mExcludedDirectories; } void postExcludedDirectories(void); bool forEachIncludedDirectory(bool (*func)(const char *, int)); bool pathIsExcluded(const char *path); void addIncludedDirectory(const char *name); void addExcludedDirectory(const char *name); void removeIncludedDirectory(const char *name); void removeExcludedDirectory(const char *name); // convenience functions to access the global library config static void setConfigFile(std::string const & fileName) { gConfigFile = fileName; } static bool readLibraryConfigYAML(const char* fileName, bool standalone); static bool writeLibraryConfigYAML(const char* fileName); static void freeLibraryConfig(); static bool defaultLibraryConfig( bool standalone); static bool readLibraryConfig(bool standalone); const char* getCurrentConfigPath(); private: DirVector mIncludedDirectories; DirVector mExcludedDirectories; DirVector mDefaultClassLibraryDirectories; static std::string gConfigFile; }; extern SC_LanguageConfig* gLanguageConfig; #endif // SC_LANGUAGECONFIG_HPP_INCLUDED SuperCollider-Source/lang/LangSource/SC_TerminalClient.cpp000644 000765 000024 00000040030 12766171707 024656 0ustar00crucialstaff000000 000000 /* Commandline interpreter interface. Copyright (c) 2003-2006 stefan kersten. Copyright (c) 2013 tim blechmann. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_TerminalClient.h" #ifdef SC_QT #include "../../QtCollider/LanguageClient.h" #endif #include #ifdef _WIN32 # define __GNU_LIBRARY__ # include "getopt.h" # include "SC_Win32Utils.h" # include # include # include #endif #ifdef __APPLE__ #include "../../common/SC_Apple.hpp" #endif #ifdef HAVE_READLINE # include # include # include #endif #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrLexer.h" #include "PyrSlot.h" #include "VMGlobals.h" #include "SC_DirUtils.h" // for gIdeName #include "SC_LanguageConfig.hpp" #include "SC_Version.hpp" static FILE* gPostDest = stdout; SC_TerminalClient::SC_TerminalClient(const char* name) : SC_LanguageClient(name), mReturnCode(0), mUseReadline(false), mWork(mIoService), mTimer(mIoService), #ifndef _WIN32 mStdIn(mInputService, STDIN_FILENO) #else mStdIn(mInputService, GetStdHandle(STD_INPUT_HANDLE)) #endif {} SC_TerminalClient::~SC_TerminalClient() {} void SC_TerminalClient::postText(const char* str, size_t len) { fwrite(str, sizeof(char), len, gPostDest); } void SC_TerminalClient::postFlush(const char* str, size_t len) { fwrite(str, sizeof(char), len, gPostDest); fflush(gPostDest); } void SC_TerminalClient::postError(const char* str, size_t len) { fprintf(gPostDest, "ERROR: "); fwrite(str, sizeof(char), len, gPostDest); } void SC_TerminalClient::flush() { fflush(gPostDest); } void SC_TerminalClient::printUsage() { Options opt; const size_t bufSize = 128; char memGrowBuf[bufSize]; char memSpaceBuf[bufSize]; snprintMemArg(memGrowBuf, bufSize, opt.mMemGrow); snprintMemArg(memSpaceBuf, bufSize, opt.mMemSpace); fprintf(stdout, "Usage:\n %s [options] [file..] [-]\n\n", getName()); fprintf(stdout, "Options:\n" " -v Print supercollider version and exit\n" " -d Set runtime directory\n" " -D Enter daemon mode (no input)\n" " -g [km] Set heap growth (default %s)\n" " -h Display this message and exit\n" " -l Set library configuration file\n" " -m [km] Set initial heap size (default %s)\n" " -r Call Main.run on startup\n" " -s Call Main.stop on shutdown\n" " -u Set UDP listening port (default %d)\n" " -i Specify IDE name (for enabling IDE-specific class code, default \"%s\")\n" " -a Standalone mode (exclude SCClassLibrary and user and system Extensions folders from search path)\n", memGrowBuf, memSpaceBuf, opt.mPort, gIdeName ); } bool SC_TerminalClient::parseOptions(int& argc, char**& argv, Options& opt) { const char* optstr = ":d:Dg:hl:m:rsu:i:av"; int c; // inhibit error reporting opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'd': opt.mRuntimeDir = optarg; break; case 'D': opt.mDaemon = true; break; case 'g': if (!parseMemArg(optarg, &opt.mMemGrow)) { optopt = c; goto optArgInvalid; } break; case 'h': goto help; case 'l': opt.mLibraryConfigFile = optarg; break; case 'm': if (!parseMemArg(optarg, &opt.mMemSpace)) { optopt = c; goto optArgInvalid; } break; case 'r': opt.mCallRun = true; break; case 'v': fprintf(stdout, "sclang %s (%s)\n", SC_VersionString().c_str(), SC_BuildString().c_str()); quit(0); return false; break; case 's': opt.mCallStop = true; break; case 'u': if (!parsePortArg(optarg, &opt.mPort)) { optopt = c; goto optArgInvalid; } break; case '?': goto optInvalid; break; case ':': goto optArgExpected; break; case 'i': gIdeName = optarg; break; case 'a': opt.mStandalone = true; break; default: ::post("%s: unknown error (getopt)\n", getName()); quit(255); return false; } } argv += optind; argc -= optind; return true; help: printUsage(); quit(0); return false; optInvalid: ::post("%s: invalid option -%c\n", getName(), optopt); quit(1); return false; optArgExpected: ::post("%s: missing argument for option -%c\n", getName(), optopt); quit(1); return false; optArgInvalid: ::post("%s: invalid argument for option -%c -- %s\n", getName(), optopt, optarg); quit(1); return false; } int SC_TerminalClient::run(int argc, char** argv) { Options& opt = mOptions; if (!parseOptions(argc, argv, opt)) { return mReturnCode; } // finish argv processing const char* codeFile = 0; if (argc > 0) { codeFile = argv[0]; opt.mDaemon = true; argv++; argc--; } opt.mArgc = argc; opt.mArgv = argv; // read library configuration file if (opt.mLibraryConfigFile) SC_LanguageConfig::setConfigFile(opt.mLibraryConfigFile); SC_LanguageConfig::readLibraryConfig(opt.mStandalone); // initialize runtime initRuntime(opt); // startup library compileLibrary(opt.mStandalone); // enter main loop if (codeFile) executeFile(codeFile); if (opt.mCallRun) runMain(); if (opt.mDaemon) { daemonLoop(); } else { initInput(); startInput(); commandLoop(); endInput(); cleanupInput(); } if (opt.mCallStop) stopMain(); // shutdown library shutdownLibrary(); flush(); shutdownRuntime(); return mReturnCode; } void SC_TerminalClient::recompileLibrary() { SC_LanguageClient::recompileLibrary(mOptions.mStandalone); } void SC_TerminalClient::quit(int code) { mReturnCode = code; } static PyrSymbol * resolveMethodSymbol(bool silent) { if (silent) return s_interpretCmdLine; else return s_interpretPrintCmdLine; } void SC_TerminalClient::interpretCmdLine(const char* cmdLine, bool silent) { setCmdLine(cmdLine); runLibrary(resolveMethodSymbol(silent)); flush(); } void SC_TerminalClient::interpretCmdLine(const char *cmdLine, size_t size, bool silent) { setCmdLine(cmdLine, size); runLibrary(resolveMethodSymbol(silent)); flush(); } // Note: called only if the input thread does not perform an asynchronous read operation void SC_TerminalClient::interpretInput() { char *data = mInputBuf.getData(); int c = mInputBuf.getSize(); int i = 0; while( i < c ) { switch (data[i]) { case kInterpretCmdLine: interpretCmdLine(data, i, true); break; case kInterpretPrintCmdLine: interpretCmdLine(data, i, false); break; case kRecompileLibrary: recompileLibrary(); break; default: ++i; continue; } data += i+1; c -= i+1; i = 0; } mInputBuf.reset(); if (mUseReadline) mReadlineSem.post(); else startInputRead(); } void SC_TerminalClient::onLibraryStartup() { SC_LanguageClient::onLibraryStartup(); int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_Argv", &SC_TerminalClient::prArgv, 1, 0); definePrimitive(base, index++, "_Exit", &SC_TerminalClient::prExit, 1, 0); definePrimitive(base, index++, "_AppClock_SchedNotify", &SC_TerminalClient::prScheduleChanged, 1, 0); definePrimitive(base, index++, "_Recompile", &SC_TerminalClient::prRecompile, 1, 0); } void SC_TerminalClient::sendSignal( Signal sig ) { switch (sig) { case sig_input: mIoService.post( boost::bind(&SC_TerminalClient::interpretInput, this) ); break; case sig_recompile: mIoService.post( boost::bind(&SC_TerminalClient::recompileLibrary, this) ); break; case sig_sched: mIoService.post( boost::bind(&SC_TerminalClient::tick, this, boost::system::error_code()) ); break; case sig_stop: mIoService.post( boost::bind(&SC_TerminalClient::stopMain, this) ); break; } } void SC_TerminalClient::onQuit( int exitCode ) { postfl("main: quit request %i\n", exitCode); quit( exitCode ); stop(); } extern void ElapsedTimeToChrono(double elapsed, std::chrono::system_clock::time_point & out_time_point); void SC_TerminalClient::tick( const boost::system::error_code& error ) { mTimer.cancel(); double secs; lock(); bool haveNext = tickLocked( &secs ); unlock(); flush(); std::chrono::system_clock::time_point nextAbsTime; ElapsedTimeToChrono( secs, nextAbsTime ); if (haveNext) { mTimer.expires_at(nextAbsTime); mTimer.async_wait(boost::bind(&SC_TerminalClient::tick, this, _1)); } } void SC_TerminalClient::commandLoop() { mIoService.run(); } void SC_TerminalClient::daemonLoop() { commandLoop(); } #ifdef HAVE_READLINE static void sc_rl_cleanlf(void) { rl_reset_line_state(); rl_crlf(); rl_redisplay(); } static void sc_rl_signalhandler(int sig) { // ensure ctrl-C clears line rather than quitting (ctrl-D will quit nicely) rl_replace_line("", 0); sc_rl_cleanlf(); } static int sc_rl_mainstop(int i1, int i2) { static_cast(SC_LanguageClient::instance()) ->sendSignal( SC_TerminalClient::sig_stop ); sc_rl_cleanlf(); // We also push a newline so that there's some UI feedback return 0; } /* // Completion from sclang dictionary TODO char ** sc_rl_completion (const char *text, int start, int end); char ** sc_rl_completion (const char *text, int start, int end){ char **matches = (char **)NULL; printf("sc_rl_completion(%s, %i, %i)\n", text, start, end); return matches; } */ int SC_TerminalClient::readlineRecompile(int i1, int i2) { static_cast(SC_LanguageClient::instance())->sendSignal(sig_recompile); sc_rl_cleanlf(); return 0; } void SC_TerminalClient::readlineCmdLine( char *cmdLine ) { SC_TerminalClient *client = static_cast(instance()); if( cmdLine == NULL ) { postfl("\nExiting sclang (ctrl-D)\n"); client->onQuit(0); return; } if( *cmdLine != 0 ) { // If line wasn't empty, store it so that uparrow retrieves it add_history(cmdLine); int len = strlen(cmdLine); client->mInputBuf.append(cmdLine, len); client->mInputBuf.append(kInterpretPrintCmdLine); client->sendSignal(sig_input); client->mReadlineSem.wait(); } } void SC_TerminalClient::readlineInit() { // Setup readline rl_readline_name = "sclang"; rl_basic_word_break_characters = " \t\n\"\\'`@><=;|&{}()."; //rl_attempted_completion_function = sc_rl_completion; rl_bind_key(CTRL('t'), &sc_rl_mainstop); rl_bind_key(CTRL('x'), &readlineRecompile); rl_callback_handler_install( "sc3> ", &readlineCmdLine ); // FIXME: Implement the code below on Windows #ifndef _WIN32 // Set our handler for SIGINT that will clear the line instead of terminating. // NOTE: We prevent readline from setting its own signal handlers, // to not override ours. rl_catch_signals = 0; struct sigaction sact; memset( &sact, 0, sizeof(struct sigaction) ); sact.sa_handler = &sc_rl_signalhandler; sigaction( SIGINT, &sact, 0 ); #endif } #endif // HAVE_READLINE void SC_TerminalClient::startInputRead() { #ifndef _WIN32 if (mUseReadline) mStdIn.async_read_some(boost::asio::null_buffers(), boost::bind(&SC_TerminalClient::onInputRead, this, _1, _2)); else mStdIn.async_read_some(boost::asio::buffer(inputBuffer), boost::bind(&SC_TerminalClient::onInputRead, this, _1, _2)); #else mStdIn.async_wait( [&] (const boost::system::error_code & error) { if(error) onInputRead(error, 0); else { DWORD bytes_transferred; ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), inputBuffer.data(), inputBuffer.size(), &bytes_transferred, nullptr); onInputRead(error, bytes_transferred); } }); #endif } void SC_TerminalClient::onInputRead(const boost::system::error_code &error, std::size_t bytes_transferred) { if (error == boost::asio::error::operation_aborted) { postfl("SCLang Input: Quit requested\n"); return; } if (error == boost::asio::error::eof) { postfl("SCLang Input: EOF. Will quit.\n"); onQuit(0); return; } if (error) { postfl("SCLang Input: %s.\n", error.message().c_str()); onQuit(1); return; } if (!error) { #if HAVE_READLINE if (mUseReadline) { rl_callback_read_char(); startInputRead(); return; } #endif pushCmdLine( inputBuffer.data(), bytes_transferred ); } } void SC_TerminalClient::inputThreadFn() { #if HAVE_READLINE if (mUseReadline) readlineInit(); #endif startInputRead(); boost::asio::io_service::work work(mInputService); mInputService.run(); } void SC_TerminalClient::pushCmdLine( const char *newData, size_t size) { bool signal = false; while (size--) { char c = *newData++; switch (c) { case kRecompileLibrary: case kInterpretCmdLine: case kInterpretPrintCmdLine: mInputBuf.append( mInputThrdBuf.getData(), mInputThrdBuf.getSize() ); mInputBuf.append(c); signal = true; mInputThrdBuf.reset(); break; default: mInputThrdBuf.append(c); } } if (signal) sendSignal(sig_input); else startInputRead(); } void SC_TerminalClient::initInput() { #ifdef HAVE_READLINE if (strcmp(gIdeName, "none") == 0) { // Other clients (emacs, vim, ...) won't want to interact through rl mUseReadline = true; return; } #endif } void SC_TerminalClient::startInput() { thread thread(std::bind(&SC_TerminalClient::inputThreadFn, this)); mInputThread = std::move(thread); } void SC_TerminalClient::endInput() { mInputService.stop(); mStdIn.cancel(); #ifdef _WIN32 // Note this breaks Windows XP compatibility, since this function is only defined in Vista and later ::CancelIoEx(GetStdHandle(STD_INPUT_HANDLE), nullptr); #endif postfl("main: waiting for input thread to join...\n"); mInputThread.join(); postfl("main: quitting...\n"); } void SC_TerminalClient::cleanupInput() { #ifdef HAVE_READLINE if( mUseReadline ) rl_callback_handler_remove(); #endif } int SC_TerminalClient::prArgv(struct VMGlobals* g, int) { int argc = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgc; char** argv = ((SC_TerminalClient*)SC_TerminalClient::instance())->options().mArgv; PyrSlot* argvSlot = g->sp; PyrObject* argvObj = newPyrArray(g->gc, argc * sizeof(PyrObject), 0, true); SetObject(argvSlot, argvObj); for (int i=0; i < argc; i++) { PyrString* str = newPyrString(g->gc, argv[i], 0, true); SetObject(argvObj->slots+i, str); argvObj->size++; g->gc->GCWriteNew(argvObj, (PyrObject*)str); // we know str is white so we can use GCWriteNew } return errNone; } int SC_TerminalClient::prExit(struct VMGlobals* g, int) { int code; int err = slotIntVal(g->sp, &code); if (err) return err; ((SC_TerminalClient*)SC_LanguageClient::instance())->onQuit( code ); return errNone; } int SC_TerminalClient::prScheduleChanged( struct VMGlobals *g, int numArgsPushed) { static_cast(instance())->sendSignal(sig_sched); return errNone; } int SC_TerminalClient::prRecompile(struct VMGlobals *, int) { static_cast(instance())->sendSignal(sig_recompile); return errNone; } SCLANG_DLLEXPORT SC_LanguageClient * createLanguageClient(const char * name) { if (SC_LanguageClient::instance()) return NULL; #ifdef __APPLE__ SC::Apple::disableAppNap(); #endif #ifdef SC_QT return new QtCollider::LangClient(name); #else return new SC_TerminalClient(name); #endif } SCLANG_DLLEXPORT void destroyLanguageClient(class SC_LanguageClient * languageClient) { delete languageClient; } SuperCollider-Source/lang/LangSource/SC_TerminalClient.h000644 000765 000024 00000012326 12756531745 024333 0ustar00crucialstaff000000 000000 /* -*- c++ -*- Commandline interpreter interface. Copyright (c) 2003 2004 stefan kersten. Copyright (c) 2013 tim blechmann. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SC_TERMINALCLIENT_H_INCLUDED #define SC_TERMINALCLIENT_H_INCLUDED #include "SC_LanguageClient.h" #include "SC_StringBuffer.h" #include "SC_Lock.h" #include #include #include // ===================================================================== // SC_TerminalClient - command line sclang client. // ===================================================================== // TODO: move locks & thread out of the header, possibly using pimpl class SCLANG_DLLEXPORT SC_TerminalClient : public SC_LanguageClient { public: enum { kInterpretCmdLine = 0x1b, kInterpretPrintCmdLine = 0x0c, kRecompileLibrary = 0x18 // ctrl+x }; enum Signal { sig_input = 0x01, // there is new input sig_sched = 0x02, // something has been scheduled sig_recompile = 0x04, // class lib recompilation requested sig_stop = 0x08 // call Main:-stop }; struct Options : public SC_LanguageClient::Options { Options() : mLibraryConfigFile(0), mDaemon(false), mCallRun(false), mCallStop(false), mStandalone(false), mArgc(0), mArgv(0) { } const char* mLibraryConfigFile; bool mDaemon; bool mCallRun; bool mCallStop; int mArgc; char** mArgv; bool mStandalone; }; SC_TerminalClient(const char* name); virtual ~SC_TerminalClient(); const Options& options() const { return mOptions; } int run(int argc, char** argv); void quit(int code); void recompileLibrary(); virtual void postText(const char* str, size_t len); virtual void postFlush(const char* str, size_t len); virtual void postError(const char* str, size_t len); virtual void flush(); // Requests an action to be taken on the main thread. // NOTE: It may be called from any thread, and with interpreter locked. virtual void sendSignal( Signal code ); void stop() { mIoService.stop(); } protected: bool parseOptions(int& argc, char**& argv, Options& opt); void printUsage(); void interpretCmdLine(const char* cmdLine, bool silent); void interpretCmdLine(const char *buf, size_t size, bool silent); // -------------------------------------------------------------- // NOTE: Subclasses should call from main thread // after receiving sig_input void interpretInput(); // -------------------------------------------------------------- // Language requested the application to quit // NOTE: It may be called from any thread, and with interpreter locked. virtual void onQuit( int exitCode ); // See super class virtual void onLibraryStartup(); // -------------------------------------------------------------- // NOTE: Subclasses should override: virtual void commandLoop(); virtual void daemonLoop(); // -------------------------------------------------------------- static int prArgv(struct VMGlobals* g, int); static int prExit(struct VMGlobals* g, int); static int prScheduleChanged( struct VMGlobals *, int); static int prRecompile(struct VMGlobals *, int); void tick(const boost::system::error_code& error); private: // NOTE: called from input thread: #ifdef HAVE_READLINE static void readlineInit(); static void readlineFunc(SC_TerminalClient *); static int readlineRecompile(int, int); static void readlineCmdLine(char *cmdLine); #endif static void *pipeFunc( void * ); void pushCmdLine( const char *newData, size_t size ); void initInput(); void startInput(); void endInput(); void cleanupInput(); int mReturnCode; Options mOptions; // app-clock io service protected: boost::asio::io_service mIoService; private: boost::asio::io_service::work mWork; boost::asio::basic_waitable_timer mTimer; // input io service boost::asio::io_service mInputService; thread mInputThread; void inputThreadFn(); static const size_t inputBufferSize = 256; boost::array inputBuffer; SC_StringBuffer mInputThrdBuf; SC_StringBuffer mInputBuf; #ifndef _WIN32 boost::asio::posix::stream_descriptor mStdIn; #else boost::asio::windows::object_handle mStdIn; #endif void startInputRead(); void onInputRead(const boost::system::error_code& error, std::size_t bytes_transferred); // command input bool mUseReadline; boost::sync::semaphore mReadlineSem; }; #endif // SC_TERMINALCLIENT_H_INCLUDED SuperCollider-Source/lang/LangSource/SCBase.h000644 000765 000024 00000004606 12524671173 022127 0ustar00crucialstaff000000 000000 // SuperCollider real time audio synthesis system // Copyright (c) 2002 James McCartney. All rights reserved. // http://www.audiosynth.com // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // Contains the most common definitions. #ifndef _SCBASE_ #define _SCBASE_ #include #include #ifdef _WIN32 # include #ifndef PATH_MAX # define PATH_MAX _MAX_PATH #endif #endif #include "SC_BoundsMacros.h" #include "SC_Types.h" #include "PyrErrors.h" #include "AllocPools.h" #include "SC_Export.h" void postfl(const char *fmt, ...); void post(const char *fmt, ...); void error(const char *fmt, ...); void postText(const char *text, long length); void postChar(char c); void flushPostBuf(); void setPostFile(FILE *file); // If file is not NULL, causes all posted text to also be written to the file. void debugf(char *fmt, ...); void pprintf(unsigned char *str, char *fmt, ...); SCLANG_DLLEXPORT_C void schedInit(); SCLANG_DLLEXPORT_C void schedCleanup(); SCLANG_DLLEXPORT_C void init_OSC(int port); SCLANG_DLLEXPORT_C void cleanup_OSC(); SCLANG_DLLEXPORT_C bool pyr_init_mem_pools(int runtime_space, int runtime_grow); SCLANG_DLLEXPORT_C void schedRun(); SCLANG_DLLEXPORT_C void schedStop(); SCLANG_DLLEXPORT_C void schedClear(); SCLANG_DLLEXPORT_C bool compileLibrary(bool standalone); SCLANG_DLLEXPORT_C void runLibrary(struct PyrSymbol* selector); SCLANG_DLLEXPORT_C void runInterpreter(struct VMGlobals *g, struct PyrSymbol *selector, int numArgsPushed); SCLANG_DLLEXPORT_C struct VMGlobals* scGlobals(); SCLANG_DLLEXPORT_C struct PyrSymbol* getsym(const char *inName); SCLANG_DLLEXPORT_C struct PyrSymbol* getmetasym(const char *name); SCLANG_DLLEXPORT_C struct PyrSymbol* findsym(const char *name); #endif SuperCollider-Source/lang/LangSource/SimpleStack.cpp000644 000765 000024 00000004425 12756531745 023607 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include //#include #include "SCBase.h" #include "SimpleStack.h" #include "InitAlloc.h" void initLongStack(LongStack *self) { //dbg("initLongStack"); self->maxsize = 0; self->stak = NULL; self->num = 0; } void freeLongStack(LongStack *self) { //dbg("freeLongStack"); self->maxsize = 0; self->num = 0; if (self->stak) { pyr_pool_compile->Free((void*)self->stak); self->stak = NULL; } } void growLongStack(LongStack *self) { if (self->maxsize) { intptr_t *oldstak; self->maxsize += self->maxsize >> 1; // grow by 50% oldstak = self->stak; // pyrmalloc: // lifetime: kill after compile. self->stak = (intptr_t*)pyr_pool_compile->Alloc(self->maxsize * sizeof(intptr_t)); MEMFAIL(self->stak); //BlockMoveData(oldstak, self->stak, self->num * sizeof(intptr_t)); memcpy(self->stak, oldstak, self->num * sizeof(intptr_t)); pyr_pool_compile->Free((void*)oldstak); } else { self->maxsize = 32; self->stak = (intptr_t*)pyr_pool_compile->Alloc(self->maxsize * sizeof(intptr_t)); MEMFAIL(self->stak); } } void pushls(LongStack *self, intptr_t value) { //dbg2("pushls %lX", value); if (self->num+1 > self->maxsize) { growLongStack(self); } self->stak[self->num++] = value; } intptr_t popls(LongStack *self) { if (self->num > 0) return self->stak[--self->num]; else { error("stack empty! (pop)\n"); return 0; } } int emptyls(LongStack *self) { return self->num <= 0; } SuperCollider-Source/lang/LangSource/SimpleStack.h000644 000765 000024 00000002305 12756531745 023247 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LANG_SIMPLESTACK_H #define LANG_SIMPLESTACK_H typedef struct { intptr_t *stak; short num, maxsize; } LongStack; void initLongStack(LongStack *self) ; void freeLongStack(LongStack *self); void growLongStack(LongStack *self); void pushls(LongStack *self, intptr_t value); intptr_t popls(LongStack *self); int emptyls(LongStack *self); #endif SuperCollider-Source/lang/LangSource/VMGlobals.cpp000644 000765 000024 00000002201 12321461511 023161 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "VMGlobals.h" VMGlobals::VMGlobals() : allocPool(0), process(0), gc(0), classvars(0), canCallOS(false), thread(0), method(0), block(0), frame(0), primitiveMethod(0), ip(0), sp(0), numpop(0), primitiveIndex(0), execMethod(0) { SetNil(&receiver); SetNil(&result); } SuperCollider-Source/lang/LangSource/VMGlobals.h000644 000765 000024 00000004653 12321461511 022643 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Each virtual machine has a copy of VMGlobals, which contains the state of the virtual machine. */ #ifndef _VMGLOBALS_H_ #define _VMGLOBALS_H_ #include "PyrSlot.h" #include "SC_AllocPool.h" #include "SC_RGen.h" #include #define TAILCALLOPTIMIZE 1 typedef void (*FifoMsgFunc)(struct VMGlobals*, struct FifoMsg*); struct FifoMsg { FifoMsg() : func(0), dataPtr(0) { dataWord[0] = dataWord[1] = 0; } void Perform(struct VMGlobals* g); void Free(struct VMGlobals* g); FifoMsgFunc func; void* dataPtr; long dataWord[2]; }; struct VMGlobals { VMGlobals(); // global context class AllocPool *allocPool; struct PyrProcess *process; class SymbolTable *symbolTable; class PyrGC *gc; // garbage collector for this process PyrObject *classvars; #if TAILCALLOPTIMIZE int tailCall; // next byte code is a tail call. #endif bool canCallOS; // thread context struct PyrThread *thread; struct PyrMethod *method; struct PyrBlock *block; struct PyrFrame *frame; struct PyrMethod *primitiveMethod; unsigned char *ip; // current instruction pointer PyrSlot *sp; // current stack ptr PyrSlot *args; PyrSlot receiver; // the receiver PyrSlot result; int numpop; // number of args to pop for primitive long primitiveIndex; RGen *rgen; jmp_buf escapeInterpreter; // scratch context long execMethod; } ; inline void FifoMsg::Perform(struct VMGlobals* g) { (func)(g, this); } inline void FifoMsg::Free(struct VMGlobals* g) { g->allocPool->Free(dataPtr); } extern VMGlobals gVMGlobals; extern VMGlobals *gMainVMGlobals; extern VMGlobals *gCompilingVMGlobals; #endif SuperCollider-Source/lang/LangSource/Bison/lang11d000644 000765 000024 00000137720 12756531745 023115 0ustar00crucialstaff000000 000000 %token NAME INTEGER SC_FLOAT ACCIDENTAL SYMBOL STRING ASCII PRIMITIVENAME CLASSNAME CURRYARG %token VAR ARG CLASSVAR SC_CONST %token NILOBJ TRUEOBJ FALSEOBJ %token PSEUDOVAR %token ELLIPSIS DOTDOT PIE BEGINCLOSEDFUNC %token BADTOKEN INTERPRET %token BEGINGENERATOR LEFTARROW WHILE %left ':' %right '=' %left BINOP KEYBINOP '-' '<' '>' '*' '+' '|' READWRITEVAR %left '.' %right '`' %right UMINUS %start root %{ #include #include #include "PyrLexer.h" #include "PyrParseNode.h" #include "SC_Constants.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "InitAlloc.h" #include "PredefinedSymbols.h" #include "SimpleStack.h" void bcopy(void *src, void *dst, size_t size) ; int yyparse(); extern bool compilingCmdLine; extern LongStack generatorStack; %} %error-verbose %% root : classes { gRootParseNode = (PyrParseNode*)$1; gParserResult = 1; } | classextensions { gRootParseNode = (PyrParseNode*)$1; gParserResult = 1; } | INTERPRET cmdlinecode { gRootParseNode = (PyrParseNode*)$2; gParserResult = 2; } ; classes : { $$ = 0; } | classes classdef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; classextensions : classextension | classextensions classextension { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; classdef : classname superclass '{' classvardecls methods '}' { $$ = (intptr_t)newPyrClassNode((PyrSlotNode*)$1, (PyrSlotNode*)$2, (PyrVarListNode*)$4, (PyrMethodNode*)$5, 0); } | classname '[' optname ']' superclass '{' classvardecls methods '}' { $$ = (intptr_t)newPyrClassNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, (PyrVarListNode*)$7, (PyrMethodNode*)$8, (PyrSlotNode*)$3); } ; classextension : '+' classname '{' methods '}' { $$ = (intptr_t)newPyrClassExtNode((PyrSlotNode*)$2, (PyrMethodNode*)$4); } ; optname : { $$ = 0; } | name ; superclass : { $$ = 0; } | ':' classname { $$ = $2; } ; classvardecls : { $$ = 0; } | classvardecls classvardecl { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; classvardecl : CLASSVAR rwslotdeflist ';' { $$ = (intptr_t)newPyrVarListNode((PyrVarDefNode*)$2, varClass); } | VAR rwslotdeflist ';' { $$ = (intptr_t)newPyrVarListNode((PyrVarDefNode*)$2, varInst); } | SC_CONST constdeflist ';' { $$ = (intptr_t)newPyrVarListNode((PyrVarDefNode*)$2, varConst); } ; methods : { $$ = 0; } | methods methoddef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; methoddef : name '{' argdecls funcvardecls primitive methbody '}' { $$ = (intptr_t)newPyrMethodNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, (PyrArgListNode*)$3, (PyrVarListNode*)$4, (PyrParseNode*)$6, 0); } | '*' name '{' argdecls funcvardecls primitive methbody '}' { $$ = (intptr_t)newPyrMethodNode((PyrSlotNode*)$2, (PyrSlotNode*)$6, (PyrArgListNode*)$4, (PyrVarListNode*)$5, (PyrParseNode*)$7, 1); } | binop '{' argdecls funcvardecls primitive methbody '}' { $$ = (intptr_t)newPyrMethodNode((PyrSlotNode*)$1, (PyrSlotNode*)$5, (PyrArgListNode*)$3, (PyrVarListNode*)$4, (PyrParseNode*)$6, 0); } | '*' binop '{' argdecls funcvardecls primitive methbody '}' { $$ = (intptr_t)newPyrMethodNode((PyrSlotNode*)$2, (PyrSlotNode*)$6, (PyrArgListNode*)$4, (PyrVarListNode*)$5, (PyrParseNode*)$7, 1); } ; optsemi : | ';' ; optcomma : | ',' ; optequal : | '=' ; funcbody : funretval | exprseq funretval { $$ = (intptr_t)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; cmdlinecode : '(' funcvardecls1 funcbody ')' { $$ = (intptr_t)newPyrBlockNode(NULL, (PyrVarListNode*)$2, (PyrParseNode*)$3, false); } | funcvardecls1 funcbody { $$ = (intptr_t)newPyrBlockNode(NULL, (PyrVarListNode*)$1, (PyrParseNode*)$2, false); } | funcbody { $$ = (intptr_t)newPyrBlockNode(NULL, NULL, (PyrParseNode*)$1, false); } ; methbody : retval | exprseq retval { $$ = (intptr_t)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; primitive : { $$ = 0; } | primname optsemi { $$ = $1; } ; retval : { $$ = (intptr_t)newPyrReturnNode(NULL); } | '^' expr optsemi { $$ = (intptr_t)newPyrReturnNode((PyrParseNode*)$2); } ; funretval : { $$ = (intptr_t)newPyrBlockReturnNode(); } | '^' expr optsemi { $$ = (intptr_t)newPyrReturnNode((PyrParseNode*)$2); } ; blocklist1 : blocklistitem | blocklist1 blocklistitem { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; blocklistitem : blockliteral | generator ; blocklist : { $$ = 0; } | blocklist1 ; msgsend : name blocklist1 { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$1, (PyrParseNode*)$2, 0, 0); } | '(' binop2 ')' blocklist1 { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$2, (PyrParseNode*)$4, 0, 0); } | name '(' ')' blocklist1 { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$1, NULL, NULL, (PyrParseNode*)$4); } | name '(' arglist1 optkeyarglist ')' blocklist { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$1, (PyrParseNode*)$3, (PyrParseNode*)$4, (PyrParseNode*)$6); } | '(' binop2 ')' '(' ')' blocklist1 { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$2, NULL, NULL, (PyrParseNode*)$6); } | '(' binop2 ')' '(' arglist1 optkeyarglist ')' blocklist { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$2, (PyrParseNode*)$5, (PyrParseNode*)$6, (PyrParseNode*)$8); } | name '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$3)) { SetRaw(&((PyrPushNameNode*)$3)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)$3, newPyrPushLitNode((PyrSlotNode*)$1, NULL)); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$4, 0); } | '(' binop2 ')' '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_performList); selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)$5, newPyrPushLitNode((PyrSlotNode*)$2, NULL)); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); } | classname '[' arrayelems ']' { $$ = (intptr_t)newPyrDynListNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | classname blocklist1 { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, (PyrParseNode*)$2); } | classname '(' ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1); $$ = (intptr_t)newPyrCallNode(selectornode, args, NULL, (PyrParseNode*)$4); } | classname '(' keyarglist1 optcomma ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$3, (PyrParseNode*)$6); } | classname '(' arglist1 optkeyarglist ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1), (PyrParseNode*)$3); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$4, (PyrParseNode*)$6); } | classname '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode, *selectornode2; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$1)) { SetRaw(&((PyrPushNameNode*)$1)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_new); selectornode = newPyrSlotNode(&slot); selectornode2 = newPyrSlotNode(&slot2); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)$1), newPyrPushLitNode(selectornode2, NULL)); args = linkNextNode(args, (PyrParseNode*)$3); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, 0); } | expr '.' '(' ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); $$ = (intptr_t)newPyrCallNode(selectornode, (PyrParseNode*)$1, NULL, (PyrParseNode*)$5); } | expr '.' '(' keyarglist1 optcomma ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); $$ = (intptr_t)newPyrCallNode(selectornode, (PyrParseNode*)$1, (PyrParseNode*)$4, (PyrParseNode*)$7); } | expr '.' name '(' keyarglist1 optcomma ')' blocklist { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, (PyrParseNode*)$5, (PyrParseNode*)$8); } | expr '.' '(' arglist1 optkeyarglist ')' blocklist { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$4); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, (PyrParseNode*)$7); } | expr '.' '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$1)) { SetRaw(&((PyrPushNameNode*)$1)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, newPyrPushLitNode(newPyrSlotNode(&slot2), NULL)); args = linkNextNode(args, (PyrParseNode*)$4); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$5, 0); } | expr '.' name '(' ')' blocklist { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, NULL, (PyrParseNode*)$6); } | expr '.' name '(' arglist1 optkeyarglist ')' blocklist { PyrParseNode* args; args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$5); $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$3, args, (PyrParseNode*)$6, (PyrParseNode*)$8); } | expr '.' name '(' arglistv1 optkeyarglist ')' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)$1)) { SetRaw(&((PyrPushNameNode*)$1)->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkNextNode((PyrParseNode*)$1, newPyrPushLitNode((PyrSlotNode*)$3, NULL)); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)$6, 0); } | expr '.' name blocklist { $$ = (intptr_t)newPyrCallNode((PyrSlotNode*)$3, (PyrParseNode*)$1, 0, (PyrParseNode*)$4); } ; generator : '{' ':' exprseq { pushls(&generatorStack, $3); pushls(&generatorStack, 1); } ',' qual '}' { PyrSlot slot; SetSymbol(&slot, getsym("r")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$6, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); $$ = (intptr_t)newPyrCallNode(selectornode, (PyrParseNode*)blocklit, 0, 0); } | '{' ';' exprseq { pushls(&generatorStack, $3); pushls(&generatorStack, 2); } ',' qual '}' { $$ = $6; } ; nextqual : { // innermost part int action = popls(&generatorStack); PyrParseNode* expr = (PyrParseNode*)popls(&generatorStack); switch (action) { case 1 : { PyrSlot slot; SetSymbol(&slot, getsym("yield")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); $$ = (intptr_t)newPyrCallNode(selectornode, expr, 0, 0); } break; case 2 : { $$ = (intptr_t)expr; } break; } } | ',' qual { $$ = $2; } ; qual : name LEFTARROW exprseq nextqual { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)$3; if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$4, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); $$ = (intptr_t)callnode; } else goto notoptimized1; } else { notoptimized1: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$4, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); $$ = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); } } | name name LEFTARROW exprseq nextqual { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)$4; if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); $$ = (intptr_t)callnode; } else goto notoptimized2; } else { notoptimized2: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); $$ = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); } } | VAR name '=' exprseq nextqual { PyrSlot slot; SetSymbol(&slot, s_value); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)$2, NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)$5, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode(blocklit, (PyrParseNode*)$4); $$ = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); } | exprseq nextqual { PyrSlot slot; SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$2, false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)$1, blocklit); $$ = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); } | ':' ':' exprseq nextqual { $$ = (intptr_t)newPyrDropNode((PyrParseNode*)$3, (PyrParseNode*)$4); } | ':' WHILE exprseq nextqual { PyrSlot slot; SetSymbol(&slot, getsym("alwaysYield")); PyrSlotNode* selectornode1 = newPyrSlotNode(&slot); SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode2 = newPyrSlotNode(&slot); SetNil(&slot); PyrParseNode *pushnil = (PyrParseNode*)newPyrPushLitNode(newPyrSlotNode(&slot), NULL); PyrParseNode *yieldNil = (PyrParseNode*)newPyrCallNode(selectornode1, pushnil, 0, 0); PyrParseNode *block1 = (PyrParseNode*)newPyrBlockNode(0, 0, yieldNil, false); PyrParseNode *blocklit1 = (PyrParseNode*)newPyrPushLitNode(NULL, block1); PyrParseNode *block2 = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)$4, false); PyrParseNode *blocklit2 = (PyrParseNode*)newPyrPushLitNode(NULL, block2); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)$3, blocklit2); PyrParseNode* args3 = (PyrParseNode*)linkNextNode(args2, blocklit1); $$ = (intptr_t)newPyrCallNode(selectornode2, args3, 0, 0); } ; expr1 : pushliteral | blockliteral | generator | pushname | curryarg | msgsend | '(' exprseq ')' { PyrParseNode* node = (PyrParseNode*)$2; node->mParens = 1; $$ = $2; } | '~' name { PyrParseNode* argnode; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)$2, NULL); SetSymbol(&slot, s_envirGet); selectornode = newPyrSlotNode(&slot); $$ = (intptr_t)newPyrCallNode(selectornode, argnode, 0, 0); } | '[' arrayelems ']' { $$ = (intptr_t)newPyrDynListNode(0, (PyrParseNode*)$2); } | '(' valrange2 ')' { $$ = $2; } | '(' ':' valrange3 ')' { $$ = $3; } | '(' dictslotlist ')' { $$ = (intptr_t)newPyrDynDictNode((PyrParseNode*)$2); } | pseudovar { $$ = (intptr_t)newPyrPushNameNode((PyrSlotNode*)$1); } | expr1 '[' arglist1 ']' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | valrangex1 ; valrangex1 : expr1 '[' arglist1 DOTDOT ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$4); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' arglist1 DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$5); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } ; valrangeassign : expr1 '[' arglist1 DOTDOT ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$7); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$4); args = linkNextNode(args, (PyrParseNode*)$7); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr1 '[' arglist1 DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$3); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$5); args = linkNextNode(args, (PyrParseNode*)$8); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } ; valrangexd : expr '.' '[' arglist1 DOTDOT ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 DOTDOT exprseq ']' { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$6); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 DOTDOT ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$8); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)$5); args = linkNextNode(args, (PyrParseNode*)$8); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 DOTDOT exprseq ']' '=' expr { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)$4); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)$3); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)$6); args = linkNextNode(args, (PyrParseNode*)$9); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } ; valrange2 : exprseq DOTDOT { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, nilnode2); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)$2); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, (PyrParseNode*)$3); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; PyrPushLitNode *nilnode; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, nilnode); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } ; valrange3 : DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)$2); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq DOTDOT { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, nilnode2); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, nilnode); args = linkNextNode(args, (PyrParseNode*)$3); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, nilnode); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | exprseq ',' exprseq DOTDOT exprseq { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode(args, (PyrParseNode*)$5); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } ; expr : expr1 | valrangexd | valrangeassign | classname { $$ = (intptr_t)newPyrPushNameNode((PyrSlotNode*)$1); } | expr '.' '[' arglist1 ']' { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$4); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | '`' expr { PyrParseNode *node, *args; PyrSlotNode *slotnode; PyrSlot slot; SetSymbol(&slot, s_ref); slotnode = newPyrSlotNode(&slot); node = (PyrParseNode*)newPyrPushNameNode(slotnode); args = linkNextNode(node, (PyrParseNode*)$2); SetSymbol(&slot, s_new); slotnode = newPyrSlotNode(&slot); $$ = (intptr_t)newPyrCallNode(slotnode, args, 0, 0); } | expr binop2 adverb expr %prec BINOP { $$ = (intptr_t)newPyrBinopCallNode((PyrSlotNode*)$2, (PyrParseNode*)$1, (PyrParseNode*)$4, (PyrParseNode*)$3); } | name '=' expr { $$ = (intptr_t)newPyrAssignNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); } | '~' name '=' expr { PyrParseNode *argnode, *args; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)$2, NULL); args = linkNextNode(argnode, (PyrParseNode*)$4); SetSymbol(&slot, s_envirPut); selectornode = newPyrSlotNode(&slot); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' name '=' expr { $$ = (intptr_t)newPyrSetterNode((PyrSlotNode*)$3, (PyrParseNode*)$1, (PyrParseNode*)$5); } | name '(' arglist1 optkeyarglist ')' '=' expr { if ($4 != 0) { error("Setter method called with keyword arguments.\n"); nodePostErrorLine((PyrParseNode*)$4); compileErrors++; } $$ = (intptr_t)newPyrSetterNode((PyrSlotNode*)$1, (PyrParseNode*)$3, (PyrParseNode*)$7); } | '#' mavars '=' expr { $$ = (intptr_t)newPyrMultiAssignNode((PyrMultiAssignVarListNode*)$2, (PyrParseNode*)$4, 0); } | expr1 '[' arglist1 ']' '=' expr { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$3); args = linkNextNode( args, (PyrParseNode*)$6); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } | expr '.' '[' arglist1 ']' '=' expr { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)$1, (PyrParseNode*)$4); args = linkNextNode( args, (PyrParseNode*)$7); $$ = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); } ; adverb : { $$ = 0; } | '.' name { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$2, NULL); } | '.' integer { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$2, NULL); } | '.' '(' exprseq ')' { $$ = $3; } ; exprn : expr | exprn ';' expr { $$ = (intptr_t)newPyrDropNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; exprseq : exprn optsemi ; arrayelems : { $$ = 0; } | arrayelems1 optcomma { $$ = $1; } ; arrayelems1 : exprseq | exprseq ':' exprseq { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | keybinop exprseq { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL); $$ = (intptr_t)linkNextNode(key, (PyrParseNode*)$2); } | arrayelems1 ',' exprseq { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | arrayelems1 ',' keybinop exprseq { PyrParseNode* elems; PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$3, NULL); elems = (PyrParseNode*)linkNextNode(key, (PyrParseNode*)$4); $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, elems); } | arrayelems1 ',' exprseq ':' exprseq { PyrParseNode* elems; elems = (PyrParseNode*)linkNextNode((PyrParseNode*)$3, (PyrParseNode*)$5); $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, elems); } ; arglist1 : exprseq | arglist1 ',' exprseq { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; arglistv1 : '*' exprseq { $$ = $2; } | arglist1 ',' '*' exprseq { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$4); } ; keyarglist1 : keyarg | keyarglist1 ',' keyarg { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; keyarg : keybinop exprseq { $$ = (intptr_t)newPyrPushKeyArgNode((PyrSlotNode*)$1, (PyrParseNode*)$2); } ; optkeyarglist : optcomma { $$ = 0; } | ',' keyarglist1 optcomma { $$ = $2; } ; mavars : mavarlist { $$ = (intptr_t)newPyrMultiAssignVarListNode((PyrSlotNode*)$1, NULL); } | mavarlist ELLIPSIS name { $$ = (intptr_t)newPyrMultiAssignVarListNode((PyrSlotNode*)$1, (PyrSlotNode*)$3); } ; mavarlist : name | mavarlist ',' name { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; slotliteral : integer { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | floatp { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | ascii { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | string { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | symbol { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | trueobj { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | falseobj { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | nilobj { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | listlit { $$ = (intptr_t)newPyrLiteralNode(NULL, (PyrParseNode*)$1); } ; blockliteral : block { $$ = (intptr_t)newPyrPushLitNode(NULL, (PyrParseNode*)$1); } ; pushname : name { $$ = (intptr_t)newPyrPushNameNode((PyrSlotNode*)$1); } ; pushliteral : integer { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | floatp { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | ascii { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | string { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | symbol { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | trueobj { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | falseobj { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | nilobj { $$ = (intptr_t)newPyrPushLitNode((PyrSlotNode*)$1, NULL); } | listlit { $$ = (intptr_t)newPyrPushLitNode(NULL, (PyrParseNode*)$1); } ; listliteral : integer { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | floatp { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | ascii { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | string { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | symbol { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | name { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | trueobj { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | falseobj { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | nilobj { $$ = (intptr_t)newPyrLiteralNode((PyrSlotNode*)$1, NULL); } | listlit2 { $$ = (intptr_t)newPyrLiteralNode(NULL, (PyrParseNode*)$1); } | dictlit2 { $$ = (intptr_t)newPyrLiteralNode(NULL, (PyrParseNode*)$1); } ; block : '{' argdecls funcvardecls funcbody '}' { $$ = (intptr_t)newPyrBlockNode((PyrArgListNode*)$2, (PyrVarListNode*)$3, (PyrParseNode*)$4, false); } | BEGINCLOSEDFUNC argdecls funcvardecls funcbody '}' { $$ = (intptr_t)newPyrBlockNode((PyrArgListNode*)$2, (PyrVarListNode*)$3, (PyrParseNode*)$4, true); } ; funcvardecls : { $$ = 0; } | funcvardecls funcvardecl { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; funcvardecls1 : funcvardecl | funcvardecls1 funcvardecl { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$2); } ; funcvardecl : VAR vardeflist ';' { $$ = (intptr_t)newPyrVarListNode((PyrVarDefNode*)$2, varLocal); } ; argdecls : { $$ = 0; } | ARG vardeflist ';' { $$ = (intptr_t)newPyrArgListNode((PyrVarDefNode*)$2, NULL); } | ARG vardeflist0 ELLIPSIS name ';' { $$ = (intptr_t)newPyrArgListNode((PyrVarDefNode*)$2, (PyrSlotNode*)$4); } | '|' slotdeflist '|' { $$ = (intptr_t)newPyrArgListNode((PyrVarDefNode*)$2, NULL); } | '|' slotdeflist0 ELLIPSIS name '|' { $$ = (intptr_t)newPyrArgListNode((PyrVarDefNode*)$2, (PyrSlotNode*)$4); } ; constdeflist : constdef | constdeflist optcomma constdef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; constdef : rspec name '=' slotliteral { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$2, (PyrParseNode*)$4, $1); } ; slotdeflist0 : { $$ = 0; } | slotdeflist ; slotdeflist : slotdef | slotdeflist optcomma slotdef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; slotdef : name { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); } | name optequal slotliteral { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); } | name optequal '(' exprseq ')' { PyrParseNode* node = (PyrParseNode*)$4; node->mParens = 1; $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$1, node, 0); } ; vardeflist0 : { $$ = 0; } | vardeflist ; vardeflist : vardef | vardeflist ',' vardef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; vardef : name { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$1, NULL, 0); } | name '=' expr { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$1, (PyrParseNode*)$3, 0); } | name '(' exprseq ')' { PyrParseNode* node = (PyrParseNode*)$3; node->mParens = 1; $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$1, node, 0); } ; dictslotdef : exprseq ':' exprseq { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | keybinop exprseq { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL); $$ = (intptr_t)linkNextNode(key, (PyrParseNode*)$2); } ; dictslotlist1 : dictslotdef | dictslotlist1 ',' dictslotdef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; dictslotlist : { $$ = 0; } | dictslotlist1 optcomma ; rwslotdeflist : rwslotdef | rwslotdeflist ',' rwslotdef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; rwslotdef : rwspec name { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$2, NULL, $1); } | rwspec name '=' slotliteral { $$ = (intptr_t)newPyrVarDefNode((PyrSlotNode*)$2, (PyrParseNode*)$4, $1); } ; dictlit2 : '(' litdictslotlist ')' { $$ = (intptr_t)newPyrLitDictNode((PyrParseNode*)$2); } ; litdictslotdef : listliteral ':' listliteral { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } | keybinop listliteral { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)$1, NULL); $$ = (intptr_t)linkNextNode(key, (PyrParseNode*)$2); } ; litdictslotlist1 : litdictslotdef | litdictslotlist1 ',' litdictslotdef { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; litdictslotlist : { $$ = 0; } | litdictslotlist1 optcomma ; listlit : '#' '[' literallistc ']' { $$ = (intptr_t)newPyrLitListNode(0, (PyrParseNode*)$3); } | '#' classname '[' literallistc ']' { $$ = (intptr_t)newPyrLitListNode((PyrParseNode*)$2, (PyrParseNode*)$4); } ; listlit2 : '[' literallistc ']' { $$ = (intptr_t)newPyrLitListNode(0, (PyrParseNode*)$2); } | classname '[' literallistc ']' { $$ = (intptr_t)newPyrLitListNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; literallistc : { $$ = 0; } | literallist1 optcomma ; literallist1 : listliteral | literallist1 ',' listliteral { $$ = (intptr_t)linkNextNode((PyrParseNode*)$1, (PyrParseNode*)$3); } ; rwspec : { $$ = rwPrivate; } | '<' { $$ = rwReadOnly; } | READWRITEVAR { $$ = rwReadWrite; } | '>' { $$ = rwWriteOnly; } ; rspec : { $$ = rwPrivate; } | '<' { $$ = rwReadOnly; } ; integer : INTEGER { $$ = zzval; } | '-'INTEGER %prec UMINUS { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawInt(&node->mSlot)); $$ = zzval; } ; floatr : SC_FLOAT { $$ = zzval; } | '-' SC_FLOAT %prec UMINUS { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawFloat(&node->mSlot)); $$ = zzval; } ; accidental : ACCIDENTAL { $$ = zzval; } | '-' ACCIDENTAL %prec UMINUS { PyrSlotNode *node; double intval, fracval; node = (PyrSlotNode*)zzval; intval = floor(slotRawFloat(&node->mSlot) + 0.5); fracval = slotRawFloat(&node->mSlot) - intval; SetRaw(&node->mSlot, -intval + fracval); $$ = zzval; } pie : PIE { $$ = zzval; } ; floatp : floatr | accidental | floatr pie { PyrSlotNode *node; node = (PyrSlotNode*)$1; SetRaw(&node->mSlot, slotRawFloat(&node->mSlot) * pi); } | integer pie { PyrSlotNode *node; double ival; node = (PyrSlotNode*)$1; ival = slotRawInt(&node->mSlot); SetFloat(&node->mSlot, ival * pi); } | pie { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, pi); $$ = zzval; } | '-' pie { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, -pi); $$ = zzval; } ; name : NAME { $$ = zzval; } | WHILE { $$ = zzval; } ; classname : CLASSNAME { $$ = zzval; } ; primname : PRIMITIVENAME { $$ = zzval; } ; trueobj : TRUEOBJ { $$ = zzval; } ; falseobj : FALSEOBJ { $$ = zzval; } ; nilobj : NILOBJ { $$ = zzval; } ; ascii : ASCII { $$ = zzval; } ; symbol : SYMBOL { $$ = zzval; } ; string : STRING { $$ = zzval; } ; pseudovar : PSEUDOVAR { $$ = zzval; } ; binop : BINOP { $$ = zzval; } | READWRITEVAR { $$ = zzval; } | '<' { $$ = zzval; } | '>' { $$ = zzval; } | '-' { $$ = zzval; } | '*' { $$ = zzval; } | '+' { $$ = zzval; } | '|' { $$ = zzval; } ; keybinop : KEYBINOP { $$ = zzval; } ; binop2 : binop | keybinop ; curryarg : CURRYARG { $$ = zzval; } SuperCollider-Source/lang/LangSource/Bison/lang11d_tab.cpp000644 000765 000024 00000504765 12756531745 024533 0ustar00crucialstaff000000 000000 /* A Bison parser, made by GNU Bison 2.4.1. */ /* Skeleton implementation for Bison's Yacc-like parsers in C Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "2.4.1" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Using locations. */ #define YYLSP_NEEDED 0 /* Copy the first part of user declarations. */ /* Line 189 of yacc.c */ #line 16 "lang11d" #include #include #include "PyrLexer.h" #include "PyrParseNode.h" #include "SC_Constants.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "InitAlloc.h" #include "PredefinedSymbols.h" #include "SimpleStack.h" void bcopy(void *src, void *dst, size_t size) ; int yyparse(); extern bool compilingCmdLine; extern LongStack generatorStack; /* Line 189 of yacc.c */ #line 95 "lang11d_tab.cpp" /* Enabling traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 1 #endif /* Enabling the token table. */ #ifndef YYTOKEN_TABLE # define YYTOKEN_TABLE 0 #endif /* Tokens. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE /* Put the tokens into the symbol table, so that GDB and other debuggers know about them. */ enum yytokentype { NAME = 258, INTEGER = 259, SC_FLOAT = 260, ACCIDENTAL = 261, SYMBOL = 262, STRING = 263, ASCII = 264, PRIMITIVENAME = 265, CLASSNAME = 266, CURRYARG = 267, VAR = 268, ARG = 269, CLASSVAR = 270, SC_CONST = 271, NILOBJ = 272, TRUEOBJ = 273, FALSEOBJ = 274, PSEUDOVAR = 275, ELLIPSIS = 276, DOTDOT = 277, PIE = 278, BEGINCLOSEDFUNC = 279, BADTOKEN = 280, INTERPRET = 281, BEGINGENERATOR = 282, LEFTARROW = 283, WHILE = 284, READWRITEVAR = 285, KEYBINOP = 286, BINOP = 287, UMINUS = 288 }; #endif #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef int YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 #endif /* Copy the second part of user declarations. */ /* Line 264 of yacc.c */ #line 170 "lang11d_tab.cpp" #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #elif (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) typedef signed char yytype_int8; #else typedef short int yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(msgid) dgettext ("bison-runtime", msgid) # endif # endif # ifndef YY_ # define YY_(msgid) msgid # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(e) ((void) (e)) #else # define YYUSE(e) /* empty */ #endif /* Identity function, used to suppress warnings about constant conditions. */ #ifndef lint # define YYID(n) (n) #else #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static int YYID (int yyi) #else static int YYID (yyi) int yyi; #endif { return yyi; } #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's `empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined _STDLIB_H \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef _STDLIB_H # define _STDLIB_H 1 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) /* Copy COUNT objects from FROM to TO. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(To, From, Count) \ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) # else # define YYCOPY(To, From, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (To)[yyi] = (From)[yyi]; \ } \ while (YYID (0)) # endif # endif /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (YYID (0)) #endif /* YYFINAL -- State number of the termination state. */ #define YYFINAL 67 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 1945 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 55 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 101 /* YYNRULES -- Number of rules. */ #define YYNRULES 292 /* YYNRULES -- Number of states. */ #define YYNSTATES 534 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 288 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 54, 2, 2, 2, 2, 50, 51, 35, 36, 49, 32, 41, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 30, 48, 33, 31, 34, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 46, 2, 47, 52, 2, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 44, 37, 45, 53, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 38, 39, 40, 43 }; #if YYDEBUG /* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in YYRHS. */ static const yytype_uint16 yyprhs[] = { 0, 0, 3, 5, 7, 10, 11, 14, 16, 19, 26, 36, 42, 43, 45, 46, 49, 50, 53, 57, 61, 65, 66, 69, 77, 86, 94, 103, 104, 106, 107, 109, 110, 112, 114, 117, 122, 125, 127, 129, 132, 133, 136, 137, 141, 142, 146, 148, 151, 153, 155, 156, 158, 161, 166, 171, 178, 185, 194, 200, 208, 213, 216, 221, 228, 235, 241, 247, 255, 264, 272, 279, 286, 295, 303, 308, 309, 317, 318, 326, 327, 330, 335, 341, 347, 350, 355, 360, 362, 364, 366, 368, 370, 372, 376, 379, 383, 387, 392, 396, 398, 403, 405, 411, 417, 424, 432, 440, 449, 456, 463, 471, 480, 489, 499, 502, 505, 509, 515, 520, 523, 526, 530, 535, 541, 543, 545, 547, 549, 555, 558, 563, 567, 572, 578, 586, 591, 598, 606, 607, 610, 613, 618, 620, 624, 627, 628, 631, 633, 637, 640, 644, 649, 655, 657, 661, 664, 669, 671, 675, 678, 680, 684, 686, 690, 692, 696, 698, 700, 702, 704, 706, 708, 710, 712, 714, 716, 718, 720, 722, 724, 726, 728, 730, 732, 734, 736, 738, 740, 742, 744, 746, 748, 750, 752, 754, 756, 758, 764, 770, 771, 774, 776, 779, 783, 784, 788, 794, 798, 804, 806, 810, 815, 816, 818, 820, 824, 826, 830, 836, 837, 839, 841, 845, 847, 851, 856, 860, 863, 865, 869, 870, 873, 875, 879, 882, 887, 891, 895, 898, 900, 904, 905, 908, 913, 919, 923, 928, 929, 932, 934, 938, 939, 941, 943, 945, 946, 948, 950, 953, 955, 958, 960, 963, 965, 967, 969, 972, 975, 977, 980, 982, 984, 986, 988, 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020, 1022, 1024 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { 56, 0, -1, 57, -1, 58, -1, 26, 71, -1, -1, 57, 59, -1, 60, -1, 58, 60, -1, 143, 62, 44, 63, 65, 45, -1, 143, 46, 61, 47, 62, 44, 63, 65, 45, -1, 36, 143, 44, 65, 45, -1, -1, 142, -1, -1, 30, 143, -1, -1, 63, 64, -1, 15, 125, 48, -1, 13, 125, 48, -1, 16, 114, 48, -1, -1, 65, 66, -1, 142, 44, 113, 110, 73, 72, 45, -1, 35, 142, 44, 113, 110, 73, 72, 45, -1, 152, 44, 113, 110, 73, 72, 45, -1, 35, 152, 44, 113, 110, 73, 72, 45, -1, -1, 48, -1, -1, 49, -1, -1, 31, -1, 75, -1, 94, 75, -1, 50, 111, 70, 51, -1, 111, 70, -1, 70, -1, 74, -1, 94, 74, -1, -1, 144, 67, -1, -1, 52, 91, 67, -1, -1, 52, 91, 67, -1, 77, -1, 76, 77, -1, 105, -1, 80, -1, -1, 76, -1, 142, 76, -1, 50, 154, 51, 76, -1, 142, 50, 51, 76, -1, 142, 50, 97, 101, 51, 78, -1, 50, 154, 51, 50, 51, 76, -1, 50, 154, 51, 50, 97, 101, 51, 78, -1, 142, 50, 98, 101, 51, -1, 50, 154, 51, 50, 98, 101, 51, -1, 143, 46, 95, 47, -1, 143, 76, -1, 143, 50, 51, 78, -1, 143, 50, 99, 68, 51, 78, -1, 143, 50, 97, 101, 51, 78, -1, 143, 50, 98, 101, 51, -1, 91, 41, 50, 51, 78, -1, 91, 41, 50, 99, 68, 51, 78, -1, 91, 41, 142, 50, 99, 68, 51, 78, -1, 91, 41, 50, 97, 101, 51, 78, -1, 91, 41, 50, 98, 101, 51, -1, 91, 41, 142, 50, 51, 78, -1, 91, 41, 142, 50, 97, 101, 51, 78, -1, 91, 41, 142, 50, 98, 101, 51, -1, 91, 41, 142, 78, -1, -1, 44, 30, 94, 81, 49, 84, 45, -1, -1, 44, 48, 94, 82, 49, 84, 45, -1, -1, 49, 84, -1, 142, 28, 94, 83, -1, 142, 142, 28, 94, 83, -1, 13, 142, 31, 94, 83, -1, 94, 83, -1, 30, 30, 94, 83, -1, 30, 29, 94, 83, -1, 107, -1, 105, -1, 80, -1, 106, -1, 155, -1, 79, -1, 50, 94, 51, -1, 53, 142, -1, 46, 95, 47, -1, 50, 89, 51, -1, 50, 30, 90, 51, -1, 50, 124, 51, -1, 151, -1, 85, 46, 97, 47, -1, 86, -1, 85, 46, 97, 22, 47, -1, 85, 46, 22, 94, 47, -1, 85, 46, 97, 22, 94, 47, -1, 85, 46, 97, 22, 47, 31, 91, -1, 85, 46, 22, 94, 47, 31, 91, -1, 85, 46, 97, 22, 94, 47, 31, 91, -1, 91, 41, 46, 97, 22, 47, -1, 91, 41, 46, 22, 94, 47, -1, 91, 41, 46, 97, 22, 94, 47, -1, 91, 41, 46, 97, 22, 47, 31, 91, -1, 91, 41, 46, 22, 94, 47, 31, 91, -1, 91, 41, 46, 97, 22, 94, 47, 31, 91, -1, 94, 22, -1, 22, 94, -1, 94, 22, 94, -1, 94, 49, 94, 22, 94, -1, 94, 49, 94, 22, -1, 22, 94, -1, 94, 22, -1, 94, 22, 94, -1, 94, 49, 94, 22, -1, 94, 49, 94, 22, 94, -1, 85, -1, 88, -1, 87, -1, 143, -1, 91, 41, 46, 97, 47, -1, 42, 91, -1, 91, 154, 92, 91, -1, 142, 31, 91, -1, 53, 142, 31, 91, -1, 91, 41, 142, 31, 91, -1, 142, 50, 97, 101, 51, 31, 91, -1, 54, 102, 31, 91, -1, 85, 46, 97, 47, 31, 91, -1, 91, 41, 46, 97, 47, 31, 91, -1, -1, 41, 142, -1, 41, 137, -1, 41, 50, 94, 51, -1, 91, -1, 93, 48, 91, -1, 93, 67, -1, -1, 96, 68, -1, 94, -1, 94, 30, 94, -1, 153, 94, -1, 96, 49, 94, -1, 96, 49, 153, 94, -1, 96, 49, 94, 30, 94, -1, 94, -1, 97, 49, 94, -1, 35, 94, -1, 97, 49, 35, 94, -1, 100, -1, 99, 49, 100, -1, 153, 94, -1, 68, -1, 49, 99, 68, -1, 103, -1, 103, 21, 142, -1, 142, -1, 103, 49, 142, -1, 137, -1, 141, -1, 148, -1, 150, -1, 149, -1, 145, -1, 146, -1, 147, -1, 131, -1, 109, -1, 142, -1, 137, -1, 141, -1, 148, -1, 150, -1, 149, -1, 145, -1, 146, -1, 147, -1, 131, -1, 137, -1, 141, -1, 148, -1, 150, -1, 149, -1, 142, -1, 145, -1, 146, -1, 147, -1, 132, -1, 127, -1, 44, 113, 110, 70, 45, -1, 24, 113, 110, 70, 45, -1, -1, 110, 112, -1, 112, -1, 111, 112, -1, 13, 120, 48, -1, -1, 14, 120, 48, -1, 14, 119, 21, 142, 48, -1, 37, 117, 37, -1, 37, 116, 21, 142, 37, -1, 115, -1, 114, 68, 115, -1, 136, 142, 31, 104, -1, -1, 117, -1, 118, -1, 117, 68, 118, -1, 142, -1, 142, 69, 104, -1, 142, 69, 50, 94, 51, -1, -1, 120, -1, 121, -1, 120, 49, 121, -1, 142, -1, 142, 31, 91, -1, 142, 50, 94, 51, -1, 94, 30, 94, -1, 153, 94, -1, 122, -1, 123, 49, 122, -1, -1, 123, 68, -1, 126, -1, 125, 49, 126, -1, 135, 142, -1, 135, 142, 31, 104, -1, 50, 130, 51, -1, 108, 30, 108, -1, 153, 108, -1, 128, -1, 129, 49, 128, -1, -1, 129, 68, -1, 54, 46, 133, 47, -1, 54, 143, 46, 133, 47, -1, 46, 133, 47, -1, 143, 46, 133, 47, -1, -1, 134, 68, -1, 108, -1, 134, 49, 108, -1, -1, 33, -1, 38, -1, 34, -1, -1, 33, -1, 4, -1, 32, 4, -1, 5, -1, 32, 5, -1, 6, -1, 32, 6, -1, 23, -1, 138, -1, 139, -1, 138, 140, -1, 137, 140, -1, 140, -1, 32, 140, -1, 3, -1, 29, -1, 11, -1, 10, -1, 18, -1, 19, -1, 17, -1, 9, -1, 7, -1, 8, -1, 20, -1, 40, -1, 38, -1, 33, -1, 34, -1, 32, -1, 35, -1, 36, -1, 37, -1, 39, -1, 152, -1, 153, -1, 12, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 39, 39, 41, 43, 47, 48, 52, 53, 57, 61, 68, 74, 75, 78, 79, 83, 84, 88, 90, 92, 96, 97, 101, 104, 107, 110, 115, 116, 119, 120, 123, 124, 127, 128, 132, 134, 136, 140, 141, 145, 146, 151, 152, 157, 158, 162, 163, 169, 170, 173, 174, 177, 181, 185, 189, 194, 198, 203, 221, 234, 236, 247, 258, 269, 282, 303, 312, 321, 326, 339, 359, 363, 369, 387, 393, 393, 403, 403, 410, 431, 435, 469, 507, 521, 532, 536, 561, 562, 563, 564, 565, 566, 567, 573, 583, 585, 587, 589, 591, 593, 606, 609, 636, 654, 681, 709, 728, 756, 783, 801, 826, 854, 873, 901, 920, 939, 956, 970, 991, 1010, 1028, 1045, 1061, 1077, 1078, 1079, 1080, 1081, 1094, 1108, 1113, 1117, 1128, 1133, 1143, 1148, 1162, 1178, 1179, 1180, 1181, 1184, 1185, 1191, 1194, 1195, 1199, 1200, 1202, 1207, 1209, 1216, 1224, 1225, 1229, 1231, 1235, 1236, 1240, 1244, 1245, 1248, 1250, 1254, 1255, 1260, 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1271, 1274, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1301, 1304, 1309, 1310, 1314, 1315, 1319, 1323, 1324, 1328, 1332, 1336, 1342, 1343, 1347, 1351, 1352, 1355, 1356, 1360, 1362, 1364, 1372, 1373, 1376, 1377, 1381, 1383, 1385, 1393, 1395, 1402, 1403, 1407, 1408, 1411, 1412, 1416, 1418, 1422, 1426, 1428, 1435, 1436, 1440, 1441, 1446, 1448, 1452, 1454, 1458, 1459, 1462, 1463, 1467, 1468, 1470, 1472, 1476, 1477, 1481, 1482, 1491, 1492, 1501, 1502, 1513, 1516, 1517, 1518, 1524, 1532, 1539, 1548, 1549, 1552, 1555, 1558, 1561, 1564, 1567, 1570, 1573, 1576, 1579, 1580, 1581, 1582, 1583, 1584, 1585, 1586, 1589, 1592, 1593, 1596 }; #endif #if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "NAME", "INTEGER", "SC_FLOAT", "ACCIDENTAL", "SYMBOL", "STRING", "ASCII", "PRIMITIVENAME", "CLASSNAME", "CURRYARG", "VAR", "ARG", "CLASSVAR", "SC_CONST", "NILOBJ", "TRUEOBJ", "FALSEOBJ", "PSEUDOVAR", "ELLIPSIS", "DOTDOT", "PIE", "BEGINCLOSEDFUNC", "BADTOKEN", "INTERPRET", "BEGINGENERATOR", "LEFTARROW", "WHILE", "':'", "'='", "'-'", "'<'", "'>'", "'*'", "'+'", "'|'", "READWRITEVAR", "KEYBINOP", "BINOP", "'.'", "'`'", "UMINUS", "'{'", "'}'", "'['", "']'", "';'", "','", "'('", "')'", "'^'", "'~'", "'#'", "$accept", "root", "classes", "classextensions", "classdef", "classextension", "optname", "superclass", "classvardecls", "classvardecl", "methods", "methoddef", "optsemi", "optcomma", "optequal", "funcbody", "cmdlinecode", "methbody", "primitive", "retval", "funretval", "blocklist1", "blocklistitem", "blocklist", "msgsend", "generator", "$@1", "$@2", "nextqual", "qual", "expr1", "valrangex1", "valrangeassign", "valrangexd", "valrange2", "valrange3", "expr", "adverb", "exprn", "exprseq", "arrayelems", "arrayelems1", "arglist1", "arglistv1", "keyarglist1", "keyarg", "optkeyarglist", "mavars", "mavarlist", "slotliteral", "blockliteral", "pushname", "pushliteral", "listliteral", "block", "funcvardecls", "funcvardecls1", "funcvardecl", "argdecls", "constdeflist", "constdef", "slotdeflist0", "slotdeflist", "slotdef", "vardeflist0", "vardeflist", "vardef", "dictslotdef", "dictslotlist1", "dictslotlist", "rwslotdeflist", "rwslotdef", "dictlit2", "litdictslotdef", "litdictslotlist1", "litdictslotlist", "listlit", "listlit2", "literallistc", "literallist1", "rwspec", "rspec", "integer", "floatr", "accidental", "pie", "floatp", "name", "classname", "primname", "trueobj", "falseobj", "nilobj", "ascii", "symbol", "string", "pseudovar", "binop", "keybinop", "binop2", "curryarg", 0 }; #endif # ifdef YYPRINT /* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to token YYLEX-NUM. */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 58, 61, 45, 60, 62, 42, 43, 124, 285, 286, 287, 46, 96, 288, 123, 125, 91, 93, 59, 44, 40, 41, 94, 126, 35 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 55, 56, 56, 56, 57, 57, 58, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 64, 64, 64, 65, 65, 66, 66, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 71, 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 81, 80, 82, 80, 83, 83, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 87, 87, 87, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 94, 95, 95, 96, 96, 96, 96, 96, 96, 97, 97, 98, 98, 99, 99, 100, 101, 101, 102, 102, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 109, 109, 110, 110, 111, 111, 112, 113, 113, 113, 113, 113, 114, 114, 115, 116, 116, 117, 117, 118, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 135, 135, 135, 135, 136, 136, 137, 137, 138, 138, 139, 139, 140, 141, 141, 141, 141, 141, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 152, 152, 152, 152, 152, 152, 152, 153, 154, 154, 155 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 1, 2, 0, 2, 1, 2, 6, 9, 5, 0, 1, 0, 2, 0, 2, 3, 3, 3, 0, 2, 7, 8, 7, 8, 0, 1, 0, 1, 0, 1, 1, 2, 4, 2, 1, 1, 2, 0, 2, 0, 3, 0, 3, 1, 2, 1, 1, 0, 1, 2, 4, 4, 6, 6, 8, 5, 7, 4, 2, 4, 6, 6, 5, 5, 7, 8, 7, 6, 6, 8, 7, 4, 0, 7, 0, 7, 0, 2, 4, 5, 5, 2, 4, 4, 1, 1, 1, 1, 1, 1, 3, 2, 3, 3, 4, 3, 1, 4, 1, 5, 5, 6, 7, 7, 8, 6, 6, 7, 8, 8, 9, 2, 2, 3, 5, 4, 2, 2, 3, 4, 5, 1, 1, 1, 1, 5, 2, 4, 3, 4, 5, 7, 4, 6, 7, 0, 2, 2, 4, 1, 3, 2, 0, 2, 1, 3, 2, 3, 4, 5, 1, 3, 2, 4, 1, 3, 2, 1, 3, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 0, 2, 1, 2, 3, 0, 3, 5, 3, 5, 1, 3, 4, 0, 1, 1, 3, 1, 3, 5, 0, 1, 1, 3, 1, 3, 4, 3, 2, 1, 3, 0, 2, 1, 3, 2, 4, 3, 3, 2, 1, 3, 0, 2, 4, 5, 3, 4, 0, 2, 1, 3, 0, 1, 1, 1, 0, 1, 1, 2, 1, 2, 1, 2, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state STATE-NUM when YYTABLE doesn't specify something else to do. Zero means the default is an error. */ static const yytype_uint16 yydefact[] = { 5, 44, 0, 0, 2, 3, 7, 270, 257, 259, 261, 278, 279, 277, 272, 292, 0, 276, 274, 275, 280, 263, 204, 271, 0, 0, 204, 145, 230, 0, 0, 0, 37, 4, 33, 92, 89, 124, 101, 126, 125, 142, 27, 44, 88, 90, 87, 175, 44, 201, 185, 177, 264, 265, 268, 178, 176, 127, 182, 183, 184, 179, 181, 180, 99, 91, 0, 1, 6, 14, 8, 0, 221, 223, 219, 212, 199, 258, 260, 262, 269, 230, 129, 0, 0, 199, 289, 147, 0, 29, 0, 0, 0, 285, 283, 284, 286, 287, 288, 282, 281, 0, 0, 44, 228, 29, 0, 290, 291, 0, 27, 94, 247, 0, 162, 164, 0, 0, 285, 0, 291, 138, 28, 144, 34, 36, 202, 267, 266, 0, 0, 52, 46, 49, 48, 145, 0, 61, 21, 0, 12, 0, 203, 0, 0, 0, 0, 220, 0, 29, 214, 31, 44, 75, 77, 44, 0, 95, 30, 146, 149, 115, 0, 0, 0, 96, 114, 0, 0, 93, 0, 30, 231, 98, 227, 0, 28, 45, 0, 247, 241, 249, 196, 195, 0, 29, 186, 187, 191, 0, 192, 193, 194, 188, 190, 189, 0, 0, 0, 247, 0, 153, 0, 0, 0, 50, 0, 0, 143, 131, 0, 0, 29, 29, 47, 0, 50, 29, 29, 29, 157, 0, 0, 15, 0, 13, 16, 222, 224, 0, 0, 205, 0, 207, 30, 0, 32, 0, 0, 200, 0, 0, 0, 148, 150, 0, 119, 97, 120, 0, 116, 226, 0, 35, 0, 229, 0, 0, 53, 132, 0, 0, 239, 29, 0, 0, 243, 30, 248, 247, 135, 163, 165, 0, 0, 0, 100, 0, 0, 0, 50, 29, 29, 29, 0, 0, 51, 74, 0, 0, 140, 139, 130, 155, 54, 30, 160, 0, 30, 0, 60, 62, 0, 0, 30, 0, 159, 286, 11, 22, 0, 0, 14, 21, 225, 0, 0, 215, 0, 0, 217, 174, 166, 167, 171, 172, 173, 168, 170, 169, 198, 0, 0, 197, 0, 151, 121, 0, 118, 0, 29, 29, 245, 0, 30, 242, 236, 238, 250, 0, 244, 103, 102, 0, 0, 154, 0, 0, 128, 66, 0, 0, 0, 133, 50, 29, 29, 29, 0, 0, 29, 50, 58, 50, 65, 158, 50, 0, 0, 204, 204, 0, 251, 251, 255, 17, 0, 206, 208, 0, 0, 0, 0, 79, 176, 0, 152, 122, 117, 56, 0, 0, 237, 240, 246, 0, 0, 104, 136, 109, 108, 0, 0, 50, 70, 50, 71, 0, 0, 0, 141, 156, 161, 0, 55, 64, 63, 204, 204, 199, 199, 16, 252, 254, 253, 0, 232, 0, 0, 256, 29, 209, 0, 9, 218, 0, 0, 0, 76, 0, 84, 0, 0, 78, 123, 50, 59, 106, 105, 0, 0, 0, 110, 137, 69, 67, 50, 73, 50, 134, 199, 199, 40, 40, 21, 19, 251, 234, 18, 20, 255, 0, 0, 79, 79, 80, 79, 0, 57, 107, 112, 111, 0, 72, 68, 40, 40, 273, 42, 27, 42, 0, 233, 0, 210, 0, 79, 86, 85, 81, 79, 113, 42, 42, 0, 0, 38, 42, 41, 0, 10, 235, 211, 83, 82, 0, 0, 27, 23, 39, 25, 24, 26, 43 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 3, 4, 5, 68, 6, 224, 141, 313, 385, 222, 309, 123, 296, 237, 32, 33, 515, 498, 516, 34, 286, 132, 287, 35, 36, 240, 241, 450, 392, 37, 38, 39, 40, 101, 163, 41, 207, 42, 201, 88, 89, 202, 213, 370, 220, 297, 113, 114, 320, 44, 45, 46, 181, 47, 152, 48, 239, 76, 440, 441, 148, 149, 150, 146, 71, 72, 104, 105, 106, 435, 436, 182, 262, 263, 264, 50, 183, 184, 185, 437, 442, 51, 52, 53, 54, 55, 56, 57, 499, 58, 59, 60, 61, 62, 63, 64, 107, 120, 121, 65 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ #define YYPACT_NINF -358 static const yytype_int16 yypact[] = { 6, 1013, 28, 131, 28, 57, -358, -358, -358, -358, -358, -358, -358, -358, -358, -358, 17, -358, -358, -358, -358, -358, 64, -358, 236, 1689, 40, 1325, 733, 1689, 17, 147, -358, -358, -358, -358, -358, 89, -358, -358, -358, 1904, 90, 104, -358, -358, -358, -358, 1065, -358, -358, 118, 118, -358, -358, -358, 163, 93, -358, -358, -358, -358, -358, -358, -358, -358, 120, -358, -358, 38, -358, -24, -358, 68, 17, 17, -358, -358, -358, -358, -358, 857, -358, 1689, 1689, -358, -358, 154, 150, 151, 1689, 1689, 1377, 236, -358, -358, -358, -358, -358, -358, -358, 160, 15, 1065, -358, 174, 183, -358, 1689, 184, 1887, 196, 1818, 221, 12, -358, 197, 1429, -358, 19, -358, 213, 1689, -358, -358, -358, -358, -358, -358, 1689, 1117, 92, -358, -358, -358, 1325, 793, 92, -358, 28, 17, 218, -358, 17, 1689, 1689, 243, -18, 247, 74, -358, 200, 1065, -358, -358, 1065, 1689, -358, 1325, -358, -358, -358, 1689, 224, 18, -358, 1689, 1689, 1689, -358, 229, 1325, -358, -358, -358, 188, -358, -358, 1689, 1818, 1770, -358, -358, -358, 235, 246, 118, -358, -358, 252, -358, -358, -358, -358, -358, -358, 1689, 17, 17, 1818, 1689, -358, 51, 1481, 909, 186, 47, 1689, 1904, 1904, 1689, 92, 260, 261, -358, 245, 92, 260, 261, 262, -358, 1689, 1825, -358, 254, -358, -358, -358, 1904, 264, 17, -358, 17, -358, -358, 17, -358, 1740, 267, -358, 269, 270, 271, -358, 290, 1689, -358, -358, 1689, 1689, -358, -358, 299, -358, 292, -358, 1689, 1169, 92, 1904, 278, 296, -358, 279, 276, 1818, -358, 1818, -358, 1818, 1904, -358, -358, 282, 285, 1533, 303, 1689, 1689, 83, 92, 260, 261, 262, 1689, 961, 92, -358, 335, 1689, -358, -358, 307, -358, 92, 1221, -358, 293, 312, 313, -358, -358, 314, 318, 312, 319, -358, 1878, -358, -358, 310, 311, 342, 176, -358, 325, 338, -358, 1689, 7, -358, -358, 118, -358, -358, -358, -358, -358, -358, -358, -358, 1273, 1273, -358, 1689, -358, -358, 356, 1689, 92, 260, 261, -358, 1818, 1770, -358, -358, -358, -358, 336, -358, 351, 357, 337, 1689, -358, 345, 1585, 358, -358, 343, 344, 346, 1904, 92, 260, 261, 262, 347, 1689, 262, 202, -358, 92, -358, -358, 92, 355, 363, 64, 64, 364, 266, 266, 377, -358, 1840, -358, -358, 350, 17, 116, 367, 370, 31, 372, -358, 1689, -358, 92, 369, 371, -358, -358, -358, 1689, 1689, 392, 1904, 393, 394, 379, 1689, 92, -358, 92, -358, 378, 380, 382, -358, -358, -358, 1689, -358, -358, -358, 64, 64, -358, -358, -358, -358, -358, -358, 212, -358, 17, 230, -358, 257, -358, 17, -358, -358, 397, 1689, 1689, -358, 1273, -358, 1689, 408, -358, -358, 92, -358, 1904, 1904, 1689, 1689, 1689, 406, 1904, -358, -358, 92, -358, 92, 1904, -358, -358, 96, 96, 176, -358, 266, 412, -358, -358, 377, 413, 1689, 370, 370, -358, 370, 1689, -358, 1904, 1904, 1904, 1689, -358, -358, 96, 96, -358, 1637, 391, 1637, 1863, -358, 647, -358, 647, 370, -358, -358, -358, 370, 1904, 1637, 1637, 1689, 402, -358, 400, -358, 404, -358, -358, -358, -358, -358, 411, 414, 1887, -358, -358, -358, -358, -358, -358 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -358, -358, -358, -358, -358, 448, -358, 145, 27, -358, -311, -358, -109, -77, -358, -40, -358, -255, -271, -57, 418, -42, -96, 263, -358, 91, -358, -358, -357, -327, -358, -358, -358, -358, -358, -358, -19, -358, -358, -1, 328, -358, -117, -133, -100, 165, -161, -358, -358, -289, 216, -358, -358, -171, -358, -68, 443, 10, -22, -358, -3, -358, -358, 237, -358, 415, 339, 320, -358, -358, 95, 22, -358, 149, -358, -358, -214, -358, -150, -358, -358, -358, 2, -358, -358, -8, 16, 144, 511, -358, 71, 201, 255, 304, 353, 368, -358, -215, 523, -7, -358 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ #define YYTABLE_NINF -217 static const yytype_int16 yytable[] = { 43, 177, 386, 218, 85, 395, 82, 311, 125, 261, 110, 49, 159, 212, 131, 137, 80, 155, 14, 217, 7, 109, 7, 321, 142, 143, 87, 102, 172, 260, 231, 143, 1, 197, 7, 214, 219, 166, 49, 14, 248, 214, 2, 127, 128, 167, 23, 43, 23, 273, 7, 8, 299, 112, 74, 22, 302, 303, 126, 451, 23, 198, 129, 170, 168, 203, 169, 249, 139, 204, 83, 282, 235, 275, 109, 26, 23, 75, 74, 288, 102, 130, 153, 154, 140, 80, 279, 281, 84, 160, 161, 164, 378, 2, 347, -213, 348, 289, 276, 144, 277, 75, 43, 208, 283, 357, 497, 174, 268, 16, 209, 233, 238, 126, 186, 242, 22, 22, 145, 349, 360, 361, 485, 234, 341, 228, 507, 508, 187, 509, 358, 67, 277, 258, 87, 117, 26, 26, 122, 135, 340, 21, 305, 136, 229, 446, 447, 133, 133, 523, 7, 43, 366, 524, 43, 243, 29, 244, 14, 259, 73, 246, 214, 501, 138, 250, 251, 252, 365, 294, 254, 311, 402, 261, 111, 115, 23, 270, 127, 400, 401, 186, 186, 190, 156, 367, 345, 22, 292, 382, 214, 383, 384, 112, 129, 187, 187, 157, 214, 274, 158, 186, 500, -216, 417, 418, 362, 26, 290, 293, 22, 165, 22, 130, 521, 187, 522, 284, 73, 151, 306, -216, 133, 171, 512, 513, 22, 178, 133, -216, 26, 236, 26, 423, 173, 175, 285, -216, 257, 322, 77, 78, 79, 199, 335, 519, 26, 336, 337, -216, 190, 190, 196, 323, 206, 174, 188, 525, 526, 21, 475, 476, 226, 205, 230, 363, 133, 186, 232, 186, 190, 186, 134, 134, 353, 247, 355, 356, 478, 476, 253, 187, 266, 187, 225, 187, 311, 73, 368, 321, 419, 321, 300, 422, 355, 267, 133, 399, 269, 432, 433, 312, 133, 214, 434, 479, 234, 133, 324, 295, 298, 304, 330, 191, 127, 314, 333, 389, 331, 332, 334, 338, 167, 188, 188, 342, 343, 346, 344, 350, 393, 393, 351, 396, 354, 408, 190, 398, 190, 77, 190, 271, 272, 188, 371, 186, 186, 134, 119, 133, 291, 86, 131, 134, 379, 380, 411, 429, 430, 187, 187, 472, 473, 480, 372, 373, 310, 192, 421, 374, 376, 133, 139, 387, 315, 388, 316, 133, 397, 151, 191, 191, 405, 404, 407, 133, 457, 458, 406, 412, 518, 134, 409, 463, 413, 414, 454, 415, 420, 427, 191, 444, 495, 496, 469, 470, 471, 428, 431, 188, 439, 188, 448, 188, 190, 190, 193, 453, 533, 449, 455, 134, 456, 459, 460, 461, 462, 134, 482, 466, 133, 467, 134, 468, 192, 192, 487, 492, 325, 176, 489, 490, 491, 503, 505, 483, 484, 528, 393, 530, 486, 377, 514, 70, 192, 133, 531, 381, 474, 532, 529, 124, 133, 215, 133, 194, 191, 133, 191, 375, 191, 103, 317, 511, 134, 394, 394, 504, 438, 301, 195, 506, 227, 193, 193, 133, 510, 188, 188, 147, 133, 255, 326, 403, 0, 527, 134, 517, 502, 517, 0, 0, 134, 193, 133, 322, 133, 322, 0, 0, 134, 517, 517, 66, 0, 69, 0, 0, 0, 323, 192, 323, 192, 0, 192, 0, 0, 0, 0, 0, 310, 0, 194, 194, 445, 0, 0, 0, 452, 0, 0, 327, 116, 359, 191, 191, 133, 195, 195, 0, 90, 108, 194, 0, 0, 134, 0, 133, 0, 133, 0, 0, 0, 0, 0, 0, 0, 195, 0, 193, 0, 193, 0, 193, 324, 0, 324, 0, 0, 0, 134, 477, 0, 0, 0, 0, 481, 134, 0, 134, 328, 0, 134, 394, 0, 0, 0, 0, 192, 192, 0, 0, 0, 0, 108, 329, 0, 0, 0, 0, 134, 0, 0, 0, 0, 134, 0, 0, 194, 0, 194, 0, 194, 189, 0, 0, 0, 416, 0, 134, 0, 134, 0, 195, 424, 195, 425, 195, 0, 426, 0, 0, 0, 0, 0, 310, 0, 193, 193, 0, 223, 8, 9, 10, 11, 12, 13, 0, 90, 221, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 21, 134, 0, 0, 0, 0, 464, 0, 465, 24, 0, 245, 134, 0, 134, 0, 0, 0, 0, 0, 189, 189, 0, 0, 256, 0, 194, 194, 0, 0, 0, 319, 0, 265, 325, 0, 325, 0, 0, 0, 189, 195, 195, 0, 0, 0, 0, 0, 488, 0, 0, 0, 0, 0, 0, 0, 0, 221, 0, 493, 0, 494, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 0, 0, 0, 17, 18, 19, 20, 0, 91, 21, 22, 326, 0, 326, 0, 23, 92, 0, 93, 94, 95, 96, 97, 98, 99, 86, 100, 0, 25, 189, 26, 189, 27, 189, 0, 0, 81, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 327, 221, 327, 17, 18, 19, 20, 0, 0, 21, 22, 221, 0, 0, 221, 23, 0, 0, 24, 0, 221, 210, 0, 116, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 216, 0, 30, 31, 0, 0, 0, 0, 0, 0, 189, 189, 328, 0, 328, 0, 7, 8, 9, 10, 11, 12, 13, 265, 14, 15, 0, 329, 0, 329, 17, 18, 19, 20, 0, 91, 21, 22, 0, 0, 0, 0, 23, 92, 0, 93, 94, 95, 96, 97, 98, 99, 86, 100, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 280, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 364, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 28, 0, 29, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 16, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 29, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 211, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 210, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 339, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 369, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 390, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 391, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 86, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 162, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 200, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 278, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 352, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 410, 0, 0, 81, 0, 0, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 514, 30, 31, 7, 8, 9, 10, 11, 12, 13, 0, 14, 15, 0, 0, 0, 0, 17, 18, 19, 20, 0, 0, 21, 22, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 26, 0, 27, 0, 0, 0, 81, 0, 0, 30, 31, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 24, 7, 8, 9, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 17, 18, 19, 318, 0, 0, 21, 319, 0, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 180, 7, 8, 9, 10, 11, 12, 13, 7, 14, 0, 0, 0, 0, 0, 17, 18, 19, 0, 0, 0, 21, 0, 7, 0, 0, 0, 23, 0, 0, 24, 0, 0, 0, 23, 0, 0, 118, 94, 95, 307, 97, 98, 99, 179, 100, 7, 0, 180, 23, 308, 0, 118, 94, 95, 307, 97, 98, 99, 0, 100, 7, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 23, 0, 0, 118, 94, 95, 307, 97, 98, 99, 0, 100, 0, 0, 0, 23, 520, 0, 118, 94, 95, 96, 97, 98, 99, 0, 100, 118, 94, 95, 96, 97, 98, 99, 86, 100, 119, 0, 0, 0, 0, 0, 0, 176, 118, 94, 95, 96, 97, 98, 99, 86, 100, 119 }; static const yytype_int16 yycheck[] = { 1, 110, 313, 136, 26, 332, 25, 222, 48, 180, 29, 1, 89, 130, 56, 57, 24, 85, 11, 136, 3, 28, 3, 237, 48, 49, 27, 28, 105, 179, 48, 49, 26, 21, 3, 131, 136, 22, 28, 11, 22, 137, 36, 51, 52, 30, 29, 48, 29, 199, 3, 4, 213, 46, 14, 24, 217, 218, 48, 28, 29, 49, 31, 103, 49, 46, 51, 49, 30, 50, 30, 204, 149, 22, 81, 44, 29, 37, 14, 32, 81, 50, 83, 84, 46, 93, 203, 204, 48, 90, 91, 92, 307, 36, 265, 21, 267, 50, 47, 31, 49, 37, 103, 122, 204, 22, 10, 108, 185, 13, 129, 37, 152, 103, 112, 155, 24, 24, 50, 269, 281, 282, 449, 49, 257, 144, 483, 484, 112, 486, 47, 0, 49, 175, 135, 46, 44, 44, 48, 46, 257, 23, 219, 50, 145, 29, 30, 56, 57, 506, 3, 152, 285, 510, 155, 156, 52, 158, 11, 178, 16, 162, 258, 474, 44, 166, 167, 168, 285, 211, 171, 386, 343, 344, 30, 31, 29, 196, 186, 340, 341, 179, 180, 112, 30, 285, 263, 24, 207, 13, 286, 15, 16, 46, 31, 179, 180, 47, 294, 200, 49, 199, 473, 3, 365, 366, 283, 44, 206, 210, 24, 51, 24, 50, 503, 199, 505, 31, 74, 75, 221, 21, 131, 49, 495, 496, 24, 31, 137, 29, 44, 31, 44, 31, 51, 51, 50, 37, 50, 237, 4, 5, 6, 46, 245, 500, 44, 248, 249, 49, 179, 180, 31, 237, 41, 256, 112, 512, 513, 23, 48, 49, 44, 119, 21, 284, 175, 265, 21, 267, 199, 269, 56, 57, 275, 51, 277, 278, 48, 49, 51, 265, 47, 267, 140, 269, 501, 143, 289, 503, 367, 505, 47, 370, 295, 49, 205, 339, 46, 33, 34, 47, 211, 399, 38, 48, 49, 216, 237, 49, 49, 49, 45, 112, 322, 51, 45, 318, 49, 49, 30, 22, 30, 179, 180, 47, 30, 51, 49, 47, 331, 332, 47, 334, 31, 354, 265, 338, 267, 4, 269, 197, 198, 199, 51, 343, 344, 131, 41, 258, 206, 39, 394, 137, 44, 44, 357, 379, 380, 343, 344, 429, 430, 440, 51, 51, 222, 112, 369, 51, 51, 280, 30, 48, 230, 37, 232, 286, 22, 235, 179, 180, 31, 47, 47, 294, 405, 406, 31, 31, 499, 175, 47, 412, 51, 51, 397, 51, 51, 44, 199, 51, 470, 471, 423, 427, 428, 44, 44, 265, 33, 267, 45, 269, 343, 344, 112, 45, 527, 49, 51, 205, 51, 31, 31, 31, 47, 211, 31, 51, 339, 51, 216, 51, 179, 180, 28, 31, 237, 48, 459, 460, 461, 31, 31, 446, 447, 45, 449, 45, 451, 307, 52, 5, 199, 364, 45, 312, 431, 45, 517, 43, 371, 135, 373, 112, 265, 376, 267, 304, 269, 28, 235, 492, 258, 331, 332, 480, 383, 216, 112, 482, 143, 179, 180, 394, 487, 343, 344, 74, 399, 171, 237, 344, -1, 514, 280, 498, 476, 500, -1, -1, 286, 199, 413, 503, 415, 505, -1, -1, 294, 512, 513, 2, -1, 4, -1, -1, -1, 503, 265, 505, 267, -1, 269, -1, -1, -1, -1, -1, 386, -1, 179, 180, 390, -1, -1, -1, 394, -1, -1, 237, 31, 280, 343, 344, 455, 179, 180, -1, 27, 28, 199, -1, -1, 339, -1, 466, -1, 468, -1, -1, -1, -1, -1, -1, -1, 199, -1, 265, -1, 267, -1, 269, 503, -1, 505, -1, -1, -1, 364, 437, -1, -1, -1, -1, 442, 371, -1, 373, 237, -1, 376, 449, -1, -1, -1, -1, 343, 344, -1, -1, -1, -1, 81, 237, -1, -1, -1, -1, 394, -1, -1, -1, -1, 399, -1, -1, 265, -1, 267, -1, 269, 112, -1, -1, -1, 364, -1, 413, -1, 415, -1, 265, 371, 267, 373, 269, -1, 376, -1, -1, -1, -1, -1, 501, -1, 343, 344, -1, 139, 4, 5, 6, 7, 8, 9, -1, 135, 136, -1, -1, -1, -1, 17, 18, 19, -1, -1, -1, 23, 455, -1, -1, -1, -1, 413, -1, 415, 32, -1, 158, 466, -1, 468, -1, -1, -1, -1, -1, 179, 180, -1, -1, 171, -1, 343, 344, -1, -1, -1, 54, -1, 180, 503, -1, 505, -1, -1, -1, 199, 343, 344, -1, -1, -1, -1, -1, 455, -1, -1, -1, -1, -1, -1, -1, -1, 204, -1, 466, -1, 468, -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, 503, -1, 505, -1, 29, 30, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, 42, 265, 44, 267, 46, 269, -1, -1, 50, -1, -1, 53, 54, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, 503, 285, 505, 17, 18, 19, 20, -1, -1, 23, 24, 295, -1, -1, 298, 29, -1, -1, 32, -1, 304, 35, -1, 319, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, -1, -1, -1, -1, -1, -1, 343, 344, 503, -1, 505, -1, 3, 4, 5, 6, 7, 8, 9, 344, 11, 12, -1, 503, -1, 505, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, 30, -1, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, 52, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, 52, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, 51, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, 35, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, 13, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, 30, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, 39, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, 22, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, 47, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, 47, -1, -1, 50, -1, -1, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, 52, 53, 54, 3, 4, 5, 6, 7, 8, 9, -1, 11, 12, -1, -1, -1, -1, 17, 18, 19, 20, -1, -1, 23, 24, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, -1, -1, -1, 42, -1, 44, -1, 46, -1, -1, -1, 50, -1, -1, 53, 54, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 17, 18, 19, -1, -1, -1, 23, -1, -1, -1, -1, -1, -1, -1, -1, 32, 3, 4, 5, 6, 7, 8, 9, -1, 11, -1, -1, -1, -1, -1, 17, 18, 19, 50, -1, -1, 23, 54, -1, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, -1, -1, -1, 39, -1, -1, -1, -1, -1, -1, 46, -1, -1, -1, 50, 3, 4, 5, 6, 7, 8, 9, 3, 11, -1, -1, -1, -1, -1, 17, 18, 19, -1, -1, -1, 23, -1, 3, -1, -1, -1, 29, -1, -1, 32, -1, -1, -1, 29, -1, -1, 32, 33, 34, 35, 36, 37, 38, 46, 40, 3, -1, 50, 29, 45, -1, 32, 33, 34, 35, 36, 37, 38, -1, 40, 3, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, 29, -1, -1, 32, 33, 34, 35, 36, 37, 38, -1, 40, -1, -1, -1, 29, 45, -1, 32, 33, 34, 35, 36, 37, 38, -1, 40, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, -1, 48, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 26, 36, 56, 57, 58, 60, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 17, 18, 19, 20, 23, 24, 29, 32, 42, 44, 46, 50, 52, 53, 54, 70, 71, 75, 79, 80, 85, 86, 87, 88, 91, 93, 94, 105, 106, 107, 109, 111, 112, 131, 137, 138, 139, 140, 141, 142, 143, 145, 146, 147, 148, 149, 150, 151, 155, 143, 0, 59, 143, 60, 120, 121, 142, 14, 37, 113, 4, 5, 6, 140, 50, 91, 30, 48, 113, 39, 94, 95, 96, 153, 22, 30, 32, 33, 34, 35, 36, 37, 38, 40, 89, 94, 111, 122, 123, 124, 152, 153, 154, 91, 142, 46, 102, 103, 142, 143, 46, 32, 41, 153, 154, 48, 67, 75, 70, 112, 140, 140, 31, 50, 76, 77, 80, 105, 46, 50, 76, 44, 30, 46, 62, 48, 49, 31, 50, 119, 120, 116, 117, 118, 142, 110, 94, 94, 110, 30, 47, 49, 68, 94, 94, 22, 90, 94, 51, 22, 30, 49, 51, 70, 49, 68, 51, 94, 51, 48, 67, 31, 46, 50, 108, 127, 132, 133, 134, 137, 141, 142, 143, 145, 146, 147, 148, 149, 150, 31, 21, 49, 46, 22, 94, 97, 46, 50, 142, 41, 92, 91, 91, 35, 51, 97, 98, 77, 95, 51, 97, 98, 99, 100, 153, 65, 143, 61, 142, 44, 121, 91, 94, 21, 48, 21, 37, 49, 68, 31, 69, 70, 112, 81, 82, 70, 94, 94, 153, 94, 51, 22, 49, 94, 94, 94, 51, 94, 122, 153, 50, 76, 91, 133, 108, 128, 129, 130, 153, 47, 49, 68, 46, 91, 142, 142, 133, 94, 22, 47, 49, 22, 97, 51, 97, 98, 99, 31, 50, 76, 78, 32, 50, 137, 142, 91, 94, 76, 49, 68, 101, 49, 101, 47, 78, 101, 101, 49, 68, 94, 35, 45, 66, 142, 152, 47, 63, 51, 142, 142, 118, 50, 54, 104, 131, 137, 141, 145, 146, 147, 148, 149, 150, 45, 49, 49, 45, 30, 94, 94, 94, 22, 51, 97, 98, 47, 30, 49, 68, 51, 108, 108, 133, 47, 47, 47, 94, 31, 94, 94, 22, 47, 78, 101, 101, 68, 91, 51, 97, 98, 99, 94, 35, 99, 51, 51, 51, 51, 100, 51, 142, 152, 44, 44, 62, 13, 15, 16, 64, 65, 48, 37, 94, 13, 30, 84, 94, 142, 84, 94, 22, 94, 76, 101, 101, 108, 128, 47, 31, 31, 47, 91, 47, 47, 94, 31, 51, 51, 51, 78, 101, 101, 68, 51, 94, 68, 31, 78, 78, 78, 44, 44, 113, 113, 44, 33, 34, 38, 125, 126, 135, 125, 33, 114, 115, 136, 45, 51, 142, 29, 30, 45, 49, 83, 28, 142, 45, 94, 51, 51, 91, 91, 31, 31, 31, 47, 91, 78, 78, 51, 51, 51, 91, 113, 113, 110, 110, 63, 48, 49, 142, 48, 48, 68, 142, 31, 94, 94, 84, 94, 28, 78, 91, 91, 91, 31, 78, 78, 110, 110, 10, 73, 144, 73, 65, 126, 31, 115, 31, 94, 83, 83, 83, 94, 91, 73, 73, 52, 72, 74, 94, 67, 72, 45, 104, 104, 83, 83, 72, 72, 91, 45, 74, 45, 45, 45, 67 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab /* Like YYERROR except do call yyerror. This remains here temporarily to ease the transition to the new meaning of YYERROR, for GCC. Once GCC version 2 has supplanted version 1, this can go. */ #define YYFAIL goto yyerrlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY && yylen == 1) \ { \ yychar = (Token); \ yylval = (Value); \ yytoken = YYTRANSLATE (yychar); \ YYPOPSTACK (1); \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (YYID (0)) #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #define YYRHSLOC(Rhs, K) ((Rhs)[K]) #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (YYID (N)) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (YYID (0)) #endif /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if YYLTYPE_IS_TRIVIAL # define YY_LOCATION_PRINT(File, Loc) \ fprintf (File, "%d.%d-%d.%d", \ (Loc).first_line, (Loc).first_column, \ (Loc).last_line, (Loc).last_column) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif /* YYLEX -- calling `yylex' with the right arguments. */ #ifdef YYLEX_PARAM # define YYLEX yylex (YYLEX_PARAM) #else # define YYLEX yylex () #endif /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (YYID (0)) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (YYID (0)) /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_value_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # else YYUSE (yyoutput); # endif switch (yytype) { default: break; } } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) #else static void yy_symbol_print (yyoutput, yytype, yyvaluep) FILE *yyoutput; int yytype; YYSTYPE const * const yyvaluep; #endif { if (yytype < YYNTOKENS) YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); else YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) #else static void yy_stack_print (yybottom, yytop) yytype_int16 *yybottom; yytype_int16 *yytop; #endif { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (YYID (0)) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yy_reduce_print (YYSTYPE *yyvsp, int yyrule) #else static void yy_reduce_print (yyvsp, yyrule) YYSTYPE *yyvsp; int yyrule; #endif { int yynrhs = yyr2[yyrule]; int yyi; unsigned long int yylno = yyrline[yyrule]; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyvsp, Rule); \ } while (YYID (0)) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static YYSIZE_T yystrlen (const char *yystr) #else static YYSIZE_T yystrlen (yystr) const char *yystr; #endif { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static char * yystpcpy (char *yydest, const char *yysrc) #else static char * yystpcpy (yydest, yysrc) char *yydest; const char *yysrc; #endif { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into YYRESULT an error message about the unexpected token YYCHAR while in state YYSTATE. Return the number of bytes copied, including the terminating null byte. If YYRESULT is null, do not copy anything; just return the number of bytes that would be copied. As a special case, return 0 if an ordinary "syntax error" message will do. Return YYSIZE_MAXIMUM if overflow occurs during size calculation. */ static YYSIZE_T yysyntax_error (char *yyresult, int yystate, int yychar) { int yyn = yypact[yystate]; if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) return 0; else { int yytype = YYTRANSLATE (yychar); YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); YYSIZE_T yysize = yysize0; YYSIZE_T yysize1; int yysize_overflow = 0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; int yyx; # if 0 /* This is so xgettext sees the translatable formats that are constructed on the fly. */ YY_("syntax error, unexpected %s"); YY_("syntax error, unexpected %s, expecting %s"); YY_("syntax error, unexpected %s, expecting %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s"); YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); # endif char *yyfmt; char const *yyf; static char const yyunexpected[] = "syntax error, unexpected %s"; static char const yyexpecting[] = ", expecting %s"; static char const yyor[] = " or %s"; char yyformat[sizeof yyunexpected + sizeof yyexpecting - 1 + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) * (sizeof yyor - 1))]; char const *yyprefix = yyexpecting; /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yycount = 1; yyarg[0] = yytname[yytype]; yyfmt = yystpcpy (yyformat, yyunexpected); for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; yyformat[sizeof yyunexpected - 1] = '\0'; break; } yyarg[yycount++] = yytname[yyx]; yysize1 = yysize + yytnamerr (0, yytname[yyx]); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; yyfmt = yystpcpy (yyfmt, yyprefix); yyprefix = yyor; } yyf = YY_(yyformat); yysize1 = yysize + yystrlen (yyf); yysize_overflow |= (yysize1 < yysize); yysize = yysize1; if (yysize_overflow) return YYSIZE_MAXIMUM; if (yyresult) { /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ char *yyp = yyresult; int yyi = 0; while ((*yyp = *yyf) != '\0') { if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyf += 2; } else { yyp++; yyf++; } } } return yysize; } } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ /*ARGSUSED*/ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) #else static void yydestruct (yymsg, yytype, yyvaluep) const char *yymsg; int yytype; YYSTYPE *yyvaluep; #endif { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); switch (yytype) { default: break; } } /* Prevent warnings from -Wmissing-prototypes. */ #ifdef YYPARSE_PARAM #if defined __STDC__ || defined __cplusplus int yyparse (void *YYPARSE_PARAM); #else int yyparse (); #endif #else /* ! YYPARSE_PARAM */ #if defined __STDC__ || defined __cplusplus int yyparse (void); #else int yyparse (); #endif #endif /* ! YYPARSE_PARAM */ /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*-------------------------. | yyparse or yypush_parse. | `-------------------------*/ #ifdef YYPARSE_PARAM #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void *YYPARSE_PARAM) #else int yyparse (YYPARSE_PARAM) void *YYPARSE_PARAM; #endif #else /* ! YYPARSE_PARAM */ #if (defined __STDC__ || defined __C99__FUNC__ \ || defined __cplusplus || defined _MSC_VER) int yyparse (void) #else int yyparse () #endif #endif { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: `yyss': related to states. `yyvs': related to semantic values. Refer to the stacks thru separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yytoken = 0; yyss = yyssa; yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ /* Initialize stack pointers. Waste one element of value and location stack so that they stay on the same level as the state stack. The wasted elements are never initialized. */ yyssp = yyss; yyvsp = yyvs; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yyn == YYPACT_NINF) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = YYLEX; } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yyn == 0 || yyn == YYTABLE_NINF) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; *++yyvsp = yylval; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: `$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: /* Line 1455 of yacc.c */ #line 40 "lang11d" { gRootParseNode = (PyrParseNode*)(yyvsp[(1) - (1)]); gParserResult = 1; ;} break; case 3: /* Line 1455 of yacc.c */ #line 42 "lang11d" { gRootParseNode = (PyrParseNode*)(yyvsp[(1) - (1)]); gParserResult = 1; ;} break; case 4: /* Line 1455 of yacc.c */ #line 44 "lang11d" { gRootParseNode = (PyrParseNode*)(yyvsp[(2) - (2)]); gParserResult = 2; ;} break; case 5: /* Line 1455 of yacc.c */ #line 47 "lang11d" { (yyval) = 0; ;} break; case 6: /* Line 1455 of yacc.c */ #line 49 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 8: /* Line 1455 of yacc.c */ #line 54 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 9: /* Line 1455 of yacc.c */ #line 58 "lang11d" { (yyval) = (intptr_t)newPyrClassNode((PyrSlotNode*)(yyvsp[(1) - (6)]), (PyrSlotNode*)(yyvsp[(2) - (6)]), (PyrVarListNode*)(yyvsp[(4) - (6)]), (PyrMethodNode*)(yyvsp[(5) - (6)]), 0); ;} break; case 10: /* Line 1455 of yacc.c */ #line 62 "lang11d" { (yyval) = (intptr_t)newPyrClassNode((PyrSlotNode*)(yyvsp[(1) - (9)]), (PyrSlotNode*)(yyvsp[(5) - (9)]), (PyrVarListNode*)(yyvsp[(7) - (9)]), (PyrMethodNode*)(yyvsp[(8) - (9)]), (PyrSlotNode*)(yyvsp[(3) - (9)])); ;} break; case 11: /* Line 1455 of yacc.c */ #line 69 "lang11d" { (yyval) = (intptr_t)newPyrClassExtNode((PyrSlotNode*)(yyvsp[(2) - (5)]), (PyrMethodNode*)(yyvsp[(4) - (5)])); ;} break; case 12: /* Line 1455 of yacc.c */ #line 74 "lang11d" { (yyval) = 0; ;} break; case 14: /* Line 1455 of yacc.c */ #line 78 "lang11d" { (yyval) = 0; ;} break; case 15: /* Line 1455 of yacc.c */ #line 80 "lang11d" { (yyval) = (yyvsp[(2) - (2)]); ;} break; case 16: /* Line 1455 of yacc.c */ #line 83 "lang11d" { (yyval) = 0; ;} break; case 17: /* Line 1455 of yacc.c */ #line 85 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 18: /* Line 1455 of yacc.c */ #line 89 "lang11d" { (yyval) = (intptr_t)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varClass); ;} break; case 19: /* Line 1455 of yacc.c */ #line 91 "lang11d" { (yyval) = (intptr_t)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varInst); ;} break; case 20: /* Line 1455 of yacc.c */ #line 93 "lang11d" { (yyval) = (intptr_t)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varConst); ;} break; case 21: /* Line 1455 of yacc.c */ #line 96 "lang11d" { (yyval) = 0; ;} break; case 22: /* Line 1455 of yacc.c */ #line 98 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 23: /* Line 1455 of yacc.c */ #line 102 "lang11d" { (yyval) = (intptr_t)newPyrMethodNode((PyrSlotNode*)(yyvsp[(1) - (7)]), (PyrSlotNode*)(yyvsp[(5) - (7)]), (PyrArgListNode*)(yyvsp[(3) - (7)]), (PyrVarListNode*)(yyvsp[(4) - (7)]), (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 24: /* Line 1455 of yacc.c */ #line 105 "lang11d" { (yyval) = (intptr_t)newPyrMethodNode((PyrSlotNode*)(yyvsp[(2) - (8)]), (PyrSlotNode*)(yyvsp[(6) - (8)]), (PyrArgListNode*)(yyvsp[(4) - (8)]), (PyrVarListNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(7) - (8)]), 1); ;} break; case 25: /* Line 1455 of yacc.c */ #line 108 "lang11d" { (yyval) = (intptr_t)newPyrMethodNode((PyrSlotNode*)(yyvsp[(1) - (7)]), (PyrSlotNode*)(yyvsp[(5) - (7)]), (PyrArgListNode*)(yyvsp[(3) - (7)]), (PyrVarListNode*)(yyvsp[(4) - (7)]), (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 26: /* Line 1455 of yacc.c */ #line 111 "lang11d" { (yyval) = (intptr_t)newPyrMethodNode((PyrSlotNode*)(yyvsp[(2) - (8)]), (PyrSlotNode*)(yyvsp[(6) - (8)]), (PyrArgListNode*)(yyvsp[(4) - (8)]), (PyrVarListNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(7) - (8)]), 1); ;} break; case 34: /* Line 1455 of yacc.c */ #line 129 "lang11d" { (yyval) = (intptr_t)newPyrDropNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 35: /* Line 1455 of yacc.c */ #line 133 "lang11d" { (yyval) = (intptr_t)newPyrBlockNode(NULL, (PyrVarListNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)]), false); ;} break; case 36: /* Line 1455 of yacc.c */ #line 135 "lang11d" { (yyval) = (intptr_t)newPyrBlockNode(NULL, (PyrVarListNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)]), false); ;} break; case 37: /* Line 1455 of yacc.c */ #line 137 "lang11d" { (yyval) = (intptr_t)newPyrBlockNode(NULL, NULL, (PyrParseNode*)(yyvsp[(1) - (1)]), false); ;} break; case 39: /* Line 1455 of yacc.c */ #line 142 "lang11d" { (yyval) = (intptr_t)newPyrDropNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 40: /* Line 1455 of yacc.c */ #line 145 "lang11d" { (yyval) = 0; ;} break; case 41: /* Line 1455 of yacc.c */ #line 147 "lang11d" { (yyval) = (yyvsp[(1) - (2)]); ;} break; case 42: /* Line 1455 of yacc.c */ #line 151 "lang11d" { (yyval) = (intptr_t)newPyrReturnNode(NULL); ;} break; case 43: /* Line 1455 of yacc.c */ #line 153 "lang11d" { (yyval) = (intptr_t)newPyrReturnNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 44: /* Line 1455 of yacc.c */ #line 157 "lang11d" { (yyval) = (intptr_t)newPyrBlockReturnNode(); ;} break; case 45: /* Line 1455 of yacc.c */ #line 159 "lang11d" { (yyval) = (intptr_t)newPyrReturnNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 47: /* Line 1455 of yacc.c */ #line 164 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 50: /* Line 1455 of yacc.c */ #line 173 "lang11d" { (yyval) = 0; ;} break; case 52: /* Line 1455 of yacc.c */ #line 178 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)]), 0, 0); ;} break; case 53: /* Line 1455 of yacc.c */ #line 182 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), 0, 0); ;} break; case 54: /* Line 1455 of yacc.c */ #line 186 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(1) - (4)]), NULL, NULL, (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 55: /* Line 1455 of yacc.c */ #line 190 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(3) - (6)]), (PyrParseNode*)(yyvsp[(4) - (6)]), (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 56: /* Line 1455 of yacc.c */ #line 195 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(2) - (6)]), NULL, NULL, (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 57: /* Line 1455 of yacc.c */ #line 199 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(2) - (8)]), (PyrParseNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(6) - (8)]), (PyrParseNode*)(yyvsp[(8) - (8)])); ;} break; case 58: /* Line 1455 of yacc.c */ #line 204 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(3) - (5)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(3) - (5)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)(yyvsp[(3) - (5)]), newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (5)]), NULL)); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(4) - (5)]), 0); ;} break; case 59: /* Line 1455 of yacc.c */ #line 222 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_performList); selectornode = newPyrSlotNode(&slot); args = linkAfterHead( (PyrParseNode*)(yyvsp[(5) - (7)]), newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (7)]), NULL)); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 60: /* Line 1455 of yacc.c */ #line 235 "lang11d" { (yyval) = (intptr_t)newPyrDynListNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 61: /* Line 1455 of yacc.c */ #line 237 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (2)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 62: /* Line 1455 of yacc.c */ #line 248 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (4)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, NULL, (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 63: /* Line 1455 of yacc.c */ #line 259 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (6)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(3) - (6)]), (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 64: /* Line 1455 of yacc.c */ #line 270 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_new); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (6)])), (PyrParseNode*)(yyvsp[(3) - (6)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(4) - (6)]), (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 65: /* Line 1455 of yacc.c */ #line 283 "lang11d" { PyrSlotNode *selectornode, *selectornode2; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(1) - (5)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(1) - (5)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_new); selectornode = newPyrSlotNode(&slot); selectornode2 = newPyrSlotNode(&slot2); args = linkNextNode( (PyrParseNode*)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (5)])), newPyrPushLitNode(selectornode2, NULL)); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(3) - (5)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(5) - (5)]), 0); ;} break; case 66: /* Line 1455 of yacc.c */ #line 304 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); (yyval) = (intptr_t)newPyrCallNode(selectornode, (PyrParseNode*)(yyvsp[(1) - (5)]), NULL, (PyrParseNode*)(yyvsp[(5) - (5)])); ;} break; case 67: /* Line 1455 of yacc.c */ #line 313 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); (yyval) = (intptr_t)newPyrCallNode(selectornode, (PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)]), (PyrParseNode*)(yyvsp[(7) - (7)])); ;} break; case 68: /* Line 1455 of yacc.c */ #line 322 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (8)]), (PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(5) - (8)]), (PyrParseNode*)(yyvsp[(8) - (8)])); ;} break; case 69: /* Line 1455 of yacc.c */ #line 327 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(5) - (7)]), (PyrParseNode*)(yyvsp[(7) - (7)])); ;} break; case 70: /* Line 1455 of yacc.c */ #line 340 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot, slot2; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(1) - (6)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(1) - (6)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } SetSymbol(&slot2, s_value); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (6)]), newPyrPushLitNode(newPyrSlotNode(&slot2), NULL)); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(4) - (6)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(5) - (6)]), 0); ;} break; case 71: /* Line 1455 of yacc.c */ #line 360 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (6)]), (PyrParseNode*)(yyvsp[(1) - (6)]), NULL, (PyrParseNode*)(yyvsp[(6) - (6)])); ;} break; case 72: /* Line 1455 of yacc.c */ #line 364 "lang11d" { PyrParseNode* args; args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(5) - (8)])); (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (8)]), args, (PyrParseNode*)(yyvsp[(6) - (8)]), (PyrParseNode*)(yyvsp[(8) - (8)])); ;} break; case 73: /* Line 1455 of yacc.c */ #line 370 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; if (isSuperObjNode((PyrParseNode*)(yyvsp[(1) - (7)]))) { SetRaw(&((PyrPushNameNode*)(yyvsp[(1) - (7)]))->mSlot, s_this); SetSymbol(&slot, s_superPerformList); } else { SetSymbol(&slot, s_performList); } selectornode = newPyrSlotNode(&slot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), newPyrPushLitNode((PyrSlotNode*)(yyvsp[(3) - (7)]), NULL)); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (7)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, (PyrParseNode*)(yyvsp[(6) - (7)]), 0); ;} break; case 74: /* Line 1455 of yacc.c */ #line 388 "lang11d" { (yyval) = (intptr_t)newPyrCallNode((PyrSlotNode*)(yyvsp[(3) - (4)]), (PyrParseNode*)(yyvsp[(1) - (4)]), 0, (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 75: /* Line 1455 of yacc.c */ #line 393 "lang11d" { pushls(&generatorStack, (yyvsp[(3) - (3)])); pushls(&generatorStack, 1); ;} break; case 76: /* Line 1455 of yacc.c */ #line 394 "lang11d" { PyrSlot slot; SetSymbol(&slot, getsym("r")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)(yyvsp[(6) - (7)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); (yyval) = (intptr_t)newPyrCallNode(selectornode, (PyrParseNode*)blocklit, 0, 0); ;} break; case 77: /* Line 1455 of yacc.c */ #line 403 "lang11d" { pushls(&generatorStack, (yyvsp[(3) - (3)])); pushls(&generatorStack, 2); ;} break; case 78: /* Line 1455 of yacc.c */ #line 404 "lang11d" { (yyval) = (yyvsp[(6) - (7)]); ;} break; case 79: /* Line 1455 of yacc.c */ #line 410 "lang11d" { // innermost part int action = popls(&generatorStack); PyrParseNode* expr = (PyrParseNode*)popls(&generatorStack); switch (action) { case 1 : { PyrSlot slot; SetSymbol(&slot, getsym("yield")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); (yyval) = (intptr_t)newPyrCallNode(selectornode, expr, 0, 0); } break; case 2 : { (yyval) = (intptr_t)expr; } break; } ;} break; case 80: /* Line 1455 of yacc.c */ #line 432 "lang11d" { (yyval) = (yyvsp[(2) - (2)]); ;} break; case 81: /* Line 1455 of yacc.c */ #line 436 "lang11d" { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)(yyvsp[(3) - (4)]); if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (4)]), NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(4) - (4)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); (yyval) = (intptr_t)callnode; } else goto notoptimized1; } else { notoptimized1: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (4)]), NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(4) - (4)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); (yyval) = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); } ;} break; case 82: /* Line 1455 of yacc.c */ #line 470 "lang11d" { // later should check if exprseq is a series and optimize it to for loop PyrParseNode *exprseq = (PyrParseNode*)(yyvsp[(4) - (5)]); if (exprseq->mClassno == pn_CallNode) { PyrCallNode *callnode = (PyrCallNode*)exprseq; if (slotRawSymbol(&callnode->mSelector->mSlot) == s_series) { SetSymbol(&callnode->mSelector->mSlot, getsym("forSeries")); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (5)]), NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (5)]), NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(5) - (5)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); callnode->mArglist = linkNextNode(callnode->mArglist, blocklit); (yyval) = (intptr_t)callnode; } else goto notoptimized2; } else { notoptimized2: PyrSlot slot; SetSymbol(&slot, getsym("do")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var1 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (5)]), NULL, 0); PyrVarDefNode* var2 = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (5)]), NULL, 0); PyrVarDefNode* vars = (PyrVarDefNode*)linkNextNode(var1, var2); PyrArgListNode* args = newPyrArgListNode(vars, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(5) - (5)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = linkNextNode(exprseq, blocklit); (yyval) = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); } ;} break; case 83: /* Line 1455 of yacc.c */ #line 508 "lang11d" { PyrSlot slot; SetSymbol(&slot, s_value); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrVarDefNode* var = newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (5)]), NULL, 0); PyrArgListNode* args = newPyrArgListNode(var, NULL); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(args, 0, (PyrParseNode*)(yyvsp[(5) - (5)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode(blocklit, (PyrParseNode*)(yyvsp[(4) - (5)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); ;} break; case 84: /* Line 1455 of yacc.c */ #line 522 "lang11d" { PyrSlot slot; SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode = newPyrSlotNode(&slot); PyrParseNode *block = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)(yyvsp[(2) - (2)]), false); PyrParseNode *blocklit = (PyrParseNode*)newPyrPushLitNode(NULL, block); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), blocklit); (yyval) = (intptr_t)newPyrCallNode(selectornode, args2, 0, 0); ;} break; case 85: /* Line 1455 of yacc.c */ #line 533 "lang11d" { (yyval) = (intptr_t)newPyrDropNode((PyrParseNode*)(yyvsp[(3) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 86: /* Line 1455 of yacc.c */ #line 537 "lang11d" { PyrSlot slot; SetSymbol(&slot, getsym("alwaysYield")); PyrSlotNode* selectornode1 = newPyrSlotNode(&slot); SetSymbol(&slot, getsym("if")); PyrSlotNode* selectornode2 = newPyrSlotNode(&slot); SetNil(&slot); PyrParseNode *pushnil = (PyrParseNode*)newPyrPushLitNode(newPyrSlotNode(&slot), NULL); PyrParseNode *yieldNil = (PyrParseNode*)newPyrCallNode(selectornode1, pushnil, 0, 0); PyrParseNode *block1 = (PyrParseNode*)newPyrBlockNode(0, 0, yieldNil, false); PyrParseNode *blocklit1 = (PyrParseNode*)newPyrPushLitNode(NULL, block1); PyrParseNode *block2 = (PyrParseNode*)newPyrBlockNode(0, 0, (PyrParseNode*)(yyvsp[(4) - (4)]), false); PyrParseNode *blocklit2 = (PyrParseNode*)newPyrPushLitNode(NULL, block2); PyrParseNode* args2 = (PyrParseNode*)linkNextNode((PyrParseNode*)(yyvsp[(3) - (4)]), blocklit2); PyrParseNode* args3 = (PyrParseNode*)linkNextNode(args2, blocklit1); (yyval) = (intptr_t)newPyrCallNode(selectornode2, args3, 0, 0); ;} break; case 93: /* Line 1455 of yacc.c */ #line 568 "lang11d" { PyrParseNode* node = (PyrParseNode*)(yyvsp[(2) - (3)]); node->mParens = 1; (yyval) = (yyvsp[(2) - (3)]); ;} break; case 94: /* Line 1455 of yacc.c */ #line 574 "lang11d" { PyrParseNode* argnode; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL); SetSymbol(&slot, s_envirGet); selectornode = newPyrSlotNode(&slot); (yyval) = (intptr_t)newPyrCallNode(selectornode, argnode, 0, 0); ;} break; case 95: /* Line 1455 of yacc.c */ #line 584 "lang11d" { (yyval) = (intptr_t)newPyrDynListNode(0, (PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 96: /* Line 1455 of yacc.c */ #line 586 "lang11d" { (yyval) = (yyvsp[(2) - (3)]); ;} break; case 97: /* Line 1455 of yacc.c */ #line 588 "lang11d" { (yyval) = (yyvsp[(3) - (4)]); ;} break; case 98: /* Line 1455 of yacc.c */ #line 590 "lang11d" { (yyval) = (intptr_t)newPyrDynDictNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 99: /* Line 1455 of yacc.c */ #line 592 "lang11d" { (yyval) = (intptr_t)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (1)])); ;} break; case 100: /* Line 1455 of yacc.c */ #line 594 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 102: /* Line 1455 of yacc.c */ #line 610 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (5)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (5)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(3) - (5)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 103: /* Line 1455 of yacc.c */ #line 637 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (5)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(4) - (5)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 104: /* Line 1455 of yacc.c */ #line 655 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (6)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (6)])); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(3) - (6)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (6)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 105: /* Line 1455 of yacc.c */ #line 682 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (7)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (7)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(3) - (7)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(7) - (7)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 106: /* Line 1455 of yacc.c */ #line 710 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(4) - (7)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(7) - (7)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 107: /* Line 1455 of yacc.c */ #line 729 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(3) - (8)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (8)])); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(3) - (8)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (8)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(8) - (8)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 108: /* Line 1455 of yacc.c */ #line 757 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (6)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (6)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(4) - (6)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 109: /* Line 1455 of yacc.c */ #line 784 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (6)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (6)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 110: /* Line 1455 of yacc.c */ #line 802 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (7)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (7)])); compileErrors++; } SetSymbol(&selectorSlot, s_copyseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(6) - (7)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 111: /* Line 1455 of yacc.c */ #line 827 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (8)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (8)])); compileErrors++; } SetNil(&nilSlot); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), (PyrParseNode*)(yyvsp[(4) - (8)])); if (arglen < 2) { nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(8) - (8)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 112: /* Line 1455 of yacc.c */ #line 855 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (8)]), nilnode1); args = linkNextNode(args, nilnode2); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (8)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(8) - (8)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 113: /* Line 1455 of yacc.c */ #line 874 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode1; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; int arglen = nodeListLength((PyrParseNode*)(yyvsp[(4) - (9)])); if (arglen > 2) { error("ArrayedCollection subrange has too many arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(3) - (9)])); compileErrors++; } SetSymbol(&selectorSlot, s_putseries); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (9)]), (PyrParseNode*)(yyvsp[(4) - (9)])); if (arglen < 2) { SetNil(&nilSlot); nilnode1 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); args = linkNextNode(args, nilnode1); } args = linkNextNode(args, (PyrParseNode*)(yyvsp[(6) - (9)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(9) - (9)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 114: /* Line 1455 of yacc.c */ #line 902 "lang11d" { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), nilnode); args = linkNextNode(args, nilnode2); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 115: /* Line 1455 of yacc.c */ #line 921 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(2) - (2)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 116: /* Line 1455 of yacc.c */ #line 940 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(3) - (3)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 117: /* Line 1455 of yacc.c */ #line 957 "lang11d" { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(3) - (5)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (5)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 118: /* Line 1455 of yacc.c */ #line 971 "lang11d" { // if this is not used in a 'do' or list comprehension, then should return an error. PyrSlotNode *selectornode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; PyrPushLitNode *nilnode; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, s_series); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); args = linkNextNode(args, nilnode); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 119: /* Line 1455 of yacc.c */ #line 992 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *zeronode; PyrSlot selectorSlot, nilSlot, zeroSlot; PyrParseNode* args; SetInt(&zeroSlot, 0); SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); zeronode = newPyrPushLitNode(newPyrSlotNode(&zeroSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode(zeronode, nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(2) - (2)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 120: /* Line 1455 of yacc.c */ #line 1011 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode, *nilnode2; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); nilnode2 = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), nilnode); args = linkNextNode(args, nilnode2); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 121: /* Line 1455 of yacc.c */ #line 1029 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), nilnode); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(3) - (3)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 122: /* Line 1455 of yacc.c */ #line 1046 "lang11d" { PyrSlotNode *selectornode; PyrPushLitNode *nilnode; PyrSlot selectorSlot, nilSlot; PyrParseNode* args; SetNil(&nilSlot); nilnode = newPyrPushLitNode(newPyrSlotNode(&nilSlot), NULL); SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); args = linkNextNode(args, nilnode); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 123: /* Line 1455 of yacc.c */ #line 1062 "lang11d" { PyrSlotNode *selectornode; PyrSlot selectorSlot; PyrParseNode* args; SetSymbol(&selectorSlot, getsym("seriesIter")); selectornode = newPyrSlotNode(&selectorSlot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(3) - (5)])); args = linkNextNode(args, (PyrParseNode*)(yyvsp[(5) - (5)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 127: /* Line 1455 of yacc.c */ #line 1080 "lang11d" { (yyval) = (intptr_t)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (1)])); ;} break; case 128: /* Line 1455 of yacc.c */ #line 1082 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_at); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 129: /* Line 1455 of yacc.c */ #line 1095 "lang11d" { PyrParseNode *node, *args; PyrSlotNode *slotnode; PyrSlot slot; SetSymbol(&slot, s_ref); slotnode = newPyrSlotNode(&slot); node = (PyrParseNode*)newPyrPushNameNode(slotnode); args = linkNextNode(node, (PyrParseNode*)(yyvsp[(2) - (2)])); SetSymbol(&slot, s_new); slotnode = newPyrSlotNode(&slot); (yyval) = (intptr_t)newPyrCallNode(slotnode, args, 0, 0); ;} break; case 130: /* Line 1455 of yacc.c */ #line 1109 "lang11d" { (yyval) = (intptr_t)newPyrBinopCallNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 131: /* Line 1455 of yacc.c */ #line 1114 "lang11d" { (yyval) = (intptr_t)newPyrAssignNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)]), 0); ;} break; case 132: /* Line 1455 of yacc.c */ #line 1118 "lang11d" { PyrParseNode *argnode, *args; PyrSlotNode* selectornode; PyrSlot slot; argnode = (PyrParseNode*)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (4)]), NULL); args = linkNextNode(argnode, (PyrParseNode*)(yyvsp[(4) - (4)])); SetSymbol(&slot, s_envirPut); selectornode = newPyrSlotNode(&slot); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 133: /* Line 1455 of yacc.c */ #line 1129 "lang11d" { (yyval) = (intptr_t)newPyrSetterNode((PyrSlotNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(1) - (5)]), (PyrParseNode*)(yyvsp[(5) - (5)])); ;} break; case 134: /* Line 1455 of yacc.c */ #line 1134 "lang11d" { if ((yyvsp[(4) - (7)]) != 0) { error("Setter method called with keyword arguments.\n"); nodePostErrorLine((PyrParseNode*)(yyvsp[(4) - (7)])); compileErrors++; } (yyval) = (intptr_t)newPyrSetterNode((PyrSlotNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(3) - (7)]), (PyrParseNode*)(yyvsp[(7) - (7)])); ;} break; case 135: /* Line 1455 of yacc.c */ #line 1144 "lang11d" { (yyval) = (intptr_t)newPyrMultiAssignNode((PyrMultiAssignVarListNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), 0); ;} break; case 136: /* Line 1455 of yacc.c */ #line 1149 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (6)]), (PyrParseNode*)(yyvsp[(3) - (6)])); args = linkNextNode( args, (PyrParseNode*)(yyvsp[(6) - (6)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 137: /* Line 1455 of yacc.c */ #line 1163 "lang11d" { PyrSlotNode *selectornode; PyrSlot slot; PyrParseNode* args; SetSymbol(&slot, s_put); selectornode = newPyrSlotNode(&slot); args = linkNextNode( (PyrParseNode*)(yyvsp[(1) - (7)]), (PyrParseNode*)(yyvsp[(4) - (7)])); args = linkNextNode( args, (PyrParseNode*)(yyvsp[(7) - (7)])); (yyval) = (intptr_t)newPyrCallNode(selectornode, args, 0, 0); ;} break; case 138: /* Line 1455 of yacc.c */ #line 1178 "lang11d" { (yyval) = 0; ;} break; case 139: /* Line 1455 of yacc.c */ #line 1179 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL); ;} break; case 140: /* Line 1455 of yacc.c */ #line 1180 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL); ;} break; case 141: /* Line 1455 of yacc.c */ #line 1181 "lang11d" { (yyval) = (yyvsp[(3) - (4)]); ;} break; case 143: /* Line 1455 of yacc.c */ #line 1186 "lang11d" { (yyval) = (intptr_t)newPyrDropNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 145: /* Line 1455 of yacc.c */ #line 1194 "lang11d" { (yyval) = 0; ;} break; case 146: /* Line 1455 of yacc.c */ #line 1196 "lang11d" { (yyval) = (yyvsp[(1) - (2)]); ;} break; case 148: /* Line 1455 of yacc.c */ #line 1201 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 149: /* Line 1455 of yacc.c */ #line 1203 "lang11d" { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (2)]), NULL); (yyval) = (intptr_t)linkNextNode(key, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 150: /* Line 1455 of yacc.c */ #line 1208 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 151: /* Line 1455 of yacc.c */ #line 1210 "lang11d" { PyrParseNode* elems; PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(3) - (4)]), NULL); elems = (PyrParseNode*)linkNextNode(key, (PyrParseNode*)(yyvsp[(4) - (4)])); (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (4)]), elems); ;} break; case 152: /* Line 1455 of yacc.c */ #line 1217 "lang11d" { PyrParseNode* elems; elems = (PyrParseNode*)linkNextNode((PyrParseNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(5) - (5)])); (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (5)]), elems); ;} break; case 154: /* Line 1455 of yacc.c */ #line 1226 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 155: /* Line 1455 of yacc.c */ #line 1230 "lang11d" { (yyval) = (yyvsp[(2) - (2)]); ;} break; case 156: /* Line 1455 of yacc.c */ #line 1232 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)])); ;} break; case 158: /* Line 1455 of yacc.c */ #line 1237 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 159: /* Line 1455 of yacc.c */ #line 1241 "lang11d" { (yyval) = (intptr_t)newPyrPushKeyArgNode((PyrSlotNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 160: /* Line 1455 of yacc.c */ #line 1244 "lang11d" { (yyval) = 0; ;} break; case 161: /* Line 1455 of yacc.c */ #line 1245 "lang11d" { (yyval) = (yyvsp[(2) - (3)]); ;} break; case 162: /* Line 1455 of yacc.c */ #line 1249 "lang11d" { (yyval) = (intptr_t)newPyrMultiAssignVarListNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 163: /* Line 1455 of yacc.c */ #line 1251 "lang11d" { (yyval) = (intptr_t)newPyrMultiAssignVarListNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrSlotNode*)(yyvsp[(3) - (3)])); ;} break; case 165: /* Line 1455 of yacc.c */ #line 1256 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 166: /* Line 1455 of yacc.c */ #line 1260 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 167: /* Line 1455 of yacc.c */ #line 1261 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 168: /* Line 1455 of yacc.c */ #line 1262 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 169: /* Line 1455 of yacc.c */ #line 1263 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 170: /* Line 1455 of yacc.c */ #line 1264 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 171: /* Line 1455 of yacc.c */ #line 1265 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 172: /* Line 1455 of yacc.c */ #line 1266 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 173: /* Line 1455 of yacc.c */ #line 1267 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 174: /* Line 1455 of yacc.c */ #line 1268 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 175: /* Line 1455 of yacc.c */ #line 1271 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 176: /* Line 1455 of yacc.c */ #line 1274 "lang11d" { (yyval) = (intptr_t)newPyrPushNameNode((PyrSlotNode*)(yyvsp[(1) - (1)])); ;} break; case 177: /* Line 1455 of yacc.c */ #line 1277 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 178: /* Line 1455 of yacc.c */ #line 1278 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 179: /* Line 1455 of yacc.c */ #line 1279 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 180: /* Line 1455 of yacc.c */ #line 1280 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 181: /* Line 1455 of yacc.c */ #line 1281 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 182: /* Line 1455 of yacc.c */ #line 1282 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 183: /* Line 1455 of yacc.c */ #line 1283 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 184: /* Line 1455 of yacc.c */ #line 1284 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 185: /* Line 1455 of yacc.c */ #line 1285 "lang11d" { (yyval) = (intptr_t)newPyrPushLitNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 186: /* Line 1455 of yacc.c */ #line 1288 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 187: /* Line 1455 of yacc.c */ #line 1289 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 188: /* Line 1455 of yacc.c */ #line 1290 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 189: /* Line 1455 of yacc.c */ #line 1291 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 190: /* Line 1455 of yacc.c */ #line 1292 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 191: /* Line 1455 of yacc.c */ #line 1293 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 192: /* Line 1455 of yacc.c */ #line 1294 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 193: /* Line 1455 of yacc.c */ #line 1295 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 194: /* Line 1455 of yacc.c */ #line 1296 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL); ;} break; case 195: /* Line 1455 of yacc.c */ #line 1297 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 196: /* Line 1455 of yacc.c */ #line 1298 "lang11d" { (yyval) = (intptr_t)newPyrLiteralNode(NULL, (PyrParseNode*)(yyvsp[(1) - (1)])); ;} break; case 197: /* Line 1455 of yacc.c */ #line 1302 "lang11d" { (yyval) = (intptr_t)newPyrBlockNode((PyrArgListNode*)(yyvsp[(2) - (5)]), (PyrVarListNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)]), false); ;} break; case 198: /* Line 1455 of yacc.c */ #line 1305 "lang11d" { (yyval) = (intptr_t)newPyrBlockNode((PyrArgListNode*)(yyvsp[(2) - (5)]), (PyrVarListNode*)(yyvsp[(3) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)]), true); ;} break; case 199: /* Line 1455 of yacc.c */ #line 1309 "lang11d" { (yyval) = 0; ;} break; case 200: /* Line 1455 of yacc.c */ #line 1311 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 202: /* Line 1455 of yacc.c */ #line 1316 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (2)]), (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 203: /* Line 1455 of yacc.c */ #line 1320 "lang11d" { (yyval) = (intptr_t)newPyrVarListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), varLocal); ;} break; case 204: /* Line 1455 of yacc.c */ #line 1323 "lang11d" { (yyval) = 0; ;} break; case 205: /* Line 1455 of yacc.c */ #line 1325 "lang11d" { (yyval) = (intptr_t)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), NULL); ;} break; case 206: /* Line 1455 of yacc.c */ #line 1329 "lang11d" { (yyval) = (intptr_t)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (5)]), (PyrSlotNode*)(yyvsp[(4) - (5)])); ;} break; case 207: /* Line 1455 of yacc.c */ #line 1333 "lang11d" { (yyval) = (intptr_t)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (3)]), NULL); ;} break; case 208: /* Line 1455 of yacc.c */ #line 1337 "lang11d" { (yyval) = (intptr_t)newPyrArgListNode((PyrVarDefNode*)(yyvsp[(2) - (5)]), (PyrSlotNode*)(yyvsp[(4) - (5)])); ;} break; case 210: /* Line 1455 of yacc.c */ #line 1344 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 211: /* Line 1455 of yacc.c */ #line 1348 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), (yyvsp[(1) - (4)])); ;} break; case 212: /* Line 1455 of yacc.c */ #line 1351 "lang11d" { (yyval) = 0; ;} break; case 215: /* Line 1455 of yacc.c */ #line 1357 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 216: /* Line 1455 of yacc.c */ #line 1361 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL, 0); ;} break; case 217: /* Line 1455 of yacc.c */ #line 1363 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)]), 0); ;} break; case 218: /* Line 1455 of yacc.c */ #line 1365 "lang11d" { PyrParseNode* node = (PyrParseNode*)(yyvsp[(4) - (5)]); node->mParens = 1; (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (5)]), node, 0); ;} break; case 219: /* Line 1455 of yacc.c */ #line 1372 "lang11d" { (yyval) = 0; ;} break; case 222: /* Line 1455 of yacc.c */ #line 1378 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 223: /* Line 1455 of yacc.c */ #line 1382 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (1)]), NULL, 0); ;} break; case 224: /* Line 1455 of yacc.c */ #line 1384 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)]), 0); ;} break; case 225: /* Line 1455 of yacc.c */ #line 1386 "lang11d" { PyrParseNode* node = (PyrParseNode*)(yyvsp[(3) - (4)]); node->mParens = 1; (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(1) - (4)]), node, 0); ;} break; case 226: /* Line 1455 of yacc.c */ #line 1394 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 227: /* Line 1455 of yacc.c */ #line 1396 "lang11d" { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (2)]), NULL); (yyval) = (intptr_t)linkNextNode(key, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 229: /* Line 1455 of yacc.c */ #line 1404 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 230: /* Line 1455 of yacc.c */ #line 1407 "lang11d" { (yyval) = 0; ;} break; case 233: /* Line 1455 of yacc.c */ #line 1413 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 234: /* Line 1455 of yacc.c */ #line 1417 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)])); ;} break; case 235: /* Line 1455 of yacc.c */ #line 1419 "lang11d" { (yyval) = (intptr_t)newPyrVarDefNode((PyrSlotNode*)(yyvsp[(2) - (4)]), (PyrParseNode*)(yyvsp[(4) - (4)]), (yyvsp[(1) - (4)])); ;} break; case 236: /* Line 1455 of yacc.c */ #line 1423 "lang11d" { (yyval) = (intptr_t)newPyrLitDictNode((PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 237: /* Line 1455 of yacc.c */ #line 1427 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 238: /* Line 1455 of yacc.c */ #line 1429 "lang11d" { PyrParseNode* key = newPyrPushLitNode((PyrSlotNode*)(yyvsp[(1) - (2)]), NULL); (yyval) = (intptr_t)linkNextNode(key, (PyrParseNode*)(yyvsp[(2) - (2)])); ;} break; case 240: /* Line 1455 of yacc.c */ #line 1437 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 241: /* Line 1455 of yacc.c */ #line 1440 "lang11d" { (yyval) = 0; ;} break; case 243: /* Line 1455 of yacc.c */ #line 1447 "lang11d" { (yyval) = (intptr_t)newPyrLitListNode(0, (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 244: /* Line 1455 of yacc.c */ #line 1449 "lang11d" { (yyval) = (intptr_t)newPyrLitListNode((PyrParseNode*)(yyvsp[(2) - (5)]), (PyrParseNode*)(yyvsp[(4) - (5)])); ;} break; case 245: /* Line 1455 of yacc.c */ #line 1453 "lang11d" { (yyval) = (intptr_t)newPyrLitListNode(0, (PyrParseNode*)(yyvsp[(2) - (3)])); ;} break; case 246: /* Line 1455 of yacc.c */ #line 1455 "lang11d" { (yyval) = (intptr_t)newPyrLitListNode((PyrParseNode*)(yyvsp[(1) - (4)]), (PyrParseNode*)(yyvsp[(3) - (4)])); ;} break; case 247: /* Line 1455 of yacc.c */ #line 1458 "lang11d" { (yyval) = 0; ;} break; case 250: /* Line 1455 of yacc.c */ #line 1464 "lang11d" { (yyval) = (intptr_t)linkNextNode((PyrParseNode*)(yyvsp[(1) - (3)]), (PyrParseNode*)(yyvsp[(3) - (3)])); ;} break; case 251: /* Line 1455 of yacc.c */ #line 1467 "lang11d" { (yyval) = rwPrivate; ;} break; case 252: /* Line 1455 of yacc.c */ #line 1469 "lang11d" { (yyval) = rwReadOnly; ;} break; case 253: /* Line 1455 of yacc.c */ #line 1471 "lang11d" { (yyval) = rwReadWrite; ;} break; case 254: /* Line 1455 of yacc.c */ #line 1473 "lang11d" { (yyval) = rwWriteOnly; ;} break; case 255: /* Line 1455 of yacc.c */ #line 1476 "lang11d" { (yyval) = rwPrivate; ;} break; case 256: /* Line 1455 of yacc.c */ #line 1478 "lang11d" { (yyval) = rwReadOnly; ;} break; case 257: /* Line 1455 of yacc.c */ #line 1481 "lang11d" { (yyval) = zzval; ;} break; case 258: /* Line 1455 of yacc.c */ #line 1483 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawInt(&node->mSlot)); (yyval) = zzval; ;} break; case 259: /* Line 1455 of yacc.c */ #line 1491 "lang11d" { (yyval) = zzval; ;} break; case 260: /* Line 1455 of yacc.c */ #line 1493 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetRaw(&node->mSlot, -slotRawFloat(&node->mSlot)); (yyval) = zzval; ;} break; case 261: /* Line 1455 of yacc.c */ #line 1501 "lang11d" { (yyval) = zzval; ;} break; case 262: /* Line 1455 of yacc.c */ #line 1503 "lang11d" { PyrSlotNode *node; double intval, fracval; node = (PyrSlotNode*)zzval; intval = floor(slotRawFloat(&node->mSlot) + 0.5); fracval = slotRawFloat(&node->mSlot) - intval; SetRaw(&node->mSlot, -intval + fracval); (yyval) = zzval; ;} break; case 263: /* Line 1455 of yacc.c */ #line 1513 "lang11d" { (yyval) = zzval; ;} break; case 266: /* Line 1455 of yacc.c */ #line 1519 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)(yyvsp[(1) - (2)]); SetRaw(&node->mSlot, slotRawFloat(&node->mSlot) * pi); ;} break; case 267: /* Line 1455 of yacc.c */ #line 1525 "lang11d" { PyrSlotNode *node; double ival; node = (PyrSlotNode*)(yyvsp[(1) - (2)]); ival = slotRawInt(&node->mSlot); SetFloat(&node->mSlot, ival * pi); ;} break; case 268: /* Line 1455 of yacc.c */ #line 1533 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, pi); (yyval) = zzval; ;} break; case 269: /* Line 1455 of yacc.c */ #line 1540 "lang11d" { PyrSlotNode *node; node = (PyrSlotNode*)zzval; SetFloat(&node->mSlot, -pi); (yyval) = zzval; ;} break; case 270: /* Line 1455 of yacc.c */ #line 1548 "lang11d" { (yyval) = zzval; ;} break; case 271: /* Line 1455 of yacc.c */ #line 1549 "lang11d" { (yyval) = zzval; ;} break; case 272: /* Line 1455 of yacc.c */ #line 1552 "lang11d" { (yyval) = zzval; ;} break; case 273: /* Line 1455 of yacc.c */ #line 1555 "lang11d" { (yyval) = zzval; ;} break; case 274: /* Line 1455 of yacc.c */ #line 1558 "lang11d" { (yyval) = zzval; ;} break; case 275: /* Line 1455 of yacc.c */ #line 1561 "lang11d" { (yyval) = zzval; ;} break; case 276: /* Line 1455 of yacc.c */ #line 1564 "lang11d" { (yyval) = zzval; ;} break; case 277: /* Line 1455 of yacc.c */ #line 1567 "lang11d" { (yyval) = zzval; ;} break; case 278: /* Line 1455 of yacc.c */ #line 1570 "lang11d" { (yyval) = zzval; ;} break; case 279: /* Line 1455 of yacc.c */ #line 1573 "lang11d" { (yyval) = zzval; ;} break; case 280: /* Line 1455 of yacc.c */ #line 1576 "lang11d" { (yyval) = zzval; ;} break; case 281: /* Line 1455 of yacc.c */ #line 1579 "lang11d" { (yyval) = zzval; ;} break; case 282: /* Line 1455 of yacc.c */ #line 1580 "lang11d" { (yyval) = zzval; ;} break; case 283: /* Line 1455 of yacc.c */ #line 1581 "lang11d" { (yyval) = zzval; ;} break; case 284: /* Line 1455 of yacc.c */ #line 1582 "lang11d" { (yyval) = zzval; ;} break; case 285: /* Line 1455 of yacc.c */ #line 1583 "lang11d" { (yyval) = zzval; ;} break; case 286: /* Line 1455 of yacc.c */ #line 1584 "lang11d" { (yyval) = zzval; ;} break; case 287: /* Line 1455 of yacc.c */ #line 1585 "lang11d" { (yyval) = zzval; ;} break; case 288: /* Line 1455 of yacc.c */ #line 1586 "lang11d" { (yyval) = zzval; ;} break; case 289: /* Line 1455 of yacc.c */ #line 1589 "lang11d" { (yyval) = zzval; ;} break; case 292: /* Line 1455 of yacc.c */ #line 1596 "lang11d" { (yyval) = zzval; ;} break; /* Line 1455 of yacc.c */ #line 4778 "lang11d_tab.cpp" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now `shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*------------------------------------. | yyerrlab -- here on detecting error | `------------------------------------*/ yyerrlab: /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else { YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) { YYSIZE_T yyalloc = 2 * yysize; if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) yyalloc = YYSTACK_ALLOC_MAXIMUM; if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yyalloc); if (yymsg) yymsg_alloc = yyalloc; else { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; } } if (0 < yysize && yysize <= yymsg_alloc) { (void) yysyntax_error (yymsg, yystate, yychar); yyerror (yymsg); } else { yyerror (YY_("syntax error")); if (yysize != 0) goto yyexhaustedlab; } } #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule which action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (yyn != YYPACT_NINF) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } *++yyvsp = yylval; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined(yyoverflow) || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); /* Do not reclaim the symbols of the rule which action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif /* Make sure YYID is used. */ return YYID (yyresult); } SuperCollider-Source/lang/LangSource/Bison/lang11d_tab.h000644 000765 000024 00000001310 12756531745 024152 0ustar00crucialstaff000000 000000 #ifndef YYSTYPE #define YYSTYPE intptr_t #endif #define NAME 258 #define INTEGER 259 #define SC_FLOAT 260 #define ACCIDENTAL 261 #define SYMBOL 262 #define STRING 263 #define ASCII 264 #define PRIMITIVENAME 265 #define CLASSNAME 266 #define CURRYARG 267 #define VAR 268 #define ARG 269 #define CLASSVAR 270 #define SC_CONST 271 #define NILOBJ 272 #define TRUEOBJ 273 #define FALSEOBJ 274 #define PSEUDOVAR 275 #define ELLIPSIS 276 #define DOTDOT 277 #define PIE 278 #define BEGINCLOSEDFUNC 279 #define BADTOKEN 280 #define INTERPRET 281 #define BEGINGENERATOR 282 #define LEFTARROW 283 #define WHILE 284 #define READWRITEVAR 285 #define KEYBINOP 286 #define BINOP 287 #define UMINUS 288 extern YYSTYPE yylval; SuperCollider-Source/lang/LangSource/Bison/make_parser.sh000755 000765 000024 00000000054 12321461511 024535 0ustar00crucialstaff000000 000000 #!/bin/sh bison -o lang11d_tab.cpp lang11d SuperCollider-Source/lang/LangPrimSource/OSCData.cpp000644 000765 000024 00000107343 12766171707 023440 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrPrimitive.h" #include "PyrKernel.h" #include "PyrInterpreter.h" #include "PyrSched.h" #include "PyrSymbol.h" #include "GC.h" #include #include #include #include #include #include #include "scsynthsend.h" #include "sc_msg_iter.h" #include "SCBase.h" #include "server_shm.hpp" #include "SC_ComPort.h" #include "SC_Endian.h" #include "SC_Lock.h" #include "SC_Msg.h" #include "SC_SndBuf.h" #include "SC_WorldOptions.h" #include #ifndef _WIN32 #include #include #else #include #endif struct InternalSynthServerGlobals { struct World *mWorld; int mNumSharedControls; float *mSharedControls; }; const int kNumDefaultSharedControls = 1024; float gDefaultSharedControls[kNumDefaultSharedControls]; bool gUseDoubles = false; InternalSynthServerGlobals gInternalSynthServer = { 0, kNumDefaultSharedControls, gDefaultSharedControls }; SC_UdpInPort* gUDPport = 0; PyrString* newPyrString(VMGlobals *g, char *s, int flags, bool runGC); PyrSymbol *s_call, *s_write, *s_recvoscmsg, *s_recvoscbndl, *s_netaddr; extern bool compiledOK; std::vector gCustomUdpPorts; /////////// inline bool IsBundle(char* ptr) { return strcmp(ptr, "#bundle") == 0; } /////////// const int ivxNetAddr_Hostaddr = 0; const int ivxNetAddr_PortID = 1; const int ivxNetAddr_Hostname = 2; const int ivxNetAddr_Socket = 3; static int makeSynthMsgWithTags(big_scpacket *packet, PyrSlot *slots, int size); int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed); static int addMsgSlot(big_scpacket *packet, PyrSlot *slot) { switch (GetTag(slot)) { case tagInt : packet->addi(slotRawInt(slot)); break; case tagSym : packet->adds(slotRawSymbol(slot)->name); break; case tagObj : if (isKindOf(slotRawObject(slot), class_string)) { PyrString *stringObj = slotRawString(slot); packet->adds(stringObj->s, stringObj->size); } else if (isKindOf(slotRawObject(slot), class_int8array)) { PyrInt8Array *arrayObj = slotRawInt8Array(slot); packet->addb(arrayObj->b, arrayObj->size); } else if (isKindOf(slotRawObject(slot), class_array)) { PyrObject *arrayObj = slotRawObject(slot); big_scpacket packet2; if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) { makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true); } else { int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size); if (error != errNone) return error; } packet->addb((uint8*)packet2.data(), packet2.size()); } break; case tagNil : case tagTrue : case tagFalse : case tagChar : case tagPtr : break; default : if (gUseDoubles) packet->addd(slotRawFloat(slot)); else packet->addf(slotRawFloat(slot)); break; } return errNone; } static int addMsgSlotWithTags(big_scpacket *packet, PyrSlot *slot) { switch (GetTag(slot)) { case tagInt : packet->addtag('i'); packet->addi(slotRawInt(slot)); break; case tagSym : packet->addtag('s'); packet->adds(slotRawSymbol(slot)->name); break; case tagObj : if (isKindOf(slotRawObject(slot), class_string)) { PyrString *stringObj = slotRawString(slot); packet->addtag('s'); packet->adds(stringObj->s, stringObj->size); } else if (isKindOf(slotRawObject(slot), class_int8array)) { PyrInt8Array *arrayObj = slotRawInt8Array(slot); packet->addtag('b'); packet->addb(arrayObj->b, arrayObj->size); } else if (isKindOf(slotRawObject(slot), class_array)) { PyrObject *arrayObj = slotRawObject(slot); if (arrayObj->size) { packet->addtag('b'); big_scpacket packet2; if (arrayObj->size > 1 && isKindOfSlot(arrayObj->slots+1, class_array)) { makeSynthBundle(&packet2, arrayObj->slots, arrayObj->size, true); } else { int error = makeSynthMsgWithTags(&packet2, arrayObj->slots, arrayObj->size); if (error != errNone) return error; } packet->addb((uint8*)packet2.data(), packet2.size()); } else { packet->addtag('i'); packet->addi(0); } } break; case tagTrue : packet->addtag('i'); packet->addi(1); break; case tagChar : packet->addtag(slotRawChar(slot)); break; case tagFalse : case tagNil : case tagPtr : packet->addtag('i'); packet->addi(0); break; default : if (gUseDoubles) { packet->addtag('d'); packet->addd(slotRawFloat(slot)); } else { packet->addtag('f'); packet->addf(slotRawFloat(slot)); } break; } return errNone; } static int makeSynthMsgWithTags(big_scpacket *packet, PyrSlot *slots, int size) { packet->BeginMsg(); // First component: OSC Address Pattern. // For convenience, we allow the user to omit the initial '/', when // expressing it as a symbol (e.g. \g_new) - we add it back on here, for OSC compliance. if(GetTag(slots) == tagSym && slotRawSymbol(slots)->name[0]!='/'){ packet->adds_slpre(slotRawSymbol(slots)->name); } else { int error = addMsgSlot(packet, slots); if (error != errNone) return error; } // skip space for tags packet->maketags(size); packet->addtag(','); try { for (int i=1; iEndMsg(); return errNone; } void PerformOSCBundle(int inSize, char *inData, PyrObject *inReply, int inPortNum); void PerformOSCMessage(int inSize, char *inData, PyrObject *inReply, int inPortNum, double time); static PyrObject* ConvertReplyAddress(ReplyAddress *inReply); static void localServerReplyFunc(struct ReplyAddress *inReplyAddr, char* inBuf, int inSize) { double timeReceived = elapsedTime(); bool isBundle = IsBundle(inBuf); gLangMutex.lock(); if (compiledOK) { PyrObject *replyObj = ConvertReplyAddress(inReplyAddr); if (isBundle) { PerformOSCBundle(inSize, inBuf, replyObj, gUDPport->RealPortNum()); } else { PerformOSCMessage(inSize, inBuf, replyObj, gUDPport->RealPortNum(), timeReceived); } } gLangMutex.unlock(); } int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed) { double time; int err; int64 oscTime; err = slotDoubleVal(slots, &time); if (!err) { if (useElapsed) { oscTime = ElapsedTimeToOSC(time); } else { oscTime = (int64)(time * kSecondsToOSC); } } else { oscTime = 1; // immediate } packet->OpenBundle(oscTime); for (int i=1; islots, obj->size); if (error != errNone) return error; } } packet->CloseBundle(); return errNone; } static int netAddrSend(PyrObject *netAddrObj, int msglen, char *bufptr, bool sendMsgLen = true) { using namespace boost::asio; if (IsPtr(netAddrObj->slots + ivxNetAddr_Socket)) { SC_TcpClientPort* comPort = (SC_TcpClientPort*)slotRawPtr(netAddrObj->slots + ivxNetAddr_Socket); // send TCP ip::tcp::socket & socket = comPort->Socket(); boost::system::error_code errc; if (sendMsgLen) { // send length of message in network byte-order int32 sizebuf = sc_htonl(msglen); write( socket, buffer(&sizebuf, sizeof(int32)), errc ); } if (!errc) write( socket, buffer(bufptr, msglen), errc ); if (errc) { ::error("Error in netAddrSend: %s\n", errc.message().c_str()); return errFailed; } return errNone; } else { if (gUDPport == 0) return errFailed; // send UDP int addr; int err = slotIntVal(netAddrObj->slots + ivxNetAddr_Hostaddr, &addr); if (err) return err; if (addr == 0) { #ifndef NO_INTERNAL_SERVER if (gInternalSynthServer.mWorld) { World_SendPacket(gInternalSynthServer.mWorld, msglen, bufptr, &localServerReplyFunc); } #endif return errNone; } int port; err = slotIntVal(netAddrObj->slots + ivxNetAddr_PortID, &port); if (err) return err; unsigned long ulAddress = (unsigned int)addr; using namespace boost::asio; ip::udp::endpoint address(ip::address_v4(ulAddress), port); gUDPport->Socket().send_to( buffer(bufptr, msglen), address ); } return errNone; } /////////// inline size_t OSCStrLen(char *str) { return (strlen(str) + 4) & ~3; } int makeSynthBundle(big_scpacket *packet, PyrSlot *slots, int size, bool useElapsed); static void netAddrTcpClientNotifyFunc(void *clientData) { extern bool compiledOK; gLangMutex.lock(); if (compiledOK) { PyrObject* netAddrObj = (PyrObject*)clientData; VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, netAddrObj); runInterpreter(g, getsym("prConnectionClosed"), 1); g->canCallOS = false; } gLangMutex.unlock(); } static int prNetAddr_Connect(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp; PyrObject* netAddrObj = slotRawObject(netAddrSlot); int err, port, addr; err = slotIntVal(netAddrObj->slots + ivxNetAddr_PortID, &port); if (err) return err; err = slotIntVal(netAddrObj->slots + ivxNetAddr_Hostaddr, &addr); if (err) return err; unsigned long ulAddress = (unsigned int)addr; try { SC_TcpClientPort *comPort = new SC_TcpClientPort(ulAddress, port, netAddrTcpClientNotifyFunc, netAddrObj); SetPtr(netAddrObj->slots + ivxNetAddr_Socket, comPort); } catch (std::exception const & e) { printf("NetAddr-Connect failed with exception: %s\n", e.what()); return errFailed; } return errNone; } static int prNetAddr_Disconnect(VMGlobals *g, int numArgsPushed) { int err; PyrSlot* netAddrSlot = g->sp; PyrObject* netAddrObj = slotRawObject(netAddrSlot); SC_TcpClientPort *comPort = (SC_TcpClientPort*)slotRawPtr(netAddrObj->slots + ivxNetAddr_Socket); if (comPort) { err = comPort->Close(); SetPtr(netAddrObj->slots + ivxNetAddr_Socket, NULL); } return err; } static int prNetAddr_SendMsg(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp - numArgsPushed + 1; PyrSlot* args = netAddrSlot + 1; big_scpacket packet; int numargs = numArgsPushed - 1; int error = makeSynthMsgWithTags(&packet, args, numargs); if (error != errNone) return error; return netAddrSend(slotRawObject(netAddrSlot), packet.size(), (char*)packet.buf); } static int prNetAddr_SendBundle(VMGlobals *g, int numArgsPushed) { PyrSlot* netAddrSlot = g->sp - numArgsPushed + 1; PyrSlot* args = netAddrSlot + 1; big_scpacket packet; double time; int err = slotDoubleVal(args, &time); if (!err) { time += slotRawFloat(&g->thread->seconds); SetFloat(args, time); } int numargs = numArgsPushed - 1; makeSynthBundle(&packet, args, numargs, true); //for (int i=0; isp - 1; PyrSlot* arraySlot = g->sp; PyrObject* netAddrObj = slotRawObject(netAddrSlot); if (!IsObj(arraySlot) || !isKindOf(slotRawObject(arraySlot), class_rawarray)) { error("sendRaw arg must be a kind of RawArray.\n"); return errWrongType; } PyrObject *array = slotRawObject(arraySlot); char *bufptr = (char*)array->slots; int32 msglen = array->size * gFormatElemSize[array->obj_format]; return netAddrSend(netAddrObj, msglen, bufptr, false); } static int prNetAddr_GetBroadcastFlag(VMGlobals *g, int numArgsPushed) { if (gUDPport == 0) return errFailed; boost::system::error_code ec; boost::asio::socket_base::broadcast option; gUDPport->udpSocket.get_option(option, ec); if (ec) return errFailed; SetBool(g->sp, option.value()); return errNone; } static int prNetAddr_SetBroadcastFlag(VMGlobals *g, int numArgsPushed) { if (gUDPport == 0) return errFailed; boost::system::error_code ec; boost::asio::socket_base::broadcast option(IsTrue(g->sp)); gUDPport->udpSocket.set_option(option, ec); if (ec) return errFailed; return errNone; } static int prNetAddr_BundleSize(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; big_scpacket packet; int numargs = slotRawObject(args)->size; if (numargs < 1) return errFailed; makeSynthBundle(&packet, slotRawObject(args)->slots, numargs, true); SetInt(args, packet.size()); return errNone; } static int prNetAddr_MsgSize(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; big_scpacket packet; int numargs = slotRawObject(args)->size; if (numargs < 1) return errFailed; int error = makeSynthMsgWithTags(&packet, slotRawObject(args)->slots, numargs); if (error != errNone) return error; SetInt(args, packet.size()); return errNone; } static int prNetAddr_UseDoubles(VMGlobals *g, int numArgsPushed) { //PyrSlot* netAddrSlot = g->sp - 1; PyrSlot* flag = g->sp; gUseDoubles = IsTrue(flag); return errNone; } static int prArray_OSCBytes(VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; PyrObject *array = slotRawObject(a); PyrSlot* args = array->slots; int numargs = array->size; if (numargs < 1) return errFailed; big_scpacket packet; if (IsFloat(args) || IsNil(args) || IsInt(args)) { makeSynthBundle(&packet, args, numargs, false); } else if (IsSym(args) || isKindOfSlot(args, class_string)) { int error = makeSynthMsgWithTags(&packet, args, numargs); if (error != errNone) return error; } else { return errWrongType; } int size = packet.size(); PyrInt8Array* obj = newPyrInt8Array(g->gc, size, 0, true); obj->size = size; memcpy(obj->b, packet.data(), size); SetObject(a, (PyrObject*)obj); //for (int i=0; i object and copy data from `msg.getb'. // Bytes are properly untyped, but there is no type. static PyrInt8Array* MsgToInt8Array ( sc_msg_iter& msg, bool runGC ) ; static PyrInt8Array* MsgToInt8Array ( sc_msg_iter& msg, bool runGC ) { int size = msg.getbsize() ; VMGlobals *g = gMainVMGlobals ; PyrInt8Array *obj = newPyrInt8Array ( g->gc , size , 0 , runGC ) ; obj->size = size ; msg.getb ( (char *)obj->b , obj->size ) ; return obj ; } static const double dInfinity = std::numeric_limits::infinity(); static PyrObject* ConvertOSCMessage(int inSize, char *inData) { char *cmdName = inData; int cmdNameLen = OSCstrlen(cmdName); sc_msg_iter msg(inSize - cmdNameLen, inData + cmdNameLen); int numElems; if (inSize == cmdNameLen) { numElems = 0; } else { if (!msg.tags) { numElems = 0; error("OSC messages must have type tags. %s\n", cmdName); } else { numElems = strlen(msg.tags); } } //post("tags %s %d\n", msg.tags, numElems); VMGlobals *g = gMainVMGlobals; PyrObject *obj = newPyrArray(g->gc, numElems + 1, 0, false); PyrSlot *slots = obj->slots; SetSymbol(slots+0, getsym(cmdName)); for (int i=0; iname); break; case 'b' : // fall through case 'm' : SetObject(slots+i+1, (PyrObject*)MsgToInt8Array(msg, false)); break; case 'c': SetChar(slots+i+1, (char)msg.geti()); break; case 't' : SetFloat(slots+i+1, OSCToElapsedTime(msg.gett())); break; // argument tags without any associated value case 'T' : SetTrue(slots+i+1); msg.count ++; break; case 'F' : SetFalse(slots+i+1); msg.count ++; break; case 'I' : SetFloat(slots+i+1, dInfinity); msg.count ++; break; case 'N' : SetNil(slots+i+1); msg.count ++; break; // else add the type tag as a char (jrhb 2009) default: SetChar(slots+i+1, tag); msg.gets(); } } obj->size = numElems + 1; return obj; } static PyrObject* ConvertReplyAddress(ReplyAddress *inReply) { VMGlobals *g = gMainVMGlobals; PyrObject *obj = instantiateObject(g->gc, s_netaddr->u.classobj, 2, true, false); PyrSlot *slots = obj->slots; SetInt(slots+0, inReply->mAddress.to_v4().to_ulong()); SetInt(slots+1, inReply->mPort); return obj; } void PerformOSCBundle(int inSize, char* inData, PyrObject *replyObj, int inPortNum) { // convert all data to arrays int64 oscTime = OSCtime(inData + 8); double seconds = OSCToElapsedTime(oscTime); VMGlobals *g = gMainVMGlobals; char *data = inData + 16; char* dataEnd = inData + inSize; while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); if (IsBundle(data)) { PerformOSCBundle(msgSize, data, replyObj, inPortNum); } else // is a message { ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, seconds); ++g->sp; SetObject(g->sp, replyObj); ++g->sp; SetInt(g->sp, inPortNum); PyrObject *arrayObj = ConvertOSCMessage(msgSize, data); ++g->sp; SetObject(g->sp, arrayObj); runInterpreter(g, s_recvoscmsg, 5); } data += msgSize; } } void PerformOSCMessage(int inSize, char *inData, PyrObject *replyObj, int inPortNum, double time) { PyrObject *arrayObj = ConvertOSCMessage(inSize, inData); // call virtual machine to handle message VMGlobals *g = gMainVMGlobals; ++g->sp; SetObject(g->sp, g->process); ++g->sp; SetFloat(g->sp, time); // time ++g->sp; SetObject(g->sp, replyObj); ++g->sp; SetInt(g->sp, inPortNum); ++g->sp; SetObject(g->sp, arrayObj); runInterpreter(g, s_recvoscmsg, 5); } void FreeOSCPacket(OSC_Packet *inPacket) { //post("->FreeOSCPacket %p\n", inPacket); if (inPacket) { free(inPacket->mData); free(inPacket); } } // takes ownership of inPacket void ProcessOSCPacket(OSC_Packet* inPacket, int inPortNum, double time) { //post("recv '%s' %d\n", inPacket->mData, inPacket->mSize); inPacket->mIsBundle = IsBundle(inPacket->mData); gLangMutex.lock(); if (compiledOK) { PyrObject *replyObj = ConvertReplyAddress(&inPacket->mReplyAddr); if (compiledOK) { if (inPacket->mIsBundle) { PerformOSCBundle(inPacket->mSize, inPacket->mData, replyObj, inPortNum); } else { PerformOSCMessage(inPacket->mSize, inPacket->mData, replyObj, inPortNum, time); } } } gLangMutex.unlock(); FreeOSCPacket(inPacket); } void startAsioThread(); void stopAsioThread(); void init_OSC(int port) { postfl("init_OSC\n"); #ifdef _WIN32 WSAData wsaData; int nCode; if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) { error( "sclang: init_OSC: WSAStartup() failed with error code %d.\n", nCode ); } #endif startAsioThread(); try { gUDPport = new SC_UdpInPort(port); } catch (std::exception const & e) { postfl("No networking: %s", e.what()); } } int prOpenUDPPort(VMGlobals *g, int numArgsPushed); int prOpenUDPPort(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int port; int err = slotIntVal(b, &port); if (err) return err; SC_UdpCustomInPort* newUDPport; try { SetTrue(a); newUDPport = new SC_UdpCustomInPort(port); gCustomUdpPorts.push_back(newUDPport); } catch (...) { SetFalse(a); postfl("Could not bind to requested port. This may mean it is in use already by another application.\n"); } return errNone; } void closeAllCustomPorts(); void closeAllCustomPorts() { // close all custom sockets for(int i=0; isp; char hostname[256]; int err = slotStrVal(a, hostname, 255); if (err) return err; #if 1 struct hostent *he = gethostbyname(hostname); if (!he) { #ifdef _WIN32 int err = WSAGetLastError(); error("gethostbyname(\"%s\") failed with error code %i.\n", hostname, err); #endif return errFailed; } SetInt(a, sc_ntohl(*(int*)he->h_addr)); return errNone; #else boost::asio::ip::address address; boost::system::error_code err_c; using boost::asio::ip::udp; udp::resolver resolver(ioService); udp::resolver::query query(hostname, ""); udp::resolver::iterator iterator = resolver.resolve(query, err_c); if (err_c) { error("cmp::resolver::query: %s\n", err_c.message().c_str()); return errFailed; } else SetInt(a, iterator->endpoint().address().to_v4().to_ulong() ); return errNone; #endif } int prGetLangPort(VMGlobals *g, int numArgsPushed); int prGetLangPort(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!gUDPport) return errFailed; SetInt(a, gUDPport->RealPortNum()); return errNone; } int prMatchLangIP(VMGlobals *g, int numArgsPushed); int prMatchLangIP(VMGlobals *g, int numArgsPushed) { PyrSlot *argString = g->sp; char ipstring[40]; int err = slotStrVal(argString, ipstring, 39); if (err) return err; std::string loopback ("127.0.0.1"); // check for loopback address if (!loopback.compare(ipstring)) { SetTrue(g->sp - 1); return errNone; } #ifdef _WIN32 DWORD rv, size = 0; PIP_ADAPTER_ADDRESSES adapter_addresses, aa; PIP_ADAPTER_UNICAST_ADDRESS ua; // first get the size of the required buffer rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &size); if (rv != ERROR_BUFFER_OVERFLOW) { error("GetAdaptersAddresses() failed..."); return errFailed; } // now allocate a buffer for the linked list adapter_addresses = (PIP_ADAPTER_ADDRESSES)malloc(size); rv = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, adapter_addresses, &size); if (rv != ERROR_SUCCESS) { error("GetAdaptersAddresses() failed..."); free(adapter_addresses); return errFailed; } for (aa = adapter_addresses; aa != NULL; aa = aa->Next) { for (ua = aa->FirstUnicastAddress; ua != NULL; ua = ua->Next) { char buf[40]; memset(buf, 0, sizeof(buf)); getnameinfo(ua->Address.lpSockaddr, ua->Address.iSockaddrLength, buf, sizeof(buf), NULL, 0,NI_NUMERICHOST); if (strcmp(ipstring, buf) == 0) { SetTrue(g->sp - 1); free(adapter_addresses); return errNone; } } } free(adapter_addresses); #else struct ifaddrs *ifap, *ifa; struct sockaddr_in *sa; char *addr; int result = getifaddrs (&ifap); if(result) { error(strerror(errno)); return errFailed; } for (ifa = ifap; ifa; ifa = ifa->ifa_next) { int family = ifa->ifa_addr->sa_family; if (family==AF_INET || family == AF_INET6) { sa = (struct sockaddr_in *) ifa->ifa_addr; addr = inet_ntoa(sa->sin_addr); if (strcmp(ipstring, addr) == 0) { SetTrue(g->sp - 1); freeifaddrs(ifap); return errNone; } } } freeifaddrs(ifap); #endif SetFalse(g->sp - 1); return errNone; } int prExit(VMGlobals *g, int numArgsPushed); int prExit(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; exit(slotRawInt(a)); //post("exit %d\n", slotRawInt(a)); //DumpBackTrace(g); return errNone; } extern "C" { int vpost(const char *fmt, va_list vargs); } #ifndef NO_INTERNAL_SERVER int prBootInProcessServer(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!gInternalSynthServer.mWorld) { SetPrintFunc(&vpost); WorldOptions options = kDefaultWorldOptions; PyrObject *optionsObj = slotRawObject(a); PyrSlot *optionsSlots = optionsObj->slots; static char mInputStreamsEnabled[512], mOutputStreamsEnabled[512], mDeviceName[512]; int err; err = slotIntVal(optionsSlots + 0, (int*)&options.mNumAudioBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 1, (int*)&options.mNumControlBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 2, (int*)&options.mNumInputBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 3, (int*)&options.mNumOutputBusChannels); if (err) return err; err = slotIntVal(optionsSlots + 4, (int*)&options.mNumBuffers); if (err) return err; err = slotIntVal(optionsSlots + 5, (int*)&options.mMaxNodes); if (err) return err; err = slotIntVal(optionsSlots + 6, (int*)&options.mMaxGraphDefs); if (err) return err; err = slotIntVal(optionsSlots + 8, (int*)&options.mBufLength); if (err) return err; if (NotNil(optionsSlots + 9)) { err = slotIntVal(optionsSlots + 9, (int*)&options.mPreferredHardwareBufferFrameSize); if (err) return err; } err = slotIntVal(optionsSlots + 10, (int*)&options.mRealTimeMemorySize); if (err) return err; err = slotIntVal(optionsSlots + 11, (int*)&options.mNumRGens); if (err) return err; err = slotIntVal(optionsSlots + 12, (int*)&options.mMaxWireBufs); if (err) return err; if (NotNil(optionsSlots + 13)) { err = slotIntVal(optionsSlots + 13, (int*)&options.mPreferredSampleRate); if (err) return err; } options.mLoadGraphDefs = IsTrue(optionsSlots + 14) ? 1 : 0; #ifdef __APPLE__ err = slotStrVal(optionsSlots+15, mInputStreamsEnabled, 512); if(err) options.mInputStreamsEnabled = NULL; else options.mInputStreamsEnabled = mInputStreamsEnabled; err = slotStrVal(optionsSlots+16, mOutputStreamsEnabled, 512); if(err) options.mOutputStreamsEnabled = NULL; else options.mOutputStreamsEnabled = mOutputStreamsEnabled; #endif err = slotStrVal(optionsSlots+17, mDeviceName, 512); if(err) options.mInDeviceName = options.mOutDeviceName = NULL; else options.mInDeviceName = options.mOutDeviceName = mDeviceName; options.mNumSharedControls = gInternalSynthServer.mNumSharedControls; options.mSharedControls = gInternalSynthServer.mSharedControls; // internal servers use the PID to identify the shared memory region #if defined(SC_IPHONE) options.mSharedMemoryID = 0; #elif !defined(_WIN32) options.mSharedMemoryID = getpid(); #else options.mSharedMemoryID = GetCurrentProcessId(); #endif gInternalSynthServer.mWorld = World_New(&options); } return errNone; } int getScopeBuf(uint32 index, SndBuf *buf, bool& didChange) { if (gInternalSynthServer.mWorld) { int serverErr = World_CopySndBuf(gInternalSynthServer.mWorld, index, buf, true, &didChange); if (serverErr) return errFailed; } else { didChange = false; } return errNone; } int prQuitInProcessServer(VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp; if (gInternalSynthServer.mWorld) { World *world = gInternalSynthServer.mWorld; gInternalSynthServer.mWorld = 0; thread thread(std::bind(World_WaitForQuit, world, false)); thread.detach(); } return errNone; } #else // NO_INTERNAL_SERVER int prQuitInProcessServer(VMGlobals *g, int numArgsPushed) { // no-op. Better to have this than to overwrite in lang. return errNone; } #endif // NO_INTERNAL_SERVER inline int32 BUFMASK(int32 x) { return (1 << (31 - CLZ(x))) - 1; } int prAllocSharedControls(VMGlobals *g, int numArgsPushed); int prAllocSharedControls(VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (gInternalSynthServer.mWorld) { post("can't allocate while internal server is running\n"); return errNone; } if (gInternalSynthServer.mSharedControls != gDefaultSharedControls) { free(gInternalSynthServer.mSharedControls); gInternalSynthServer.mSharedControls = gDefaultSharedControls; } int numSharedControls; int err = slotIntVal(b, &numSharedControls); if (err) return err; if (numSharedControls <= 0) { gInternalSynthServer.mNumSharedControls = 0; } else if (numSharedControls < kNumDefaultSharedControls) { gInternalSynthServer.mNumSharedControls = numSharedControls; } else { gInternalSynthServer.mNumSharedControls = numSharedControls; gInternalSynthServer.mSharedControls = (float*)calloc(numSharedControls, sizeof(float)); } return errNone; } int prGetSharedControl(VMGlobals *g, int numArgsPushed); int prGetSharedControl(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int index; int err = slotIntVal(b, &index); if (err) return err; if (index < 0 || index >= gInternalSynthServer.mNumSharedControls) { SetFloat(a, 0.); return errNone; } float val = gInternalSynthServer.mSharedControls[index]; SetFloat(a, val); return errNone; } int prSetSharedControl(VMGlobals *g, int numArgsPushed); int prSetSharedControl(VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int index; int err = slotIntVal(b, &index); if (err) return err; float val; err = slotFloatVal(c, &val); if (err) return err; if (index < 0 || index >= gInternalSynthServer.mNumSharedControls) { return errNone; } gInternalSynthServer.mSharedControls[index] = val; return errNone; } static int disconnectSharedMem(VMGlobals *g, PyrObject * object) { int ptrIndex = 0; PyrSlot * ptrSlot = object->slots + ptrIndex; if (IsNil(ptrSlot)) // already disconnected return errNone; assert(IsPtr(ptrSlot)); server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); delete client; SetNil(ptrSlot); return errNone; } int prConnectSharedMem(VMGlobals *g, int numArgsPushed) { #if !defined(SC_IPHONE) PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int portNumber = slotRawInt(b); int ptrIndex = 0; int finalizerIndex = 1; try { server_shared_memory_client * client = new server_shared_memory_client(portNumber); SetPtr(self->slots + ptrIndex, client); InstallFinalizer(g, self, finalizerIndex, disconnectSharedMem); postfl("Shared memory server interface initialized\n"); } catch (std::exception & e) { postfl("Cannot connect to shared memory: %s\n", e.what()); return errFailed; } #else postfl("Warning: Shared memory server interface disabled on iphone\n"); #endif return errNone; } int prDisconnectSharedMem(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); return disconnectSharedMem(g, self); } int prGetControlBusValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (NotPtr(ptrSlot)) return errFailed; server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); float value = client->get_control_busses()[busIndex]; SetFloat(a, value); return errNone; } int prGetControlBusValues(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (!IsInt(c)) return errFailed; int numberOfChannels = slotRawInt(c); server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); PyrObject * ret = newPyrArray(g->gc, numberOfChannels, 0, 1); ret->size = numberOfChannels; for (int i = 0; i != numberOfChannels; ++i) { float value = client->get_control_busses()[busIndex + i]; SetFloat(ret->slots+i, value); } SetObject(a, ret); return errNone; } int prSetControlBusValue(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (NotPtr(ptrSlot)) return errFailed; float value; int error = slotFloatVal(c, &value); if (error != errNone) return error; server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); client->get_control_busses()[busIndex] = value; return errNone; } int prSetControlBusValues(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; assert(IsObj(a)); PyrObject * self = slotRawObject(a); int ptrIndex = 0; PyrSlot * ptrSlot = self->slots + ptrIndex; if (NotPtr(ptrSlot)) return errFailed; if (!IsInt(b)) return errFailed; int busIndex = slotRawInt(b); if (!IsObj(c)) return errFailed; PyrObject * values = slotRawObject(c); server_shared_memory_client * client = (server_shared_memory_client*)slotRawPtr(ptrSlot); float * control_busses = client->get_control_busses() + busIndex; for (int i = 0; i != values->size; ++i) { float value; int error = slotFloatVal(values->slots + i, &value); if (error != errNone) return error; control_busses[i] = value; } return errNone; } void init_OSC_primitives(); void init_OSC_primitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_NetAddr_Connect", prNetAddr_Connect, 1, 0); definePrimitive(base, index++, "_NetAddr_Disconnect", prNetAddr_Disconnect, 1, 0); definePrimitive(base, index++, "_NetAddr_SendMsg", prNetAddr_SendMsg, 1, 1); definePrimitive(base, index++, "_NetAddr_SendBundle", prNetAddr_SendBundle, 2, 1); definePrimitive(base, index++, "_NetAddr_SendRaw", prNetAddr_SendRaw, 2, 0); definePrimitive(base, index++, "_NetAddr_GetBroadcastFlag", prNetAddr_GetBroadcastFlag, 1, 0); definePrimitive(base, index++, "_NetAddr_SetBroadcastFlag", prNetAddr_SetBroadcastFlag, 2, 0); definePrimitive(base, index++, "_NetAddr_BundleSize", prNetAddr_BundleSize, 1, 0); definePrimitive(base, index++, "_NetAddr_MsgSize", prNetAddr_MsgSize, 1, 0); definePrimitive(base, index++, "_NetAddr_UseDoubles", prNetAddr_UseDoubles, 2, 0); definePrimitive(base, index++, "_Array_OSCBytes", prArray_OSCBytes, 1, 0); definePrimitive(base, index++, "_GetHostByName", prGetHostByName, 1, 0); definePrimitive(base, index++, "_GetLangPort", prGetLangPort, 1, 0); definePrimitive(base, index++, "_MatchLangIP", prMatchLangIP, 2, 0); definePrimitive(base, index++, "_Exit", prExit, 1, 0); #ifndef NO_INTERNAL_SERVER definePrimitive(base, index++, "_BootInProcessServer", prBootInProcessServer, 1, 0); #endif definePrimitive(base, index++, "_QuitInProcessServer", prQuitInProcessServer, 1, 0); definePrimitive(base, index++, "_AllocSharedControls", prAllocSharedControls, 2, 0); definePrimitive(base, index++, "_SetSharedControl", prSetSharedControl, 3, 0); definePrimitive(base, index++, "_GetSharedControl", prGetSharedControl, 2, 0); definePrimitive(base, index++, "_OpenUDPPort", prOpenUDPPort, 2, 0); // server shared memory interface definePrimitive(base, index++, "_ServerShmInterface_connectSharedMem", prConnectSharedMem, 2, 0); definePrimitive(base, index++, "_ServerShmInterface_disconnectSharedMem", prDisconnectSharedMem, 1, 0); definePrimitive(base, index++, "_ServerShmInterface_getControlBusValue", prGetControlBusValue, 2, 0); definePrimitive(base, index++, "_ServerShmInterface_getControlBusValues", prGetControlBusValues, 3, 0); definePrimitive(base, index++, "_ServerShmInterface_setControlBusValue", prSetControlBusValue, 3, 0); definePrimitive(base, index++, "_ServerShmInterface_setControlBusValues", prSetControlBusValues, 3, 0); //post("initOSCRecs###############\n"); s_call = getsym("call"); s_write = getsym("write"); s_recvoscmsg = getsym("recvOSCmessage"); s_recvoscbndl = getsym("recvOSCbundle"); s_netaddr = getsym("NetAddr"); } SuperCollider-Source/lang/LangPrimSource/PyrArchiver.cpp000644 000765 000024 00000010225 12321461511 024426 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* An object archiving system for SuperCollider. */ #include "PyrArchiverT.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "VMGlobals.h" #include "GC.h" #include "ReadWriteMacros.h" int prAsArchive(struct VMGlobals *g, int numArgsPushed); int prAsArchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrArchiver arch(g); int err = arch.prepareToWriteArchive(a); if (err) return err; int32 size = arch.calcArchiveSize(); PyrInt8Array *obj = newPyrInt8Array(g->gc, size, 0, true); obj->size = size; arch.setStream((char*)obj->b); err = arch.writeArchive(); if (err == errNone) SetObject(a, obj); else SetNil(a); return err; } int prUnarchive(struct VMGlobals *g, int numArgsPushed); int prUnarchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!isKindOfSlot(a, class_int8array)) return errWrongType; PyrArchiver arch(g); arch.setStream((char*)slotRawObject(a)->slots); int err = arch.readArchive(a); return err; } int prWriteArchive(struct VMGlobals *g, int numArgsPushed); int prWriteArchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; char pathname[PATH_MAX]; memcpy(pathname, slotRawString(b)->s, slotRawObject(b)->size); pathname[slotRawString(b)->size] = 0; PyrArchiver arch(g); FILE *file = fopen(pathname, "wb"); int err = errNone; if (file) { err = arch.prepareToWriteArchive(a); if (!err) { arch.setStream(file); err = arch.writeArchive(); } fclose(file); } else { error("file open failed\n"); err = errFailed; } return err; } int prReadArchive(struct VMGlobals *g, int numArgsPushed); int prReadArchive(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; char pathname[PATH_MAX]; memcpy(pathname, slotRawString(b)->s, slotRawObject(b)->size); pathname[slotRawString(b)->size] = 0; PyrArchiver arch(g); FILE *file = fopen(pathname, "rb"); int err; if (file) { arch.setStream(file); err = arch.readArchive(a); fclose(file); } else { error("file open failed\n"); err = errFailed; } return err; } void initArchiverPrimitives(); void initArchiverPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_AsArchive", prAsArchive, 1, 0); definePrimitive(base, index++, "_Unarchive", prUnarchive, 1, 0); definePrimitive(base, index++, "_WriteArchive", prWriteArchive, 2, 0); definePrimitive(base, index++, "_ReadArchive", prReadArchive, 2, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initArchiverPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-Source/lang/LangPrimSource/PyrArchiverT.h000644 000765 000024 00000033531 12321461511 024224 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* An object archiving system for SuperCollider. */ #ifndef _PyrArchiver_ #define _PyrArchiver_ #include "PyrObject.h" #include "SC_AllocPool.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrSymbol.h" #include "VMGlobals.h" #include "GC.h" #include "ReadWriteMacros.h" #include "SCBase.h" const int32 kArchHdrSize = 12; const int32 kObjectArrayInitialCapacity = 32; template class PyrArchiver { public: PyrArchiver(VMGlobals *inG) : g(inG), mObjectArray(mInitialObjectArray), mNumObjects(0), mObjectArrayCapacity( kObjectArrayInitialCapacity ), mReadArchiveVersion(0) { } ~PyrArchiver() { if (mObjectArray != mInitialObjectArray) { g->allocPool->Free(mObjectArray); } } void setStream(S s) { mStream.SetStream(s); } int32 calcArchiveSize() { PyrSlot *slot; int32 size = kArchHdrSize; if (mNumObjects == 0) { size += sizeOfElem(&mTopSlot) + 1; } else { // object table size for (int i=0; iclassptr->name)->length + 1; // class name symbol size += sizeof(int32); // size if (obj->obj_format <= obj_slot) { size += obj->size; // tags slot = obj->slots; for (int j=0; jsize; ++j, ++slot) { size += sizeOfElem(slot); } } else if (obj->obj_format == obj_symbol) { PyrSymbol **symbol = ((PyrSymbolArray*)obj)->symbols; for (int j=0; jsize; ++j, ++symbol) { size += (**symbol).length + 1; } } else { size += obj->size * gFormatElemSize[obj->obj_format]; } } } return size; } long prepareToWriteArchive(PyrSlot *objectSlot) { long err = errNone; try { slotCopy(&mTopSlot, objectSlot); if (IsObj(objectSlot)) constructObjectArray(slotRawObject(objectSlot)); } catch (std::exception &ex) { error(ex.what()); err = errFailed; } return err; } long writeArchive() { long err = errNone; try { writeArchiveHeader(); if (mNumObjects == 0) { writeSlot(&mTopSlot); } else { for (int i=0; ireadArchive\n"); long err = errNone; SetNil(objectSlot); try { readArchiveHeader(); //postfl("readObjectHeaders %d\n", mNumObjects); if (mNumObjects == 0) { readSlot(objectSlot); } else { for (int i=0; i kObjectArrayInitialCapacity) { mObjectArray = (PyrObject**)g->allocPool->Alloc(mNumObjects * sizeof(PyrObject*)); mObjectArrayCapacity = mNumObjects; } } void recurse(PyrObject *obj, int n) { PyrSlot *slot = obj->slots; for (int i=0; iallocPool->Alloc(newSize); memcpy(newArray, mObjectArray, mNumObjects * sizeof(PyrObject*)); if (mObjectArray != mInitialObjectArray) { g->allocPool->Free(mObjectArray); } mObjectArrayCapacity = newObjectArrayCapacity; mObjectArray = newArray; } void putObject(PyrObject *obj) { obj->SetMark(); obj->scratch1 = mNumObjects; // expand array if needed if (mNumObjects >= mObjectArrayCapacity) growObjectArray(); // add to array mObjectArray[mNumObjects++] = obj; } void constructObjectArray(PyrObject *obj) { if (!obj->IsMarked()) { if (isKindOf(obj, class_class)) { } else if (isKindOf(obj, class_process)) { } else if (isKindOf(obj, s_interpreter->u.classobj)) { } else if (isKindOf(obj, class_method)) { throw std::runtime_error("cannot archive Methods.\n"); } else if (isKindOf(obj, class_thread)) { throw std::runtime_error("cannot archive Threads.\n"); } else if (isKindOf(obj, class_frame)) { throw std::runtime_error("cannot archive Frames.\n"); } else if (isKindOf(obj, class_func)) { //if (NotNil(&((PyrClosure*)obj)->block.uoblk->context)) { // throw std::runtime_error("open Function can not be archived.\n"); //} putObject(obj); recurse(obj, obj->size); } else { if (isKindOf(obj, class_rawarray)) { putObject(obj); } else if (isKindOf(obj, class_array)) { putObject(obj); recurse(obj, obj->size); } else { putObject(obj); recurse(obj, obj->size); } } } } int32 sizeOfElem(PyrSlot *slot) { //postfl("writeSlot %08X\n", GetTag(slot)); switch (GetTag(slot)) { case tagObj : if (isKindOf(slotRawObject(slot), class_class)) { return slotRawSymbol(&slotRawClass(slot)->name)->length + 1; } else if (isKindOf(slotRawObject(slot), class_process)) { return 0; } else if (isKindOf(slotRawObject(slot), class_frame)) { return 0; } else if (isKindOf(slotRawObject(slot), s_interpreter->u.classobj)) { return 0; } else { return sizeof(int32); } break; case tagInt : return sizeof(int32); case tagSym : return slotRawSymbol(slot)->length + 1; case tagChar : return sizeof(int32); case tagNil : return 0; case tagFalse : return 0; case tagTrue : return 0; case tagPtr : throw std::runtime_error("cannot archive RawPointers."); return 0; default : return sizeof(double); } } PyrSymbol* readSymbolID() { char str[256]; mStream.readSymbol(str); return getsym(str); } PyrObject* readObjectID() { int32 objID = mStream.readInt32_be(); //postfl("readObjectID %d\n", objID); return mObjectArray[objID]; } void writeObjectHeader(PyrObject *obj) { obj->ClearMark(); //postfl("writeObjectHeader %s\n", slotRawSymbol(&obj->classptr->name)->name); mStream.writeSymbol(slotRawSymbol(&obj->classptr->name)->name); mStream.writeInt32_be(obj->size); } PyrObject* readObjectHeader() { PyrSymbol* classname = readSymbolID(); //post("readObjectHeader %s\n", classname->name); PyrObject *obj; int32 size = mStream.readInt32_be(); if (slotRawInt(&classname->u.classobj->classFlags) & classHasIndexableInstances) { obj = instantiateObject(g->gc, classname->u.classobj, size, false, false); obj->size = size; } else { obj = instantiateObject(g->gc, classname->u.classobj, 0, false, false); } return obj; } void writeSlots(PyrObject *obj) { //postfl(" writeSlots %s\n", slotRawSymbol(&obj->classptr->name)->name); if (isKindOf(obj, class_rawarray)) { writeRawArray(obj); } else if (isKindOf(obj, class_func)) { PyrClosure* closure = (PyrClosure*)obj; if (NotNil(&slotRawBlock(&closure->block)->contextDef)) { writeSlot(&closure->block); writeSlot(&closure->context); } else { writeSlot(&closure->block); writeSlot(&o_nil); } } else { for (int i=0; isize; ++i) { writeSlot(obj->slots + i); } } } void readSlots(PyrObject *obj) { //postfl("readSlots\n"); if (isKindOf(obj, class_rawarray)) { readRawArray(obj); } else if (isKindOf(obj, class_func)) { PyrClosure* closure = (PyrClosure*)obj; readSlot(&closure->block); readSlot(&closure->context); if (IsNil(&closure->context)) { slotCopy(&closure->context, &slotRawInterpreter(&g->process->interpreter)->context); } } else { for (int i=0; isize; ++i) { readSlot(obj->slots + i); } } } void writeSlot(PyrSlot *slot) { PyrObject *obj; //postfl(" writeSlot %08X\n", GetTag(slot)); switch (GetTag(slot)) { case tagObj : obj = slotRawObject(slot); if (isKindOf(obj, class_class)) { mStream.writeInt8('C'); mStream.writeSymbol(slotRawSymbol(&slotRawClass(slot)->name)->name); } else if (isKindOf(obj, class_process)) { mStream.writeInt8('P'); } else if (isKindOf(obj, s_interpreter->u.classobj)) { mStream.writeInt8('R'); } else { mStream.writeInt8('o'); mStream.writeInt32_be(obj->scratch1); } break; case tagInt : mStream.writeInt8('i'); mStream.writeInt32_be(slotRawInt(slot)); break; case tagSym : mStream.writeInt8('s'); mStream.writeSymbol(slotRawSymbol(slot)->name); break; case tagChar : mStream.writeInt8('c'); mStream.writeInt32_be(slotRawInt(slot)); break; case tagNil : mStream.writeInt8('N'); break; case tagFalse : mStream.writeInt8('F'); break; case tagTrue : mStream.writeInt8('T'); break; case tagPtr : mStream.writeInt8('N'); break; default : mStream.writeInt8('f'); mStream.writeDouble_be(slotRawFloat(slot)); break; } } void readSlot(PyrSlot *slot) { char tag = mStream.readInt8(); switch (tag) { case 'o' : SetObject(slot, readObjectID()); break; case 'z' : SetObject(slot, (PyrObject*)(size_t)mStream.readInt32_be()); // FIXME: fix 64bit safety break; case 'C' : SetObject(slot, (PyrObject*)readSymbolID()->u.classobj); break; case 'P' : SetObject(slot, (PyrObject*)g->process); break; case 'R' : SetObject(slot, slotRawObject(&g->process->interpreter)); break; case 'i' : SetInt(slot, mStream.readInt32_be()); break; case 's' : SetSymbol(slot, readSymbolID()); break; case 'c' : SetChar(slot, mStream.readInt32_be()); break; case 'f' : SetFloat(slot, mStream.readDouble_be()); break; case 'T' : SetTrue(slot); break; case 'F' : SetFalse(slot); break; case 'N' : default : SetNil(slot); break; } } void writeRawArray(PyrObject *obj) { int32 size = obj->size; //postfl("writeRawArray %d\n", size); switch (obj->obj_format) { case obj_char : case obj_int8 : { char *data = (char*)obj->slots; mStream.writeData(data, size); } break; case obj_int16 : { int16 *data = (int16*)obj->slots; for (int i=0; islots; for (int i=0; islots; for (int i=0; islots; for (int i=0; iname); } } break; } } void readRawArray(PyrObject *obj) { //postfl("readRawArray\n"); int32 size = obj->size; switch (obj->obj_format) { case obj_char : case obj_int8 : { int8 *data = (int8*)obj->slots; for (int i=0; islots; for (int i=0; islots; for (int i=0; islots; for (int i=0; islots; for (int i=0; i mStream; int32 mReadArchiveVersion; PyrObject *mInitialObjectArray[kObjectArrayInitialCapacity]; }; #endif SuperCollider-Source/lang/LangPrimSource/PyrArrayPrimitives.cpp000644 000765 000024 00000170610 12756531745 026045 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Arrays. */ #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "SC_InlineBinaryOp.h" #include "SC_Constants.h" #include int basicSize(VMGlobals *g, int numArgsPushed); int basicMaxSize(VMGlobals *g, int numArgsPushed); int basicSwap(struct VMGlobals *g, int numArgsPushed); int basicAt(VMGlobals *g, int numArgsPushed); int basicRemoveAt(VMGlobals *g, int numArgsPushed); int basicClipAt(VMGlobals *g, int numArgsPushed); int basicWrapAt(VMGlobals *g, int numArgsPushed); int basicFoldAt(VMGlobals *g, int numArgsPushed); int basicPut(VMGlobals *g, int numArgsPushed); int basicClipPut(VMGlobals *g, int numArgsPushed); int basicWrapPut(VMGlobals *g, int numArgsPushed); int basicFoldPut(VMGlobals *g, int numArgsPushed); int prArrayAdd(VMGlobals *g, int numArgsPushed); int prArrayFill(VMGlobals *g, int numArgsPushed); int prArrayPop(VMGlobals *g, int numArgsPushed); int prArrayGrow(VMGlobals *g, int numArgsPushed); int prArrayCat(VMGlobals *g, int numArgsPushed); int prArrayReverse(VMGlobals *g, int numArgsPushed); int prArrayScramble(VMGlobals *g, int numArgsPushed); int prArrayRotate(VMGlobals *g, int numArgsPushed); int prArrayStutter(VMGlobals *g, int numArgsPushed); int prArrayMirror(VMGlobals *g, int numArgsPushed); int prArrayMirror1(VMGlobals *g, int numArgsPushed); int prArrayMirror2(VMGlobals *g, int numArgsPushed); int prArrayExtendWrap(VMGlobals *g, int numArgsPushed); int prArrayExtendFold(VMGlobals *g, int numArgsPushed); int prArrayPermute(VMGlobals *g, int numArgsPushed); int prArrayPyramid(VMGlobals *g, int numArgsPushed); int prArraySlide(VMGlobals *g, int numArgsPushed); int prArrayLace(VMGlobals *g, int numArgsPushed); int prArrayContainsSeqColl(VMGlobals *g, int numArgsPushed); int prArrayWIndex(VMGlobals *g, int numArgsPushed); int prArrayNormalizeSum(VMGlobals *g, int numArgsPushed); int prArrayIndexOfGreaterThan(VMGlobals *g, int numArgsPushed); int basicSize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *obj; a = g->sp; if (NotObj(a)) { SetInt(a, 0); return errNone; } obj = slotRawObject(a); SetInt(a, obj->size); return errNone; } int basicMaxSize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *obj; int maxsize; a = g->sp; if (NotObj(a)) { SetInt(a, 0); return errNone; } obj = slotRawObject(a); maxsize = MAXINDEXSIZE(obj); SetInt(a, maxsize); return errNone; } int basicSwap(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, tempi, tempj; int i, j; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(a)) return errWrongType; if (NotInt(b)) return errIndexNotAnInteger; if (NotInt(c)) return errIndexNotAnInteger; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; i = slotRawInt(b); j = slotRawInt(c); if (i < 0 || i >= obj->size) return errIndexOutOfRange; if (j < 0 || j >= obj->size) return errIndexOutOfRange; getIndexedSlot(obj, &tempi, i); getIndexedSlot(obj, &tempj, j); putIndexedSlot(g, obj, &tempi, j); putIndexedSlot(g, obj, &tempj, i); // in case it is partial scan obj g->gc->GCWrite(obj, &tempi); g->gc->GCWrite(obj, &tempj); return errNone; } int getIndexedInt(PyrObject *obj, int index, int *value); void DumpBackTrace(VMGlobals *g); int basicAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; int err = slotIntVal(b, &index); if (!err) { if (index < 0 || index >= obj->size) { slotCopy(a,&o_nil); } else { getIndexedSlot(obj, a, index); } } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; i= obj->size) { slotCopy(&outArraySlots[i],&o_nil); } else { getIndexedSlot(obj, outArraySlots + i, index); } } outArray->size = size; SetObject(a, outArray); } else { return errIndexNotAnInteger; } return errNone; } int basicRemoveAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index, length, elemsize; PyrObject *obj; void *ptr; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (err) return errWrongType; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { default : case obj_slot : ptr = obj->slots + index; slotCopy(a, (PyrSlot*)ptr); break; case obj_double : ptr = obj->slots + index; SetFloat(a, *(double*)ptr); break; case obj_float : ptr = ((float*)(obj->slots)) + index; SetFloat(a, *(float*)ptr); break; case obj_int32 : ptr = ((int32*)(obj->slots)) + index; SetInt(a, *(int32*)ptr); break; case obj_int16 : ptr = ((int16*)(obj->slots)) + index; SetInt(a, *(int16*)ptr); break; case obj_int8 : ptr = ((int8*)(obj->slots)) + index; SetInt(a, *(int8*)ptr); break; case obj_symbol : ptr = ((int*)(obj->slots)) + index; SetSymbol(a, *(PyrSymbol**)ptr); break; case obj_char : ptr = ((unsigned char*)(obj->slots)) + index; SetChar(a, *(unsigned char*)ptr); break; } length = obj->size - index - 1; if (length > 0) { elemsize = gFormatElemSize[obj->obj_format]; memmove(ptr, (char*)ptr + elemsize, length * elemsize); if (obj->obj_format <= obj_slot) { // might be partial scan object g->gc->GCWrite(obj, obj->slots + index); } } obj->size -- ; return errNone; } int basicTakeAt(struct VMGlobals *g, int numArgsPushed); int basicTakeAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index, lastIndex; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (err) return errWrongType; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; lastIndex = obj->size - 1; if (index < 0 || index >= obj->size) return errIndexOutOfRange; switch (obj->obj_format) { case obj_slot : { PyrSlot* ptr = obj->slots + index; PyrSlot* lastptr = obj->slots + lastIndex; slotCopy(a, ptr); *ptr = *lastptr; // might be partial scan obj g->gc->GCWrite(obj, ptr); } break; case obj_double : { PyrSlot* ptr = obj->slots + index; PyrSlot* lastptr = obj->slots + lastIndex; SetFloat(a, *(double*)ptr); *ptr = *lastptr; // might be partial scan obj g->gc->GCWrite(obj, ptr); } break; case obj_float : { float* ptr = ((float*)(obj->slots)) + index; float* lastptr = ((float*)(obj->slots)) + lastIndex; SetFloat(a, *(float*)ptr); *ptr = *lastptr; } break; case obj_int32 : { int32* ptr = ((int32*)(obj->slots)) + index; int32* lastptr = ((int32*)(obj->slots)) + lastIndex; SetInt(a, *(int32*)ptr); *ptr = *lastptr; } break; case obj_int16 : { int16* ptr = ((int16*)(obj->slots)) + index; int16* lastptr = ((int16*)(obj->slots)) + lastIndex; SetInt(a, *(int16*)ptr); *ptr = *lastptr; } break; case obj_int8 : { int8* ptr = ((int8*)(obj->slots)) + index; int8* lastptr = ((int8*)(obj->slots)) + lastIndex; SetInt(a, *(int8*)ptr); *ptr = *lastptr; } break; case obj_symbol : { int32* ptr = ((int32*)(obj->slots)) + index; int32* lastptr = ((int32*)(obj->slots)) + lastIndex; SetSymbol(a, *(PyrSymbol**)ptr); *ptr = *lastptr; } break; case obj_char : { unsigned char* ptr = ((unsigned char*)(obj->slots)) + index; unsigned char* lastptr = ((unsigned char*)(obj->slots)) + lastIndex; SetChar(a, *(unsigned char*)ptr); *ptr = *lastptr; } break; } obj->size -- ; return errNone; } int basicWrapAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if(obj->size==0) {SetNil(a); return errNone; } int err = slotIntVal(b, &index); if (!err) { index = sc_mod((int)index, (int)obj->size); getIndexedSlot(obj, a, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; isize); getIndexedSlot(obj, outArraySlots + i, index); } outArray->size = size; SetObject(a, outArray); } else return errIndexNotAnInteger; return errNone; } int basicFoldAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if(obj->size==0) {SetNil(a); return errNone; } int err = slotIntVal(b, &index); if (!err) { index = sc_fold(index, 0, obj->size-1); getIndexedSlot(obj, a, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; isize-1); getIndexedSlot(obj, outArraySlots + i, index); } outArray->size = size; SetObject(a, outArray); } else return errIndexNotAnInteger; return errNone; } int basicClipAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; PyrObject *obj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if(obj->size==0) {SetNil(a); return errNone; } int err = slotIntVal(b, &index); if (!err) { index = sc_clip(index, 0, obj->size - 1); getIndexedSlot(obj, a, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = indexArray->size; PyrObject *outArray = newPyrArray(g->gc, size, 0, true); PyrSlot *outArraySlots = outArray->slots; for (int i=0; isize - 1); getIndexedSlot(obj, outArraySlots + i, index); } outArray->size = size; SetObject(a, outArray); } else return errIndexNotAnInteger; return errNone; } int basicPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { if (index < 0 || index >= obj->size) return errIndexOutOfRange; return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; i= obj->size) return errIndexOutOfRange; err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int basicClipPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { index = sc_clip(index, 0, obj->size - 1); return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; isize - 1); err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int basicWrapPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { index = sc_mod((int)index, (int)obj->size); return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; isize); err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int basicFoldPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (NotObj(a)) return errWrongType; int err = slotIntVal(b, &index); if (!err) { index = sc_fold(index, 0, obj->size-1); return putIndexedSlot(g, obj, c, index); } else if (isKindOfSlot(b, class_arrayed_collection)) { PyrObject *indexArray = slotRawObject(b); int size = slotRawObject(b)->size; for (int i=0; isize-1); err = putIndexedSlot(g, obj, c, index); if (err) return err; } return errNone; } else return errIndexNotAnInteger; } int prArrayPutEach(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if (!isKindOfSlot(b, class_arrayed_collection)) return errWrongType; if (!isKindOfSlot(c, class_arrayed_collection)) return errWrongType; PyrSlot *indices = slotRawObject(b)->slots; PyrSlot *values = slotRawObject(c)->slots; int size = slotRawObject(b)->size; int valsize = slotRawObject(c)->size; for (int i=0; i= obj->size) return errIndexOutOfRange; int valindex = sc_mod(i, valsize); err = putIndexedSlot(g, obj, values + valindex, index); if (err) return err; } return errNone; } int prArrayAssocAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj; bool found = false; a = g->sp - 1; b = g->sp; obj = slotRawObject(a); int size = obj->size; if (obj->obj_format == obj_slot) { PyrSlot *slots = obj->slots; for (int i=0; i= size) return errFailed; slotCopy(a,&slots[i+1]); found = true; break; } } } else { PyrSlot slot; for (int i=0; i= size) return errFailed; getIndexedSlot(obj, &slot, i+1); slotCopy(a,&slot); found = true; break; } } } if (!found) SetNil(a); return errNone; } int prArrayAssocPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrObject *obj; bool found = false; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; int size = obj->size; if (obj->obj_format == obj_slot) { PyrSlot *slots = obj->slots; for (int i=0; i= size) return errFailed; slotCopy(&slots[i+1],c); g->gc->GCWrite(obj, c); found = true; break; } } } else { PyrSlot slot; for (int i=0; i= size) return errFailed; putIndexedSlot(g, obj, &slot, i+1); g->gc->GCWrite(obj, c); found = true; break; } } } if (!found) SetNil(a); return errNone; } int prArrayIndexOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj; bool found = false; a = g->sp - 1; b = g->sp; obj = slotRawObject(a); int size = obj->size; if (obj->obj_format == obj_slot) { PyrSlot *slots = obj->slots; for (int i=0; isp - 4; b = g->sp - 3; c = g->sp - 2; d = g->sp - 1; e = g->sp; PyrObject *inobj = slotRawObject(a); if (inobj->IsImmutable()) return errImmutableObject; int size = inobj->size; if (NotInt(b) && NotNil(b)) return errWrongType; if (NotInt(c) && NotNil(c)) return errWrongType; if (NotInt(d) && NotNil(d)) return errWrongType; int first = IsInt(b) ? slotRawInt(b) : 0; int last = IsInt(d) ? slotRawInt(d) : size - 1; int second = IsInt(c) ? slotRawInt(c) : (first < last ? first + 1 : first - 1); int step = second - first; first = sc_clip(first, 0, size-1); last = sc_clip(last, 0, size-1); int err = errNone; if (step == 0) return errFailed; if (step == 1) { for (int i=first; i<=last; ++i) { err = putIndexedSlot(g, inobj, e, i); if (err) return err; } } else if (step == -1) { for (int i=last; i>=first; --i) { err = putIndexedSlot(g, inobj, e, i); if (err) return err; } } else if (step > 0) { int length = (last - first) / step + 1; for (int i=first, j=0; jsp - 1; b = g->sp; PyrObject *array = slotRawObject(a); if (array->IsImmutable()) return errImmutableObject; format = slotRawObject(a)->obj_format; tag = gFormatElemTag[format]; /*if (tag > 0) { if (GetTag(b) != tag) return errWrongType; } else if (tag == 0) { if (NotFloat(b)) return errWrongType; } // else format is obj_slot, any tag is acceptable*/ elemsize = gFormatElemSize[format]; maxelems = MAXINDEXSIZE(array); if (array->size >= maxelems || array->IsImmutable()) { numbytes = sizeof(PyrSlot) << (array->obj_sizeclass + 1); array = g->gc->New(numbytes, 0, format, true); array->classptr = slotRawObject(a)->classptr; array->size = slotRawObject(a)->size; memcpy(array->slots, slotRawObject(a)->slots, slotRawObject(a)->size * elemsize); SetRaw(a, array); } slots = array->slots; switch (format) { case obj_slot : slotCopy(&slots[array->size++],b); g->gc->GCWrite(array, b); break; case obj_int32 : err = slotIntVal(b, &ival); if (err) return err; ((int32*)slots)[array->size++] = ival; break; case obj_int16 : err = slotIntVal(b, &ival); if (err) return err; ((int16*)slots)[array->size++] = ival; break; case obj_int8 : err = slotIntVal(b, &ival); if (err) return err; ((int8*)slots)[array->size++] = ival; break; case obj_char : if (NotChar(b)) return errWrongType; ((char*)slots)[array->size++] = slotRawChar(b); break; case obj_symbol : if (NotSym(b)) return errWrongType; ((PyrSymbol**)slots)[array->size++] = slotRawSymbol(b); break; case obj_float : err = slotDoubleVal(b, &fval); if (err) return err; ((float*)slots)[array->size++] = fval; break; case obj_double : err = slotDoubleVal(b, &fval); if (err) return err; ((double*)slots)[array->size++] = fval; break; } return errNone; } int prArrayInsert(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slots1, *slots2; PyrObject *array, *oldarray; int err, ival; double fval; a = g->sp - 2; // array b = g->sp - 1; // index c = g->sp; // value if (NotInt(b)) return errWrongType; array = slotRawObject(a); const int format = slotRawObject(a)->obj_format; const int tag = gFormatElemTag[format]; const int size = array->size; int index = slotRawInt(b); index = sc_clip(index, 0, size); const int remain = size - index; const int elemsize = gFormatElemSize[format]; const int maxelems = MAXINDEXSIZE(array); if (size+1 > maxelems || array->IsImmutable()) { oldarray = array; const int numbytes = sizeof(PyrSlot) << (array->obj_sizeclass + 1); array = g->gc->New(numbytes, 0, format, true); array->classptr = oldarray->classptr; array->size = size+1; SetRaw(a, array); slots1 = array->slots; slots2 = oldarray->slots; if (index) memcpy(slots1, slots2, index * elemsize); switch (format) { case obj_slot : slotCopy(&slots1[index],c); if (remain) memcpy(slots1 + index + 1, slots2 + index, remain * elemsize); if (!g->gc->ObjIsGrey(array)) g->gc->ToGrey(array); break; case obj_int32 : err = slotIntVal(c, &ival); if (err) return err; ((int32*)slots1)[index] = ival; if (remain) { memcpy((int*)slots1 + index + 1, (int*)slots2 + index, remain * elemsize); } break; case obj_int16 : err = slotIntVal(c, &ival); if (err) return err; ((int16*)slots1)[index] = ival; if (remain) { memcpy((short*)slots1 + index + 1, (short*)slots2 + index, remain * elemsize); } break; case obj_int8 : err = slotIntVal(c, &ival); if (err) return err; ((int8*)slots1)[index] = ival; if (remain) { memcpy((char*)slots1 + index + 1, (char*)slots2 + index, remain * elemsize); } break; case obj_char : if (NotChar(c)) return errWrongType; ((char*)slots1)[index] = slotRawInt(c); if (remain) { memcpy((char*)slots1 + index + 1, (char*)slots2 + index, remain * elemsize); } break; case obj_symbol : if (NotSym(c)) return errWrongType; ((PyrSymbol**)slots1)[index] = slotRawSymbol(c); if (remain) { memcpy((int*)slots1 + index + 1, (int*)slots2 + index, remain * elemsize); } break; case obj_float : err = slotDoubleVal(c, &fval); if (err) return err; ((float*)slots1)[index] = fval; if (remain) { memcpy((float*)slots1 + index + 1, (float*)slots2 + index, remain * elemsize); } break; case obj_double : err = slotDoubleVal(c, &fval); if (err) return err; ((double*)slots1)[index] = fval; if (remain) { memcpy((double*)slots1 + index + 1, (double*)slots2 + index, remain * elemsize); } break; } } else { array->size = size+1; slots1 = array->slots; switch (format) { case obj_slot : if (remain) memmove(slots1 + index + 1, slots1 + index, remain * elemsize); slotCopy(&slots1[index],c); if (!g->gc->ObjIsGrey(array)) g->gc->ToGrey(array); break; case obj_int32 : if (remain) { memmove((int*)slots1 + index + 1, (int*)slots1 + index, remain * elemsize); } err = slotIntVal(c, &ival); if (err) return err; ((int32*)slots1)[index] = ival; break; case obj_int16 : if (remain) { memmove((short*)slots1 + index + 1, (short*)slots1 + index, remain * elemsize); } err = slotIntVal(c, &ival); if (err) return err; ((int16*)slots1)[index] = ival; break; case obj_int8 : if (remain) { memmove((char*)slots1 + index + 1, (char*)slots1 + index, remain * elemsize); } err = slotIntVal(c, &ival); if (err) return err; ((int8*)slots1)[index] = ival; break; case obj_char : if (remain) { memmove((char*)slots1 + index + 1, (char*)slots1 + index, remain * elemsize); } if (NotChar(c)) return errWrongType; ((char*)slots1)[index] = slotRawInt(c); break; case obj_symbol : if (remain) { memmove((int*)slots1 + index + 1, (int*)slots1 + index, remain * elemsize); } if (NotSym(c)) return errWrongType; ((PyrSymbol**)slots1)[index] = slotRawSymbol(c); break; case obj_float : if (remain) { memmove((float*)slots1 + index + 1, (float*)slots1 + index, remain * elemsize); } err = slotDoubleVal(c, &fval); if (err) return err; ((float*)slots1)[index] = fval; break; case obj_double : if (remain) { memmove((double*)slots1 + index + 1, (double*)slots1 + index, remain * elemsize); } err = slotDoubleVal(c, &fval); if (err) return err; ((double*)slots1)[index] = fval; break; } } return errNone; } int prArrayFill(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *array; PyrSymbol *sym; int i; int format, tag; int err, ival; double fval; a = g->sp - 1; b = g->sp; array = slotRawObject(a); format = slotRawObject(a)->obj_format; tag = gFormatElemTag[format]; /*if (tag > 0) { if (GetTag(b) != tag) return errWrongType; } else if (tag == 0) { if (NotFloat(b)) return errWrongType; } // else format is obj_slot, any tag is acceptable*/ slots = array->slots; switch (format) { case obj_slot : if (array->IsImmutable()) return errImmutableObject; for (i=0; isize; ++i) { slotCopy(&slots[i],b); } g->gc->GCWrite(array, b); break; case obj_int32 : err = slotIntVal(b, &ival); if (err) return err; for (i=0; isize; ++i) { ((int32*)slots)[i] = ival; } break; case obj_int16 : err = slotIntVal(b, &ival); if (err) return err; for (i=0; isize; ++i) { ((int16*)slots)[i] = ival; } break; case obj_int8 : err = slotIntVal(b, &ival); if (err) return err; for (i=0; isize; ++i) { ((int8*)slots)[i] = ival; } break; case obj_char : if (NotChar(b)) return errWrongType; ival = slotRawInt(b); for (i=0; isize; ++i) { ((char*)slots)[i] = ival; } break; case obj_symbol : if (NotSym(b)) return errWrongType; sym = slotRawSymbol(b); for (i=0; isize; ++i) { ((PyrSymbol**)slots)[i] = sym; } break; case obj_float : err = slotDoubleVal(b, &fval); if (err) return err; for (i=0; isize; ++i) { ((float*)slots)[i] = fval; } break; case obj_double : err = slotDoubleVal(b, &fval); if (err) return err; for (i=0; isize; ++i) { ((double*)slots)[i] = fval; } break; } return errNone; } int prArrayPop(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *array; int z; int format; PyrSymbol *sym; a = g->sp; array = slotRawObject(a); if (array->IsImmutable()) return errImmutableObject; if (array->size > 0) { format = array->obj_format; slots = array->slots; switch (format) { case obj_slot : slotCopy(a,&slots[--array->size]); break; case obj_int32 : z = ((int32*)slots)[--array->size]; SetInt(a, z); break; case obj_int16 : z = ((int16*)slots)[--array->size]; SetInt(a, z); break; case obj_int8 : z = ((int8*)slots)[--array->size]; SetInt(a, z); break; case obj_char : z = ((char*)slots)[--array->size]; SetChar(a, z); break; case obj_symbol : sym = ((PyrSymbol**)slots)[--array->size]; SetSymbol(a, sym); break; case obj_float : SetFloat(a, ((float*)slots)[--array->size]); break; case obj_double : SetFloat(a, slotRawFloat(&slots[--array->size])); break; } } else { slotCopy(a,&o_nil); } return errNone; } int prArrayExtend(struct VMGlobals *g, int numArgsPushed) { int numbytes, elemsize, format; int err; PyrSlot *a = g->sp - 2; // array PyrSlot *b = g->sp - 1; // size PyrSlot *c = g->sp; // filler item if (NotInt(b)) return errWrongType; PyrObject* aobj = slotRawObject(a); if (slotRawInt(b) <= aobj->size) { aobj->size = slotRawInt(b); return errNone; } format = aobj->obj_format; if (slotRawInt(b) > MAXINDEXSIZE(aobj) || aobj->IsImmutable()) { elemsize = gFormatElemSize[format]; numbytes = slotRawInt(b) * elemsize; PyrObject *obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; obj->size = aobj->size; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); aobj = obj; SetRaw(a, aobj); } int fillSize = slotRawInt(b) - aobj->size; int32 ival; float fval; double dval; PyrSlot *slots = aobj->slots; switch (format) { case obj_slot : fillSlots(slots + aobj->size, fillSize, c); g->gc->GCWrite(aobj, c); break; case obj_int32 : { int32* ptr = (int32*)slots + aobj->size; err = slotIntVal(c, &ival); if (err) return err; for (int i=0; isize; err = slotIntVal(c, &ival); if (err) return err; for (int i=0; isize; err = slotIntVal(c, &ival); if (err) return err; for (int i=0; isize; if (NotChar(c)) return errWrongType; ival = slotRawChar(c); for (int i=0; isize; if (NotSym(c)) return errWrongType; PyrSymbol *sym = slotRawSymbol(c); for (int i=0; isize; err = slotFloatVal(c, &fval); for (int i=0; isize; err = slotDoubleVal(c, &dval); for (int i=0; isize = slotRawInt(b); return errNone; } int prArrayGrow(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj; int numbytes, elemsize, format; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; if (slotRawInt(b) <= 0) return errNone; aobj = slotRawObject(a); if (aobj->size + slotRawInt(b) <= MAXINDEXSIZE(aobj)) return errNone; format = aobj->obj_format; elemsize = gFormatElemSize[format]; numbytes = ((aobj->size + slotRawInt(b)) * elemsize); obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; obj->size = aobj->size; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); SetRaw(a, obj); return errNone; } int prArrayGrowClear(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj; int numbytes, elemsize, format; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; if (slotRawInt(b) <= 0) return errNone; aobj = slotRawObject(a); if (aobj->size + slotRawInt(b) <= MAXINDEXSIZE(aobj) && aobj->IsMutable()) { obj = aobj; } else { format = aobj->obj_format; elemsize = gFormatElemSize[format]; numbytes = ((aobj->size + slotRawInt(b)) * elemsize); obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); } if (obj->obj_format == obj_slot) { nilSlots(obj->slots + aobj->size, slotRawInt(b)); } else { memset((char*)(obj->slots) + aobj->size * gFormatElemSize[format], 0, slotRawInt(b) * gFormatElemSize[format]); } obj->size = aobj->size + slotRawInt(b); SetRaw(a, obj); return errNone; } int prArrayCat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj, *bobj; int elemsize, size; int numbytes, format; a = g->sp - 1; b = g->sp; if (NotObj(b) || slotRawObject(a)->classptr != slotRawObject(b)->classptr) return errWrongType; aobj = slotRawObject(a); bobj = slotRawObject(b); size = aobj->size + bobj->size; format = aobj->obj_format; assert(aobj->obj_format == bobj->obj_format); elemsize = gFormatElemSize[format]; numbytes = (size * elemsize); obj = g->gc->New(numbytes, 0, format, true); obj->classptr = aobj->classptr; obj->size = size; memcpy(obj->slots, aobj->slots, aobj->size * elemsize); memcpy((char*)obj->slots + aobj->size * elemsize, bobj->slots, bobj->size * elemsize); SetObject(a, obj); return errNone; } int prArrayAddAll(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrObject *obj, *aobj; int elemsize, newindexedsize, newsizebytes, asize, bsize; int format; a = g->sp - 1; b = g->sp; if (NotObj(b) || slotRawObject(a)->classptr != slotRawObject(b)->classptr) return errWrongType; aobj = slotRawObject(a); format = aobj->obj_format; elemsize = gFormatElemSize[format]; asize = aobj->size; bsize = slotRawObject(b)->size; newindexedsize = asize + bsize; newsizebytes = newindexedsize * elemsize; if (newindexedsize > MAXINDEXSIZE(aobj) || aobj->IsImmutable()) { obj = g->gc->New(newsizebytes, 0, format, true); obj->classptr = aobj->classptr; memcpy(obj->slots, aobj->slots, asize * elemsize); SetObject(a, obj); } else { obj = aobj; if (format == obj_slot && !g->gc->ObjIsGrey(obj)) g->gc->ToGrey(obj); } obj->size = newindexedsize; memcpy((char*)obj->slots + asize * elemsize, slotRawObject(b)->slots, bsize * elemsize); return errNone; } int prArrayOverwrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrObject *obj, *aobj; int err, elemsize, newindexedsize, newsizebytes, pos, asize, bsize; int format; a = g->sp - 2; b = g->sp - 1; c = g->sp; // pos if (NotObj(b) || slotRawObject(a)->classptr != slotRawObject(b)->classptr) return errWrongType; err = slotIntVal(c, &pos); if (err) return errWrongType; if (pos < 0 || pos > slotRawObject(a)->size) return errIndexOutOfRange; aobj = slotRawObject(a); format = aobj->obj_format; elemsize = gFormatElemSize[format]; asize = aobj->size; bsize = slotRawObject(b)->size; newindexedsize = pos + bsize; newindexedsize = sc_max(asize, newindexedsize); newsizebytes = newindexedsize * elemsize; if (newindexedsize > MAXINDEXSIZE(aobj) || aobj->IsImmutable()) { obj = g->gc->New(newsizebytes, 0, format, true); obj->classptr = aobj->classptr; memcpy(obj->slots, aobj->slots, asize * elemsize); SetObject(a, obj); } else { obj = aobj; if (format == obj_slot && !g->gc->ObjIsGrey(obj)) g->gc->ToGrey(obj); } obj->size = newindexedsize; memcpy((char*)(obj->slots) + pos * elemsize, slotRawObject(b)->slots, bsize * elemsize); return errNone; } int prArrayReverse(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots1, *slots2; PyrObject *obj1, *obj2; int i, j, size; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots1 = obj1->slots; slots2 = obj2->slots; for (i=0, j=size-1; isize = size; SetRaw(a, obj2); return errNone; } int prArrayScramble(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots1, *slots2, temp; PyrObject *obj1, *obj2; int i, j, k, m, size; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots1 = obj1->slots; slots2 = obj2->slots; memcpy(slots2, slots1, size * sizeof(PyrSlot)); if (size > 1) { k = size; for (i=0, m=k; irgen->irand(m); slotCopy(&temp,&slots2[i]); slotCopy(&slots2[i],&slots2[j]); slotCopy(&slots2[j],&temp); } } obj2->size = size; SetRaw(a, obj2); return errNone; } int prArrayRotate(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, n, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); size = obj1->size; n = sc_mod((int)slotRawInt(b), (int)size); slots = obj1->slots; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); for (i=0, j=n; islots[j],&slots[i]); if (++j >= size) j=0; } obj2->size = size; SetRaw(a, obj2); return errNone; } int prArrayStutter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots1, *slots2; PyrObject *obj1, *obj2; int i, j, k, m, n, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); n = slotRawInt(b); m = obj1->size; size = m * n; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots1 = obj1->slots; slots2 = obj2->slots; for (i=0,j=0; isize = size; SetRaw(a, obj2); return errNone; } int prArrayMirror(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj1, *obj2; int i, j, k, size; a = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size * 2 - 1; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; // copy first part of list memcpy(obj2->slots, slots, obj1->size * sizeof(PyrSlot)); // copy second part k = size/2; for (i=0, j=size-1; islots[j],&slots[i]); } SetRaw(a, obj2); return errNone; } int prArrayMirror1(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj1, *obj2; int i, j, k, size; a = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size * 2 - 2; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; // copy first part of list memcpy(obj2->slots, slots, obj1->size * sizeof(PyrSlot)); // copy second part k = size/2; for (i=1, j=size-1; islots[j],&slots[i]); } SetRaw(a, obj2); return errNone; } int prArrayMirror2(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj1, *obj2; int i, j, k, size; a = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size * 2; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; // copy first part of list memcpy(obj2->slots, slots, obj1->size * sizeof(PyrSlot)); // copy second part k = size/2; for (i=0, j=size-1; islots[j],&slots[i]); } SetRaw(a, obj2); return errNone; } int prArrayExtendWrap(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, m, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; size = slotRawInt(b); if (size < 0) return errFailed; obj1 = slotRawObject(a); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots = obj2->slots; // copy first part of list memcpy(slots, obj1->slots, sc_min(size, obj1->size) * sizeof(PyrSlot)); if (size > obj1->size) { // copy second part m = obj1->size; for (i=0,j=m; jgc, obj1->classptr, size, true, true); } SetRaw(a, obj2); return errNone; } int prArrayExtendFold(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, m, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; size = slotRawInt(b); if (size < 0) return errFailed; obj1 = slotRawObject(a); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots = obj2->slots; // copy first part of list memcpy(slots, obj1->slots, sc_min(size, obj1->size) * sizeof(PyrSlot)); if (size > obj1->size) { // copy second part m = obj1->size; for (i=0,j=m; jgc, obj1->classptr, size, true, true); } SetRaw(a, obj2); return errNone; } int prArrayExtendLast(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots, last; PyrObject *obj1, *obj2; int i, j, m, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; size = slotRawInt(b); if (size < 0) return errFailed; obj1 = slotRawObject(a); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots = obj2->slots; // copy first part of list memcpy(slots, obj1->slots, sc_min(size, obj1->size) * sizeof(PyrSlot)); if (size > obj1->size) { // copy second part m = obj1->size; slotCopy(&last,&slots[m-1]); for (i=0,j=m; jgc, obj1->classptr, size, true, true); } SetRaw(a, obj2); return errNone; } int prArrayPermute(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots1, *slots2, temp; PyrObject *obj1, *obj2; int i, j, m, z, size; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); obj2->size = size; slots1 = obj1->slots; slots2 = obj2->slots; memcpy(slots2, slots1, size * sizeof(PyrSlot)); z = slotRawInt(b); for (i=0, m=size; isp - 1; b = g->sp; if (NotInt(b)) return errWrongType; int maxSize = slotRawInt(b); obj1 = slotRawObject(a); slots1 = obj1->slots; int newSize = 1; int tupSize = obj1->size; for (int i=0; i < tupSize; ++i) { if (isKindOfSlot(slots1+i, class_array)) { newSize *= slotRawObject(&slots1[i])->size; } } if (newSize > maxSize) newSize = maxSize; obj2 = instantiateObject(g->gc, obj1->classptr, newSize, false, true); slots2 = obj2->slots; SetObject(b, obj2); // store reference on stack, so both source and destination objects can be reached by the gc for (int i=0; i < newSize; ++i) { int k = i; obj3 = instantiateObject(g->gc, obj1->classptr, tupSize, false, true); slots3 = obj3->slots; for (int j=tupSize-1; j >= 0; --j) { if (isKindOfSlot(slots1+j, class_array)) { PyrObject *obj4 = slotRawObject(&slots1[j]); slotToCopy = &obj4->slots[k % obj4->size]; slotCopy(&slots3[j], slotToCopy); g->gc->GCWrite(obj3, slotToCopy); k /= obj4->size; } else { slotToCopy = &slots1[j]; slotCopy(&slots3[j], slotToCopy); g->gc->GCWrite(obj3, slotToCopy); } } obj3->size = tupSize; SetObject(obj2->slots+i, obj3); g->gc->GCWriteNew(obj2, obj3); obj2->size++; } SetRaw(a, obj2); return errNone; } int prArrayPyramid(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots; PyrObject *obj1, *obj2; int i, j, k, n, m, numslots, x; a = g->sp - 1; b = g->sp; if (NotInt(b)) return errWrongType; obj1 = slotRawObject(a); slots = obj1->slots; m = sc_clip(slotRawInt(b), 1, 10); x = numslots = obj1->size; switch (m) { case 1 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 2 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 3 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 4 : n = (x*x + x)/2; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } obj2->size = k; break; case 5 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; case 6 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; case 7 : n = x*x + x - 1; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=1; islots[k],&slots[j]); } } obj2->size = k; break; case 8 : n = x*x + x - 1; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=1; islots[k],&slots[j]); } } obj2->size = k; break; case 9 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; case 10 : n = x*x; obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=0,k=0; islots[k],&slots[j]); } } for (i=0; islots[k],&slots[j]); } } obj2->size = k; break; } SetRaw(a, obj2); return errNone; } int prArraySlide(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slots; PyrObject *obj1, *obj2; int h, i, j, k, numslots, numwin; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotInt(b)) return errWrongType; if (NotInt(c)) return errWrongType; obj1 = slotRawObject(a); slots = obj1->slots; int m = slotRawInt(b); int n = slotRawInt(c); if (n <= 0) return errFailed; numwin = (obj1->size + n - m) / n; numslots = numwin * m; obj2 = instantiateObject(g->gc, obj1->classptr, numslots, false, true); for (i=h=k=0; islots[k++],&slots[j]); } obj2->size = k; SetRaw(a, obj2); return errNone; } int prArrayLace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *slots, *slot; PyrObject *obj1, *obj2, *obj3; int i, j, k, n, m, numLists, len; a = g->sp - 1; b = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; numLists = obj1->size; if(IsNil(b)) { for (j=0; jsize; if(j==0 || n>len) { n = len; } } else { return errFailed; // this primitive only handles Arrays. } } n = n * numLists; } else if (IsInt(b)) { n = slotRawInt(b); } else { return errWrongType; } n = sc_max(1, n); if(obj1->size > 0) { obj2 = instantiateObject(g->gc, obj1->classptr, n, false, true); for (i=j=k=0; islots[0]); // get the list's array } if (obj3 && isKindOf(obj3, class_array)) { m = j % obj3->size; slotCopy(&obj2->slots[i],&obj3->slots[m]); } else { slotCopy(&obj2->slots[i],&slots[k]); } } else { slotCopy(&obj2->slots[i],&slots[k]); } k = (k+1) % obj1->size; if (k == 0) j++; } } else { obj2 = instantiateObject(g->gc, obj1->classptr, n, true, true); } obj2->size = n; SetRaw(a, obj2); return errNone; } int prArrayContainsSeqColl(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slot, *endptr; PyrObject *obj; int size; a = g->sp; obj = slotRawObject(a); size = obj->size; slot = obj->slots - 1; endptr = slot + size; while (slot < endptr) { ++slot; if (IsObj(slot)) { if (isKindOf(slotRawObject(slot), class_sequenceable_collection)) { SetTrue(a); return errNone; } } } SetFalse(a); return errNone; } int prArrayNormalizeSum(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots2; PyrObject *obj1, *obj2; int i, size, err; double w, sum, rsum; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; obj2 = instantiateObject(g->gc, obj1->classptr, size, false, true); slots2 = obj2->slots; sum = 0.0; for (i=0; isize = size; SetRaw(a, obj2); return errNone; } int prArrayWIndex(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slots; PyrObject *obj; int i, j, size, err; double r, w, sum; a = g->sp; sum = 0.0; r = g->rgen->frand(); obj = slotRawObject(a); size = obj->size; j = size - 1; slots = obj->slots; for (i=0; i= r) { j = i; break; } } SetInt(a, j); return errNone; } enum { shape_Step, shape_Linear, shape_Exponential, shape_Sine, shape_Welch, shape_Curve, shape_Squared, shape_Cubed, shape_Hold }; enum { kEnv_initLevel, kEnv_numStages, kEnv_releaseNode, kEnv_loopNode }; int prArrayEnvAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; PyrObject* env = slotRawObject(a); PyrSlot* slots = env->slots; // Env:asArray always gives at least 8 array elements if(env->size < 8) return errFailed; double time; int err = slotDoubleVal(b, &time); if (err) return err; double begLevel; err = slotDoubleVal(slots + kEnv_initLevel, &begLevel); if (err) return err; int numStages; err = slotIntVal(slots + kEnv_numStages, &numStages); if (err) return err; double begTime = 0.; double endTime = 0.; for (int i=0; isp - 1; b = g->sp; obj = slotRawObject(a); size = obj->size; slots = obj->slots; err = slotDoubleVal(b, &s); if (err) return err; for (i=0; i s) { SetInt(a, i); return errNone; } } SetNil(a); return errNone; } int prArrayUnlace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slots, *slots2, *slots3; PyrObject *obj1, *obj2, *obj3; int i, j, k, clump, numLists, size, size3, err; a = g->sp - 2; b = g->sp - 1; c = g->sp; obj1 = slotRawObject(a); slots = obj1->slots; size = obj1->size; err = slotIntVal(b, &numLists); if (err) return err; err = slotIntVal(c, &clump); if (err) return err; obj2 = instantiateObject(g->gc, obj1->classptr, numLists, false, true); slots2 = obj2->slots; SetObject(b, obj2); // store reference on stack, so both source and destination objects can be reached by the gc size3 = size / numLists; size3 = size3 - (size3 % clump); if(size3 < 1) return errFailed; for(i=0; igc, obj1->classptr, size3, false, true); obj3->size = size3; slots3 = obj3->slots; for(j=0; jgc->GCWriteNew(obj2, obj3); // we know obj3 is white so we can use GCWriteNew obj2->size++; } SetRaw(a, obj2); return errNone; } void initArrayPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_BasicSize", basicSize, 1, 0); definePrimitive(base, index++, "_BasicMaxSize", basicMaxSize, 1, 0); definePrimitive(base, index++, "_BasicSwap", basicSwap, 3, 0); definePrimitive(base, index++, "_BasicAt", basicAt, 2, 0); definePrimitive(base, index++, "_BasicRemoveAt", basicRemoveAt, 2, 0); definePrimitive(base, index++, "_BasicTakeAt", basicTakeAt, 2, 0); definePrimitive(base, index++, "_BasicClipAt", basicClipAt, 2, 0); definePrimitive(base, index++, "_BasicWrapAt", basicWrapAt, 2, 0); definePrimitive(base, index++, "_BasicFoldAt", basicFoldAt, 2, 0); definePrimitive(base, index++, "_BasicPut", basicPut, 3, 0); definePrimitive(base, index++, "_BasicClipPut", basicClipPut, 3, 0); definePrimitive(base, index++, "_BasicWrapPut", basicWrapPut, 3, 0); definePrimitive(base, index++, "_BasicFoldPut", basicFoldPut, 3, 0); definePrimitive(base, index++, "_ArrayExtend", prArrayExtend, 3, 0); definePrimitive(base, index++, "_ArrayGrow", prArrayGrow, 2, 0); definePrimitive(base, index++, "_ArrayGrowClear", prArrayGrowClear, 2, 0); definePrimitive(base, index++, "_ArrayAdd", prArrayAdd, 2, 0); definePrimitive(base, index++, "_ArrayInsert", prArrayInsert, 3, 0); definePrimitive(base, index++, "_ArrayFill", prArrayFill, 2, 0); definePrimitive(base, index++, "_ArrayPop", prArrayPop, 1, 0); definePrimitive(base, index++, "_ArrayCat", prArrayCat, 2, 0); definePrimitive(base, index++, "_ArrayPutEach", prArrayPutEach, 3, 0); definePrimitive(base, index++, "_ArrayAddAll", prArrayAddAll, 2, 0); definePrimitive(base, index++, "_ArrayPutSeries", prArrayPutSeries, 5, 0); definePrimitive(base, index++, "_ArrayOverwrite", prArrayOverwrite, 3, 0); definePrimitive(base, index++, "_ArrayIndexOf", prArrayIndexOf, 2, 0); definePrimitive(base, index++, "_ArrayNormalizeSum", prArrayNormalizeSum, 1, 0); definePrimitive(base, index++, "_ArrayWIndex", prArrayWIndex, 1, 0); definePrimitive(base, index++, "_ArrayReverse", prArrayReverse, 1, 0); definePrimitive(base, index++, "_ArrayScramble", prArrayScramble, 1, 0); definePrimitive(base, index++, "_ArrayMirror", prArrayMirror, 1, 0); definePrimitive(base, index++, "_ArrayMirror1", prArrayMirror1, 1, 0); definePrimitive(base, index++, "_ArrayMirror2", prArrayMirror2, 1, 0); definePrimitive(base, index++, "_ArrayRotate", prArrayRotate, 2, 0); definePrimitive(base, index++, "_ArrayPermute", prArrayPermute, 2, 0); definePrimitive(base, index++, "_ArrayAllTuples", prArrayAllTuples, 2, 0); definePrimitive(base, index++, "_ArrayPyramid", prArrayPyramid, 2, 0); definePrimitive(base, index++, "_ArrayRotate", prArrayRotate, 2, 0); definePrimitive(base, index++, "_ArrayExtendWrap", prArrayExtendWrap, 2, 0); definePrimitive(base, index++, "_ArrayExtendFold", prArrayExtendFold, 2, 0); definePrimitive(base, index++, "_ArrayExtendLast", prArrayExtendLast, 2, 0); definePrimitive(base, index++, "_ArrayLace", prArrayLace, 2, 0); definePrimitive(base, index++, "_ArrayStutter", prArrayStutter, 2, 0); definePrimitive(base, index++, "_ArraySlide", prArraySlide, 3, 0); definePrimitive(base, index++, "_ArrayContainsSeqColl", prArrayContainsSeqColl, 1, 0); definePrimitive(base, index++, "_ArrayEnvAt", prArrayEnvAt, 2, 0); definePrimitive(base, index++, "_ArrayIndexOfGreaterThan", prArrayIndexOfGreaterThan, 2, 0); definePrimitive(base, index++, "_ArrayUnlace", prArrayUnlace, 3, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initArrayPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-Source/lang/LangPrimSource/PyrBitPrim.cpp000644 000765 000024 00000010616 12321461511 024235 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for some bit operations. */ #include "PyrPrimitive.h" #include "VMGlobals.h" #include "clz.h" int prNumBits(VMGlobals *g, int numArgsPushed); int prNumBits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, NUMBITS(slotRawInt(a))); return errNone; } int prLog2Ceil(VMGlobals *g, int numArgsPushed); int prLog2Ceil(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, LOG2CEIL(slotRawInt(a))); return errNone; } int prCLZ(VMGlobals *g, int numArgsPushed); int prCLZ(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, CLZ(slotRawInt(a))); return errNone; } int prCTZ(VMGlobals *g, int numArgsPushed); int prCTZ(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetRaw(a, CTZ(slotRawInt(a))); return errNone; } int prNextPowerOfTwo(VMGlobals *g, int numArgsPushed); int prNextPowerOfTwo(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRaw(a, NEXTPOWEROFTWO(slotRawInt(a))); return errNone; } int prIsPowerOfTwo(VMGlobals *g, int numArgsPushed); int prIsPowerOfTwo(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetBool(a, ISPOWEROFTWO(slotRawInt(a))); return errNone; } int prBinaryGrayCode(VMGlobals *g, int numArgsPushed); int prBinaryGrayCode(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRaw(a, GRAYCODE(slotRawInt(a))); return errNone; } int prSetBit(VMGlobals *g, int numArgsPushed); int prSetBit(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int32 bit, mask; int err = slotIntVal(b, &bit); if (err) return err; bit = bit & 31; mask = 1L << bit; if (IsFalse(c)) { SetRaw(a, slotRawInt(a) & ~mask); } else { SetRaw(a, slotRawInt(a) | mask); } return errNone; } int prHammingDistance(VMGlobals *g, int numArgsPushed); int prHammingDistance(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (NotInt(a) || NotInt(b)) return errWrongType; int aInt = slotRawInt(a); int bInt = slotRawInt(b); int count = 0, mask = 1; for(int i = 0; i < 32; i++) { if((aInt & mask) != (bInt & mask)) count = count + 1; mask = mask << 1; } SetRaw(a, count); return errNone; } void initBitPrimitives(); void initBitPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_NextPowerOfTwo", prNextPowerOfTwo, 1, 0); definePrimitive(base, index++, "_IsPowerOfTwo", prIsPowerOfTwo, 1, 0); definePrimitive(base, index++, "_CLZ", prCLZ, 1, 0); definePrimitive(base, index++, "_CTZ", prCTZ, 1, 0); definePrimitive(base, index++, "_NumBits", prNumBits, 1, 0); definePrimitive(base, index++, "_Log2Ceil", prLog2Ceil, 1, 0); definePrimitive(base, index++, "_SetBit", prSetBit, 3, 0); definePrimitive(base, index++, "_BinaryGrayCode", prBinaryGrayCode, 1, 0); definePrimitive(base, index++, "_HammingDistance", prHammingDistance, 2, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initBitPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-Source/lang/LangPrimSource/PyrCharPrim.cpp000644 000765 000024 00000014161 12321461511 024373 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Char. */ #include #include "PyrPrimitive.h" #include "VMGlobals.h" int prToLower(struct VMGlobals *g, int numArgsPushed); int prToLower(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRawChar(a, tolower(slotRawChar(a))); return errNone; } int prToUpper(struct VMGlobals *g, int numArgsPushed); int prToUpper(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetRawChar(a, toupper(slotRawChar(a))); return errNone; } int prIsLower(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (islower(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsUpper(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (isupper(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsAlpha(struct VMGlobals *g, int numArgsPushed); int prIsAlpha(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isalpha(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsAlphaNum(struct VMGlobals *g, int numArgsPushed); int prIsAlphaNum(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isalnum(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsControl(struct VMGlobals *g, int numArgsPushed); int prIsControl(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (iscntrl(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsDigit(struct VMGlobals *g, int numArgsPushed); int prIsDigit(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isdigit(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsPrint(struct VMGlobals *g, int numArgsPushed); int prIsPrint(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isprint(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsPunct(struct VMGlobals *g, int numArgsPushed); int prIsPunct(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (ispunct(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prIsSpace(struct VMGlobals *g, int numArgsPushed); int prIsSpace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (isspace(slotRawChar(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prAsciiValue(struct VMGlobals *g, int numArgsPushed); int prAsciiValue(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetTagRaw(a, tagInt); return errNone; } int prDigitValue(struct VMGlobals *g, int numArgsPushed); int prDigitValue(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char c; a = g->sp; c = slotRawChar(a); if (c >= '0' && c <= '9') { SetInt(a, c - '0'); } else if (c >= 'a' && c <= 'z') { SetInt(a, c - 'a' + 10); } else if (c >= 'A' && c <= 'Z') { SetInt(a, c - 'A' + 10); } else { return errFailed; } return errNone; } int prAsAscii(struct VMGlobals *g, int numArgsPushed); int prAsAscii(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetChar(a, slotRawInt(a) & 255); return errNone; } int prAsDigit(struct VMGlobals *g, int numArgsPushed); int prAsDigit(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; int c; a = g->sp; c = slotRawInt(a); if (c >= 0 && c <= 9) { SetChar(a, slotRawInt(a) + '0'); } else if (c >= 10 && c <= 35) { SetChar(a, slotRawInt(a) + 'A' - 10); } else { return errFailed; } return errNone; } void initCharPrimitives(); void initCharPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_AsciiValue", prAsciiValue, 1, 0); definePrimitive(base, index++, "_DigitValue", prDigitValue, 1, 0); definePrimitive(base, index++, "_AsAscii", prAsAscii, 1, 0); definePrimitive(base, index++, "_AsDigit", prAsDigit, 1, 0); definePrimitive(base, index++, "_ToLower", prToLower, 1, 0); definePrimitive(base, index++, "_ToUpper", prToUpper, 1, 0); definePrimitive(base, index++, "_IsLower", prIsLower, 1, 0); definePrimitive(base, index++, "_IsUpper", prIsUpper, 1, 0); definePrimitive(base, index++, "_IsAlpha", prIsAlpha, 1, 0); definePrimitive(base, index++, "_IsAlphaNum", prIsAlphaNum, 1, 0); definePrimitive(base, index++, "_IsPrint", prIsPrint, 1, 0); definePrimitive(base, index++, "_IsPunct", prIsPunct, 1, 0); definePrimitive(base, index++, "_IsControl", prIsControl, 1, 0); definePrimitive(base, index++, "_IsSpace", prIsSpace, 1, 0); definePrimitive(base, index++, "_IsDecDigit", prIsDigit, 1, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initCharPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-Source/lang/LangPrimSource/PyrDeepCopier.h000644 000765 000024 00000012147 12321461511 024354 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* An object archiving system for SuperCollider. */ #ifndef _PyrDeepCopier_ #define _PyrDeepCopier_ #include "PyrObject.h" #include "SC_AllocPool.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "VMGlobals.h" #include "GC.h" const int32 kDeepCopierObjectArrayInitialCapacity = 32; class PyrDeepCopier { public: PyrDeepCopier(VMGlobals *inG) : g(inG), objectArray(initialObjectArray), numObjects(0), objectArrayCapacity( kDeepCopierObjectArrayInitialCapacity ) {} ~PyrDeepCopier() { if (objectArrayCapacity > kDeepCopierObjectArrayInitialCapacity) { g->allocPool->Free(objectArray); } } long doDeepCopy(PyrSlot *objectSlot) { long err = errNone; try { if (IsObj(objectSlot)) { constructObjectArray(slotRawObject(objectSlot)); for (int i=0; iClearMark(); } } } catch (std::exception &ex) { error(ex.what()); err = errFailed; } return err; } private: void recurse(PyrObject *obj, size_t n) { //post("->recurse %s %08X\n", obj->classptr->name.us->name, obj); PyrSlot *slot = obj->slots; for (size_t i=0; iclassptr->name.us->name, obj); } void growObjectArray() { int32 newObjectArrayCapacity = objectArrayCapacity << 1; int32 newSize = newObjectArrayCapacity * sizeof(PyrObject*); PyrObject** newArray = (PyrObject**)g->allocPool->Alloc(newSize); memcpy(newArray, objectArray, numObjects * sizeof(PyrObject*)); if (objectArrayCapacity > kDeepCopierObjectArrayInitialCapacity) { g->allocPool->Free(objectArray); } objectArrayCapacity = newObjectArrayCapacity; objectArray = newArray; } void putSelf(PyrObject *obj) { obj->SetMark(); obj->scratch1 = numObjects; // expand array if needed if (numObjects >= objectArrayCapacity) growObjectArray(); //post("putSelf %d %08X\n", numObjects, obj); // add to array objectArray[numObjects++] = obj; } void putCopy(PyrObject *obj) { obj->SetMark(); obj->scratch1 = numObjects; // expand array if needed if (numObjects+2 >= objectArrayCapacity) growObjectArray(); // add a shallow copy to object array PyrObject *copy = copyObject(g->gc, obj, false); copy->ClearMark(); //post("putCopy %d %08X\n", numObjects, copy); // add to array objectArray[numObjects++] = copy; objectArray[numObjects++] = obj; } void constructObjectArray(PyrObject *obj) { //post("->constructObjectArray %s %08X\n", obj->classptr->name.us->name, obj); if (!obj->IsMarked()) { if (obj->obj_flags & (obj_immutable) && obj->obj_flags & (obj_permanent)) { putSelf(obj); } else if (isKindOf(obj, class_class)) { putSelf(obj); } else if (isKindOf(obj, class_process)) { putSelf(obj); } else if (isKindOf(obj, s_interpreter->u.classobj)) { putSelf(obj); } else if (isKindOf(obj, class_rawarray)) { putCopy(obj); } else if (isKindOf(obj, class_array)) { putCopy(obj); recurse(obj, obj->size); } else if (isKindOf(obj, class_func)) { putSelf(obj); } else if (isKindOf(obj, class_method)) { putSelf(obj); } else if (isKindOf(obj, class_thread)) { putSelf(obj); } else if (isKindOf(obj, class_server_shm_interface)) { putSelf(obj); } else { putCopy(obj); recurse(obj, obj->size); } } //post("<-constructObjectArray %s %08X\n", obj->classptr->name.us->name, obj); } void fixObjSlot(PyrSlot* slot) { //post("fixObjSlot %s %08X %d %08X\n", slotRawObject(slot)->classptr->name.us->name, slotRawObject(slot), slot->uo->scratch1, objectArray[slot->uo->scratch1]); SetRaw(slot, objectArray[slotRawObject(slot)->scratch1]); } void fixSlots(PyrObject *obj) { //post("fixSlots %s %08X %d\n", obj->classptr->name.us->name, obj, obj->IsMarked()); if (!obj->IsMarked() && obj->obj_format <= obj_slot) { // it is a copy PyrSlot *slot = obj->slots; for (int i=0; isize; ++i, ++slot) { if (IsObj(slot)) fixObjSlot(slot); } } } VMGlobals *g; PyrObject **objectArray; int32 numObjects; int32 objectArrayCapacity; PyrObject *initialObjectArray[kDeepCopierObjectArrayInitialCapacity]; }; #endif SuperCollider-Source/lang/LangPrimSource/PyrDeepFreezer.h000644 000765 000024 00000010024 12321461511 024525 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* An object archiving system for SuperCollider. */ #ifndef _PyrDeepFreezer_ #define _PyrDeepFreezer_ #include #include #include "PyrObject.h" #include "SC_AllocPool.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "VMGlobals.h" #include "GC.h" const int32 kDeepFreezerObjectArrayInitialCapacity = 32; class PyrDeepFreezer { public: PyrDeepFreezer(VMGlobals *inG) : g(inG), objectArray(initialObjectArray), numObjects(0), objectArrayCapacity( kDeepFreezerObjectArrayInitialCapacity ) {} ~PyrDeepFreezer() { if (objectArrayCapacity > kDeepFreezerObjectArrayInitialCapacity) g->allocPool->Free(objectArray); } long doDeepFreeze(PyrSlot *objectSlot) { long err = errNone; try { if (IsObj(objectSlot)) { constructObjectArray(slotRawObject(objectSlot)); for (int i=0; igc->BecomePermanent( objectArray[i] ); objectArray[i]->ClearMark(); } } } catch (std::exception &ex) { error(ex.what()); err = errFailed; for (int i=0; iClearMark(); } return err; } private: void recurse(PyrObject *obj, int n) { PyrSlot *slot = obj->slots; for (int i=0; iallocPool->Alloc(newSize); memcpy(newArray, objectArray, numObjects * sizeof(PyrObject*)); if (objectArrayCapacity > kDeepFreezerObjectArrayInitialCapacity) g->allocPool->Free(objectArray); objectArrayCapacity = newObjectArrayCapacity; objectArray = newArray; } void putObject(PyrObject *obj) { obj->SetMark(); // expand array if needed if (numObjects >= objectArrayCapacity) growObjectArray(); // add to array objectArray[numObjects++] = obj; } void constructObjectArray(PyrObject *obj) { if (obj->IsPermanent()) return; if (!obj->IsMarked()) { if (isKindOf(obj, class_process)) { throw std::runtime_error("cannot freeze Process.\n"); } else if (isKindOf(obj, s_interpreter->u.classobj)) { throw std::runtime_error("cannot freeze Interpreter.\n"); } else if (isKindOf(obj, class_rawarray)) { putObject(obj); } else if (isKindOf(obj, class_array)) { putObject(obj); recurse(obj, obj->size); } else if (isKindOf(obj, class_func)) { if (NotNil(&slotRawBlock(&((PyrClosure*)obj)->block)->contextDef)) { throw std::runtime_error("open Function can not be frozen.\n"); } putObject(obj); recurse(obj, obj->size); } else if (isKindOf(obj, class_method)) { throw std::runtime_error("cannot freeze Methods.\n"); } else if (isKindOf(obj, class_thread)) { throw std::runtime_error("cannot freeze Threads.\n"); } else if (isKindOf(obj, class_frame)) { throw std::runtime_error("cannot freeze Frames.\n"); } else { putObject(obj); recurse(obj, obj->size); } } } VMGlobals *g; PyrObject **objectArray; int32 numObjects; int32 objectArrayCapacity; PyrObject *initialObjectArray[kDeepFreezerObjectArrayInitialCapacity]; }; #endif SuperCollider-Source/lang/LangPrimSource/PyrFilePrim.cpp000644 000765 000024 00000115630 12756531745 024423 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for File i/o. */ #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrSymbol.h" #include "PyrFilePrim.h" #include "ReadWriteMacros.h" #include "SCBase.h" #include "SC_DirUtils.h" #include "sc_popen.h" #include #include #include #include #include "../../common/SC_SndFileHelpers.hpp" #ifndef _WIN32 # include #else # include #endif #include #include #include #if defined(__APPLE__) || defined(SC_IPHONE) #ifndef _SC_StandAloneInfo_ # include "SC_StandAloneInfo_Darwin.h" #endif # include # include #ifndef SC_IPHONE # include #endif #endif #define DELIMITOR ':' int prFileDelete(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; boost::system::error_code error_code; boost::filesystem::remove(filename, error_code); if (error_code) SetFalse(a); else SetTrue(a); return errNone; } int prFileMTime(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; time_t mtime = boost::filesystem::last_write_time(filename); SetInt(a, mtime); return errNone; } int prFileExists(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; bool res = boost::filesystem::exists(filename); SetBool(a, res); return errNone; } int prFileRealPath(struct VMGlobals* g, int numArgsPushed ) { PyrSlot *a = g->sp - 1, *b = g->sp; char ipath[PATH_MAX]; char opath[PATH_MAX]; int err; err = slotStrVal(b, ipath, PATH_MAX); if (err) return err; bool isAlias = false; if(sc_ResolveIfAlias(ipath, opath, isAlias, PATH_MAX)!=0) { return errFailed; } boost::system::error_code error_code; boost::filesystem::path p = boost::filesystem::canonical(opath,error_code); if(error_code) { SetNil(a); return errNone; } strcpy(opath,p.string().c_str()); #if __APPLE__ CFStringRef cfstring = CFStringCreateWithCString(NULL, opath, kCFStringEncodingUTF8); err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX); CFRelease(cfstring); if (err) return errFailed; #endif // __APPLE__ PyrString* pyrString = newPyrString(g->gc, opath, 0, true); SetObject(a, pyrString); return errNone; } int prFileMkDir(struct VMGlobals * g, int numArgsPushed) { PyrSlot *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; boost::system::error_code error_code; boost::filesystem::create_directories(filename, error_code); if (error_code) postfl("Warning: %s (\"%s\")\n", error_code.message().c_str(), filename); return errNone; } int prFileCopy(struct VMGlobals * g, int numArgsPushed) { PyrSlot *b = g->sp - 1, *c = g->sp; char filename1[PATH_MAX]; char filename2[PATH_MAX]; int error; error = slotStrVal(b, filename1, PATH_MAX); if (error != errNone) return error; error = slotStrVal(c, filename2, PATH_MAX); if (error != errNone) return error; boost::filesystem::copy(filename1, filename2); return errNone; } int prFileType(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; boost::filesystem::file_status s(boost::filesystem::symlink_status(filename)); SetInt(a, s.type()); return errNone; } int prFileSize(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp - 1, *b = g->sp; char filename[PATH_MAX]; int error = slotStrVal(b, filename, PATH_MAX); if (error != errNone) return error; uintmax_t sz = boost::filesystem::file_size(filename); SetInt(a, sz); return errNone; } int prFileOpen(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; char filename[PATH_MAX]; char mode[12]; PyrFile *pfile; FILE *file; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(c) || !isKindOf(slotRawObject(c), class_string) || NotObj(b) || !isKindOf(slotRawObject(b), class_string)) return errWrongType; if (slotRawObject(b)->size > PATH_MAX - 1) return errFailed; if (slotRawObject(c)->size > 11) return errFailed; pfile = (PyrFile*)slotRawObject(a); memcpy(filename, slotRawString(b)->s, slotRawObject(b)->size); filename[slotRawString(b)->size] = 0; memcpy(mode, slotRawString(c)->s, slotRawObject(c)->size); mode[slotRawString(c)->size] = 0; #ifdef _WIN32 win32_ReplaceCharInString(filename,PATH_MAX,'/','\\'); if(strcmp(mode,"w") == 0) strcpy(mode,"wb"); if(strcmp(mode,"r") == 0) strcpy(mode,"rb"); #endif //_WIN32 file = fopen(filename, mode); if (file) { SetPtr(&pfile->fileptr, file); SetTrue(a); } else { #ifdef _WIN32 // check if directory exisits // create a temporary file (somewhere) for a handle // the file is deleted automatically when closed if (sc_DirectoryExists(filename)) { int err; #ifdef _MSC_VER err = tmpfile_s(&file); if (!err) { SetPtr(&pfile->fileptr, file); SetTrue(a); return errNone; } #elif defined(__MINGW32__) file = tmpfile(); if (file) { SetPtr(&pfile->fileptr, file); SetTrue(a); return errNone; } #else #error compiler unsupported #endif } #endif SetNil(a); SetFalse(a); } return errNone; } int prFileClose(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errNone; SetPtr(&pfile->fileptr, NULL); if (fclose(file)) return errFailed; return errNone; } int prFileFlush(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file != NULL) fflush(file); return errNone; } int prFilePos(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; long length; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if ((length=ftell(file)) == -1) return errFailed; SetInt(a, (int)length); return errNone; } int prFileLength(struct VMGlobals *g, int numArgsPushed) { PyrSlot * a = g->sp; PyrFile *pfile = (PyrFile*)slotRawObject(a); FILE *file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; // preserve file position fpos_t pos; if (fgetpos(file, &pos)) return errFailed; if (fseek(file, 0, SEEK_END)) return errFailed; size_t length; length = ftell(file); if (fsetpos(file, &pos)) return errFailed; SetInt(a, length); return errNone; } int prFileSeek(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; PyrFile *pfile; FILE *file; size_t offset; int origin; static int originTable[3] = { SEEK_SET, SEEK_CUR, SEEK_END }; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotInt(b)) return errWrongType; if (NotInt(c)) return errWrongType; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; offset = slotRawInt(b); origin = slotRawInt(c); if (origin < 0 || origin > 2) return errIndexOutOfRange; origin = originTable[origin]; // translate in case ANSI constants ever change.. if (fseek(file, offset, origin)) return errFailed; return errNone; } int prFileWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *ptr; PyrFile *pfile; FILE *file; PyrObject *obj; char chr; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; switch (GetTag(b)) { case tagInt : { SC_IOStream scio(file); scio.writeInt32_be(slotRawInt(b)); break; } case tagSym : fwrite(slotRawSymbol(b)->name, sizeof(char), slotRawSymbol(b)->length, file); break; case tagChar : chr = slotRawChar(b); fwrite(&chr, sizeof(char), 1, file); break; case tagNil : case tagFalse : case tagTrue : case tagPtr : return errWrongType; case tagObj : { // writes the indexable part of any non obj_slot format object obj = slotRawObject(b); if (!isKindOf(obj, class_rawarray) || isKindOf(obj, class_symbolarray)) return errWrongType; if (obj->size) { ptr = obj->slots; int elemSize = gFormatElemSize[obj->obj_format]; int numElems = obj->size; #if BYTE_ORDER != BIG_ENDIAN switch (elemSize) { case 1: fwrite(ptr, elemSize, numElems, file); break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { fputc(ptr[7], file); fputc(ptr[6], file); fputc(ptr[5], file); fputc(ptr[4], file); fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } } #else fwrite(ptr, elemSize, numElems, file); #endif } break; } default : // double { SC_IOStream scio(file); scio.writeDouble_be(slotRawFloat(b)); break; } } return errNone; } int prFileWriteLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *ptr; PyrFile *pfile; FILE *file; PyrObject *obj; char chr; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; switch (GetTag(b)) { case tagInt : { SC_IOStream scio(file); scio.writeInt32_le(slotRawInt(b)); break; } case tagSym : fwrite(slotRawSymbol(b)->name, sizeof(char), slotRawSymbol(b)->length, file); break; case tagChar : chr = slotRawInt(b); fwrite(&chr, sizeof(char), 1, file); break; case tagNil : case tagFalse : case tagTrue : case tagPtr : return errWrongType; case tagObj : { // writes the indexable part of any non obj_slot format object obj = slotRawObject(b); if (!isKindOf(obj, class_rawarray) || isKindOf(obj, class_symbolarray)) return errWrongType; if (obj->size) { ptr = obj->slots; int elemSize = gFormatElemSize[obj->obj_format]; int numElems = obj->size; #if BYTE_ORDER == BIG_ENDIAN switch (elemSize) { case 1: fwrite(ptr, elemSize, numElems, file); break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { fputc(ptr[7], file); fputc(ptr[6], file); fputc(ptr[5], file); fputc(ptr[4], file); fputc(ptr[3], file); fputc(ptr[2], file); fputc(ptr[1], file); fputc(ptr[0], file); } break; } } #else fwrite(ptr, elemSize, numElems, file); #endif } break; } default : // double { SC_IOStream scio(file); scio.writeDouble_le(slotRawFloat(b)); break; } } return errNone; } int prFileReadLine(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; // receiver(a File), string PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; char* result = fgets(slotRawString(b)->s, MAXINDEXSIZE(slotRawObject(b)) - 1, file); if (!result) { SetNil(a); } else { slotRawString(b)->size = strlen(slotRawString(b)->s); if (slotRawString(b)->s[slotRawString(b)->size-1] == '\n') slotRawString(b)->size--; slotCopy(a,b); } return errNone; } int prFilePutInt32(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt32_be(val); return errNone; } int prFilePutInt16(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt16_be(val); return errNone; } int prFilePutInt32LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt32_le(val); return errNone; } int prFilePutInt16LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt16_le(val); return errNone; } int prFilePutInt8(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int val; int err = slotIntVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeInt8(val); return errNone; } int prFilePutChar(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; char z; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (NotChar(b)) return errWrongType; z = slotRawChar(b); SC_IOStream scio(file); scio.writeInt8(z); return errNone; } int prFilePutFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) { dumpObjectSlot(a); return errFailed; } float val; int err = slotFloatVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeFloat_be(val); return errNone; } int prFilePutDouble(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; double val; int err = slotDoubleVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeDouble_be(val); return errNone; } int prFilePutFloatLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) { dumpObjectSlot(a); return errFailed; } float val; int err = slotFloatVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeFloat_le(val); return errNone; } int prFilePutDoubleLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; double val; int err = slotDoubleVal(b, &val); if (err) return err; SC_IOStream scio(file); scio.writeDouble_le(val); return errNone; } int prFilePutString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrFile *pfile; FILE *file; PyrString *string; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (NotObj(b) || slotRawObject(b)->classptr != class_string) return errWrongType; string = slotRawString(b); if (string->size) { fwrite(string->s, 1, string->size, file); } return errNone; } int prFileGetDouble(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readDouble_be()); } return errNone; } int prFileGetFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readFloat_be()); } return errNone; } int prFileGetDoubleLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readDouble_le()); } return errNone; } int prFileGetFloatLE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetFloat(a, scio.readFloat_le()); } return errNone; } int prFileGetChar(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; char z; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int count = fread(&z, sizeof(char), 1, file); if (count==0) SetNil(a); else SetChar(a, z); return errNone; } int prFileGetInt8(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; int8 z; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int count = fread(&z, sizeof(int8), 1, file); if (count==0) SetNil(a); else SetInt(a, z); return errNone; } int prFileGetInt16(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt16_be()); } return errNone; } int prFileGetInt32(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt32_be()); } return errNone; } int prFileGetInt16LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt16_le()); } return errNone; } int prFileGetInt32LE(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrFile *pfile; FILE *file; a = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; if (feof(file)) SetNil(a); else { SC_IOStream scio(file); SetInt(a, scio.readInt32_le()); } return errNone; } int prFileReadRaw(struct VMGlobals *g, int numArgsPushed) { PyrFile *pfile; FILE *file; PyrSlot* a = g->sp - 1; PyrSlot* b = g->sp; if (!isKindOfSlot(b, class_rawarray) || isKindOfSlot(b, class_symbolarray)) return errWrongType; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int elemSize = gFormatElemSize[slotRawObject(b)->obj_format]; int numElems = slotRawObject(b)->size; numElems = fread(slotRawString(b)->s, elemSize, numElems, file); slotRawObject(b)->size = numElems; #if BYTE_ORDER != BIG_ENDIAN switch (elemSize) { case 1: break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { char temp = ptr[0]; ptr[0] = ptr[1]; ptr[1] = temp; } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { char temp = ptr[0]; ptr[0] = ptr[3]; ptr[3] = temp; temp = ptr[1]; ptr[1] = ptr[2]; ptr[2] = temp; } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { char temp = ptr[0]; ptr[0] = ptr[7]; ptr[7] = temp; temp = ptr[1]; ptr[1] = ptr[6]; ptr[6] = temp; temp = ptr[2]; ptr[2] = ptr[5]; ptr[5] = temp; temp = ptr[3]; ptr[3] = ptr[4]; ptr[4] = temp; } break; } } #endif if (slotRawObject(b)->size==0) SetNil(a); else slotCopy(a,b); return errNone; } int prFileReadRawLE(struct VMGlobals *g, int numArgsPushed) { PyrFile *pfile; FILE *file; PyrSlot* a = g->sp - 1; PyrSlot* b = g->sp; if (!isKindOfSlot(b, class_rawarray) || isKindOfSlot(b, class_symbolarray)) return errWrongType; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errFailed; int elemSize = gFormatElemSize[slotRawObject(b)->obj_format]; int numElems = slotRawObject(b)->size; numElems = fread(slotRawString(b)->s, elemSize, numElems, file); slotRawObject(b)->size = numElems; #if BYTE_ORDER == BIG_ENDIAN switch (elemSize) { case 1: break; case 2: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*2; for (; ptr < ptrend; ptr+=2) { char temp = ptr[0]; ptr[0] = ptr[1]; ptr[1] = temp; } break; } case 4: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*4; for (; ptr < ptrend; ptr+=4) { char temp = ptr[0]; ptr[0] = ptr[3]; ptr[3] = temp; temp = ptr[1]; ptr[1] = ptr[2]; ptr[2] = temp; } break; } case 8: { char *ptr = slotRawString(b)->s; char *ptrend = ptr + numElems*8; for (; ptr < ptrend; ptr+=8) { char temp = ptr[0]; ptr[0] = ptr[7]; ptr[7] = temp; temp = ptr[1]; ptr[1] = ptr[6]; ptr[6] = temp; temp = ptr[2]; ptr[2] = ptr[5]; ptr[5] = temp; temp = ptr[3]; ptr[3] = ptr[4]; ptr[4] = temp; } break; } } #endif if (slotRawObject(b)->size==0) SetNil(a); else slotCopy(a,b); return errNone; } int prFileGetcwd(struct VMGlobals *g, int numArgsPushed) { //PyrSlot* a = g->sp - 1; // File PyrSlot* string = g->sp; if (!isKindOfSlot(string, class_string)) return errWrongType; char * cwd = getcwd(slotRawString(string)->s,255); if (cwd == NULL) { error(strerror(errno)); return errFailed; } slotRawString(string)->size = strlen(slotRawString(string)->s); return errNone; } //////// int prPipeOpen(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; char mode[12]; PyrFile *pfile; FILE *file; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(c) || !isKindOf(slotRawObject(c), class_string) || NotObj(b) || !isKindOf(slotRawObject(b), class_string)) return errWrongType; if (slotRawObject(c)->size > 11) return errFailed; pfile = (PyrFile*)slotRawObject(a); char *commandLine = (char*)malloc(slotRawObject(b)->size + 1); memcpy(commandLine, slotRawString(b)->s, slotRawObject(b)->size); commandLine[slotRawString(b)->size] = 0; memcpy(mode, slotRawString(c)->s, slotRawObject(c)->size); mode[slotRawString(c)->size] = 0; pid_t pid; file = sc_popen(commandLine, &pid, mode); free(commandLine); if (file) { SetPtr(&pfile->fileptr, file); SetInt(a, pid); } else { SetNil(a); } return errNone; } int prPipeClose(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrSlot *b; PyrFile *pfile; FILE *file; pid_t pid; a = g->sp - 1; b = g->sp; pfile = (PyrFile*)slotRawObject(a); file = (FILE*)slotRawPtr(&pfile->fileptr); if (file == NULL) return errNone; pid = (pid_t) slotRawInt(b); SetPtr(&pfile->fileptr, NULL); int perr = sc_pclose(file, pid); SetInt(a, perr); if (perr == -1) return errFailed; return errNone; } //////// #ifndef NO_LIBSNDFILE #include int sampleFormatToString(struct SF_INFO *info, const char **string); int sampleFormatToString(struct SF_INFO *info, const char **string) { unsigned int format = info->format & SF_FORMAT_SUBMASK; switch (format) { case SF_FORMAT_DPCM_8: case SF_FORMAT_PCM_S8: *string = "int16"; break; case SF_FORMAT_DPCM_16: case SF_FORMAT_PCM_16: case SF_FORMAT_DWVW_16: *string = "int16"; break; case SF_FORMAT_PCM_24: case SF_FORMAT_DWVW_24: *string = "int24"; break; case SF_FORMAT_PCM_32: *string = "int32"; break; case SF_FORMAT_FLOAT: *string = "float"; break; case SF_FORMAT_DOUBLE: *string = "double"; break; case SF_FORMAT_ULAW: *string = "ulaw"; break; case SF_FORMAT_ALAW: *string = "alaw"; break; default: *string = "float"; break; } return errNone; } int headerFormatToString(struct SF_INFO *info, const char **string); int headerFormatToString(struct SF_INFO *info, const char **string){ switch (info->format & SF_FORMAT_TYPEMASK) { case SF_FORMAT_WAV : *string = "WAV"; break; case SF_FORMAT_AIFF : *string = "AIFF"; break ; case SF_FORMAT_AU : *string = "SUN"; break ; case SF_FORMAT_IRCAM : *string = "IRCAM"; break ; case SF_FORMAT_RAW : *string = "raw"; break ; case SF_FORMAT_W64 : *string = "WAV"; break ; case SF_FORMAT_FLAC : *string = "FLAC"; break ; // TODO allow other platforms to know vorbis once libsndfile 1.0.18 is established #if __APPLE__ || _WIN32 || LIBSNDFILE_1018 case SF_FORMAT_VORBIS : *string = "vorbis"; break ; #endif /* case SF_FORMAT_PAF : break ; case SF_FORMAT_SVX : break ; case SF_FORMAT_NIST : break ; case SF_FORMAT_VOC : break ; case SF_FORMAT_MAT4 : break ; case SF_FORMAT_MAT5 : break ; case SF_FORMAT_PVF : break ; case SF_FORMAT_XI : break ; case SF_FORMAT_HTK : break ; case SF_FORMAT_SDS : break ; */ default : *string = " "; break ; } return errNone; } int sndfileFormatInfoToStrings(struct SF_INFO *info, const char **stringHead, const char **stringSample); int sndfileFormatInfoToStrings(struct SF_INFO *info, const char **stringHead, const char **stringSample) { int error = 0; error = headerFormatToString(info, stringHead); error = sampleFormatToString(info, stringSample); return error; } int prSFOpenRead(struct VMGlobals *g, int numArgsPushed); int prSFOpenRead(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; char filename[PATH_MAX]; SNDFILE *file; SF_INFO info; const char *headerstr; const char *sampleformatstr; a = g->sp - 1; b = g->sp; PyrObject *obj1 = slotRawObject(a); if (!isKindOfSlot(b, class_string)) return errWrongType; if (slotRawObject(b)->size > PATH_MAX - 1) return errFailed; memcpy(filename, slotRawString(b)->s, slotRawObject(b)->size); filename[slotRawString(b)->size] = 0; info.format = 0; file = sf_open(filename, SFM_READ, &info); if (file) { SetPtr(obj1->slots + 0, file); sndfileFormatInfoToStrings(&info, &headerstr, &sampleformatstr); //headerFormatToString(&info, &headerstr); PyrString *hpstr = newPyrString(g->gc, headerstr, 0, true); SetObject(obj1->slots+1, hpstr); g->gc->GCWriteNew(obj1, (PyrObjectHdr*)hpstr); // we know hpstr is white so we can use GCWriteNew PyrString *smpstr = newPyrString(g->gc, sampleformatstr, 0, true); SetObject(obj1->slots+2, smpstr); g->gc->GCWriteNew(obj1, (PyrObjectHdr*)smpstr); // we know smpstr is white so we can use GCWriteNew SetInt(obj1->slots + 3, info.frames); SetInt(obj1->slots + 4, info.channels); SetInt(obj1->slots + 5, info.samplerate); SetTrue(a); } else { SetNil(a); SetFalse(a); } return errNone; } int prSFOpenWrite(struct VMGlobals *g, int numArgsPushed); int prSFOpenWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; char filename[PATH_MAX]; SNDFILE *file; SF_INFO info; PyrSlot *headerSlot; PyrSlot *formatSlot; int error; a = g->sp - 1; b = g->sp; headerSlot = (slotRawObject(a)->slots + 1); formatSlot = (slotRawObject(a)->slots + 2); if (!isKindOfSlot(headerSlot, class_string)) return errWrongType; if (!isKindOfSlot(formatSlot, class_string)) return errWrongType; if (!isKindOfSlot(b, class_string)) return errWrongType; if (slotRawObject(b)->size > PATH_MAX - 1) return errFailed; memcpy(filename, slotRawString(b)->s, slotRawObject(b)->size); filename[slotRawString(b)->size] = 0; #ifdef _WIN32 char* headerFormat = (char *)malloc(slotRawObject(headerSlot)->size); #else char headerFormat[slotRawString(headerSlot)->size]; #endif memcpy(headerFormat, slotRawString(headerSlot)->s, slotRawObject(headerSlot)->size); headerFormat[slotRawString(headerSlot)->size] = 0; #ifdef _WIN32 char* sampleFormat = (char *)malloc(slotRawString(formatSlot)->size); #else char sampleFormat[slotRawString(formatSlot)->size]; #endif memcpy(sampleFormat, slotRawString(formatSlot)->s, slotRawObject(formatSlot)->size); sampleFormat[slotRawString(formatSlot)->size] = 0; error = sndfileFormatInfoFromStrings(&info, headerFormat, sampleFormat); if(error) { #ifdef _WIN32 free(sampleFormat); free(headerFormat); #endif return errFailed; } if(error) return errFailed; //slotIntVal(slotRawObject(a)->slots + 3, &info.frames); slotIntVal(slotRawObject(a)->slots + 4, &info.channels); slotIntVal(slotRawObject(a)->slots + 5, &info.samplerate); file = sf_open(filename, SFM_WRITE, &info); sf_command(file, SFC_SET_CLIPPING, NULL, SF_TRUE); if (file) { SetPtr(slotRawObject(a)->slots+0, file); SetTrue(a); } else { SetNil(a); SetFalse(a); } return errNone; } int prSFClose(struct VMGlobals *g, int numArgsPushed); int prSFClose(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if (file) { sf_close(file); SetNil(slotRawObject(a)->slots + 0); } return errNone; } int prSFRead(struct VMGlobals *g, int numArgsPushed); int prSFRead(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if (!isKindOfSlot(b, class_rawarray)) return errWrongType; switch (slotRawObject(b)->obj_format) { case obj_int16 : slotRawObject(b)->size = sf_read_short(file, (short*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_int32 : slotRawObject(b)->size = sf_read_int(file, (int*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_float : slotRawObject(b)->size = sf_read_float(file, (float*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_double : slotRawObject(b)->size = sf_read_double(file, (double*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; default: error("sample format not supported.\n"); return errFailed; } return errNone; } int prSFWrite(struct VMGlobals *g, int numArgsPushed); int prSFWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if (!isKindOfSlot(b, class_rawarray)) return errWrongType; switch (slotRawObject(b)->obj_format) { case obj_int16 : sf_write_short(file, (short*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_int32 : sf_write_int(file, (int*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_float : sf_write_float(file, (float*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; case obj_double : sf_write_double(file, (double*)slotRawInt8Array(b)->b, slotRawObject(b)->size); break; default: error("sample format not supported.\n"); return errFailed; } return errNone; } int prSFSeek(struct VMGlobals *g, int numArgsPushed); int prSFSeek(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; a = g->sp - 2; b = g->sp - 1; c = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); int origin, offset; int err = slotIntVal(b, &offset); if (err) return err; err = slotIntVal(c, &origin); if (err) return err; sf_seek(file, offset, origin); return errNone; } int prSFHeaderInfoString(struct VMGlobals *g, int numArgsPushed); int prSFHeaderInfoString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SNDFILE *file = (SNDFILE*)slotRawPtr(&slotRawObject(a)->slots[0]); if(file){ static char strbuffer [(1 << 16)] ; sf_command (file, SFC_GET_LOG_INFO, strbuffer, (1 << 16)) ; PyrString *pstring = newPyrString(g->gc, strbuffer, 0, true); // post(strbuffer); SetObject(a, pstring); return errNone; } return errFailed; } #else // !NO_LIBSNDFILE int prSFOpenRead(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFOpenWrite(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFClose(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFWrite(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFRead(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFSeek(struct VMGlobals *g, int numArgsPushed) { return errFailed; } int prSFHeaderInfoString(struct VMGlobals *g, int numArgsPushed) { return errFailed; } #endif // !NO_LIBSNDFILE ///////////// void initFilePrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_SFOpenRead", prSFOpenRead, 2, 0); definePrimitive(base, index++, "_SFOpenWrite", prSFOpenWrite, 2, 0); definePrimitive(base, index++, "_SFClose", prSFClose, 1, 0); definePrimitive(base, index++, "_SFWrite", prSFWrite, 2, 0); definePrimitive(base, index++, "_SFRead", prSFRead, 2, 0); definePrimitive(base, index++, "_SFSeek", prSFSeek, 3, 0); definePrimitive(base, index++, "_SFHeaderInfoString", prSFHeaderInfoString, 1, 0); definePrimitive(base, index++, "_PipeOpen", prPipeOpen, 3, 0); definePrimitive(base, index++, "_PipeClose", prPipeClose, 2, 0); definePrimitive(base, index++, "_FileDelete", prFileDelete, 2, 0); definePrimitive(base, index++, "_FileMTime", prFileMTime, 2, 0); definePrimitive(base, index++, "_FileExists", prFileExists, 2, 0); definePrimitive(base, index++, "_FileRealPath", prFileRealPath, 2, 0); definePrimitive(base, index++, "_FileMkDir", prFileMkDir, 2, 0); definePrimitive(base, index++, "_FileCopy", prFileCopy, 3, 0); definePrimitive(base, index++, "_FileType", prFileType, 2, 0); definePrimitive(base, index++, "_FileSize", prFileSize, 2, 0); definePrimitive(base, index++, "_FileOpen", prFileOpen, 3, 0); definePrimitive(base, index++, "_FileClose", prFileClose, 1, 0); definePrimitive(base, index++, "_FileFlush", prFileFlush, 1, 0); definePrimitive(base, index++, "_FileSeek", prFileSeek, 3, 0); definePrimitive(base, index++, "_FilePos", prFilePos, 1, 0); definePrimitive(base, index++, "_FileLength", prFileLength, 1, 0); definePrimitive(base, index++, "_FileWrite", prFileWrite, 2, 0); definePrimitive(base, index++, "_FileWriteLE", prFileWriteLE, 2, 0); definePrimitive(base, index++, "_FileReadLine", prFileReadLine, 2, 0); definePrimitive(base, index++, "_File_getcwd", prFileGetcwd, 2, 0); definePrimitive(base, index++, "_FilePutChar", prFilePutChar, 2, 0); definePrimitive(base, index++, "_FilePutInt8", prFilePutInt8, 2, 0); definePrimitive(base, index++, "_FilePutInt16", prFilePutInt16, 2, 0); definePrimitive(base, index++, "_FilePutInt32", prFilePutInt32, 2, 0); definePrimitive(base, index++, "_FilePutFloat", prFilePutFloat, 2, 0); definePrimitive(base, index++, "_FilePutDouble", prFilePutDouble, 2, 0); definePrimitive(base, index++, "_FilePutInt16LE", prFilePutInt16LE, 2, 0); definePrimitive(base, index++, "_FilePutInt32LE", prFilePutInt32LE, 2, 0); definePrimitive(base, index++, "_FilePutFloatLE", prFilePutFloatLE, 2, 0); definePrimitive(base, index++, "_FilePutDoubleLE", prFilePutDoubleLE, 2, 0); definePrimitive(base, index++, "_FileGetChar", prFileGetChar, 1, 0); definePrimitive(base, index++, "_FileGetInt8", prFileGetInt8, 1, 0); definePrimitive(base, index++, "_FileGetInt16", prFileGetInt16, 1, 0); definePrimitive(base, index++, "_FileGetInt32", prFileGetInt32, 1, 0); definePrimitive(base, index++, "_FileGetFloat", prFileGetFloat, 1, 0); definePrimitive(base, index++, "_FileGetDouble", prFileGetDouble, 1, 0); definePrimitive(base, index++, "_FileGetInt16LE", prFileGetInt16LE, 1, 0); definePrimitive(base, index++, "_FileGetInt32LE", prFileGetInt32LE, 1, 0); definePrimitive(base, index++, "_FileGetFloatLE", prFileGetFloatLE, 1, 0); definePrimitive(base, index++, "_FileGetDoubleLE", prFileGetDoubleLE, 1, 0); definePrimitive(base, index++, "_FilePutString", prFilePutString, 2, 0); definePrimitive(base, index++, "_FileReadRaw", prFileReadRaw, 2, 0); definePrimitive(base, index++, "_FileReadRawLE", prFileReadRawLE, 2, 0); } SuperCollider-Source/lang/LangPrimSource/PyrFilePrim.h000644 000765 000024 00000004432 12321461511 024042 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRFILEPRIM_H_ #define _PYRFILEPRIM_H_ #include "PyrObject.h" struct PyrFile : public PyrObjectHdr { PyrSlot fileptr; }; void initFilePrimitives(); long prFileDelete(VMGlobals *g, long numArgsPushed); long prFileOpen(VMGlobals *g, long numArgsPushed); long prFileClose(VMGlobals *g, long numArgsPushed); long prFileSeek(VMGlobals *g, long numArgsPushed); long prFilePos(VMGlobals *g, long numArgsPushed); long prFileLength(VMGlobals *g, long numArgsPushed); long prFileWrite(VMGlobals *g, long numArgsPushed); long prFileReadLine(VMGlobals *g, long numArgsPushed); long prFilePutRGB(VMGlobals *g, long numArgsPushed); long prFilePutInt32(VMGlobals *g, long numArgsPushed); long prFilePutInt16(VMGlobals *g, long numArgsPushed); long prFilePutInt8(VMGlobals *g, long numArgsPushed); long prFilePutChar(VMGlobals *g, long numArgsPushed); long prFilePutFloat(VMGlobals *g, long numArgsPushed); long prFilePutDouble(VMGlobals *g, long numArgsPushed); long prFileGetRGB(VMGlobals *g, long numArgsPushed); long prFileGetInt32(VMGlobals *g, long numArgsPushed); long prFileGetInt16(VMGlobals *g, long numArgsPushed); long prFileGetInt8(VMGlobals *g, long numArgsPushed); long prFileGetChar(VMGlobals *g, long numArgsPushed); long prFileGetFloat(VMGlobals *g, long numArgsPushed); long prFileGetDouble(VMGlobals *g, long numArgsPushed); long prFilePutString(VMGlobals *g, long numArgsPushed); long prFileRead(VMGlobals *g, long numArgsPushed); #endif SuperCollider-Source/lang/LangPrimSource/PyrListPrim.cpp000644 000765 000024 00000051070 12756531745 024454 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrKernelProto.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrSymbol.h" #include "PyrListPrim.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSignal.h" #include "PyrMessage.h" #include "PyrSched.h" #include "SC_RGen.h" #include "SCBase.h" #include #include int objectPerform(VMGlobals *g, int numArgsPushed); int ivxIdentDict_array, ivxIdentDict_size, ivxIdentDict_parent, ivxIdentDict_proto, ivxIdentDict_know; int class_array_index, class_array_maxsubclassindex; int class_identdict_index, class_identdict_maxsubclassindex; PyrClass *class_identdict; PyrSymbol *s_proto, *s_parent; PyrSymbol *s_delta, *s_dur, *s_stretch; #define HASHSYMBOL(sym) (sym >> 5) #define ISKINDOF(obj, lo, hi) (\ objClassIndex = slotRawInt(&obj->classptr->classIndex), \ objClassIndex >= lo && objClassIndex <= hi) int prArrayMultiChanExpand(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *slot, *slots1, *slots2, *slots3, *slots4; PyrObject *obj1, *obj2, *obj3, *obj4; int i, j, size, len, maxlen; a = g->sp; obj1 = slotRawObject(a); size = obj1->size; slots1 = obj1->slots; maxlen = 1; for (j=0; jclassptr == class_array) { len = slotRawObject(slot)->size; maxlen = len > maxlen ? len : maxlen; } else if (isKindOf(slotRawObject(slot), class_sequenceable_collection) && (slotRawObject(slot)->classptr != class_string)) { return errFailed; // this primitive only handles Arrays. } } } obj2 = newPyrArray(g->gc, maxlen, 0, true); SetObject(a, obj2); slots2 = obj2->slots; for (i=0; igc, size, 0, true); obj3->size = size; SetObject(slots2 + i, obj3); g->gc->GCWriteNew(obj2, obj3); // we know obj3 is white so we can use GCWriteNew obj2->size++; slots1 = obj1->slots; slots3 = obj3->slots; for (j=0; jclassptr == class_array && slotRawObject(slot)->size > 0) { PyrSlot *slotToCopy; obj4 = slotRawObject(slot); slots4 = obj4->slots; slotToCopy = &slots4[i % obj4->size]; slotCopy(&slots3[j],slotToCopy); g->gc->GCWrite(obj3, slotToCopy); } else { slotCopy(&slots3[j],slot); g->gc->GCWrite(obj3, slot); } } else { slotCopy(&slots3[j],slot); // we don't need GCWrite here, as slot is not an object } } } return errNone; } int arrayAtIdentityHash(PyrObject *array, PyrSlot *key) { PyrSlot *slots, *test; unsigned int i, start, end, hash, maxHash; hash = calcHash(key); maxHash = array->size; start = hash % maxHash; end = array->size; slots = array->slots; for (i=start; isp - 1; // array b = g->sp; // key array = slotRawObject(a); if(array->size == 0) return errFailed; index = arrayAtIdentityHash(array, b); SetInt(a, index); return errNone; } int arrayAtIdentityHashInPairs(PyrObject *array, PyrSlot *key) { PyrSlot *slots, *test; unsigned int i, start, end, hash, maxHash; hash = calcHash(key); maxHash = array->size >> 1; start = (hash % maxHash) << 1; end = array->size; slots = array->slots; for (i=start; isize >> 1; start = (hash % maxHash) << 1; end = array->size; slots = array->slots; for (i=start; islots + ivxIdentDict_know); if (knows && IsSym(key)) { if (slotRawSymbol(key) == s_parent) { slotCopy(&dict->slots[ivxIdentDict_parent],value); g->gc->GCWrite(dict, value); return errNone; } if (slotRawSymbol(key) == s_proto) { slotCopy(&dict->slots[ivxIdentDict_proto],value); g->gc->GCWrite(dict, value); return errNone; } } array = slotRawObject(&dict->slots[ivxIdentDict_array]); if (array->IsImmutable()) return errImmutableObject; if (!isKindOf((PyrObject*)array, class_array)) return errFailed; index = arrayAtIdentityHashInPairs(array, key); slot = array->slots + index; slotCopy(&slot[1],value); g->gc->GCWrite(array, value); if (IsNil(slot)) { slotCopy(slot,key); g->gc->GCWrite(array, key); size = slotRawInt(&dict->slots[ivxIdentDict_size]) + 1; SetRaw(&dict->slots[ivxIdentDict_size], size); if (array->size < size*3) { PyrObject *newarray; newarray = newPyrArray(g->gc, size*3, 0, false); newarray->size = ARRAYMAXINDEXSIZE(newarray); nilSlots(newarray->slots, newarray->size); slot = array->slots; for (i=0; isize; i+=2, slot+=2) { if (NotNil(slot)) { index = arrayAtIdentityHashInPairs(newarray, slot); newslot = newarray->slots + index; slotCopy(&newslot[0],&slot[0]); slotCopy(&newslot[1],&slot[1]); } } SetRaw(&dict->slots[ivxIdentDict_array], newarray); g->gc->GCWriteNew(dict, newarray); // we know newarray is white so we can use GCWriteNew } } return errNone; } int prIdentDict_Put(struct VMGlobals *g, int numArgsPushed); int prIdentDict_Put(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; a = g->sp - 2; // dict b = g->sp - 1; // key c = g->sp; // value if(IsNil(b)) return errWrongType; if(IsNil(c)) return errFailed; // will call removeAt return identDictPut(g, slotRawObject(a), b, c); } int prIdentDict_PutGet(struct VMGlobals *g, int numArgsPushed); int prIdentDict_PutGet(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d, *slot, *newslot; int i, index, size; PyrObject *dict; PyrObject *array; a = g->sp - 2; // dict b = g->sp - 1; // key c = g->sp; // value d = ++g->sp; // push the stack to save the receiver slotCopy(d,a); dict = slotRawObject(d); array = slotRawObject(&dict->slots[ivxIdentDict_array]); if (!isKindOf((PyrObject*)array, class_array)) { SetNil(a); --g->sp; return errFailed; } index = arrayAtIdentityHashInPairs(array, b); slot = array->slots + index; slotCopy(a,&slot[1]); slotCopy(&slot[1],c); g->gc->GCWrite(array, c); if (IsNil(slot)) { slotCopy(slot,b); g->gc->GCWrite(array, b); size = slotRawInt(&dict->slots[ivxIdentDict_size]) + 1; SetRaw(&dict->slots[ivxIdentDict_size], size); if (array->size < size*3) { PyrObject *newarray; newarray = newPyrArray(g->gc, size*3, 0, true); newarray->size = ARRAYMAXINDEXSIZE(newarray); nilSlots(newarray->slots, newarray->size); slot = array->slots; for (i=0; isize; i+=2, slot+=2) { if (NotNil(slot)) { index = arrayAtIdentityHashInPairs(newarray, slot); newslot = newarray->slots + index; slotCopy(&newslot[0],&slot[0]); slotCopy(&newslot[1],&slot[1]); } } SetRaw(&dict->slots[ivxIdentDict_array], newarray); g->gc->GCWriteNew(dict, newarray); // we know newarray is white so we can use GCWriteNew } } --g->sp; return errNone; } int prArray_AtIdentityHashInPairs(struct VMGlobals *g, int numArgsPushed); int prArray_AtIdentityHashInPairs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; unsigned int i; a = g->sp - 1; // array b = g->sp; // key if(slotRawObject(a)->size < 2) return errFailed; i = arrayAtIdentityHashInPairs(slotRawObject(a), b); SetInt(a, i); return errNone; } bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result); bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result) { again: PyrSlot *dictslots = dict->slots; PyrSlot *arraySlot = dictslots + ivxIdentDict_array; if (isKindOfSlot(arraySlot, class_array)) { PyrObject *array = slotRawObject(arraySlot); int index = arrayAtIdentityHashInPairsWithHash(array, key, hash); if (SlotEq(key, array->slots + index)) { slotCopy(result,&array->slots[index + 1]); return true; } } PyrClass *identDictClass = s_identitydictionary->u.classobj; PyrSlot *parentSlot = dictslots + ivxIdentDict_parent; PyrSlot * protoSlot = dictslots + ivxIdentDict_proto; if (isKindOfSlot(parentSlot, identDictClass)) { if (isKindOfSlot(protoSlot, identDictClass)) { // recursive call. if (identDict_lookupNonNil(slotRawObject(protoSlot), key, hash, result)) return true; } dict = slotRawObject(parentSlot); goto again; // tail call } else { if (isKindOfSlot(protoSlot, identDictClass)) { dict = slotRawObject(protoSlot); goto again; // tail call } } return false; } bool identDict_lookup(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result); bool identDict_lookup(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result) { again: PyrSlot *dictslots = dict->slots; PyrSlot *arraySlot = dictslots + ivxIdentDict_array; if (isKindOfSlot(arraySlot, class_array)) { PyrObject *array = slotRawObject(arraySlot); int index = arrayAtIdentityHashInPairsWithHash(array, key, hash); if (SlotEq(key, array->slots + index)) { slotCopy(result,&array->slots[index + 1]); return true; } } PyrClass *identDictClass = s_identitydictionary->u.classobj; PyrSlot *parentSlot = dictslots + ivxIdentDict_parent; PyrSlot * protoSlot = dictslots + ivxIdentDict_proto; if (isKindOfSlot(parentSlot, identDictClass)) { if (isKindOfSlot(protoSlot, identDictClass)) { // recursive call. if (identDict_lookup(slotRawObject(protoSlot), key, hash, result)) return true; } dict = slotRawObject(parentSlot); goto again; // tail call } else { if (isKindOfSlot(protoSlot, identDictClass)) { dict = slotRawObject(protoSlot); goto again; // tail call } } SetNil(result); return false; } int prIdentDict_At(struct VMGlobals *g, int numArgsPushed); int prIdentDict_At(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp - 1; // dict PyrSlot* key = g->sp; // key PyrObject *dict = slotRawObject(a); bool knows = IsTrue(dict->slots + ivxIdentDict_know); if (knows && IsSym(key)) { if (slotRawSymbol(key) == s_parent) { slotCopy(a,&dict->slots[ivxIdentDict_parent]); return errNone; } if (slotRawSymbol(key) == s_proto) { slotCopy(a,&dict->slots[ivxIdentDict_proto]); return errNone; } } identDict_lookup(dict, key, calcHash(key), a); return errNone; } int prSymbol_envirGet(struct VMGlobals *g, int numArgsPushed); int prSymbol_envirGet(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, result; int objClassIndex; a = g->sp; // key PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; PyrObject *dict = slotRawObject(currentEnvironmentSlot); if (!IsObj(currentEnvironmentSlot)) return errFailed; if (!ISKINDOF(dict, class_identdict_index, class_identdict_maxsubclassindex)) return errFailed; identDict_lookup(dict, a, calcHash(a), &result); slotCopy(a,&result); return errNone; } int prSymbol_envirPut(struct VMGlobals *g, int numArgsPushed); int prSymbol_envirPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int objClassIndex; a = g->sp - 1; // key b = g->sp; // value PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; PyrObject *dict = slotRawObject(currentEnvironmentSlot); if (!IsObj(currentEnvironmentSlot)) return errFailed; if (!ISKINDOF(dict, class_identdict_index, class_identdict_maxsubclassindex)) return errFailed; int err = identDictPut(g, dict, a, b); if (err) return err; slotCopy(a,b); return errNone; } int prEvent_Delta(struct VMGlobals *g, int numArgsPushed); int prEvent_Delta(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, key, dur, stretch, delta; double fdur, fstretch; int err; a = g->sp; // dict SetSymbol(&key, s_delta); identDict_lookup(slotRawObject(a), &key, calcHash(&key), &delta); if (NotNil(&delta)) { slotCopy(a,&delta); } else { SetSymbol(&key, s_dur); identDict_lookup(slotRawObject(a), &key, calcHash(&key), &dur); err = slotDoubleVal(&dur, &fdur); if (err) { if (NotNil(&dur)) return err; SetNil(a); return errNone; } SetSymbol(&key, s_stretch); identDict_lookup(slotRawObject(a), &key, calcHash(&key), &stretch); err = slotDoubleVal(&stretch, &fstretch); if (err) { if (NotNil(&stretch)) return err; SetFloat(a, fdur); return errNone; } SetFloat(a, fdur * fstretch ); } return errNone; } void PriorityQueueAdd(struct VMGlobals *g, PyrObject* queueobj, PyrSlot* item, double time); void PriorityQueueAdd(struct VMGlobals *g, PyrObject* queueobj, PyrSlot* item, double time) { PyrObject *schedq, *newschedq; int size, maxsize; PyrSlot *schedqSlot = queueobj->slots; if (!IsObj(schedqSlot)) { size = 32; schedq = newPyrArray(g->gc, size, 0, true); schedq->size = 1; SetInt(schedq->slots + 0, 0); // stability count SetObject(schedqSlot, schedq); g->gc->GCWriteNew(queueobj, schedq); // we know schedq is white so we can use GCWriteNew } else { schedq = slotRawObject(schedqSlot); maxsize = ARRAYMAXINDEXSIZE(schedq); size = schedq->size; if (size+3 > maxsize) { newschedq = newPyrArray(g->gc, maxsize*2, 0, true); newschedq->size = size; slotCopy(newschedq->slots, schedq->slots, size); assert(IsInt(newschedq->slots)); SetObject(schedqSlot, newschedq); g->gc->GCWriteNew(queueobj, newschedq); // we know newschedq is white so we can use GCWriteNew schedq = newschedq; } } addheap(g, schedq, time, item); } int prPriorityQueueAdd(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueAdd(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; // priority queue PyrSlot *b = g->sp - 1; // time PyrSlot *c = g->sp; // item double time; int err = slotDoubleVal(b, &time); if (err) return errNone; // nil is OK, nothing gets added PriorityQueueAdd(g, slotRawObject(a), c, time); return errNone; } void PriorityQueuePop(VMGlobals *g, PyrObject *queueobj, PyrSlot *result); void PriorityQueuePop(VMGlobals *g, PyrObject *queueobj, PyrSlot *result) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); double time; if (!getheap(g, schedq, &time, result)) { SetNil(result); } } else { SetNil(result); } } void PriorityQueueTop(PyrObject *queueobj, PyrSlot *result); void PriorityQueueTop(PyrObject *queueobj, PyrSlot *result) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); if (schedq->size > 1) { slotCopy(result,&schedq->slots[1]); } else { SetNil(result); } } else { SetNil(result); } } void PriorityQueueClear(PyrObject *queueobj); void PriorityQueueClear(PyrObject *queueobj) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); SetInt(schedq->slots, 0); // stability count schedq->size = 1; } } bool PriorityQueueEmpty(PyrObject *queueobj); bool PriorityQueueEmpty(PyrObject *queueobj) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); if (schedq->size > 1) { return false; } } return true; } int prPriorityQueuePop(struct VMGlobals *g, int numArgsPushed); int prPriorityQueuePop(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; // priority queue PriorityQueuePop(g, slotRawObject(a), a); return errNone; } int prPriorityQueueTop(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueTop(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; // priority queue PriorityQueueTop(slotRawObject(a), a); return errNone; } int prPriorityQueueClear(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueClear(struct VMGlobals *g, int numArgsPushed) { PyrSlot* a = g->sp; // priority queue PriorityQueueClear(slotRawObject(a)); return errNone; } int prPriorityQueueEmpty(struct VMGlobals *g, int numArgsPushed); int prPriorityQueueEmpty(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; // priority queue if (PriorityQueueEmpty(slotRawObject(a))) { SetTrue(a); } else { SetFalse(a); } return errNone; } void PriorityQueuePostpone(PyrObject* queueobj, double time); void PriorityQueuePostpone(PyrObject* queueobj, double time) { PyrSlot *schedqSlot = queueobj->slots; if (IsObj(schedqSlot)) { PyrObject *schedq = slotRawObject(schedqSlot); PyrSlot* slots = schedq->slots; for (int i=1; i < schedq->size; i+=3) { SetRaw(&slots[i], slotRawFloat(&slots[i]) + time); } } } int prPriorityQueuePostpone(struct VMGlobals *g, int numArgsPushed); int prPriorityQueuePostpone(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; // priority queue PyrSlot *b = g->sp; // time double time; int err = slotDoubleVal(b, &time); if (err) return err; PyrObject *queueobj = slotRawObject(a); PriorityQueuePostpone(queueobj, time); return errNone; } void initListPrimitives(); void initListPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_Array_AtIdentityHash", prArray_AtIdentityHash, 2, 0); definePrimitive(base, index++, "_Array_AtIdentityHashInPairs", prArray_AtIdentityHashInPairs, 2, 0); definePrimitive(base, index++, "_IdentDict_Put", prIdentDict_Put, 3, 0); definePrimitive(base, index++, "_IdentDict_PutGet", prIdentDict_PutGet, 3, 0); definePrimitive(base, index++, "_IdentDict_At", prIdentDict_At, 2, 0); definePrimitive(base, index++, "_Symbol_envirGet", prSymbol_envirGet, 1, 0); definePrimitive(base, index++, "_Symbol_envirPut", prSymbol_envirPut, 2, 0); definePrimitive(base, index++, "_ArrayMultiChannelExpand", prArrayMultiChanExpand, 1, 0); definePrimitive(base, index++, "_PriorityQueueAdd", prPriorityQueueAdd, 3, 0); definePrimitive(base, index++, "_PriorityQueuePop", prPriorityQueuePop, 1, 0); definePrimitive(base, index++, "_PriorityQueueTop", prPriorityQueueTop, 1, 0); definePrimitive(base, index++, "_PriorityQueueClear", prPriorityQueueClear, 1, 0); definePrimitive(base, index++, "_PriorityQueueEmpty", prPriorityQueueEmpty, 1, 0); definePrimitive(base, index++, "_PriorityQueuePostpone", prPriorityQueuePostpone, 2, 0); definePrimitive(base, index++, "_Event_Delta", prEvent_Delta, 1, 0); } void initPatterns(); void initPatterns() { PyrSymbol *sym; ivxIdentDict_array = instVarOffset("IdentityDictionary", "array"); ivxIdentDict_size = instVarOffset("IdentityDictionary", "size"); ivxIdentDict_parent = instVarOffset("IdentityDictionary", "parent"); ivxIdentDict_proto = instVarOffset("IdentityDictionary", "proto"); ivxIdentDict_know = instVarOffset("IdentityDictionary", "know"); sym = getsym("IdentityDictionary"); class_identdict = sym ? sym->u.classobj : NULL; class_identdict_index = slotRawInt(&class_identdict->classIndex); class_identdict_maxsubclassindex = slotRawInt(&class_identdict->maxSubclassIndex); class_array_index = slotRawInt(&class_array->classIndex); class_array_maxsubclassindex = slotRawInt(&class_array->maxSubclassIndex); s_parent = getsym("parent"); s_proto = getsym("proto"); s_delta = getsym("delta"); s_dur = getsym("dur"); s_stretch = getsym("stretch"); } SuperCollider-Source/lang/LangPrimSource/PyrListPrim.h000644 000765 000024 00000002307 12321461511 024075 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRARRAYPRIM_H_ #define _PYRARRAYPRIM_H_ void initArrayPrimitives(); int prArrayMultiChanExpand(VMGlobals *g, int numArgsPushed); int arrayAtIdentityHash(PyrObject *array, PyrSlot *key); int arrayAtIdentityHashInPairs(PyrObject *array, PyrSlot *key); int arrayAtIdentityHashInPairsWithHash(PyrObject *array, PyrSlot *key, int hash); #endif SuperCollider-Source/lang/LangPrimSource/PyrMathPrim.cpp000644 000765 000024 00000062411 12524671173 024424 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrMathPrim.h" #include "MiscInlineMath.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSignal.h" #include "PyrParseNode.h" #include "PyrMessage.h" #include "clz.h" #include #include #include #include "SC_Endian.h" #include "SCBase.h" #include "boost/math/special_functions.hpp" const int INT_MAX_BY_PyrSlot = INT_MAX / sizeof(PyrSlot); inline bool IsSignal(PyrSlot* slot) { return (IsObj(slot) && slotRawObject(slot)->classptr == class_signal); } inline bool NotSignal(PyrSlot* slot) { return (NotObj(slot) || slotRawObject(slot)->classptr != class_signal); } /* functors for dispatching template code */ struct addNum { static inline double run(double lhs, double rhs) { return lhs + rhs; } static inline int run(int lhs, int rhs) { return lhs + rhs; } static inline PyrObject* signal_xf(VMGlobals *g, PyrObject* ina, float inb) { return signal_add_xf(g, ina, inb); } static inline PyrObject* signal_fx(VMGlobals *g, float ina, PyrObject* inb) { return signal_xf(g, inb, ina); } static inline PyrObject* signal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { return signal_add_xx(g, ina, inb); } }; struct mulNum { static inline double run(double lhs, double rhs) { return lhs * rhs; } static inline int run(int lhs, int rhs) { return lhs * rhs; } static inline PyrObject* signal_xf(VMGlobals *g, PyrObject* ina, float inb) { return signal_mul_xf(g, ina, inb); } static inline PyrObject* signal_fx(VMGlobals *g, float ina, PyrObject* inb) { return signal_xf(g, inb, ina); } static inline PyrObject* signal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { return signal_mul_xx(g, ina, inb); } }; struct subNum { static inline double run(double lhs, double rhs) { return lhs - rhs; } static inline int run(int lhs, int rhs) { return lhs - rhs; } static inline PyrObject* signal_xf(VMGlobals *g, PyrObject* ina, float inb) { return signal_sub_xf(g, ina, inb); } static inline PyrObject* signal_fx(VMGlobals *g, float ina, PyrObject* inb) { return signal_sub_fx(g, ina, inb); } static inline PyrObject* signal_xx(VMGlobals *g, PyrObject* ina, PyrObject* inb) { return signal_sub_xx(g, ina, inb); } }; template inline int prOpNum(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(a)) { case tagInt : switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawInt(a), slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawInt(a), slotRawObject(b))); else goto send_normal_2; break; default : SetFloat(a, slotRawInt(a) + slotRawFloat(b)); break; } break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : // leave self in 'a' break; case tagObj : if (isKindOf(slotRawObject(a), class_signal)) { switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::signal_xf(g, slotRawObject(a), slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) { SetRaw(a, Functor::signal_xx(g, slotRawObject(a), slotRawObject(b))); } else goto send_normal_2; break; default : // double SetRaw(a, Functor::signal_xf(g, slotRawObject(a), slotRawFloat(b))); break; } } else goto send_normal_2; break; default : // double switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawFloat(a), (double)slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawFloat(a), slotRawObject(b))); else goto send_normal_2; break; default : // double SetRaw(a, Functor::run(slotRawFloat(a), slotRawFloat(b))); break; } break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; } template inline int prOpInt(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawInt(a), slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawInt(a), slotRawObject(b))); else goto send_normal_2; break; default : SetFloat(a, Functor::run((double)slotRawInt(a), slotRawFloat(b))); break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; } template inline int prOpFloat(VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrSymbol *msg; a = g->sp - 1; b = g->sp; switch (GetTag(b)) { case tagInt : SetRaw(a, Functor::run(slotRawFloat(a), (double)slotRawInt(b))); break; case tagChar : case tagPtr : case tagNil : case tagFalse : case tagTrue : goto send_normal_2; case tagSym : SetSymbol(a, slotRawSymbol(b)); break; case tagObj : if (isKindOf(slotRawObject(b), class_signal)) SetObject(a, Functor::signal_fx(g, slotRawFloat(a), slotRawObject(b))); else goto send_normal_2; break; default : SetRaw(a, Functor::run(slotRawFloat(a), slotRawFloat(b))); break; } g->sp-- ; // drop g->numpop = 0; #if TAILCALLOPTIMIZE g->tailCall = 0; #endif return errNone; send_normal_2: if (numArgsPushed != -1) // special case flag meaning it is a primitive return errFailed; // arguments remain on the stack msg = gSpecialBinarySelectors[g->primitiveIndex]; sendMessage(g, msg, 2); return errNone; } int prAddNum(VMGlobals *g, int numArgsPushed) { return prOpNum(g, numArgsPushed); } int prSubNum(VMGlobals *g, int numArgsPushed) { return prOpNum(g, numArgsPushed); } int prMulNum(VMGlobals *g, int numArgsPushed) { return prOpNum(g, numArgsPushed); } int prAddFloat(VMGlobals *g, int numArgsPushed) { return prOpFloat(g, numArgsPushed); } int prSubFloat(VMGlobals *g, int numArgsPushed) { return prOpFloat(g, numArgsPushed); } int prMulFloat(VMGlobals *g, int numArgsPushed) { return prOpFloat(g, numArgsPushed); } int prAddInt(VMGlobals *g, int numArgsPushed) { return prOpInt(g, numArgsPushed); } int prSubInt(VMGlobals *g, int numArgsPushed) { return prOpInt(g, numArgsPushed); } int prMulInt(VMGlobals *g, int numArgsPushed) { return prOpInt(g, numArgsPushed); } int prNthPrime(VMGlobals *g, int numArgsPushed); int prNthPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p; a = g->sp; n = slotRawInt(a); p = nthPrime(n); if (p == 0) { SetNil(a); } else { SetInt(a, p); } return errNone; } int prPrevPrime(VMGlobals *g, int numArgsPushed); int prPrevPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p, i; a = g->sp; n = slotRawInt(a); i = prevPrime(n); p = nthPrime(i); if (p == 0) { SetNil(a); } else { SetInt(a, p); } return errNone; } int prNextPrime(VMGlobals *g, int numArgsPushed); int prNextPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p, i; a = g->sp; n = slotRawInt(a); i = nextPrime(n); p = nthPrime(i); if (p == 0) { SetNil(a); } else { SetInt(a, p); } return errNone; } int prIsPrime(VMGlobals *g, int numArgsPushed); int prIsPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p, sqrtn, i; a = g->sp; n = slotRawInt(a); SetNil(a); if (n <= 2) { if (n == 2) { SetTrue(a); } else { SetFalse(a); } } else if (n <= nthPrime(NUMPRIMES-1)) { // do a search of the primes table i = findPrime(n); if (i >= 0) { SetTrue(a); } else { SetFalse(a); } } else { #ifdef _WIN32 sqrtn = (int)sqrt(static_cast(n)); #else sqrtn = (int)sqrt(n); #endif for (i=0; i= sqrtn) { SetTrue(a); break; } } } return errNone; } int prIndexOfPrime(VMGlobals *g, int numArgsPushed); int prIndexOfPrime(VMGlobals *g, int numArgsPushed) { PyrSlot *a; int n, p; a = g->sp; n = slotRawInt(a); if (n <= 2) { if (n == 2) { SetInt(a, 0); } else { SetNil(a); } } else if (n <= nthPrime(NUMPRIMES-1)) { p = findPrime(n); if (p < 0) { SetNil(a); } else { SetInt(a, p); } } else { SetNil(a); } return errNone; } int prAs32Bits(VMGlobals *g, int numArgsPushed); int prAs32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; // return an integer that is a bit pattern for the 32 bit float representation union { float f; int32 i; } u; u.f = slotRawFloat(a); SetInt(a, u.i); return errNone; } int prHigh32Bits(VMGlobals *g, int numArgsPushed); int prHigh32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.f = slotRawFloat(a); SetInt(a, du.i.hi); return errNone; } int prLow32Bits(VMGlobals *g, int numArgsPushed); int prLow32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.f = slotRawFloat(a); SetInt(a, du.i.lo); return errNone; } int prFrom32Bits(VMGlobals *g, int numArgsPushed); int prFrom32Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int err, word; err = slotIntVal(b, &word); if (err) return err; union { float f; int32 i; } u; u.i = word; SetFloat(a, u.f); return errNone; } int prFrom64Bits(VMGlobals *g, int numArgsPushed); int prFrom64Bits(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, hi, lo; err = slotIntVal(b, &hi); if (err) return err; err = slotIntVal(c, &lo); if (err) return err; #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.i.hi = hi; du.i.lo = lo; SetFloat(a, du.f); return errNone; } int mathClipInt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsInt(b) && IsInt(c)) { SetRaw(a, sc_clip(slotRawInt(a), slotRawInt(b), slotRawInt(c))); } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetFloat(a, sc_clip((double)slotRawInt(a), lo, hi)); } return errNone; } int mathClipFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_clip(slotRawFloat(a), lo, hi)); } return errNone; } int mathClipSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; float lo, hi; int err; PyrObject *sig; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsSignal(b) && IsSignal(c)) { sig = signal_clip_x(g, slotRawObject(a), slotRawObject(b), slotRawObject(c)); SetObject(a, sig); } else { err = slotFloatVal(b, &lo); if (err) return err; err = slotFloatVal(c, &hi); if (err) return err; sig = signal_clip_f(g, slotRawObject(a), lo, hi); SetObject(a, sig); } return errNone; } int mathWrapInt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsInt(b) && IsInt(c)) { SetRaw(a, sc_mod((int)(slotRawInt(a) - slotRawInt(b)), (int)(slotRawInt(c) - slotRawInt(b) + 1)) + slotRawInt(b)); } else { double x, lo, hi; x = slotRawInt(a); err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetFloat(a, sc_mod(x - lo, hi - lo) + lo); } return errNone; } int mathWrapFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_mod(slotRawFloat(a) - lo, hi - lo) + lo); } return errNone; } int mathWrapSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; float lo, hi; int err; PyrObject *sig; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsSignal(b) && IsSignal(c)) { sig = signal_wrap_x(g, slotRawObject(a), slotRawObject(b), slotRawObject(c)); SetObject(a, sig); } else { err = slotFloatVal(b, &lo); if (err) return err; err = slotFloatVal(c, &hi); if (err) return err; sig = signal_wrap_f(g, slotRawObject(a), lo, hi); SetObject(a, sig); } return errNone; } int mathFoldInt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsInt(b) && IsInt(c)) { SetRaw(a, sc_fold(slotRawInt(a), slotRawInt(b), slotRawInt(c))); } else { double x, lo, hi; x = slotRawInt(a); err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetFloat(a, sc_fold(x, lo, hi)); } return errNone; } int mathFoldFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; double lo, hi; int err; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else { err = slotDoubleVal(b, &lo); if (err) return err; err = slotDoubleVal(c, &hi); if (err) return err; SetRaw(a, sc_fold(slotRawFloat(a), lo, hi)); } return errNone; } int mathFoldSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; float lo, hi; int err; PyrObject *sig; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (IsSym(b)) { *a = *b; } else if (IsSym(c)) { *a = *c; } else if (IsSignal(b) && IsSignal(c)) { sig = signal_fold_x(g, slotRawObject(a), slotRawObject(b), slotRawObject(c)); SetObject(a, sig); } else { err = slotFloatVal(b, &lo); if (err) return err; err = slotFloatVal(c, &hi); if (err) return err; sig = signal_fold_f(g, slotRawObject(a), lo, hi); SetObject(a, sig); } return errNone; } int prSimpleNumberSeries(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, size; if (IsInt(a) && (IsInt(b) || IsNil(b)) && IsInt(c)) { int first, second, last, step; first = slotRawInt(a); last = slotRawInt(c); second = IsInt(b) ? slotRawInt(b) : (first < last ? first + 1 : first - 1); step = second - first; if ( step == 0 ) size = 1; else size = ((last - first) / step) + 1; if ((size < 1) || ((step >= 0) && (last < first)) || ((step <= 0) && (last > first))) { post("prSimpleNumberSeries: arguments do not form an arithmetic progression: first: %i, step: %i, last %i\n", first, step, last); return errFailed; } if(size > INT_MAX_BY_PyrSlot){ post("prSimpleNumberSeries: array size %i exceeds limit (%i)\n", size, INT_MAX_BY_PyrSlot); return errFailed; } PyrObject *obj = newPyrArray(g->gc, size, 0, true); obj->size = size; PyrSlot *slots = obj->slots; if(step==1){ // Faster iteration for common case if(first==0){ for (int i=0; i= 0) && (last < first)) || ((step <= 0) && (last > first))) { post("prSimpleNumberSeries: arguments do not form an arithmetic progression: first: %f, step: %f, last %f\n", first, step, last); return errFailed; } if(size > INT_MAX_BY_PyrSlot){ post("prSimpleNumberSeries: array size %i exceeds limit (%i)\n", size, INT_MAX_BY_PyrSlot); return errFailed; } PyrObject *obj = newPyrArray(g->gc, size, 0, true); obj->size = size; PyrSlot *slots = obj->slots; if(first==0. && step==1.){ // Faster iteration for common case for (long i=0; i mediant[0] } { if (maxDenominator < mediant[1]) {^upper}; d = upper[0] - (this * upper[1]); if (d == 0) {^upper}; lower = mediant; k = floor(((this * lower[1]) - lower[0]) / d); k1 = k + 1; temp = [lower[0] + (k1 * upper[0]), lower[1] + (k1 * upper[1])]; lower = [lower[0] + (k * upper[0]), lower[1] + (k * upper[1])]; upper = temp; } { (this * mediant[1]) == mediant[0] } { if (maxDenominator >= mediant[1]) {^mediant}; if (lower[1] < upper[1]) {^lower}; ^upper } { if (maxDenominator < mediant[1]) {^lower}; d = lower[0] - (this * lower[1]); if (d == 0) {^lower}; upper = mediant; k = floor(((this * upper[1]) - upper[0]) / d); k1 = k + 1; temp = [(k1 * lower[0]) + upper[0], (k1 * lower[1]) + upper[1]]; upper = [(k * lower[0]) + upper[0], (k * lower[1]) + upper[1]]; lower = temp; }; } } */ int prAsFraction(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double mediant_num, lower_num, upper_num, temp_num; double mediant_den, lower_den, upper_den, temp_den; double x, d; int k, k1; int maxDenominator; int err; bool neg = false; err = slotDoubleVal(a, &x); if (err) return err; err = slotIntVal(b, &maxDenominator); if (err) return err; bool faster = IsTrue(c); PyrObject *obj = newPyrArray(g->gc, 2, 0, true); obj->size = 2; PyrSlot *slots = obj->slots; SetObject(a, obj); if (x < 0.0) { x = -x; neg = true; } if (x == 0.0) { SetInt(slots+0, 0); SetInt(slots+1, 1); return errNone; } if (x < 1.0) { upper_num = 1.0; upper_den = floor(1./x); lower_num = 1.0; lower_den = upper_den + 1.; } else { lower_num = floor(x); lower_den = 1.0; upper_num = lower_num + 1.; upper_den = 1.0; } while (true) { mediant_num = lower_num + upper_num; mediant_den = lower_den + upper_den; //post(" md %g %g %g %g %g %g\n", mediant_num, mediant_den, lower_num, lower_den, upper_num, upper_den); if (x * mediant_den > mediant_num) { d = upper_num - (x * upper_den); if (maxDenominator < mediant_den || fabs(d) < 1e-5) { if (neg) upper_num = -upper_num; SetInt(slots+0, (int)upper_num); SetInt(slots+1, (int)upper_den); return errNone; } lower_num = mediant_num; lower_den = mediant_den; if (faster) { k = (int)floor(((x * lower_den) - lower_num) / d); if (k < 10000) { k1 = k + 1; temp_num = lower_num + (k1 * upper_num); temp_den = lower_den + (k1 * upper_den); lower_num = lower_num + (k * upper_num); lower_den = lower_den + (k * upper_den); upper_num = temp_num; upper_den = temp_den; } } } else if (x * mediant_den == mediant_num) { if (maxDenominator >= mediant_den) { if (neg) mediant_num = -mediant_num; SetInt(slots+0, (int)mediant_num); SetInt(slots+1, (int)mediant_den); return errNone; } else if (lower_den < upper_den) { if (neg) lower_num = -lower_num; SetInt(slots+0, (int)lower_num); SetInt(slots+1, (int)lower_den); return errNone; } else { if (neg) upper_num = -upper_num; SetInt(slots+0, (int)upper_num); SetInt(slots+1, (int)upper_den); return errNone; } } else { d = lower_num - (x * lower_den); if (maxDenominator < mediant_den || fabs(d) < 1e-5) { if (neg) lower_num = -lower_num; SetInt(slots+0, (int)lower_num); SetInt(slots+1, (int)lower_den); return errNone; } upper_num = mediant_num; upper_den = mediant_den; if (faster) { k = (int)floor(((x * upper_den) - upper_num) / d); if (k < 10000) { k1 = k + 1; temp_num = (k1 * lower_num) + upper_num; temp_den = (k1 * lower_den) + upper_den; upper_num = (k * lower_num) + upper_num; upper_den = (k * lower_den) + upper_den; lower_num = temp_num; lower_den = temp_den; } } } } } void initMathPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_AddInt", prAddInt, 2, 0); definePrimitive(base, index++, "_SubInt", prSubInt, 2, 0); definePrimitive(base, index++, "_MulInt", prMulInt, 2, 0); definePrimitive(base, index++, "_AddFloat", prAddFloat, 2, 0); definePrimitive(base, index++, "_SubFloat", prSubFloat, 2, 0); definePrimitive(base, index++, "_MulFloat", prMulFloat, 2, 0); definePrimitive(base, index++, "_NthPrime", prNthPrime, 1, 0); definePrimitive(base, index++, "_PrevPrime", prPrevPrime, 1, 0); definePrimitive(base, index++, "_NextPrime", prNextPrime, 1, 0); definePrimitive(base, index++, "_IsPrime", prIsPrime, 1, 0); definePrimitive(base, index++, "_IndexOfPrime", prIndexOfPrime, 1, 0); definePrimitive(base, index++, "_As32Bits", prAs32Bits, 1, 0); definePrimitive(base, index++, "_High32Bits", prHigh32Bits, 1, 0); definePrimitive(base, index++, "_Low32Bits", prLow32Bits, 1, 0); definePrimitive(base, index++, "_From32Bits", prFrom32Bits, 2, 0); definePrimitive(base, index++, "_From64Bits", prFrom64Bits, 3, 0); definePrimitive(base, index++, "_ClipInt", mathClipInt, 3, 0); definePrimitive(base, index++, "_ClipFloat", mathClipFloat, 3, 0); definePrimitive(base, index++, "_ClipSignal", mathClipSignal, 3, 0); definePrimitive(base, index++, "_WrapInt", mathWrapInt, 3, 0); definePrimitive(base, index++, "_WrapFloat", mathWrapFloat, 3, 0); definePrimitive(base, index++, "_WrapSignal", mathWrapSignal, 3, 0); definePrimitive(base, index++, "_FoldInt", mathFoldInt, 3, 0); definePrimitive(base, index++, "_FoldFloat", mathFoldFloat, 3, 0); definePrimitive(base, index++, "_FoldSignal", mathFoldSignal, 3, 0); definePrimitive(base, index++, "_SimpleNumberSeries", prSimpleNumberSeries, 3, 0); definePrimitive(base, index++, "_AsFraction", prAsFraction, 3, 0); } SuperCollider-Source/lang/LangPrimSource/PyrMathPrim.h000644 000765 000024 00000003707 12321461511 024060 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRMATHPRIM_H_ #define _PYRMATHPRIM_H_ void initMathPrimitives(); int prAddNum(VMGlobals *g, int numArgsPushed); int prSubNum(VMGlobals *g, int numArgsPushed); int prMulNum(VMGlobals *g, int numArgsPushed); int prAddInt(VMGlobals *g, int numArgsPushed); int prSubInt(VMGlobals *g, int numArgsPushed); int prMulInt(VMGlobals *g, int numArgsPushed); int prAddFloat(VMGlobals *g, int numArgsPushed); int prSubFloat(VMGlobals *g, int numArgsPushed); int prMulFloat(VMGlobals *g, int numArgsPushed); int mathClip(VMGlobals *g, int numArgsPushed); int mathWrap(VMGlobals *g, int numArgsPushed); int mathFold(VMGlobals *g, int numArgsPushed); int mathClipInt(VMGlobals *g, int numArgsPushed); int mathWrapInt(VMGlobals *g, int numArgsPushed); int mathFoldInt(VMGlobals *g, int numArgsPushed); int mathClipFloat(VMGlobals *g, int numArgsPushed); int mathWrapFloat(VMGlobals *g, int numArgsPushed); int mathFoldFloat(VMGlobals *g, int numArgsPushed); int mathClipSignal(VMGlobals *g, int numArgsPushed); int mathWrapSignal(VMGlobals *g, int numArgsPushed); int mathFoldSignal(VMGlobals *g, int numArgsPushed); #endif SuperCollider-Source/lang/LangPrimSource/PyrPlatformPrim.cpp000644 000765 000024 00000007273 12321461511 025310 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for platform dependent directories, constants etc. */ #include "SC_DirUtils.h" #include "PyrPrimitive.h" #include "PyrKernel.h" #ifdef _WIN32 # include "SC_Win32Utils.h" # include "Shlobj.h" #endif #define PATH_CONSTANT_PRIM_BODY(func) \ PyrSlot *a = g->sp; \ char path[PATH_MAX]; \ func(path, PATH_MAX); \ PyrString* string = newPyrString(g->gc, path, 0, true); \ SetObject(a, string); \ return errNone static int prPlatform_userHomeDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserHomeDirectory); } static int prPlatform_systemAppSupportDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetSystemAppSupportDirectory); } static int prPlatform_userAppSupportDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserAppSupportDirectory); } static int prPlatform_systemExtensionDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetSystemExtensionDirectory); } static int prPlatform_userExtensionDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserExtensionDirectory); } static int prPlatform_userConfigDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetUserConfigDirectory); } static int prPlatform_resourceDir(struct VMGlobals *g, int numArgsPushed) { PATH_CONSTANT_PRIM_BODY(sc_GetResourceDirectory); } #ifdef _WIN32 static int prWinPlatform_myDocumentsDir(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char path[PATH_MAX]; win32_GetKnownFolderPath(CSIDL_PERSONAL, path, PATH_MAX); \ PyrString* string = newPyrString(g->gc, path, 0, true); \ SetObject(a, string); return errNone; } #endif static int prPlatform_ideName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* string = newPyrString(g->gc, gIdeName, 0, true); SetObject(a, string); return errNone; } void initPlatformPrimitives(); void initPlatformPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_Platform_userHomeDir", prPlatform_userHomeDir, 1, 0); definePrimitive(base, index++, "_Platform_systemAppSupportDir", prPlatform_systemAppSupportDir, 1, 0); definePrimitive(base, index++, "_Platform_userAppSupportDir", prPlatform_userAppSupportDir, 1, 0); definePrimitive(base, index++, "_Platform_systemExtensionDir", prPlatform_systemExtensionDir, 1, 0); definePrimitive(base, index++, "_Platform_userExtensionDir", prPlatform_userExtensionDir, 1, 0); definePrimitive(base, index++, "_Platform_userConfigDir", prPlatform_userConfigDir, 1, 0); definePrimitive(base, index++, "_Platform_resourceDir", prPlatform_resourceDir, 1, 0); definePrimitive(base, index++, "_Platform_ideName", prPlatform_ideName, 1, 0); #ifdef _WIN32 definePrimitive(base, index++, "_WinPlatform_myDocumentsDir", prWinPlatform_myDocumentsDir, 1, 0); #endif } // EOF SuperCollider-Source/lang/LangPrimSource/PyrPrimitive.cpp000644 000765 000024 00000363134 12771207467 024666 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "PyrKernel.h" #include "PyrObject.h" #include "PyrPrimitive.h" #include "PyrPrimitiveProto.h" #include "PyrSignal.h" #include "PyrSched.h" #include "PyrSignalPrim.h" #include "PyrFilePrim.h" #include "PyrMathPrim.h" #include "PyrListPrim.h" #include "Opcodes.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrMessage.h" #include "PyrParseNode.h" #include "PyrLexer.h" #include "PyrKernelProto.h" #include "PyrInterpreter.h" #include "PyrObjectProto.h" #include "PyrArchiverT.h" #include "PyrDeepCopier.h" #include "PyrDeepFreezer.h" //#include "Wacom.h" #include "InitAlloc.h" #include "../LangSource/SC_LanguageConfig.hpp" #include "SC_DirUtils.h" #include "SC_Version.hpp" #ifdef _WIN32 # include #else # include #endif #ifdef SC_QT # include "QtCollider.h" #endif #include "SCDocPrim.h" #ifdef __clang__ #pragma clang diagnostic ignored "-Warray-bounds" #endif int yyparse(); extern bool gTraceInterpreter; PyrSymbol *s_recvmsg; void initPatternPrimitives(); typedef struct { PrimitiveHandler func; PyrSymbol* name; unsigned short base; unsigned char numArgs; unsigned char varArgs; unsigned char keyArgs; } PrimitiveDef; typedef struct { int size, maxsize; PrimitiveDef *table; } PrimitiveTable; extern PrimitiveTable gPrimitiveTable; extern PyrSlot o_nullframe; int getPrimitiveNumArgs(int index) { return gPrimitiveTable.table[index].numArgs; } PyrSymbol* getPrimitiveName(int index) { return gPrimitiveTable.table[index].name; } int slotStrLen(PyrSlot *slot) { if (IsSym(slot)) return slotRawSymbol(slot)->length; if (isKindOfSlot(slot, class_string)) return slotRawObject(slot)->size; return -1; } int slotStrVal(PyrSlot *slot, char *str, int maxlen) { if (IsSym(slot)) { strncpy(str, slotRawSymbol(slot)->name, maxlen); return errNone; } else if (isKindOfSlot(slot, class_string)) { int len; len = sc_min(maxlen-1, slotRawObject(slot)->size); memcpy(str, slotRawString(slot)->s, len); str[len] = 0; return errNone; } return errWrongType; } int slotPStrVal(PyrSlot *slot, unsigned char *str) { if (IsSym(slot)) { strncpy((char*)str+1, slotRawSymbol(slot)->name, 255); str[0] = slotRawSymbol(slot)->length; return errNone; } else if (isKindOfSlot(slot, class_string)) { int len; len = sc_min(255, slotRawObject(slot)->size); memcpy(str+1, slotRawString(slot)->s, len); str[0] = len; return errNone; } return errWrongType; } int instVarAt(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int index; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; PyrObject *obj = slotRawObject(a); if (IsInt(b)) { index = slotRawInt(b); if (index < 0 || index >= obj->size) return errIndexOutOfRange; slotCopy(a,&obj->slots[index]); } else if (IsSym(b)) { PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames; if (!isKindOfSlot(instVarNamesSlot, class_symbolarray)) return errFailed; PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot); PyrSymbol **names = instVarNames->symbols; PyrSymbol *name = slotRawSymbol(b); for (int i=0; isize; ++i) { if (names[i] == name) { slotCopy(a,&obj->slots[i]); return errNone; } } return errFailed; } else return errWrongType; return errNone; } int instVarPut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *slot; int index; PyrObject *obj; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (obj->IsImmutable()) return errImmutableObject; if (IsInt(b)) { index = slotRawInt(b); if (index < 0 || index >= obj->size) return errIndexOutOfRange; slot = obj->slots + index; slotCopy(slot,c); g->gc->GCWrite(obj, slot); } else if (IsSym(b)) { PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames; if (!IsObj(instVarNamesSlot)) return errFailed; PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot); PyrSymbol **names = instVarNames->symbols; PyrSymbol *name = slotRawSymbol(b); for (int i=0; isize; ++i) { if (names[i] == name) { slot = obj->slots + i; slotCopy(slot,c); g->gc->GCWrite(obj, slot); return errNone; } } post("WARNING: %s instVarPut '%s' failed.\n", slotRawSymbol(&obj->classptr->name)->name, name->name); return errNone; } else return errWrongType; return errNone; } int instVarSize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *obj; a = g->sp; if (NotObj(a)) { SetInt(a, 0); return errNone; } obj = slotRawObject(a); if (obj->obj_format == obj_notindexed) { SetInt(a, obj->size); } else { SetInt(a, 0); } return errNone; } int objectHash(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; int hash; a = g->sp; hash = calcHash(a); SetInt(a, hash); return errNone; } int objectClass(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; a = g->sp; classobj = classOfSlot(a); SetObject(a, classobj); return errNone; } int prPrimitiveError(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; slotCopy(a,&g->thread->primitiveError); return errNone; } int prStackDepth(struct VMGlobals *g, int numArgsPushed); int prStackDepth(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetInt(a, g->gc->StackDepth()); return errNone; } extern void DumpStack(VMGlobals *g, PyrSlot *sp); int prDumpStack(struct VMGlobals *g, int numArgsPushed) { DumpStack(g, g->sp); return errNone; } void DumpDetailedBackTrace(VMGlobals *g); int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed); int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed) { DumpDetailedBackTrace(g); return errNone; } int prPrimitiveErrorString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; const char *str; a = g->sp; switch (slotRawInt(&g->thread->primitiveError)) { case errReturn : str = "Return (not an error)."; break; case errNone : str = "No Error"; break; case errFailed : str = "Failed."; break; case errBadPrimitive : str = "Bad Primitive."; break; case errWrongType : str = "Wrong type."; break; case errIndexNotAnInteger : str = "Index not an Integer"; break; case errIndexOutOfRange : str = "Index out of range."; break; case errImmutableObject : str = "Attempted write to immutable object."; break; case errNotAnIndexableObject : str = "Not an indexable object."; break; case errStackOverflow : str = "Stack overflow."; break; case errOutOfMemory : str = "Out of memory."; break; case errCantCallOS : str = "Operation cannot be called from this Process. Try using AppClock instead of SystemClock."; break; default : str = "Failed."; } string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } int prPostString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; //if (NotObj(a)) return errWrongType; // assume it is a string! postText(slotRawString(a)->s, slotRawString(a)->size); return errNone; } int prPostLine(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; //if (NotObj(a)) return errWrongType; // assume it is a string! postText(slotRawString(a)->s, slotRawString(a)->size); postChar('\n'); return errNone; } int prDebugger(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; //Debugger(); return errNone; } int prObjectString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; char str[256]; a = g->sp; if (IsSym(a)) { string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true); SetObject(a, string); return errNone; } else if (postString(a, str)) { string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } else { return errFailed; } } int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed); int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; int precision; int err = slotIntVal(b, &precision); if (err) return err; char fmt[8], str[256]; // if our precision is bigger than our stringsize, we can generate a very nasty buffer overflow here. So if( precision <= 0 ) precision = 1; if( precision >= 200 ) precision = 200; // Nothing is that big anyway. And we know we will be smaller than our 256 char string sprintf(fmt, "%%.%dg", precision); sprintf(str, fmt, slotRawFloat(a)); PyrString *string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } int prAsCompileString(struct VMGlobals *g, int numArgsPushed); int prAsCompileString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; int err = errNone; a = g->sp; if (IsSym(a)) { int len = strlen(slotRawSymbol(a)->name) + 1; if (len < 255) { char str[256]; sprintf(str, "'%s'", slotRawSymbol(a)->name); string = newPyrString(g->gc, str, 0, true); } else { char *str = (char*)malloc(len+2); sprintf(str, "'%s'", slotRawSymbol(a)->name); string = newPyrString(g->gc, str, 0, true); free(str); } } else { char str[256]; err = asCompileString(a, str); if (err) return err; string = newPyrString(g->gc, str, 0, true); } SetObject(a, string); return err; } int prClassString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; PyrString *string; a = g->sp; classobj = classOfSlot(a); string = newPyrString(g->gc, slotRawSymbol(&classobj->name)->name, 0, true); SetObject(a, string); return errNone; } int prPrimName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrThread *thread; a = g->sp; thread = slotRawThread(a); if (slotRawInt(&thread->primitiveIndex) <= gPrimitiveTable.size) { SetSymbol(a, gPrimitiveTable.table[slotRawInt(&thread->primitiveIndex)].name); } else { SetSymbol(a, s_none); } return errNone; } int objectIsKindOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj, *testclass; int objClassIndex, testClassIndex, maxSubclassIndex; a = g->sp - 1; b = g->sp; if (NotObj(b)) return errWrongType; testclass = (PyrClass*)slotRawObject(b); classobj = classOfSlot(a); #if 0 while (classobj) { if (classobj == testclass) { SetTrue(a); return errNone; } classobj = slotRawSymbol(&classobj->superclass)->u.classobj; } SetFalse(a); #else // constant time lookup method: objClassIndex = slotRawInt(&classobj->classIndex); testClassIndex = slotRawInt(&testclass->classIndex); maxSubclassIndex = slotRawInt(&testclass->maxSubclassIndex); /*post("%s %s\n", slotRawSymbol(&classobj->name)->name, testclass->name.us->name); post("objClassIndex %d\n", objClassIndex); post("testClassIndex %d\n", testClassIndex); post("maxSubclassIndex %d\n", maxSubclassIndex);*/ if (objClassIndex >= testClassIndex && objClassIndex <= maxSubclassIndex) { SetTrue(a); return errNone; } else { SetFalse(a); return errNone; } #endif return errNone; } int objectIsMemberOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj, *testclass; a = g->sp - 1; b = g->sp; if (NotObj(b)) return errWrongType; testclass = (PyrClass*)slotRawObject(b); classobj = classOfSlot(a); if (classobj == testclass) { SetTrue(a); } else { SetFalse(a); } return errNone; } int objectIdentical(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; if (SlotEq(a, b)) SetTrue(a); else SetFalse(a); return errNone; } int objectNotIdentical(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; if ( !SlotEq(a, b) ) SetTrue(a); else SetFalse(a); return errNone; } int basicNewClear(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int size; PyrClass *classobj; PyrObject *newobj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; classobj = (PyrClass*)slotRawObject(a); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { // create an indexable object if (NotInt(b)) { if (IsFloat(b)) { size = (int)slotRawFloat(b); } else if (NotNil(b)) return errIndexNotAnInteger; else size = 8; } else { size = slotRawInt(b); } if (size < 0) size = 0; } else { size = 0; } newobj = instantiateObject(g->gc, classobj, size, true, true); SetObject(a, newobj); return errNone; } int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed); int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj; PyrObject *newobj; a = g->sp - numArgsPushed + 1; b = a + 1; if (NotObj(a)) return errWrongType; classobj = (PyrClass*)slotRawObject(a); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { error("CopyArgs : object has no instance variables.\n"); return errFailed; } newobj = instantiateObject(g->gc, classobj, 0, true, true); SetObject(a, newobj); int length = sc_min(numArgsPushed-1, newobj->size); for (int i=0; islots[i],&b[i]); } return errNone; } int basicNew(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int size; PyrClass *classobj; PyrObject *newobj; a = g->sp - 1; b = g->sp; if (NotObj(a)) return errWrongType; classobj = (PyrClass*)slotRawObject(a); if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) { // create an indexable object if (NotInt(b)) { if (IsFloat(b)) { size = (int)slotRawFloat(b); } else if (NotNil(b)) return errIndexNotAnInteger; else size = 8; } else { size = slotRawInt(b); } if (size < 0) size = 0; } else { size = 0; } newobj = instantiateObject(g->gc, classobj, size, false, true); SetObject(a, newobj); return errNone; } bool isClosed(PyrBlock* fundef); bool isClosed(PyrBlock* fundef) { return IsNil(&fundef->contextDef) && fundef->classptr == class_fundef; } bool isWithinClosed(PyrBlock* fundef); bool isWithinClosed(PyrBlock* fundef) { while (fundef) { if (isClosed(fundef)) return true; fundef = slotRawBlock(&fundef->contextDef); } return false; } int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed); int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; if (!isClosed(slotRawBlock(a))) { dumpObjectSlot(a); error("Only closed FunctionDef may be converted to a Function using asFunction.\n"); return errFailed; } PyrClosure* closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true); closure->classptr = gSpecialClasses[op_class_func]->u.classobj; closure->size = 2; slotCopy(&closure->block,a); slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context); SetObject(a, closure); return errNone; } int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed); int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int i=0; while (slotRawBlock(a)) { post("%2d context %s %p\n", i++, slotRawSymbol(&slotRawObject(a)->classptr->name)->name, slotRawInt(&slotRawBlock(a)->contextDef)); a = &slotRawBlock(a)->contextDef; } return errNone; } int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed); int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrBlock *block = slotRawBlock(a); SetBool(a, isClosed(block)); return errNone; } int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed); int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrBlock *block = slotRawBlock(a); SetBool(a, isWithinClosed(block)); return errNone; } void reallocStack(struct VMGlobals *g, int stackNeeded, int stackDepth) { //PyrThread *thread = g->thread; PyrGC *gc = g->gc; int newStackSize = NEXTPOWEROFTWO(stackNeeded); PyrObject* array = newPyrArray(gc, newStackSize, 0, false); memcpy(array->slots, gc->Stack()->slots, stackDepth * sizeof(PyrSlot)); gc->SetStack(array); gc->ToBlack(gc->Stack()); g->sp = array->slots + stackDepth - 1; } int blockValueArray(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b; PyrObject *array; PyrList *list; PyrSlot *pslot, *qslot; int m, size; //a = g->sp - numArgsPushed + 1; b = g->sp; if (IsObj(b)) { if (slotRawObject(b)->classptr == class_array) { array = (PyrObject*)slotRawObject(b); above: size = array->size; PyrObject *stack = g->gc->Stack(); int stackDepth = g->sp - stack->slots + 1; int stackSize = ARRAYMAXINDEXSIZE(stack); int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations. if (stackNeeded > stackSize) { reallocStack(g, stackNeeded, stackDepth); b = g->sp; } pslot = array->slots - 1; qslot = b - 1; //pend = (double*)(pslot + size); //while (pslotsp += size - 1; return blockValue(g, size+numArgsPushed-1); } else if (slotRawObject(b)->classptr == class_list) { list = slotRawList(b); if (NotObj(&list->array)) return errWrongType; array = slotRawObject(&list->array); if (array->classptr != class_array) return errWrongType; goto above; } else { // last arg is not a list or array, so pass as normal return blockValue(g, numArgsPushed); } } else { return blockValue(g, numArgsPushed); } } int blockValueEnvir(struct VMGlobals *g, int numArgsPushed); int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed); int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b; PyrObject *array; PyrList *list; PyrSlot *pslot, *qslot; int m, size; //a = g->sp - numArgsPushed + 1; b = g->sp; if (IsObj(b)) { if (slotRawObject(b)->classptr == class_array) { array = (PyrObject*)slotRawObject(b); above: size = array->size; PyrObject *stack = g->gc->Stack(); int stackDepth = g->sp - stack->slots + 1; int stackSize = ARRAYMAXINDEXSIZE(stack); int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations. if (stackNeeded > stackSize) { reallocStack(g, stackNeeded, stackDepth); b = g->sp; } pslot = array->slots - 1; qslot = b - 1; //pend = (double*)(pslot + size); //while (pslotsp += size - 1; return blockValueEnvir(g, size+numArgsPushed-1); } else if (slotRawObject(b)->classptr == class_list) { list = slotRawList(b); if (NotObj(&list->array)) return errWrongType; array = slotRawObject(&list->array); if (array->classptr != class_array) return errWrongType; goto above; } else { // last arg is not a list or array, so pass as normal return blockValueEnvir(g, numArgsPushed); } } else { return blockValueEnvir(g, numArgsPushed); } } HOT int blockValue(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, m, mmax, numtemps; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 30; args = g->sp - numArgsPushed + 1; numArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; for (m=0,mmax=methraw->numvars; mhomeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed); int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, j, m, mmax, numtemps, numArgsPushed; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 40; args = g->sp - allArgsPushed + 1; allArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mvarargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero //lend = lslot + i; //while (lslot < lend) slotCopy(++lslot, ++qslot); for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; //pend = pslot + methraw->numargs; //while (pslot < pend) slotCopy(++pslot, ++qslot); for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; //pend = pslot + methraw->numvars; //while (pslotnumvars; mposargs) { PyrSlot *key; PyrSymbol **name0, **name; name0 = slotRawSymbolArray(&block->argNames)->symbols; key = args + numArgsPushed + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j+1],&key[1]); goto found1; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to function.\n", slotRawSymbol(key)->name); } found1: ; } } homeContext = slotRawFrame(&frame->homeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result); int blockValueEnvir(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, m, mmax, numtemps; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; PyrSlot *curEnvirSlot; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 50; args = g->sp - numArgsPushed + 1; numArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mclassvars->slots[1]; // currentEnvironment is the second class var. if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) { PyrSymbol **argNames; argNames = slotRawSymbolArray(&block->argNames)->symbols; for (m=numArgsPushed; mnumargs; ++m) { // replace the args with values from the environment if they exist PyrSlot keyslot; SetSymbol(&keyslot, argNames[m]); identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1); } } } else if (methraw->varargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; for (m=0,mmax=methraw->numvars; mhomeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed); int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed) { PyrSlot *args; PyrSlot *vars; PyrFrame *frame; PyrSlot *pslot, *qslot; PyrSlot *rslot; PyrObject *proto; int i, j, m, mmax, numtemps, numArgsPushed; PyrBlock *block; PyrFrame *context; PyrFrame *caller; PyrFrame *homeContext; PyrClosure *closure; PyrMethodRaw *methraw; PyrSlot *curEnvirSlot; #if TAILCALLOPTIMIZE int tailCall = g->tailCall; if (tailCall) { if (tailCall == 1) { returnFromMethod(g); } else { returnFromBlock(g); } } #endif g->execMethod = 60; args = g->sp - allArgsPushed + 1; allArgsPushed -- ; g->numpop = 0; closure = (PyrClosure*)slotRawObject(args); block = slotRawBlock(&closure->block); context = slotRawFrame(&closure->context); proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL; methraw = METHRAW(block); numtemps = methraw->numtemps; caller = g->frame; numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1); frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext); vars = frame->vars - 1; frame->classptr = class_frame; frame->size = FRAMESIZE + numtemps; SetObject(&frame->method, block); slotCopy(&frame->homeContext,&context->homeContext); slotCopy(&frame->context,&closure->context); if (caller) { SetPtr(&caller->ip, g->ip); SetObject(&frame->caller, g->frame); } else { SetInt(&frame->caller, 0); } SetPtr(&frame->ip, 0); g->sp = args - 1; g->ip = slotRawInt8Array(&block->code)->b - 1; g->frame = frame; g->block = block; if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */ /* push all args to frame */ qslot = args; pslot = vars; for (m=0; mslots + numArgsPushed - 1; for (m=0; mclassvars->slots[1]; // currentEnvironment is the second class var. if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) { PyrSymbol **argNames; argNames = slotRawSymbolArray(&block->argNames)->symbols; for (m=numArgsPushed; mnumargs; ++m) { // replace the args with values from the environment if they exist PyrSlot keyslot; SetSymbol(&keyslot, argNames[m]); identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1); } } } else if (methraw->varargs) { PyrObject *list; PyrSlot *lslot; /* push all normal args to frame */ qslot = args; pslot = vars; for (m=0,mmax=methraw->numargs; mnumargs; list = newPyrArray(g->gc, i, 0, false); list->size = i; rslot = pslot+1; SetObject(rslot, list); //SetObject(vars + methraw->numargs + 1, list); /* put extra args into list */ lslot = list->slots - 1; // fixed and raw sizes are zero //lend = lslot + i; //while (lslot < lend) slotCopy(++lslot, ++qslot); for (m=0; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs + 1; qslot = proto->slots + methraw->numargs; for (m=0,mmax=methraw->numvars; mnumargs) { /* push all args to frame */ qslot = args; pslot = vars; //pend = pslot + methraw->numargs; //while (pslot < pend) slotCopy(++pslot, ++qslot); for (m=0,mmax=methraw->numargs; mnumvars) { /* push default keyword and var values */ pslot = vars + methraw->numargs; qslot = proto->slots + methraw->numargs - 1; //pend = pslot + methraw->numvars; //while (pslotnumvars; mposargs) { PyrSymbol **name0, **name; PyrSlot *key; name0 = slotRawSymbolArray(&block->argNames)->symbols; key = args + numArgsPushed + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j+1],&key[1]); goto found1; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to function.\n", slotRawSymbol(key)->name); } found1: ; } } homeContext = slotRawFrame(&frame->homeContext); if (homeContext) { PyrMethodRaw *methraw; g->method = slotRawMethod(&homeContext->method); methraw = METHRAW(g->method); slotCopy(&g->receiver,&homeContext->vars[0]); } else { slotCopy(&g->receiver,&g->process->interpreter); } return errNone; } int objectPerform(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed); int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); g->numpop = 0; return errNone; } int objectPerformList(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax, numargslots; PyrObject *array; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; listSlot = g->sp; numargslots = numArgsPushed - 3; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); if (NotObj(listSlot)) { return objectPerform(g, numArgsPushed); } if (slotRawObject(listSlot)->classptr == class_array) { doarray: array = slotRawObject(listSlot); PyrObject *stack = g->gc->Stack(); int stackDepth = g->sp - stack->slots + 1; int stackSize = ARRAYMAXINDEXSIZE(stack); int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations. if (stackNeeded > stackSize) { reallocStack(g, stackNeeded, stackDepth); recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; } pslot = recvrSlot; if (numargslots>0) { qslot = selSlot; for (m=0; mslots - 1; for (m=0,mmax=array->size; mclassptr == class_list) { listSlot = slotRawObject(listSlot)->slots; if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { error("List array not an Array.\n"); dumpObjectSlot(listSlot); return errWrongType; } goto doarray; } else { return objectPerform(g, numArgsPushed); } g->sp += array->size - 2; numArgsPushed = numargslots + array->size + 1; // now the stack looks just like it would for a normal message send sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectSuperPerform(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; if (!isKindOfSlot(recvrSlot, classobj)) { error("superPerform must be called with 'this' as the receiver.\n"); return errFailed; } selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendSuperMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed); int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; recvrSlot = g->sp - numArgsPushed + 1; PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj; if (!isKindOfSlot(recvrSlot, classobj)) { error("superPerform must be called with 'this' as the receiver.\n"); return errFailed; } selSlot = recvrSlot + 1; if (IsSym(selSlot)) { selector = slotRawSymbol(selSlot); // move args down one to fill selector's position pslot = selSlot - 1; qslot = selSlot; for (m=0; msp -- ; numArgsPushed -- ; // now the stack looks just like it would for a normal message send } else if (IsObj(selSlot)) { listSlot = selSlot; if (slotRawObject(listSlot)->classptr == class_list) { listSlot = slotRawObject(listSlot)->slots; } if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { goto badselector; } PyrObject *array = slotRawObject(listSlot); if (array->size < 1) { error("Array must have a selector.\n"); return errFailed; } selSlot = array->slots; selector = slotRawSymbol(selSlot); if (numArgsPushed>2) { qslot = recvrSlot + numArgsPushed; pslot = recvrSlot + numArgsPushed + array->size - 2; for (m=0; msize-1; msp += array->size - 2; numArgsPushed += array->size - 2; // now the stack looks just like it would for a normal message send } else { badselector: error("perform selector not a Symbol or Array.\n"); dumpObjectSlot(selSlot); return errWrongType; } sendSuperMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed); g->numpop = 0; return errNone; } int objectSuperPerformList(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax, numargslots; PyrObject *array; recvrSlot = g->sp - numArgsPushed + 1; selSlot = recvrSlot + 1; listSlot = g->sp; numargslots = numArgsPushed - 3; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); if (NotObj(listSlot)) { return objectPerform(g, numArgsPushed); } if (slotRawObject(listSlot)->classptr == class_array) { doarray: pslot = recvrSlot; if (numargslots>0) { qslot = selSlot; for (m=0; mslots - 1; for (m=0,mmax=array->size; mclassptr == class_list) { listSlot = slotRawObject(listSlot)->slots; if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { error("List array not an Array.\n"); dumpObjectSlot(listSlot); return errWrongType; } goto doarray; } else { return objectSuperPerform(g, numArgsPushed); } g->sp += array->size - 2; numArgsPushed = numargslots + array->size + 1; // now the stack looks just like it would for a normal message send sendSuperMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectPerformSelList(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *listSlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax; PyrObject *array; recvrSlot = g->sp - 1; listSlot = g->sp; if (NotObj(listSlot)) { error("Expected Array or List.. Got :\n"); dumpObjectSlot(listSlot); return errWrongType; } if (slotRawObject(listSlot)->classptr == class_array) { doarray: array = slotRawObject(listSlot); selSlot = array->slots; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); pslot = recvrSlot; qslot = selSlot; for (m=0,mmax=array->size-1; mclassptr == class_list) { listSlot = slotRawObject(listSlot)->slots; if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) { error("List array not an Array.\n"); dumpObjectSlot(listSlot); return errWrongType; } goto doarray; } else { error("Expected Array or List.. Got :\n"); dumpObjectSlot(listSlot); return errWrongType; } g->sp += array->size - 2; numArgsPushed = array->size; // now the stack looks just like it would for a normal message send sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed); int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed) { PyrSlot *recvrSlot, *selSlot, *arraySlot; PyrSlot *pslot, *qslot; PyrSymbol *selector; int m, mmax, numargslots; PyrObject *array; arraySlot = g->sp - numArgsPushed + 1; array = slotRawObject(arraySlot); if (array->size < 2) { error("Array must contain a receiver and a selector.\n"); return errFailed; } recvrSlot = array->slots; selSlot = recvrSlot + 1; numargslots = numArgsPushed - 1; if (NotSym(selSlot)) { error("Selector not a Symbol :\n"); return errWrongType; } selector = slotRawSymbol(selSlot); slotCopy(arraySlot,recvrSlot); if (numargslots>0) { qslot = arraySlot + numargslots + 1; pslot = arraySlot + numargslots + array->size - 1; for (m=0; msize-2; msp += array->size - 2; numArgsPushed = numargslots + array->size - 1; // now the stack looks just like it would for a normal message send sendMessage(g, selector, numArgsPushed); g->numpop = 0; return errNone; } int objectDump(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; dumpObjectSlot(a); return errNone; } int prTotalFree(struct VMGlobals *g, int numArgsPushed); int prTotalFree(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, g->allocPool->TotalFree()); return errNone; } int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed); int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, g->allocPool->LargestFreeChunk()); return errNone; } int dumpGCinfo(struct VMGlobals *g, int numArgsPushed); int dumpGCinfo(struct VMGlobals *g, int numArgsPushed) { g->gc->DumpInfo(); return errNone; } int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed); int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed) { g->gc->DumpGrey(); return errNone; } int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed); int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp; int set; int err = slotIntVal(b, &set); if (err) return err; g->gc->DumpSet(set); return errNone; } int prGCSanity(struct VMGlobals *g, int numArgsPushed); int prGCSanity(struct VMGlobals *g, int numArgsPushed) { g->gc->SanityCheck(); return errNone; } #if GCDEBUG int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed); int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; g->gc->TracePathsTo(slotRawObject(a), false); return errNone; } int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed); int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; g->gc->TracePathsTo(slotRawObject(a), true); return errNone; } int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed); int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; g->gc->TraceAnyPathToAllInstancesOf(slotRawClass(a)->name.us); return errNone; } #endif extern PyrClass *gClassList; int prAllClasses(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; PyrObject *array; int i; a = g->sp; array = newPyrArray(g->gc, gNumClasses, 0, true); classobj = gClassList; for (i=0; classobj; ++i) { SetObject(array->slots + i, classobj); classobj = slotRawClass(&classobj->nextclass); } array->size = gNumClasses; SetObject(a, array); return errNone; } int prPostClassTree(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; postClassTree(slotRawClass(a), 0); return errNone; } int prDumpBackTrace(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; DumpBackTrace(g); return errNone; } /* the DebugFrameConstructor uses a work queue in order to avoid recursions, which could lead to stack overflows */ struct DebugFrameConstructor { void makeDebugFrame (VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot) { workQueue.push_back(std::make_pair(frame, outSlot)); run_queue(g); } private: void run_queue(VMGlobals *g) { while (!workQueue.empty()) { WorkQueueItem work = workQueue.back(); workQueue.pop_back(); fillDebugFrame(g, work.first, work.second); } } void fillDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot) { PyrMethod *meth = slotRawMethod(&frame->method); PyrMethodRaw * methraw = METHRAW(meth); PyrObject* debugFrameObj = instantiateObject(g->gc, getsym("DebugFrame")->u.classobj, 0, false, false); SetObject(outSlot, debugFrameObj); SetObject(debugFrameObj->slots + 0, meth); SetPtr(debugFrameObj->slots + 5, meth); int numargs = methraw->numargs; int numvars = methraw->numvars; if (numargs) { PyrObject* argArray = (PyrObject*)newPyrArray(g->gc, numargs, 0, false); SetObject(debugFrameObj->slots + 1, argArray); for (int i=0; islots[i], &frame->vars[i]); argArray->size = numargs; } else SetNil(debugFrameObj->slots + 1); if (numvars) { PyrObject* varArray = (PyrObject*)newPyrArray(g->gc, numvars, 0, false); SetObject(debugFrameObj->slots + 2, varArray); for (int i=0, j=numargs; islots[i], &frame->vars[j]); varArray->size = numvars; } else SetNil(debugFrameObj->slots + 2); if (slotRawFrame(&frame->caller)) { WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->caller), debugFrameObj->slots + 3); workQueue.push_back(newWork); } else SetNil(debugFrameObj->slots + 3); if (IsObj(&frame->context) && slotRawFrame(&frame->context) == frame) SetObject(debugFrameObj->slots + 4, debugFrameObj); else if (NotNil(&frame->context)) { WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->context), debugFrameObj->slots + 4); workQueue.push_back(newWork); } else SetNil(debugFrameObj->slots + 4); } typedef std::pair WorkQueueItem; typedef std::vector WorkQueueType; WorkQueueType workQueue; }; static void MakeDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot) { DebugFrameConstructor constructor; constructor.makeDebugFrame(g, frame, outSlot); } int prGetBackTrace(VMGlobals *g, int numArgsPushed); int prGetBackTrace(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; MakeDebugFrame(g, g->frame, a); return errNone; } int prObjectShallowCopy(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; switch (GetTag(a)) { case tagObj : SetRaw(a, copyObject(g->gc, slotRawObject(a), true)); break; // the default case is to leave the argument unchanged on the stack } return errNone; } int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed); int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; switch (GetTag(a)) { case tagObj : if (slotRawObject(a)->obj_flags & obj_immutable) { SetRaw(a, copyObject(g->gc, slotRawObject(a), true)); } break; } return errNone; } int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed); int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (IsObj(a)) { if (slotRawObject(a)->obj_flags & obj_immutable) { SetFalse(a); } else { SetTrue(a); } } else { SetFalse(a); } return errNone; } int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed); int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (IsObj(a)) { if (slotRawObject(a)->gc_color == obj_permanent) { SetTrue(a); } else { SetFalse(a); } } else { SetTrue(a); } return errNone; } int prDeepFreeze(struct VMGlobals *g, int numArgsPushed); int prDeepFreeze(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; PyrDeepFreezer freezer(g); int err = freezer.doDeepFreeze(a); return err; } int prDeepCopy(struct VMGlobals *g, int numArgsPushed); int prDeepCopy(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; PyrDeepCopier copier(g); int err = copier.doDeepCopy(a); return err; } bool IsSimpleLiteralSlot(PyrSlot* slot); bool IsSimpleLiteralSlot(PyrSlot* slot) { switch (GetTag(slot)) { case tagObj : return slotRawObject(slot)->IsPermanent(); case tagInt : return true; case tagSym : return true; case tagChar : return true; case tagNil : return true; case tagFalse : return true; case tagTrue : return true; case tagPtr : return false; default : return true; } } int prObjectCopyRange(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(a)) return errWrongType; if (NotInt(b)) return errWrongType; if (NotInt(c)) return errWrongType; SetRaw(a, copyObjectRange(g->gc, slotRawObject(a), slotRawInt(b), slotRawInt(c), true)); return errNone; } int prObjectCopySeries(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d; a = g->sp - 3; b = g->sp - 2; c = g->sp - 1; d = g->sp; PyrObject *inobj = slotRawObject(a); PyrObject *newobj; int size = inobj->size; int flags = ~(obj_immutable) & inobj->obj_flags; int first, second, last; if (IsInt(b)) first = slotRawInt(b); else if (IsNil(b)) first = 0; else return errWrongType; if (IsInt(d)) { last = slotRawInt(d); if (last < 0 && IsNil(b)) { zerolength: newobj = g->gc->New(0, flags, inobj->obj_format, true); newobj->size = 0; newobj->classptr = inobj->classptr; SetRaw(a, newobj); return errNone; } } else if (IsNil(d)) { if (first >= size) goto zerolength; last = size - 1; } else return errWrongType; if (IsInt(c)) second = slotRawInt(c); else if (IsNil(c)) second = first < last ? first + 1 : first - 1; else return errWrongType; int step = second - first; int elemsize = gFormatElemSize[inobj->obj_format]; int length; if (step > 0) { length = (last - first) / step + 1; } else if (step < 0) { length = (first - last) / -step + 1; } else return errFailed; int numbytes = length * elemsize; newobj = g->gc->New(numbytes, flags, inobj->obj_format, true); newobj->size = 0; newobj->classptr = inobj->classptr; for (int i=first, j=0; j= 0 && i < inobj->size) { getIndexedSlot(inobj, &slot, i); int err = putIndexedSlot(g, newobj, &slot, newobj->size++); if (err) return err; } } SetRaw(a, newobj); return errNone; } void switchToThread(struct VMGlobals *g, struct PyrThread *newthread, int oldstate, int *numArgsPushed); int haltInterpreter(struct VMGlobals *g, int numArgsPushed) { switchToThread(g, slotRawThread(&g->process->mainThread), tDone, &numArgsPushed); // return all the way out. //PyrSlot *bottom = g->gc->Stack()->slots; //slotCopy(bottom,g->sp); //g->sp = bottom; // ??!! pop everybody g->method = NULL; g->block = NULL; g->frame = NULL; SetNil(g->sp); longjmp(g->escapeInterpreter, 3); //hmm need to fix this to work only on main thread. //!!! //g->sp = g->gc->Stack()->slots - 1; return errReturn; } int prCanCallOS(struct VMGlobals *g, int numArgsPushed); int prCanCallOS(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetBool(a, g->canCallOS); return errNone; } extern bool gGenerateTailCallByteCodes; int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed); int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetBool(a, gGenerateTailCallByteCodes); return errNone; } int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed); int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 1; #if TAILCALLOPTIMIZE PyrSlot *b = g->sp; if (IsTrue(b)) { gGenerateTailCallByteCodes = true; } else if (IsFalse(b)) { gGenerateTailCallByteCodes = false; } else return errWrongType; #endif return errNone; } int prTraceOn(struct VMGlobals *g, int numArgsPushed); int prTraceOn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; gTraceInterpreter = IsTrue(a); return errNone; } int prKeywordError(struct VMGlobals *g, int numArgsPushed); int prKeywordError(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; gKeywordError = IsTrue(a); return errNone; } int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed); int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrMethodRaw *methraw; a = g->sp; methraw = METHRAW(slotRawBlock(a)); SetInt(a, methraw->numargs); return errNone; } int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed); int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrMethodRaw *methraw; a = g->sp; methraw = METHRAW(slotRawBlock(a)); SetInt(a, methraw->numvars); return errNone; } int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed); int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrMethodRaw *methraw; a = g->sp; methraw = METHRAW(slotRawBlock(a)); if (methraw->varargs) { SetTrue(a); } else { SetFalse(a); } return errNone; } int undefinedPrimitive(struct VMGlobals *g, int numArgsPushed) { error("A primitive was not bound. %d %d\n", g->primitiveIndex, gPrimitiveTable.size); dumpObject((PyrObject*)g->primitiveMethod); return errFailed; } void dumpByteCodes(PyrBlock *theBlock); int prDumpByteCodes(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; dumpByteCodes(slotRawBlock(a)); return errNone; } int prObjectPointsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, temp; PyrObject *obj; int i; a = g->sp - 1; b = g->sp; if (NotObj(a)) slotCopy(a,&o_false); else { obj = slotRawObject(a); for (i=0; isize; ++i) { getIndexedSlot(obj, &temp, i); if (SlotEq(&temp, b)) { slotCopy(a,&o_true); return errNone; } } slotCopy(a,&o_false); } return errNone; } int prObjectRespondsTo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrClass *classobj; PyrMethod *meth; PyrSymbol *selector; int index; a = g->sp - 1; b = g->sp; classobj = classOfSlot(a); if (IsSym(b)) { selector = slotRawSymbol(b); index = slotRawInt(&classobj->classIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { slotCopy(a,&o_false); } else { slotCopy(a,&o_true); } } else if (isKindOfSlot(b, class_array)) { int size = slotRawObject(b)->size; PyrSlot *slot = slotRawObject(b)->slots; for (int i=0; iclassIndex) + selector->u.index; meth = gRowTable[index]; if (slotRawSymbol(&meth->name) != selector) { slotCopy(a,&o_false); return errNone; } } slotCopy(a,&o_true); } else return errWrongType; return errNone; } PyrMethod* GetFunctionCompileContext(VMGlobals* g); PyrMethod* GetFunctionCompileContext(VMGlobals* g) { PyrClass *classobj; PyrSymbol *classsym, *contextsym; PyrMethod *meth; // lookup interpreter class classsym = getsym("Interpreter"); classobj = classsym->u.classobj; if (!classobj) { error("There is no Interpreter class.\n"); return 0; } // lookup functionCompileContext method contextsym = getsym("functionCompileContext"); int index = slotRawInt(&classobj->classIndex) + contextsym->u.index; meth = gRowTable[index]; if (!meth || slotRawSymbol(&meth->name) != contextsym) { error("compile context method 'functionCompileContext' not found.\n"); return 0; } gCompilingClass = classobj; gCompilingMethod = meth; gCompilingBlock = (PyrBlock*)meth; return meth; } #if !SCPLAYER int prCompileString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; PyrString *string; PyrMethod *meth; a = g->sp - 1; b = g->sp; // check b is a string if (NotObj(b)) return errWrongType; if (!isKindOf(slotRawObject(b), class_string)) return errWrongType; string = slotRawString(b); gRootParseNode = NULL; initParserPool(); //assert(g->gc->SanityCheck()); startLexerCmdLine(string->s, string->size); compileErrors = 0; compilingCmdLine = true; gCompilingVMGlobals = g; compilingCmdLineErrorWindow = false; //assert(g->gc->SanityCheck()); parseFailed = yyparse(); //assert(g->gc->SanityCheck()); if (!parseFailed && gRootParseNode) { PyrSlot slotResult; meth = GetFunctionCompileContext(g); if (!meth) return errFailed; ((PyrBlockNode*)gRootParseNode)->mIsTopLevel = true; SetNil(&slotResult); COMPILENODE(gRootParseNode, &slotResult, true); if (NotObj(&slotResult) || slotRawObject(&slotResult)->classptr != class_fundef) { compileErrors++; error("Compile did not return a FunctionDef..\n"); } if (compileErrors) { SetNil(a); } else { PyrBlock *block; PyrClosure *closure; block = slotRawBlock(&slotResult); // create a closure closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, false); closure->classptr = class_func; closure->size = 2; SetObject(&closure->block, block); slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context); SetObject(a, closure); } } else { if (parseFailed) { compileErrors++; error("Command line parse failed\n"); } else { postfl("\n"); } SetNil(a); } finiLexer(); freeParserPool(); pyr_pool_compile->FreeAll(); //flushErrors(); compilingCmdLine = false; return !(parseFailed || compileErrors) ? errNone : errFailed; } #endif char sCodeStringIn[8192]; char sCodeStringOut[8192]; int prUGenCodeString(struct VMGlobals *g, int numArgsPushed); int prUGenCodeString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *aa, *bb, *cc, *dd, *ee; char *out = sCodeStringOut; char ugenPrefix[16]; int err; aa = g->sp - 4; // code string bb = g->sp - 3; // ugen prefix ee = g->sp - 2; // isDecl cc = g->sp - 1; // input names dd = g->sp; // input value strings int ugenIndex; err = slotIntVal(bb, &ugenIndex); if (err) return err; if (!isKindOfSlot(cc, class_array) && !isKindOfSlot(cc, class_symbolarray)) return errWrongType; if (!isKindOfSlot(dd, class_array)) return errWrongType; bool isDecl = IsTrue(ee); PyrObject *inputNamesObj = slotRawObject(cc); PyrObject *inputStringsObj = slotRawObject(dd); sprintf(ugenPrefix, "u%d", ugenIndex); int ugenPrefixSize = strlen(ugenPrefix); PyrString* codeStringObj = slotRawString(aa); int codeStringSize = codeStringObj->size; if (codeStringSize > 8000) { error("input string too int.\n"); return errFailed; } memcpy(sCodeStringIn, codeStringObj->s, codeStringSize); sCodeStringIn[codeStringSize] = 0; char* in = sCodeStringIn; int c; while ((c = *in++) != 0) { if (c == '@') { if (!isDecl) { if (*in != '@') { *out++ = 's'; *out++ = '-'; *out++ = '>'; } else in++; } for (int j=0; j= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) { --in; break; } name[j++] = c; } while (c); bool found = false; int nameSize = j; int slotIndex = -1; for (int j=0; jsize; ++j) { PyrSlot inputNameSlot; getIndexedSlot(inputNamesObj, &inputNameSlot, j); if (!IsSym(&inputNameSlot)) return errWrongType; PyrSymbol* inputSym = slotRawSymbol(&inputNameSlot); char *inputName = inputSym->name; int inputNameSize = inputSym->length; if (inputNameSize == nameSize && strncmp(inputName, name, nameSize)==0) { found = true; slotIndex = j; break; } } if (slotIndex >= 0) { PyrSlot *inputStringSlot = inputStringsObj->slots + slotIndex; if (!isKindOfSlot(inputStringSlot, class_string)) return errWrongType; PyrString *inputStringObj = slotRawString(inputStringSlot); char *input = inputStringObj->s; int inputStringSize = inputStringObj->size; for (int j=0; j 8000) { *out++ = '\n'; *out++ = '.'; *out++ = '.'; *out++ = '.'; *out++ = '\n'; break; } } *out++ = 0; PyrString* outString = newPyrString(g->gc, sCodeStringOut, 0, true); SetObject(aa, outString); return errNone; } /*void threadSanity(VMGlobals *g, PyrThread *thread); void threadSanity(VMGlobals *g, PyrThread *thread) { int state; g->gc->numToScan = 1000000; doGC(g, 0); assert(g->gc->SanityCheck()); state = slotRawInt(&thread->state); if (state == tYield) { if (!IsObj(&thread->method)) { error("thread method not an Object\n"); } else if (!isKindOf(slotRawObject(&thread->method), class_method)) { error("thread method not a Method\n"); } else if (slotRawObject(&thread->method)->gc_color == gcColor.gcFree) { error("thread method is FREE\n"); } if (!IsObj(&thread->block)) { error("thread block not an Object\n"); } else if (!isKindOf(slotRawObject(&thread->block), class_func)) { error("thread block not a Function\n"); } else if (slotRawObject(&thread->block)->gc_color == gcColor.gcFree) { error("thread block is FREE\n"); } if (IsObj(&thread->receiver) &slotRawObject(&& thread->receiver)->gc_color == gcColor.gcFree) { error("thread receiver is FREE\n"); } FrameSanity(thread->frame.uof); oldthread->method.uom = g->method; oldthread->block.uoblk = g->block; SetObject(&oldthread->frame, g->frame); slotRawInt(&oldthread->ip) = (int)g->ip; slotRawInt(&oldthread->sp) = (int)g->sp; } else if (state == tInit) { } else { postfl("bad state\n"); } }*/ PyrSymbol *s_prready; PyrSymbol *s_prrunnextthread; void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed); void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed) { PyrThread *oldthread; PyrGC *gc; PyrFrame *frame; #if TAILCALLOPTIMIZE g->tailCall = 0; // ?? prevent a crash. is there a way to allow a TCO ? #endif oldthread = g->thread; if (newthread == oldthread) return; //postfl("->switchToThread %d %p -> %p\n", oldstate, oldthread, newthread); //post("->switchToThread from %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name); //post("->stack %p g->sp %p [%d] g->top %p [%d]\n", // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "switchToThreadA"); //gcDumpInfo(g->gc); gc = g->gc; // save environment in oldthread PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; slotCopy(&oldthread->environment,currentEnvironmentSlot); gc->GCWrite(oldthread, currentEnvironmentSlot); SetRaw(&oldthread->state, oldstate); if (oldstate == tDone) { SetObject(&oldthread->stack, gc->Stack()); gc->ToWhite(gc->Stack()); gc->Stack()->size = 0; gc->GCWrite(oldthread, gc->Stack()); SetNil(&oldthread->method); SetNil(&oldthread->block); SetNil(&oldthread->receiver); SetNil(&oldthread->frame); SetRaw(&oldthread->ip, (void*)0); SetRaw(&oldthread->sp, (void*)0); SetRaw(&oldthread->numArgsPushed, 0); SetRaw(&oldthread->numpop, 0); SetNil(&oldthread->parent); } else if (oldstate == tInit) { SetObject(&oldthread->stack, gc->Stack()); gc->ToWhite(gc->Stack()); gc->Stack()->size = 0; gc->GCWrite(oldthread, gc->Stack()); SetNil(&oldthread->method); SetNil(&oldthread->block); SetNil(&oldthread->receiver); SetNil(&oldthread->frame); SetRaw(&oldthread->ip, (void*)0); SetRaw(&oldthread->sp, (void*)0); SetRaw(&oldthread->numArgsPushed, 0); SetRaw(&oldthread->numpop, 0); SetNil(&oldthread->parent); } else { // save old thread's state SetObject(&oldthread->stack, gc->Stack()); gc->ToWhite(gc->Stack()); gc->Stack()->size = g->sp - gc->Stack()->slots + 1; //post("else %p %p\n", slotRawObject(&oldthread->stack), gc->Stack()); SetObject(&oldthread->method, g->method); SetObject(&oldthread->block, g->block); SetObject(&oldthread->frame, g->frame); SetPtr(&oldthread->ip, g->ip); SetPtr(&oldthread->sp, g->sp); slotCopy(&oldthread->receiver,&g->receiver); SetRaw(&oldthread->numArgsPushed, *numArgsPushed); SetRaw(&oldthread->numpop, g->numpop); //gc->ToGrey(oldthread); if (gc->ObjIsBlack(oldthread)) { gc->GCWriteBlack(gc->Stack()); gc->GCWriteBlack(g->method); gc->GCWriteBlack(g->block); frame = slotRawFrame(&oldthread->frame); gc->GCWriteBlack(frame); gc->GCWriteBlack(&g->receiver); } } // restore new thread's state g->thread = newthread; SetObject(&g->process->curThread, newthread); gc->GCWrite(g->process, newthread); gc->SetStack(slotRawObject(&newthread->stack)); gc->ToBlack(gc->Stack()); SetNil(&newthread->stack); g->method = slotRawMethod(&newthread->method); g->block = slotRawBlock(&newthread->block); g->frame = slotRawFrame(&newthread->frame); g->ip = (unsigned char *)slotRawPtr(&newthread->ip); g->sp = (PyrSlot*)slotRawPtr(&newthread->sp); slotCopy(&g->receiver,&newthread->receiver); g->rgen = (RGen*)(slotRawObject(&newthread->randData)->slots); *numArgsPushed = slotRawInt(&newthread->numArgsPushed); // these are perhaps unecessary because a thread may not // legally block within a C primitive g->numpop = slotRawInt(&newthread->numpop); g->execMethod = 99; //post("switchToThread ip %p\n", g->ip); //post(slotRawInt(&"switchToThread newthread->ip) %d\n", slotRawInt(&newthread->ip)); //post(slotRawInt(&"switchToThread oldthread->ip) %d\n", slotRawInt(&oldthread->ip)); // wipe out values which will become stale as new thread executes: SetNil(&newthread->method); SetNil(&newthread->block); SetNil(&newthread->frame); SetRaw(&newthread->ip, (void*)0); SetRaw(&newthread->sp, (void*)0); SetNil(&newthread->receiver); SetRaw(&newthread->state, tRunning); // set new environment slotCopy(currentEnvironmentSlot,&g->thread->environment); g->gc->GCWrite(g->classvars, currentEnvironmentSlot); //post("old thread %p stack %p\n", oldthread, slotRawObject(&oldthread->stack)); //post("new thread %p stack %p\n", g->thread, slotRawObject(&g->thread->stack)); //post("main thread %p stack %p\n", slotRawThread(&g->process->mainThread), slotRawObject(&slotRawThread(&g->process->mainThread)->stack)); //postfl("<-switchToThread\n"); //post("<-stack %p g->sp %p [%d] g->top %p [%d]\n", // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "switchToThreadB"); //post("switchToThread ip2 %p\n", g->ip); } void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray, double beats, double seconds, PyrSlot* clock, bool runGC); void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray, double beats, double seconds, PyrSlot* clock, bool runGC) { PyrObject *array; PyrGC* gc = g->gc; slotCopy(&thread->func, func); gc->GCWrite(thread, func); array = newPyrArray(gc, stacksize, 0, runGC); SetObject(&thread->stack, array); gc->GCWriteNew(thread, array); // we know array is white so we can use GCWriteNew SetInt(&thread->state, tInit); SetPtr(&thread->ip, 0); SetPtr(&thread->sp, 0); SetObject(&thread->randData, rgenArray); gc->GCWrite(thread, rgenArray); SetFloat(&thread->beats, beats); SetFloat(&thread->seconds, seconds); SetInt(&thread->numArgsPushed, 0); SetInt(&thread->numpop, 0); if (IsNil(clock)) { SetObject(&thread->clock, s_systemclock->u.classobj); } else { slotCopy(&thread->clock,clock); gc->GCWrite(thread, clock); } PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1]; slotCopy(&thread->environment,currentEnvironmentSlot); gc->GCWrite(thread, currentEnvironmentSlot); if(g->process) { // check we're not just starting up slotCopy(&thread->executingPath,&g->process->nowExecutingPath); gc->GCWrite(thread, &g->process->nowExecutingPath); } SetInt(&thread->stackSize, stacksize); } extern PyrSymbol *s_prstart; int prThreadInit(struct VMGlobals *g, int numArgsPushed); int prThreadInit(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int stacksize, err; PyrThread *thread; //postfl("->prThreadInit\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prThreadInit"); a = g->sp - 2; // thread b = g->sp - 1; // function c = g->sp; // stacksize thread = slotRawThread(a); if (NotObj(b) || !isKindOf(slotRawObject(b), class_func)) { error("Thread function arg not a Function.\n"); return errWrongType; } err = slotIntVal(c, &stacksize); if (err) return err; stacksize = std::max(stacksize, EVALSTACKDEPTH); double beats, seconds; err = slotDoubleVal(&g->thread->beats, &beats); if (err) return err; err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return err; initPyrThread(g, thread, b, stacksize, (PyrInt32Array*)(slotRawObject(&g->thread->randData)), beats, seconds, &g->thread->clock, true); //postfl("<-prThreadInit\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "sp - 1; // thread PyrSlot *b = g->sp; // rand seed PyrThread *thread = slotRawThread(a); int32 seed; int err = slotIntVal(b, &seed); if (err) return err; PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, true); rgenArray->size = 4; ((RGen*)(rgenArray->i))->init(seed); if (thread == g->thread) { g->rgen = (RGen*)(rgenArray->i); } SetObject(&thread->randData, rgenArray); g->gc->GCWriteNew(thread, rgenArray); // we know rgenArray is white so we can use GCWriteNew return errNone; } int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed); int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; // thread PyrThread *thread = slotRawThread(a); RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots; PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false); rgenArray->size = 3; rgenArray->i[0] = rgen->s1; rgenArray->i[1] = rgen->s2; rgenArray->i[2] = rgen->s3; SetObject(a, rgenArray); return errNone; } int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed); int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; // thread PyrSlot *b = g->sp; // rand data array if (!isKindOfSlot(b, class_int32array)) return errWrongType; if (slotRawObject(b)->size < 3) return errWrongType; PyrThread *thread = slotRawThread(a); RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots; PyrInt32Array *rgenArray = (PyrInt32Array*)slotRawObject(b); rgen->s1 = rgenArray->i[0]; rgen->s2 = rgenArray->i[1]; rgen->s3 = rgenArray->i[2]; return errNone; } #if 0 int32 timeseed(); int transformMainThreadToRoutine(VMGlobals *g) { PyrProcess* process = g->process; if (g->thread != process->mainThread.uot) return errFailed; //if (g->thread != process->curThread.uot) return errFailed; PyrThread* curthread = (PyrThread*)slotRawObject(&process->mainThread); // create a new main thread PyrThread* newthread = (PyrThread*)instantiateObject(g->gc, class_thread, 0, true, false); PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false); rgenArray->size = 4; ((RGen*)(rgenArray->i))->init(timeseed()); PyrSlot clockSlot; SetObject(&clockSlot, s_systemclock->u.classobj); initPyrThread(g, newthread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false); slotRawInt(&newthread->sp) = (int)slotRawObject(&newthread->stack)->slots - 1; SetObject(&process->mainThread, newthread); g->gc->GCWrite(process, newthread); curthread->classptr = class_routine; PyrSlot *cmdFunc = &process->interpreter.uoi->cmdFunc; slotCopy(&curthread->func,cmdFunc); g->gc->GCWrite(curthread, cmdFunc); return errNone; } void schedAdd(VMGlobals *g, PyrObject* inQueue, double inSeconds, PyrSlot* inTask); #endif int prRoutineYield(struct VMGlobals *g, int numArgsPushed); int prRoutineYield(struct VMGlobals *g, int numArgsPushed) { PyrSlot value; //postfl("->prRoutineYield %p\n", g->thread); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYield"); //postfl("->numArgsPushed %d\n", numArgsPushed); slotCopy(&value,g->sp); if (!isKindOf((PyrObject*)g->thread, class_routine)) { error ("yield was called outside of a Routine.\n"); return errFailed; } PyrThread *parent = slotRawThread(&g->thread->parent); SetNil(&g->thread->parent); slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath); //debugf("yield from thread %p to parent %p\n", g->thread, slotRawThread(&g->thread->parent)); switchToThread(g, parent, tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); //postfl("<-numArgsPushed %d\n", numArgsPushed); //postfl("<-prRoutineYield\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineAlwaysYield ip %p\n", g->ip); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineAlwaysYield"); if (!isKindOf((PyrObject*)g->thread, class_routine)) { error ("alwaysYield was called outside of a Routine.\n"); return errFailed; } slotCopy(&value,g->sp); slotCopy(&g->thread->terminalValue,&value); g->gc->GCWrite(g->thread, g->sp); PyrThread *parent = slotRawThread(&g->thread->parent); SetNil(&g->thread->parent); slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath); //post("alwaysYield from thread %p to parent %p\n", g->thread, parent); switchToThread(g, parent, tDone, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); //postfl("<-prRoutineAlwaysYield ip %p\n", g->ip); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "gc->SanityCheck()); //CallStackSanity(g, "prRoutineResume"); a = g->sp - 1; b = g->sp; thread = slotRawThread(a); state = slotRawInt(&thread->state); //postfl("->prRoutineResume %d\n", state); slotCopy(&thread->oldExecutingPath,&g->process->nowExecutingPath); slotCopy(&g->process->nowExecutingPath, &thread->executingPath); if (state == tInit) { slotCopy(&threadSlot,a); slotCopy(&value,b); //post("g->thread %p\n", g->thread); //post("thread %p\n", thread); SetObject(&thread->parent, g->thread); g->gc->GCWrite(thread, g->thread); slotCopy(&thread->beats, &g->thread->beats); slotCopy(&thread->seconds, &g->thread->seconds); slotCopy(&thread->clock, &g->thread->clock); g->gc->GCWrite(thread, &g->thread->beats); g->gc->GCWrite(thread, &g->thread->seconds); g->gc->GCWrite(thread, &g->thread->clock); //postfl("start into thread %p from parent %p\n", thread, g->thread); switchToThread(g, thread, tSuspended, &numArgsPushed); // set stack //post("set stack %p %p\n", g->sp, g->gc->Stack()->slots - 1); g->sp = g->gc->Stack()->slots - 1; slotCopy((++g->sp), &threadSlot); slotCopy(&g->receiver, &threadSlot); slotCopy((++g->sp),&value); sendMessage(g, s_prstart, 2); } else if (state == tSuspended) { if (IsNil(&thread->parent)) { SetObject(&thread->parent, g->thread); } g->gc->GCWrite(thread, g->thread); slotCopy(&thread->beats, &g->thread->beats); slotCopy(&thread->seconds, &g->thread->seconds); slotCopy(&thread->clock,&g->thread->clock); g->gc->GCWrite(thread, &g->thread->beats); g->gc->GCWrite(thread, &g->thread->seconds); g->gc->GCWrite(thread, &g->thread->clock); slotCopy(&value,b); //debugf("resume into thread %p from parent %p\n", thread, g->thread); switchToThread(g, thread, tSuspended, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); } else if (state == tDone) { slotCopy(a,&thread->terminalValue); } else if (state == tRunning) { error("Tried to resume the running thread.\n"); return errFailed; } else { error("Thread in strange state: %d\n", state); return errFailed; } //postfl("<-prRoutineResume\n"); //CallStackSanity(g); return errNone; } int prRoutineReset(struct VMGlobals *g, int numArgsPushed); int prRoutineReset(struct VMGlobals *g, int numArgsPushed) { PyrThread *thread; int state; //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineReset"); thread = slotRawThread(g->sp); state = slotRawInt(&thread->state); //post("->prRoutineReset %d\n", state); if (state == tSuspended) { SetRaw(&thread->state, tInit); slotRawObject(&thread->stack)->size = 0; SetNil(&thread->method); SetNil(&thread->block); SetNil(&thread->receiver); SetNil(&thread->frame); SetRaw(&thread->ip, (void*)0); SetRaw(&thread->sp, (void*)0); SetRaw(&thread->numArgsPushed, 0); SetRaw(&thread->numpop, 0); SetNil(&thread->parent); } else if (state == tDone) { SetRaw(&thread->state, tInit); slotRawObject(&thread->stack)->size = 0; SetNil(&thread->method); SetNil(&thread->block); SetNil(&thread->receiver); SetNil(&thread->frame); SetRaw(&thread->ip, (void*)0); SetRaw(&thread->sp, (void*)0); SetRaw(&thread->numArgsPushed, 0); SetRaw(&thread->numpop, 0); SetNil(&thread->parent); } else if (state == tInit) { // do nothing } else if (state == tRunning) { error("A Routine cannot reset itself except by yieldAndReset.\n"); return errFailed; } else { error("Routine in unknown state. %d\n", state); return errFailed; } //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineStop\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineStop"); thread = slotRawThread(g->sp); state = slotRawInt(&thread->state); if (state == tSuspended || state == tInit) { slotCopy(&g->process->nowExecutingPath, &thread->oldExecutingPath); SetNil(&g->thread->terminalValue); SetRaw(&thread->state, tDone); slotRawObject(&thread->stack)->size = 0; } else if (state == tDone) { // do nothing } else if (state == tRunning) { error("Do not call .stop from within the Routine.\n"); post("A Routine should stop itself using nil.alwaysYield.\n"); return errFailed; } else { error("Routine in unknown state. %d\n", state); return errFailed; } //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYieldAndReset\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYieldAndReset"); a = g->sp - 1; b = g->sp; if (!isKindOf((PyrObject*)g->thread, class_routine)) { error ("yieldAndReset was called outside of a Routine.\n"); return errFailed; } /*if (!slotRawThread(&g->thread->parent)) { error ("yieldAndReset was called from a thread with no parent.\n"); return errFailed; }*/ slotCopy(&value,a); if (IsFalse(b)) state = tSuspended; else state = tInit; PyrThread *parent = slotRawThread(&g->thread->parent); SetNil(&g->thread->parent); switchToThread(g, parent, state, &numArgsPushed); // on the other side of the looking glass, put the yielded value on the stack as the result.. slotCopy((g->sp - numArgsPushed + 1),&value); //slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath); //post("<-prRoutineYieldAndReset\n"); //assert(g->gc->SanityCheck()); //CallStackSanity(g, "prRoutineYieldAndReset"); return errNone; } bool gBlork = false; int prBlork(struct VMGlobals *g, int numArgsPushed); int prBlork(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (IsTrue(a)) gBlork = true; else gBlork = false; return errNone; } int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed); int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* string = newPyrString(g->gc, overwriteMsg.c_str(), 0, false); SetObject(a, string); return errNone; } int prAppClockSchedNotify(struct VMGlobals *g, int numArgsPushed) { //NOTE: the _AppClock_SchedNotify primitive shall be redefined by language clients // if they wish to respond to AppClock scheduling notifications return errNone; } enum {includePaths, excludePaths}; static int prLanguageConfig_getLibraryPaths(struct VMGlobals * g, int numArgsPushed, int pathType) { PyrSlot *result = g->sp; typedef SC_LanguageConfig::DirVector DirVector; DirVector const & dirVector = (pathType == includePaths) ? gLanguageConfig->includedDirectories() : gLanguageConfig->excludedDirectories(); size_t numberOfPaths = dirVector.size(); PyrObject * resultArray = newPyrArray(g->gc, numberOfPaths, 0, true); SetObject(result, resultArray); for (size_t i = 0; i != numberOfPaths; ++i) { PyrString * pyrString = newPyrString(g->gc, dirVector[i].c_str(), 0, true); SetObject(resultArray->slots + i, pyrString); g->gc->GCWriteNew( resultArray, pyrString ); // we know pyrString is white so we can use GCWriteNew resultArray->size++; } return errNone; } static int prLanguageConfig_getIncludePaths(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_getLibraryPaths(g, numArgsPushed, includePaths); } static int prLanguageConfig_getExcludePaths(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_getLibraryPaths(g, numArgsPushed, excludePaths); } static int prLanguageConfig_addLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType) { PyrSlot *removeString = g->sp; char path[MAXPATHLEN]; bool error = slotStrVal(removeString, path, MAXPATHLEN); if (error) return errWrongType; if (pathType == includePaths) gLanguageConfig->addIncludedDirectory(path); else gLanguageConfig->addExcludedDirectory(path); return errNone; } static int prLanguageConfig_addIncludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_addLibraryPath(g, numArgsPushed, includePaths); } static int prLanguageConfig_addExcludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_addLibraryPath(g, numArgsPushed, excludePaths); } static int prLanguageConfig_removeLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType) { PyrSlot *dirString = g->sp; char path[MAXPATHLEN]; bool error = slotStrVal(dirString, path, MAXPATHLEN); if (error) return errWrongType; if (pathType == includePaths) gLanguageConfig->removeIncludedDirectory(path); else gLanguageConfig->removeExcludedDirectory(path); return errNone; } static int prLanguageConfig_removeIncludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_removeLibraryPath(g, numArgsPushed, includePaths); } static int prLanguageConfig_removeExcludePath(struct VMGlobals * g, int numArgsPushed) { return prLanguageConfig_removeLibraryPath(g, numArgsPushed, excludePaths); } static int prLanguageConfig_getCurrentConfigPath(struct VMGlobals * g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* str = newPyrString(g->gc, gLanguageConfig->getCurrentConfigPath(), 0, false); if(str->size == 0) { SetNil(a); } else { SetObject(a, str); } return errNone; } static int prLanguageConfig_writeConfigFile(struct VMGlobals * g, int numArgsPushed) { PyrSlot *fileString = g->sp; char path[MAXPATHLEN]; if (NotNil(fileString)) { bool error = slotStrVal(fileString, path, MAXPATHLEN); if (error) return errWrongType; } else { sc_GetUserConfigDirectory(path, PATH_MAX); sc_AppendToPath(path, MAXPATHLEN, "sclang_conf.yaml"); } gLanguageConfig->writeLibraryConfigYAML(path); return errNone; } extern bool gPostInlineWarnings; static int prLanguageConfig_getPostInlineWarnings(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetBool(result, gPostInlineWarnings); return errNone; } static int prLanguageConfig_setPostInlineWarnings(struct VMGlobals * g, int numArgsPushed) { PyrSlot *arg = g->sp; if (IsTrue(arg)) gPostInlineWarnings = true; else if (IsFalse(arg)) gPostInlineWarnings = false; else return errWrongType; return errNone; } static int prVersionMajor(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetInt(result, SC_VersionMajor); return errNone; } static int prVersionMinor(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetInt(result, SC_VersionMinor); return errNone; } static int prVersionPatch(struct VMGlobals * g, int numArgsPushed) { PyrSlot *result = g->sp; SetObject(result, newPyrString(g->gc, SC_VersionPatch, 0, 1)); return errNone; } #define PRIMGROWSIZE 480 PrimitiveTable gPrimitiveTable; void initPrimitiveTable() { int i; gPrimitiveTable.maxsize = PRIMGROWSIZE; gPrimitiveTable.size = 0; // pyrmalloc: // lifetime: runtime. primitives are reloaded when library is compiled. gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef)); MEMFAIL(gPrimitiveTable.table); for (i=0; iAlloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef)); MEMFAIL(gPrimitiveTable.table); memcpy(gPrimitiveTable.table, oldtable, oldsize * sizeof(PrimitiveDef)); for (i=oldsize; iFree(oldtable); } int definePrimitive(int base, int index, const char *name, PrimitiveHandler handler, int numArgs, int varArgs) { int tableIndex; PyrSymbol *sym; if (name[0] != '_') { error("*** Primitive Name must begin with an underscore ***\n"); postfl("name: '%s' index: %d\n", name, index); return -1; } tableIndex = base + index; if (tableIndex < 0) { error("*** Negative Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } if (tableIndex >= gPrimitiveTable.maxsize) { growPrimitiveTable(tableIndex + PRIMGROWSIZE); } if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) { error("*** Duplicate Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } sym = getsym(name); gPrimitiveTable.table[tableIndex].func = handler; gPrimitiveTable.table[tableIndex].name = sym; gPrimitiveTable.table[tableIndex].base = base; gPrimitiveTable.table[tableIndex].numArgs = numArgs; gPrimitiveTable.table[tableIndex].varArgs = varArgs; gPrimitiveTable.table[tableIndex].keyArgs = 0; if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex; sym->u.index = tableIndex; return tableIndex; } int definePrimitiveWithKeys(int base, int index, const char *name, PrimitiveHandler handler, PrimitiveWithKeysHandler keyhandler, int numArgs, int varArgs) { int tableIndex; PyrSymbol *sym; if (name[0] != '_') { error("*** Primitive Name must begin with an underscore ***\n"); postfl("name: '%s' index: %d\n", name, index); return -1; } tableIndex = base + index; if (tableIndex < 0) { error("*** Negative Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } if (tableIndex+1 >= gPrimitiveTable.maxsize) { growPrimitiveTable(tableIndex + PRIMGROWSIZE); } if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) { error("*** Duplicate Primitive Index ***\n"); postfl("name: '%s' index: %d\n", name, tableIndex); return -1; } sym = getsym(name); gPrimitiveTable.table[tableIndex].func = handler; gPrimitiveTable.table[tableIndex].name = sym; gPrimitiveTable.table[tableIndex].base = base; gPrimitiveTable.table[tableIndex].numArgs = numArgs; gPrimitiveTable.table[tableIndex].varArgs = varArgs; gPrimitiveTable.table[tableIndex].keyArgs = 1; sym->u.index = tableIndex; tableIndex++; gPrimitiveTable.table[tableIndex].func = (PrimitiveHandler)keyhandler; gPrimitiveTable.table[tableIndex].name = sym; gPrimitiveTable.table[tableIndex].base = base; gPrimitiveTable.table[tableIndex].numArgs = numArgs; gPrimitiveTable.table[tableIndex].varArgs = varArgs; gPrimitiveTable.table[tableIndex].keyArgs = 1; if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex; return tableIndex; } int nextPrimitiveIndex() { return gPrimitiveTable.size + 1; } void doPrimitive(VMGlobals* g, PyrMethod* meth, int numArgsPushed) { #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); PyrMethodRaw *methraw = METHRAW(meth); int primIndex = methraw->specialIndex; PrimitiveDef *def = gPrimitiveTable.table + primIndex; int numArgsNeeded = def->numArgs; int diff = numArgsNeeded - numArgsPushed; if (diff != 0) { // incorrect num of args if (diff > 0) { // not enough args PyrSlot* pslot = g->sp; PyrSlot* qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (int m=0; msp += diff; } else if (def->varArgs) { // has var args numArgsNeeded = numArgsPushed; } else { g->sp += diff; // remove excess args } } g->numpop = numArgsNeeded - 1; g->primitiveIndex = primIndex - def->base; g->primitiveMethod = meth; g->args = g->sp - numArgsNeeded; int err; try { #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif err = (*def->func)(g, numArgsNeeded); #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } catch (std::exception& ex) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); error(ex.what()); err = errException; } catch (...) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); err = errException; } if (err <= errNone) g->sp -= g->numpop; else { //post("primitive failed %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); SetInt(&g->thread->primitiveIndex, methraw->specialIndex); SetInt(&g->thread->primitiveError, err); executeMethod(g, meth, numArgsNeeded); } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } void doPrimitiveWithKeys(VMGlobals* g, PyrMethod* meth, int allArgsPushed, int numKeyArgsPushed) { int i, j, m, diff, err; PyrSlot *pslot, *qslot; int numArgsNeeded, numArgsPushed; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); //printf("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); PyrMethodRaw *methraw = METHRAW(meth); int primIndex = methraw->specialIndex; PrimitiveDef *def = gPrimitiveTable.table + primIndex; g->primitiveIndex = primIndex - def->base; g->primitiveMethod = meth; if (def->keyArgs && numKeyArgsPushed) { g->numpop = allArgsPushed - 1; try { err = ((PrimitiveWithKeysHandler)def[1].func)(g, allArgsPushed, numKeyArgsPushed); } catch (std::exception& ex) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); error(ex.what()); err = errException; } catch (...) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); err = errException; } if (err <= errNone) g->sp -= g->numpop; else { //post("primerr %d\n", err); SetInt(&g->thread->primitiveIndex, methraw->specialIndex); SetInt(&g->thread->primitiveError, err); executeMethodWithKeys(g, meth, allArgsPushed, numKeyArgsPushed); } } else { numArgsNeeded = def->numArgs; numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1); if (numKeyArgsPushed) { // evacuate keyword args to separate area pslot = keywordstack + (numKeyArgsPushed<<1); qslot = g->sp + 1; for (m=0; m 0) { // not enough args g->sp += numArgsNeeded - allArgsPushed; // remove excess args pslot = g->sp - diff; qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1; for (m=0; mvarArgs) { // has var args numArgsNeeded = numArgsPushed; g->sp += numArgsNeeded - allArgsPushed; // remove excess args } else { g->sp += numArgsNeeded - allArgsPushed; // remove excess args } } // do keyword lookup: if (numKeyArgsPushed && methraw->posargs) { PyrSymbol **name0, **name; PyrSlot *key, *vars; name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1; key = keywordstack; vars = g->sp - numArgsNeeded + 1; for (i=0; iposargs; ++j, ++name) { if (*name == slotRawSymbol(key)) { slotCopy(&vars[j],&key[1]); goto found; } } if (gKeywordError) { post("WARNING: keyword arg '%s' not found in call to %s:%s\n", slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); } found: ; } } g->numpop = numArgsNeeded - 1; try { err = (*def->func)(g, numArgsNeeded); } catch (std::exception& ex) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); error(ex.what()); err = errException; } catch (...) { post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name); err = errException; } if (err <= errNone) g->sp -= g->numpop; else { //post("primerr %d\n", err); SetInt(&g->thread->primitiveIndex, methraw->specialIndex); SetInt(&g->thread->primitiveError, err); executeMethod(g, meth, numArgsNeeded); } } #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif } void initPrimitives() { int base, index; initPrimitiveTable(); // unary operators base = nextPrimitiveIndex(); definePrimitive(base, opNeg, "_Neg", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opBitNot, "_BitNot", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAbs, "_Abs", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAsFloat, "_AsFloat", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAsInt, "_AsInt", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCeil, "_Ceil", doSpecialUnaryArithMsg, 1, 0); // 5 definePrimitive(base, opFloor, "_Floor", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opFrac, "_Frac", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSign, "_Sign", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSquared, "_Squared", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCubed, "_Cubed", doSpecialUnaryArithMsg, 1, 0); //10 definePrimitive(base, opSqrt, "_Sqrt", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opExp, "_Exp", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRecip, "_Recip", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opMIDICPS, "_MIDICPS", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCPSMIDI, "_CPSMIDI", doSpecialUnaryArithMsg, 1, 0); //15 definePrimitive(base, opMIDIRatio, "_MIDIRatio", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRatioMIDI, "_RatioMIDI", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opDbAmp, "_DbAmp", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opAmpDb, "_AmpDb", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opOctCPS, "_OctCPS", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCPSOct, "_CPSOct", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLog, "_Log", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLog2, "_Log2", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLog10, "_Log10", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSin, "_Sin", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCos, "_Cos", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opTan, "_Tan", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opArcSin, "_ArcSin", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opArcCos, "_ArcCos", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opArcTan, "_ArcTan", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSinH, "_SinH", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCosH, "_CosH", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opTanH, "_TanH", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRand, "_Rand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRand2, "_Rand2", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opLinRand, "_LinRand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opBiLinRand, "_BiLinRand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSum3Rand, "_Sum3Rand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opExpRand, "_ExpRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opBiExpRand, "_BiExpRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opGammaRand, "_GammaRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opGaussRand, "_GaussRand", doSpecialUnaryArithMsg, 1, 0); // definePrimitive(base, opPoiRand, "_PoiRand", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opDistort, "_Distort", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSoftClip, "_SoftClip", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opCoin, "_Coin", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRectWindow, "_RectWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opHanWindow, "_HanWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opWelchWindow, "_WelchWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opTriWindow, "_TriWindow", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opSCurve, "_SCurve", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opRamp, "_Ramp", doSpecialUnaryArithMsg, 1, 0); definePrimitive(base, opDigitValue, "_DigitValue", doSpecialUnaryArithMsg, 1, 0); // binary operators base = nextPrimitiveIndex(); definePrimitive(base, opAdd, "_Add", prAddNum, 2, 0); definePrimitive(base, opSub, "_Sub", prSubNum, 2, 0); definePrimitive(base, opMul, "_Mul", prMulNum, 2, 0); definePrimitive(base, opIDiv, "_IDiv", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFDiv, "_FDiv", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opMod, "_Mod", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opEQ, "_EQ", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opNE, "_NE", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opLT, "_LT", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opGT, "_GT", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opLE, "_LE", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opGE, "_GE", prSpecialBinaryArithMsg, 3, 0); //definePrimitive(base, opIdentical, "_Identical", prSpecialBinaryArithMsg, 3, 0); //definePrimitive(base, opNotIdentical, "_NotIdentical", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opMin, "_Min", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opMax, "_Max", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opBitAnd, "_BitAnd", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opBitOr, "_BitOr", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opBitXor, "_BitXor", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opLCM, "_LCM", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opGCD, "_GCD", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRound, "_Round", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRoundUp, "_RoundUp", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opTrunc, "_Trunc", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opAtan2, "_Atan2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opHypot, "_Hypot", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opHypotx, "_HypotApx", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opPow, "_Pow", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opShiftLeft, "_ShiftLeft", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opShiftRight, "_ShiftRight", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opUnsignedShift, "_UnsignedShift", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFill, "_Fill", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRing1, "_Ring1", prSpecialBinaryArithMsg, 3, 0); // a * (b + 1) == a * b + a definePrimitive(base, opRing2, "_Ring2", prSpecialBinaryArithMsg, 3, 0); // a * b + a + b definePrimitive(base, opRing3, "_Ring3", prSpecialBinaryArithMsg, 3, 0); // a*a*b definePrimitive(base, opRing4, "_Ring4", prSpecialBinaryArithMsg, 3, 0); // a*a*b - a*b*b definePrimitive(base, opDifSqr, "_DifSqr", prSpecialBinaryArithMsg, 3, 0); // a*a - b*b definePrimitive(base, opSumSqr, "_SumSqr", prSpecialBinaryArithMsg, 3, 0); // a*a + b*b definePrimitive(base, opSqrSum, "_SqrSum", prSpecialBinaryArithMsg, 3, 0); // (a + b)^2 definePrimitive(base, opSqrDif, "_SqrDif", prSpecialBinaryArithMsg, 3, 0); // (a - b)^2 definePrimitive(base, opAbsDif, "_AbsDif", prSpecialBinaryArithMsg, 3, 0); // abs(a - b) definePrimitive(base, opThresh, "_Thresh", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b) definePrimitive(base, opAMClip, "_AMClip", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b) definePrimitive(base, opScaleNeg, "_ScaleNeg", prSpecialBinaryArithMsg, 3, 0); // a < 0 ? a*b : a definePrimitive(base, opClip2, "_Clip2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFold2, "_Fold2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opWrap2, "_Wrap2", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opExcess, "_Excess", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opFirstArg, "_FirstArg", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opRandRange, "_RandRange", prSpecialBinaryArithMsg, 3, 0); definePrimitive(base, opExpRandRange, "_ExpRandRange", prSpecialBinaryArithMsg, 3, 0); // general primitives base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_Halt", haltInterpreter, 1, 0); definePrimitive(base, index++, "_InstVarAt", instVarAt, 2, 0); definePrimitive(base, index++, "_InstVarPut", instVarPut, 3, 0); definePrimitive(base, index++, "_InstVarSize", instVarSize, 1, 0); definePrimitive(base, index++, "_ObjectHash", objectHash, 1, 0); definePrimitive(base, index++, "_ObjectClass", objectClass, 1, 0); definePrimitive(base, index++, "_BasicNew", basicNew, 2, 0); definePrimitive(base, index++, "_BasicNewClear", basicNewClear, 2, 0); definePrimitive(base, index++, "_BasicNewCopyArgsToInstVars", basicNewCopyArgsToInstanceVars, 1, 1); //definePrimitive(base, index++, "_BasicNewCopyArgsByName", basicNewCopyArgsByName, 1, 1); definePrimitiveWithKeys(base, index, "_FunctionValue", blockValue, blockValueWithKeys, 1, 1); index+=2; definePrimitiveWithKeys(base, index, "_FunctionValueEnvir", blockValueEnvir, blockValueEnvirWithKeys, 1, 1); index+=2; definePrimitive(base, index++, "_FunctionValueArray", blockValueArray, 1, 1); definePrimitive(base, index++, "_FunctionValueArrayEnvir", blockValueArrayEnvir, 1, 1); definePrimitive(base, index++, "_FunctionDefAsFunction", prFunctionDefAsFunction, 1, 0); definePrimitive(base, index++, "_FunctionDefDumpContexts", prFunctionDefDumpContexts, 1, 0); definePrimitive(base, index++, "_FunctionDefIsClosed", prFunctionDefIsClosed, 1, 0); definePrimitive(base, index++, "_FunctionDefIsWithinClosed", prFunctionDefIsWithinClosed, 1, 0); definePrimitive(base, index++, "_ObjectIsKindOf", objectIsKindOf, 2, 0); definePrimitive(base, index++, "_ObjectIsMemberOf", objectIsMemberOf, 2, 0); definePrimitive(base, index++, "_ObjectDump", objectDump, 1, 0); definePrimitive(base, index++, "_TotalFree", prTotalFree, 1, 0); definePrimitive(base, index++, "_LargestFreeBlock", prLargestFreeBlock, 1, 0); definePrimitive(base, index++, "_GCInfo", dumpGCinfo, 1, 0); definePrimitive(base, index++, "_GCDumpGrey", dumpGCdumpGrey, 1, 0); definePrimitive(base, index++, "_GCDumpSet", dumpGCdumpSet, 2, 0); definePrimitive(base, index++, "_GCSanity", prGCSanity, 1, 0); #if GCDEBUG definePrimitive(base, index++, "_TraceAllPathsTo", prTraceAllPathsTo, 1, 0); definePrimitive(base, index++, "_TraceAnyPathsTo", prTraceAnyPathsTo, 1, 0); definePrimitive(base, index++, "_TraceAnyPathToAllInstancesOf", prTraceAnyPathToAllInstancesOf, 1, 0); #endif definePrimitive(base, index++, "_Identical", objectIdentical, 2, 0); definePrimitive(base, index++, "_NotIdentical", objectNotIdentical, 2, 0); definePrimitiveWithKeys(base, index, "_ObjectPerform", objectPerform, objectPerformWithKeys, 2, 1); index+=2; definePrimitive(base, index++, "_ObjectPerformList", objectPerformList, 2, 1); definePrimitiveWithKeys(base, index, "_SuperPerform", objectSuperPerform, objectSuperPerformWithKeys, 2, 1); index+=2; definePrimitive(base, index++, "_SuperPerformList", objectSuperPerformList, 2, 1); definePrimitive(base, index++, "_ObjectPerformMsg", objectPerformSelList, 2, 0); //definePrimitive(base, index++, "_ArrayPerformMsg", arrayPerformMsg, 1, 1); definePrimitive(base, index++, "_ObjectString", prObjectString, 1, 0); definePrimitive(base, index++, "_Float_AsStringPrec", prFloat_AsStringPrec, 2, 0); definePrimitive(base, index++, "_ObjectCompileString", prAsCompileString, 1, 0); definePrimitive(base, index++, "_ClassString", prClassString, 1, 0); definePrimitive(base, index++, "_PostString", prPostString, 1, 0); definePrimitive(base, index++, "_PostLine", prPostLine, 1, 0); definePrimitive(base, index++, "_HostDebugger", prDebugger, 1, 0); definePrimitive(base, index++, "_Trace", prTraceOn, 1, 0); definePrimitive(base, index++, "_CanCallOS", prCanCallOS, 1, 0); definePrimitive(base, index++, "_KeywordError", prKeywordError, 1, 0); definePrimitive(base, index++, "_GetTailCallOptimize", prGetTailCallOptimize, 1, 0); definePrimitive(base, index++, "_SetTailCallOptimize", prSetTailCallOptimize, 2, 0); definePrimitive(base, index++, "_PrimitiveError", prPrimitiveError, 1, 0); definePrimitive(base, index++, "_PrimitiveErrorString", prPrimitiveErrorString, 1, 0); definePrimitive(base, index++, "_DumpStack", prDumpStack, 1, 0); definePrimitive(base, index++, "_DumpDetailedBackTrace", prDumpDetailedBackTrace, 1, 0); definePrimitive(base, index++, "_StackDepth", prStackDepth, 1, 0); definePrimitive(base, index++, "_PrimName", prPrimName, 1, 0); definePrimitive(base, index++, "_ObjectShallowCopy", prObjectShallowCopy, 1, 0); definePrimitive(base, index++, "_ObjectCopyImmutable", prObjectCopyImmutable, 1, 0); definePrimitive(base, index++, "_ObjectCopyRange", prObjectCopyRange, 3, 0); definePrimitive(base, index++, "_ObjectCopySeries", prObjectCopySeries, 4, 0); definePrimitive(base, index++, "_ObjectPointsTo", prObjectPointsTo, 2, 0); definePrimitive(base, index++, "_ObjectRespondsTo", prObjectRespondsTo, 2, 0); definePrimitive(base, index++, "_ObjectIsMutable", prObjectIsMutable, 1, 0); definePrimitive(base, index++, "_ObjectIsPermanent", prObjectIsPermanent, 1, 0); definePrimitive(base, index++, "_ObjectDeepFreeze", prDeepFreeze, 1, 0); definePrimitive(base, index++, "_ObjectDeepCopy", prDeepCopy, 1, 0); #if !SCPLAYER definePrimitive(base, index++, "_CompileExpression", prCompileString, 2, 0); #endif definePrimitive(base, index++, "_GetBackTrace", prGetBackTrace, 1, 0); definePrimitive(base, index++, "_DumpBackTrace", prDumpBackTrace, 1, 0); definePrimitive(base, index++, "_DumpByteCodes", prDumpByteCodes, 1, 0); definePrimitive(base, index++, "_AllClasses", prAllClasses, 1, 0); definePrimitive(base, index++, "_DumpClassSubtree", prPostClassTree, 1, 0); // definePrimitive(base, index++, "_TabletTracking", prTabletTracking, 1, 0); definePrimitive(base, index++, "_FunDef_NumArgs", prFunDef_NumArgs, 1, 0); definePrimitive(base, index++, "_FunDef_NumVars", prFunDef_NumVars, 1, 0); definePrimitive(base, index++, "_FunDef_VarArgs", prFunDef_VarArgs, 1, 0); definePrimitive(base, index++, "_Thread_Init", prThreadInit, 3, 0); definePrimitive(base, index++, "_Thread_RandSeed", prThreadRandSeed, 2, 0); definePrimitive(base, index++, "_Thread_GetRandData", prThreadGetRandData, 1, 0); definePrimitive(base, index++, "_Thread_SetRandData", prThreadSetRandData, 2, 0); // definePrimitive(base, index++, "_ThreadRun", prThreadRun, 2, 0); // definePrimitive(base, index++, "_RunNextThread", prRunNextThread, 1, 0); definePrimitive(base, index++, "_RoutineYield", prRoutineYield, 1, 0); definePrimitive(base, index++, "_RoutineAlwaysYield", prRoutineAlwaysYield, 1, 0); definePrimitive(base, index++, "_RoutineResume", prRoutineResume, 2, 0); definePrimitive(base, index++, "_RoutineReset", prRoutineReset, 1, 0); definePrimitive(base, index++, "_RoutineYieldAndReset", prRoutineYieldAndReset, 2, 0); definePrimitive(base, index++, "_RoutineStop", prRoutineStop, 1, 0); // definePrimitive(base, index++, "_IsDemo", prIsDemo, 1, 0); definePrimitive(base, index++, "_Blork", prBlork, 1, 0); definePrimitive(base, index++, "_UGenCodeString", prUGenCodeString, 5, 0); definePrimitive(base, index++, "_MainOverwriteMsg", prOverwriteMsg, 1, 0); definePrimitive(base, index++, "_AppClock_SchedNotify", prAppClockSchedNotify, 1, 0); definePrimitive(base, index++, "_LanguageConfig_getCurrentConfigPath", prLanguageConfig_getCurrentConfigPath, 1, 0); definePrimitive(base, index++, "_LanguageConfig_getIncludePaths", prLanguageConfig_getIncludePaths, 1, 0); definePrimitive(base, index++, "_LanguageConfig_getExcludePaths", prLanguageConfig_getExcludePaths, 1, 0); definePrimitive(base, index++, "_LanguageConfig_addIncludePath", prLanguageConfig_addIncludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_addExcludePath", prLanguageConfig_addExcludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_removeIncludePath", prLanguageConfig_removeIncludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_removeExcludePath", prLanguageConfig_removeExcludePath, 2, 0); definePrimitive(base, index++, "_LanguageConfig_writeConfigFile", prLanguageConfig_writeConfigFile, 2, 0); definePrimitive(base, index++, "_LanguageConfig_getPostInlineWarnings", prLanguageConfig_getPostInlineWarnings, 1, 0); definePrimitive(base, index++, "_LanguageConfig_setPostInlineWarnings", prLanguageConfig_setPostInlineWarnings, 2, 0); definePrimitive(base, index++, "_SC_VersionMajor", prVersionMajor, 1, 0); definePrimitive(base, index++, "_SC_VersionMinor", prVersionMinor, 1, 0); definePrimitive(base, index++, "_SC_VersionPatch", prVersionPatch, 1, 0); //void initOscilPrimitives(); //void initControllerPrimitives(); //initOscilPrimitives(); //initControllerPrimitives(); initMathPrimitives(); initSignalPrimitives(); initArrayPrimitives(); void initSymbolPrimitives(); initSymbolPrimitives(); void initArchiverPrimitives(); initArchiverPrimitives(); void initArrayPrimitives(); initArrayPrimitives(); void initBitPrimitives(); initBitPrimitives(); void initCharPrimitives(); initCharPrimitives(); void initFilePrimitives(); initFilePrimitives(); void initPlatformPrimitives(); initPlatformPrimitives(); void initStringPrimitives(); initStringPrimitives(); void initListPrimitives(); initListPrimitives(); void initUnixPrimitives(); initUnixPrimitives(); void init_OSC_primitives(); init_OSC_primitives(); void initGUIPrimitives(); initGUIPrimitives(); #ifdef SC_APP void initSCViewPrimitives(); initSCViewPrimitives(); void initRendezvousPrimitives(); initRendezvousPrimitives(); void initCocoaFilePrimitives(); initCocoaFilePrimitives(); #endif void initSchedPrimitives(); initSchedPrimitives(); void initHIDAPIPrimitives(); initHIDAPIPrimitives(); #if defined(__APPLE__) || defined(HAVE_ALSA) || defined(HAVE_PORTMIDI) void initMIDIPrimitives(); initMIDIPrimitives(); #endif #if !defined(_WIN32) && !defined(SC_IPHONE) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__APPLE__) void initLIDPrimitives(); initLIDPrimitives(); #endif #if !defined(_WIN32) && !defined(SC_IPHONE) && !defined(__OpenBSD__) && !defined(__NetBSD__) void initSerialPrimitives(); initSerialPrimitives(); #ifdef HAVE_WII void initWiiPrimitives(); initWiiPrimitives(); #endif #endif #ifdef __APPLE__ void initCoreAudioPrimitives(); initCoreAudioPrimitives(); #endif #ifdef SCOGL_COMPILE void initOpenGLPrimitives(); initOpenGLPrimitives(); #endif #ifdef __APPLE__ void initSpeechPrimitives(); initSpeechPrimitives(); #endif #ifdef SC_QT QtCollider::initPrimitives(); #endif #ifdef SC_IDE void initScIDEPrimitives(); initScIDEPrimitives(); #endif initSCDocPrimitives(); s_recvmsg = getsym("receiveMsg"); post("\tNumPrimitives = %d\n", nextPrimitiveIndex()); } void deinitPrimitives() { void deinitHIDAPIPrimitives(); deinitHIDAPIPrimitives(); #if defined(HAVE_PORTMIDI) || defined(HAVE_ALSA) void deinitMIDIPrimitives(); deinitMIDIPrimitives(); #endif } void initThreads(); void initThreads() { s_prrunnextthread = getsym("prRunNextThread"); s_prready = getsym("prReady"); } SuperCollider-Source/lang/LangPrimSource/PyrSched.cpp000644 000765 000024 00000114205 12756531745 023737 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrKernel.h" #include "PyrSched.h" #include "GC.h" #include "PyrPrimitive.h" #include "PyrSymbol.h" #ifdef __APPLE__ # include #endif #ifdef _MSC_VER #include "wintime.h" #else #include #endif #include #include #include #include #include #if defined(__APPLE__) || defined(__linux__) # include #endif #include "SC_Win32Utils.h" #include "SCBase.h" #include "SC_Lock.h" #include #include static const double dInfinity = std::numeric_limits::infinity(); void runAwakeMessage(VMGlobals *g); // heaps use an integer timestamp to ensure stable heap order struct PyrHeap: PyrObjectHdr { PyrSlot count; // stability count PyrSlot slots[0]; // slots }; bool addheap(VMGlobals *g, PyrObject *heapArg, double schedtime, PyrSlot *task) { PyrHeap * heap = (PyrHeap*)heapArg; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif if (heap->size >= ARRAYMAXINDEXSIZE(heap)) return false; assert(heap->size); // post("->addheap\n"); // dumpheap(heapArg); /* parent and sibling in the heap, not in the task hierarchy */ int mom = heap->size - 1; PyrSlot * pme = heap->slots + mom; int stabilityCount = slotRawInt(&heap->count); SetRaw(&heap->count, stabilityCount + 1); for (; mom>0;) { /* percolate up heap */ int newMom = ((mom - 3) / 2); mom = newMom - newMom % 3; /// LATER: we could avoid the division by using 4 slots per element PyrSlot * pmom = heap->slots + mom; if (schedtime < slotRawFloat(pmom)) { assert(slotRawInt(pmom + 2) < stabilityCount); slotCopy(&pme[0], &pmom[0]); slotCopy(&pme[1], &pmom[1]); slotCopy(&pme[2], &pmom[2]); pme = pmom; } else break; } SetFloat(&pme[0], schedtime); slotCopy(&pme[1], task); SetInt(&pme[2], stabilityCount); g->gc->GCWrite(heap, task); heap->size += 3; #ifdef GC_SANITYCHECK g->gc->SanityCheck(); #endif // dumpheap(heapArg); // post("<-addheap %g\n", schedtime); return true; } bool lookheap(PyrObject *heap, double *schedtime, PyrSlot *task) { if (heap->size > 1) { *schedtime = slotRawFloat(&heap->slots[0]); slotCopy(task, &heap->slots[1]); return true; } else return false; } bool getheap(VMGlobals *g, PyrObject *heapArg, double *schedtime, PyrSlot *task) { PyrHeap * heap = (PyrHeap*)heapArg; PyrGC* gc = g->gc; bool isPartialScanObj = gc->IsPartialScanObject(heapArg); assert(heap->size); // post("->getheap\n"); // dumpheap(heapArg); if (heap->size>1) { *schedtime = slotRawFloat(&heap->slots[0]); slotCopy(task, &heap->slots[1]); heap->size -= 3; int size = heap->size - 1; slotCopy(&heap->slots[0], &heap->slots[size]); slotCopy(&heap->slots[1], &heap->slots[size+1]); slotCopy(&heap->slots[2], &heap->slots[size+2]); /* parent and sibling in the heap, not in the task hierarchy */ int mom = 0; int me = 3; PyrSlot * pmom = heap->slots + mom; PyrSlot * pme = heap->slots + me; PyrSlot * pend = heap->slots + size; double timetemp = slotRawFloat(&pmom[0]); int stabilityCountTemp = slotRawInt(&pmom[2]); PyrSlot tasktemp; slotCopy(&tasktemp, &pmom[1]); for (;pme < pend;) { /* demote heap */ if (pme+3 < pend && ((slotRawFloat(&pme[0]) > slotRawFloat(&pme[3])) || ((slotRawFloat(&pme[0]) == slotRawFloat(&pme[3])) && (slotRawInt(&pme[2]) > slotRawInt(&pme[5])) ))) { me += 3; pme += 3; } if (timetemp > slotRawFloat(&pme[0]) || (timetemp == slotRawFloat(&pme[0]) && stabilityCountTemp > slotRawInt(&pme[2]))) { slotCopy(&pmom[0], &pme[0]); slotCopy(&pmom[1], &pme[1]); slotCopy(&pmom[2], &pme[2]); if (isPartialScanObj) { gc->GCWriteBlack(pmom+1); } pmom = pme; me = ((mom = me) * 2) + 3; pme = heap->slots + me; } else break; } SetRaw(&pmom[0], timetemp); slotCopy(&pmom[1], &tasktemp); SetRaw(&pmom[2], stabilityCountTemp); if (isPartialScanObj) gc->GCWriteBlack(pmom+1); if (size == 0) SetInt(&heap->count, 0); // dumpheap(heapArg); // post("<-getheap true\n"); return true; } else { // post("<-getheap false\n"); return false; } } void offsetheap(VMGlobals *g, PyrObject *heap, double offset) { long i; for (i=0; isize; i+=2) { SetRaw(&heap->slots[i], slotRawFloat(&heap->slots[i]) + offset); //post("%3d %9.2f %9.2f\n", i>>1, heap->slots[i].uf, offset); } } void dumpheap(PyrObject *heapArg) { PyrHeap * heap = (PyrHeap*)heapArg; double mintime = slotRawFloat(&heap->slots[0]); int count = slotRawFloat(&heap->slots[2]); int heapSize = heap->size - 1; post("SCHED QUEUE (%d)\n", heapSize); for (int i=0; islots[i]), slotRawObject(&heap->slots[i+1]), slotRawInt(&heap->slots[i+2])); if ((slotRawFloat(&heap->slots[i]) < mintime) || (slotRawFloat(&heap->slots[i]) == mintime && slotRawInt(&heap->slots[i+2]) < count ) ) post("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"); } } bool gRunSched = false; static std::thread gSchedThread; static std::thread gResyncThread; static boost::sync::semaphore gResyncThreadSemaphore; std::condition_variable_any gSchedCond; std::timed_mutex gLangMutex; int64 gHostOSCoffset = 0; int64 gHostStartNanos = 0; int64 gElapsedOSCoffset = 0; const int32 kSECONDS_FROM_1900_to_1970 = (int32)2208988800UL; /* 17 leap years */ const double fSECONDS_FROM_1900_to_1970 = 2208988800.; /* 17 leap years */ static void syncOSCOffsetWithTimeOfDay(); void resyncThread(); // Use the highest resolution clock available for monotonic clock time using monotonic_clock = std::conditional::type; static std::chrono::high_resolution_clock::time_point hrTimeOfInitialization; template inline double DurToFloat(DurationType dur) { using namespace std::chrono; seconds secs = duration_cast(dur); nanoseconds nanosecs = dur - secs; return secs.count() + 1.0e-9 * nanosecs.count(); } SCLANG_DLLEXPORT_C void schedInit() { using namespace std::chrono; hrTimeOfInitialization = high_resolution_clock::now(); syncOSCOffsetWithTimeOfDay(); gResyncThread = std::thread(resyncThread); gHostStartNanos = duration_cast(hrTimeOfInitialization.time_since_epoch()).count(); gElapsedOSCoffset = (int64)(gHostStartNanos * kNanosToOSC) + gHostOSCoffset; } SCLANG_DLLEXPORT_C void schedCleanup() { gResyncThreadSemaphore.post(); gResyncThread.join(); } double elapsedTime() { return DurToFloat(std::chrono::high_resolution_clock::now() - hrTimeOfInitialization); } double monotonicClockTime() { return DurToFloat(monotonic_clock::now().time_since_epoch()); } int64 ElapsedTimeToOSC(double elapsed) { return (int64)(elapsed * kSecondsToOSC) + gElapsedOSCoffset; } double OSCToElapsedTime(int64 oscTime) { return (double)(oscTime - gElapsedOSCoffset) * kOSCtoSecs; } void ElapsedTimeToChrono(double elapsed, std::chrono::system_clock::time_point & out_time_point) { int64 oscTime = ElapsedTimeToOSC(elapsed); int64 secs = ((oscTime >> 32) - kSECONDS_FROM_1900_to_1970); int32 nano_secs = (int32)((oscTime & 0xFFFFFFFF) * kOSCtoNanos); using namespace std::chrono; #if 0 // TODO: check system_clock precision system_clock::time_point time_point = system_clock::time_point(seconds(secs) + nanoseconds(nano_secs)); #else int32 usecs = nano_secs / 1000; system_clock::time_point time_point = system_clock::time_point(seconds(secs) + microseconds(usecs)); #endif out_time_point = time_point; } int64 OSCTime() { return ElapsedTimeToOSC(elapsedTime()); } void syncOSCOffsetWithTimeOfDay() { // generate a value gHostOSCoffset such that // (gHostOSCoffset + systemTimeInOSCunits) // is equal to gettimeofday time in OSCunits. // Then if this machine is synced via NTP, we are synced with the world. // more accurate way to do this?? using namespace std::chrono; struct timeval tv; nanoseconds systemTimeBefore, systemTimeAfter; int64 diff, minDiff = 0x7fffFFFFffffFFFFLL; // take best of several tries const int numberOfTries = 8; int64 newOffset = gHostOSCoffset; for (int i=0; isize > 1 ? slotRawFloat(inQueue->slots + 1) : -1e10; bool added = addheap(g, inQueue, inSeconds, inTask); if (!added) post("scheduler queue is full.\n"); else { if (isKindOfSlot(inTask, class_thread)) { SetFloat(&slotRawThread(inTask)->nextBeat, inSeconds); } if (slotRawFloat(inQueue->slots + 1) != prevTime) { gSchedCond.notify_all(); } } } SCLANG_DLLEXPORT_C void schedStop() { //printf("->schedStop\n"); gLangMutex.lock(); if (gRunSched) { gRunSched = false; gLangMutex.unlock(); gSchedCond.notify_all(); gSchedThread.join(); } else { gLangMutex.unlock(); } //printf("<-schedStop\n"); } void schedClearUnsafe(); SCLANG_DLLEXPORT_C void schedClear() { gLangMutex.lock(); schedClearUnsafe(); gLangMutex.unlock(); } void schedClearUnsafe() { //postfl("->schedClear %d\n", gRunSched); if (gRunSched) { VMGlobals *g = gMainVMGlobals; PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); inQueue->size = 1; gSchedCond.notify_all(); } //postfl("<-schedClear %d\n", gRunSched); } void post(const char *fmt, ...); void resyncThread() { while (true) { if( gResyncThreadSemaphore.wait_for( std::chrono::seconds(20) ) ) return; syncOSCOffsetWithTimeOfDay(); gElapsedOSCoffset = (int64)(gHostStartNanos * kNanosToOSC) + gHostOSCoffset; } } extern bool gTraceInterpreter; static void schedRunFunc() { using namespace std::chrono; unique_lock lock(gLangMutex); VMGlobals *g = gMainVMGlobals; PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); //dumpObject(inQueue); gRunSched = true; while (true) { assert(inQueue->size); //postfl("wait until there is something in scheduler\n"); // wait until there is something in scheduler while (inQueue->size == 1) { //postfl("wait until there is something in scheduler\n"); gSchedCond.wait(lock); if (!gRunSched) goto leave; } //postfl("wait until an event is ready\n"); // wait until an event is ready high_resolution_clock::duration schedSecs; high_resolution_clock::time_point now, schedPoint; do { now = high_resolution_clock::now(); schedSecs = duration_cast(duration(slotRawFloat(inQueue->slots + 1))); schedPoint = hrTimeOfInitialization + schedSecs; if(now >= schedPoint) break; //postfl("wait until an event is ready\n"); gSchedCond.wait_until(lock, schedPoint); if (!gRunSched) goto leave; //postfl("time diff %g\n", elapsedTime() - inQueue->slots->uf); } while (inQueue->size > 1); //postfl("perform all events that are ready %d %.9f\n", inQueue->size, elapsed); // perform all events that are ready //postfl("perform all events that are ready\n"); while ((inQueue->size > 1) && now >= hrTimeOfInitialization + duration_cast(duration(slotRawFloat(inQueue->slots + 1)))) { double schedtime, delta; PyrSlot task; //postfl("while %.6f >= %.6f\n", elapsed, inQueue->slots->uf); getheap(g, inQueue, &schedtime, &task); if (isKindOfSlot(&task, class_thread)) { SetNil(&slotRawThread(&task)->nextBeat); } slotCopy((++g->sp), &task); SetFloat(++g->sp, schedtime); SetFloat(++g->sp, schedtime); ++g->sp; SetObject(g->sp, s_systemclock->u.classobj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double time = schedtime + delta; schedAdd(g, inQueue, time, &task); } } //postfl("loop\n"); } //postfl("exitloop\n"); leave: return; } #ifdef __APPLE__ #include #include //Polls a (non-realtime) thread to find out how it is scheduled //Results are undefined of an error is returned. Otherwise, the //priority is returned in the address pointed to by the priority //parameter, and whether or not the thread uses timeshare scheduling //is returned at the address pointed to by the isTimeShare parameter kern_return_t GetStdThreadSchedule( mach_port_t machThread, int *priority, boolean_t *isTimeshare ) { kern_return_t result = 0; thread_extended_policy_data_t timeShareData; thread_precedence_policy_data_t precedenceData; mach_msg_type_number_t structItemCount; boolean_t fetchDefaults = false; memset( &timeShareData, 0, sizeof( thread_extended_policy_data_t )); memset( &precedenceData, 0, sizeof( thread_precedence_policy_data_t )); if( 0 == machThread ) machThread = mach_thread_self(); if( NULL != isTimeshare ) { structItemCount = THREAD_EXTENDED_POLICY_COUNT; result = thread_policy_get( machThread, THREAD_EXTENDED_POLICY, (integer_t*)&timeShareData, &structItemCount, &fetchDefaults ); *isTimeshare = timeShareData.timeshare; if( 0 != result ) return result; } if( NULL != priority ) { fetchDefaults = false; structItemCount = THREAD_PRECEDENCE_POLICY_COUNT; result = thread_policy_get( machThread, THREAD_PRECEDENCE_POLICY, (integer_t*)&precedenceData, &structItemCount, &fetchDefaults ); *priority = precedenceData.importance; } return result; } // Reschedules the indicated thread according to new parameters: // // machThread The mach thread id. Pass 0 for the current thread. // newPriority The desired priority. // isTimeShare false for round robin (fixed) priority, // true for timeshare (normal) priority // // A standard new thread usually has a priority of 0 and uses the // timeshare scheduling scheme. Use pthread_mach_thread_np() to // to convert a pthread id to a mach thread id kern_return_t RescheduleStdThread( mach_port_t machThread, int newPriority, boolean_t isTimeshare ) { kern_return_t result = 0; thread_extended_policy_data_t timeShareData; thread_precedence_policy_data_t precedenceData; //Set up some variables that we need for the task precedenceData.importance = newPriority; timeShareData.timeshare = isTimeshare; if( 0 == machThread ) machThread = mach_thread_self(); //Set the scheduling flavor. We want to do this first, since doing so //can alter the priority result = thread_policy_set( machThread, THREAD_EXTENDED_POLICY, (integer_t*)&timeShareData, THREAD_EXTENDED_POLICY_COUNT ); if( 0 != result ) return result; //Now set the priority return thread_policy_set( machThread, THREAD_PRECEDENCE_POLICY, (integer_t*)&precedenceData, THREAD_PRECEDENCE_POLICY_COUNT ); } #endif // __APPLE__ #ifdef __linux__ #include static void SC_LinuxSetRealtimePriority(pthread_t thread, int priority) { int policy; struct sched_param param; pthread_getschedparam(thread, &policy, ¶m); policy = SCHED_FIFO; const int minprio = sched_get_priority_min(policy); const int maxprio = sched_get_priority_max(policy); param.sched_priority = sc_clip(priority, minprio, maxprio); int err = pthread_setschedparam(thread, policy, ¶m); if (err != 0) { post("Couldn't set realtime scheduling priority %d: %s\n", param.sched_priority, strerror(err)); } } #endif // __linux__ SCLANG_DLLEXPORT_C void schedRun() { thread thread(schedRunFunc); gSchedThread = std::move(thread); #ifdef __APPLE__ int policy; struct sched_param param; //pthread_t thread = pthread_self (); pthread_getschedparam (gSchedThread.native_handle(), &policy, ¶m); //post("param.sched_priority %d\n", param.sched_priority); policy = SCHED_RR; // round-robin, AKA real-time scheduling int machprio; boolean_t timeshare; GetStdThreadSchedule(pthread_mach_thread_np(gSchedThread.native_handle()), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); // what priority should gSchedThread use? RescheduleStdThread(pthread_mach_thread_np(gSchedThread.native_handle()), 62, false); GetStdThreadSchedule(pthread_mach_thread_np(gSchedThread.native_handle()), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); //param.sched_priority = 70; // you'll have to play with this to see what it does //pthread_setschedparam (gSchedThread, policy, ¶m); pthread_getschedparam (gSchedThread.native_handle(), &policy, ¶m); //post("param.sched_priority %d\n", param.sched_priority); #endif // __APPLE__ #ifdef __linux__ SC_LinuxSetRealtimePriority(gSchedThread.native_handle(), 1); #endif // __linux__ } /* unscheduled events: startup, receive OSC, mouse, keyboard, MIDI all these happen in the main thread. */ /* new clock: create destroy wake up at time x. unschedule awake reschedules. */ class TempoClock { public: TempoClock(VMGlobals *inVMGlobals, PyrObject* inTempoClockObj, double inTempo, double inBaseBeats, double inBaseSeconds); ~TempoClock() {} void StopReq(); void Stop(); void StopAndDelete() { Stop(); delete this; } void* Run(); void Add(double inBeats, PyrSlot* inTask); void SetTempoAtBeat(double inTempo, double inBeats); void SetTempoAtTime(double inTempo, double inSeconds); void SetAll(double inTempo, double inBeats, double inSeconds); double ElapsedBeats(); void Clear(); //void Flush(); double GetTempo() const { return mTempo; } double GetBeatDur() const { return mBeatDur; } double BeatsToSecs(double beats) const { return (beats - mBaseBeats) * mBeatDur + mBaseSeconds; } double SecsToBeats(double secs) const { return (secs - mBaseSeconds) * mTempo + mBaseBeats; } void Dump(); //protected: VMGlobals* g; PyrObject* mTempoClockObj; PyrHeap* mQueue; double mTempo; // beats per second double mBeatDur; // 1/tempo double mBeats; // beats double mBaseSeconds; double mBaseBeats; bool mRun; thread mThread; condition_variable_any mCondition; TempoClock *mPrev, *mNext; static TempoClock *sAll; }; TempoClock *TempoClock::sAll = 0; void TempoClock_stopAll(void) { //printf("->TempoClock_stopAll %p\n", TempoClock::sAll); TempoClock *clock = TempoClock::sAll; while (clock) { TempoClock* next = clock->mNext; clock->Stop(); //printf("delete\n"); delete clock; clock = next; } //printf("<-TempoClock_stopAll %p\n", TempoClock::sAll); TempoClock::sAll = 0; } TempoClock::TempoClock(VMGlobals *inVMGlobals, PyrObject* inTempoClockObj, double inTempo, double inBaseBeats, double inBaseSeconds) : g(inVMGlobals), mTempoClockObj(inTempoClockObj), mTempo(inTempo), mBeatDur(1./inTempo), mBaseSeconds(inBaseSeconds), mBaseBeats(inBaseBeats), mRun(true), mPrev(0), mNext(sAll) { if (sAll) sAll->mPrev = this; sAll = this; mQueue = (PyrHeap*)slotRawObject(&mTempoClockObj->slots[0]); mQueue->size = 1; SetInt(&mQueue->count, 0); thread thread(std::bind(&TempoClock::Run, this)); mThread = std::move(thread); #ifdef __APPLE__ int machprio; boolean_t timeshare; GetStdThreadSchedule(pthread_mach_thread_np(mThread.native_handle()), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); // what priority should gSchedThread use? RescheduleStdThread(pthread_mach_thread_np(mThread.native_handle()), 10, false); GetStdThreadSchedule(pthread_mach_thread_np(mThread.native_handle()), &machprio, ×hare); //post("mach priority %d timeshare %d\n", machprio, timeshare); //param.sched_priority = 70; // you'll have to play with this to see what it does //pthread_setschedparam (mThread, policy, ¶m); #endif // __APPLE__ #ifdef __linux__ SC_LinuxSetRealtimePriority(mThread.native_handle(), 1); #endif // __linux__ } void TempoClock::StopReq() { //printf("->TempoClock::StopReq\n"); thread stopThread(std::bind(&TempoClock::StopAndDelete, this)); stopThread.detach(); //printf("<-TempoClock::StopReq\n"); } void TempoClock::Stop() { //printf("->TempoClock::Stop\n"); { lock_guard lock(gLangMutex); //printf("Stop mRun %d\n", mRun); if (mRun) { mRun = false; // unlink if (mPrev) mPrev->mNext = mNext; else sAll = mNext; if (mNext) mNext->mPrev = mPrev; mCondition.notify_all(); } } mThread.join(); //printf("<-TempoClock::Stop\n"); } void TempoClock::SetAll(double inTempo, double inBeats, double inSeconds) { mBaseSeconds = inSeconds; mBaseBeats = inBeats; mTempo = inTempo; mBeatDur = 1. / mTempo; mCondition.notify_one(); } void TempoClock::SetTempoAtBeat(double inTempo, double inBeats) { mBaseSeconds = BeatsToSecs(inBeats); mBaseBeats = inBeats; mTempo = inTempo; mBeatDur = 1. / mTempo; mCondition.notify_one(); } void TempoClock::SetTempoAtTime(double inTempo, double inSeconds) { mBaseBeats = SecsToBeats(inSeconds); mBaseSeconds = inSeconds; mTempo = inTempo; mBeatDur = 1. / mTempo; mCondition.notify_one(); } double TempoClock::ElapsedBeats() { return SecsToBeats(elapsedTime()); } void* TempoClock::Run() { using namespace std::chrono; //printf("->TempoClock::Run\n"); unique_lock lock(gLangMutex); while (mRun) { assert(mQueue->size); //printf("tempo %g dur %g beats %g\n", mTempo, mBeatDur, mBeats); //printf("wait until there is something in scheduler\n"); // wait until there is something in scheduler while (mQueue->size == 1) { //printf("wait until there is something in scheduler\n"); mCondition.wait(gLangMutex); //printf("mRun a %d\n", mRun); if (!mRun) goto leave; } //printf("wait until an event is ready\n"); // wait until an event is ready double elapsedBeats; high_resolution_clock::duration schedSecs; high_resolution_clock::time_point schedPoint; do { elapsedBeats = ElapsedBeats(); if (elapsedBeats >= slotRawFloat(mQueue->slots)) break; //printf("event ready at %g . elapsed beats %g\n", mQueue->slots->uf, elapsedBeats); double wakeTime = BeatsToSecs(slotRawFloat(mQueue->slots)); schedSecs = duration_cast(duration(wakeTime)); schedPoint = hrTimeOfInitialization + schedSecs; //printf("wait until an event is ready. wake %g now %g\n", wakeTime, elapsedTime()); mCondition.wait_until(lock, schedPoint); //printf("mRun b %d\n", mRun); if (!mRun) goto leave; //printf("time diff %g\n", elapsedTime() - mQueue->slots->uf); } while (mQueue->size > 1); //printf("perform all events that are ready %d %.9f\n", mQueue->size, elapsedBeats); // perform all events that are ready //printf("perform all events that are ready\n"); while (mQueue->size > 1 && elapsedBeats >= slotRawFloat(mQueue->slots)) { double delta; PyrSlot task; //printf("while %.6f >= %.6f\n", elapsedBeats, mQueue->slots->uf); getheap(g, (PyrObject*)mQueue, &mBeats, &task); if (isKindOfSlot(&task, class_thread)) { SetNil(&slotRawThread(&task)->nextBeat); } slotCopy((++g->sp), &task); SetFloat(++g->sp, mBeats); SetFloat(++g->sp, BeatsToSecs(mBeats)); ++g->sp; SetObject(g->sp, mTempoClockObj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double beats = mBeats + delta; Add(beats, &task); } } } leave: //printf("<-TempoClock::Run\n"); return 0; } /* void TempoClock::Flush() { while (mQueue->size && elapsedBeats >= mQueue->slots->uf) { double delta; PyrSlot task; //printf("while %.6f >= %.6f\n", elapsedBeats, mQueue->slots->uf); getheap(g, mQueue, &mBeats, &task); slotCopy((++g->sp), &task); (++g->sp)->uf = mBeats; (++g->sp)->uf = BeatsToSecs(mBeats); ++g->sp; SetObject(g->sp, mTempoClockObj); runAwakeMessage(g); long err = slotDoubleVal(&g->result, &delta); if (!err) { // add delta time and reschedule double beats = mBeats + delta; Add(beats, &task); } } } */ void TempoClock::Add(double inBeats, PyrSlot* inTask) { double prevBeats = mQueue->size > 1 ? slotRawFloat(mQueue->slots) : -1e10; bool added = addheap(g, (PyrObject*)mQueue, inBeats, inTask); if (!added) post("scheduler queue is full.\n"); else { if (isKindOfSlot(inTask, class_thread)) { SetFloat(&slotRawThread(inTask)->nextBeat, inBeats); } if (slotRawFloat(mQueue->slots) != prevBeats) mCondition.notify_one(); } } void TempoClock::Clear() { if (mRun) { mQueue->size = 1; mCondition.notify_one(); } } void TempoClock::Dump() { post("mTempo %g\n", mTempo); post("mBeatDur %g\n", mBeatDur); post("mBeats %g\n", mBeats); post("seconds %g\n", BeatsToSecs(mBeats)); post("mBaseSeconds %g\n", mBaseSeconds); post("mBaseBeats %g\n", mBaseBeats); } int prTempoClock_New(struct VMGlobals *g, int numArgsPushed); int prTempoClock_New(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; PyrSlot *b = g->sp - 2; PyrSlot *c = g->sp - 1; PyrSlot *d = g->sp; double tempo; int err = slotDoubleVal(b, &tempo); if (err) tempo = 1.; if (tempo <= 0.) { error("invalid tempo %g\n", tempo); SetPtr(slotRawObject(a)->slots+1, NULL); return errFailed; } double beats; err = slotDoubleVal(c, &beats); if (err) beats = 0.; double seconds; err = slotDoubleVal(d, &seconds); if (err) { err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return err; } TempoClock* clock = new TempoClock(g, slotRawObject(a), tempo, beats, seconds); SetPtr(slotRawObject(a)->slots+1, clock); return errNone; } int prTempoClock_Free(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Free(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) return errNone; // not running SetNil(slotRawObject(a)->slots + 1); clock->StopReq(); return errNone; } int prTempoClock_Clear(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Clear(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (clock) clock->Clear(); return errNone; } int prTempoClock_Dump(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Dump(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (clock) clock->Dump(); return errNone; } int prTempoClock_Tempo(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Tempo(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } SetFloat(a, clock->mTempo); return errNone; } int prTempoClock_BeatDur(struct VMGlobals *g, int numArgsPushed); int prTempoClock_BeatDur(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } SetFloat(a, clock->mBeatDur); return errNone; } int prTempoClock_ElapsedBeats(struct VMGlobals *g, int numArgsPushed); int prTempoClock_ElapsedBeats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } SetFloat(a, clock->ElapsedBeats()); return errNone; } int prTempoClock_Beats(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Beats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; double beats, seconds; if (SlotEq(&g->thread->clock, a)) { int err = slotDoubleVal(&g->thread->beats, &beats); if (err) return errWrongType; } else { TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } int err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return errWrongType; beats = clock->SecsToBeats(seconds); } SetFloat(a, beats); return errNone; } int prTempoClock_SetBeats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double beats, seconds; int err; err = slotDoubleVal(b, &beats); if (err) return errWrongType; err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return errWrongType; clock->SetAll(clock->mTempo, beats, seconds); return errNone; } int prTempoClock_Sched(struct VMGlobals *g, int numArgsPushed); int prTempoClock_Sched(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double delta, beats; int err; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } if (SlotEq(&g->thread->clock, a)) { err = slotDoubleVal(&g->thread->beats, &beats); if (err) return errNone; // return nil OK, just don't schedule } else { double seconds; err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return errNone; beats = clock->SecsToBeats(seconds); } err = slotDoubleVal(b, &delta); if (err) return errNone; // return nil OK, just don't schedule beats += delta; if (beats == dInfinity) return errNone; // return nil OK, just don't schedule clock->Add(beats, c); return errNone; } int prTempoClock_SchedAbs(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SchedAbs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double beats; int err = slotDoubleVal(b, &beats) || (beats == dInfinity); if (err) return errNone; // return nil OK, just don't schedule clock->Add(beats, c); return errNone; } int prTempoClock_SetTempoAtBeat(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SetTempoAtBeat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double tempo, beat; int err = slotDoubleVal(b, &tempo); if (err) return errFailed; if (tempo <= 0.) { error("invalid tempo %g\n", tempo); return errFailed; } err = slotDoubleVal(c, &beat); if (err) return errFailed; clock->SetTempoAtBeat(tempo, beat); return errNone; } int prTempoClock_SetAll(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SetAll(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; PyrSlot *b = g->sp - 2; PyrSlot *c = g->sp - 1; PyrSlot *d = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double tempo, beat, secs; int err = slotDoubleVal(b, &tempo); if (err) return errFailed; err = slotDoubleVal(c, &beat); if (err) return errFailed; err = slotDoubleVal(d, &secs); if (err) return errFailed; clock->SetAll(tempo, beat, secs); return errNone; } int prTempoClock_SetTempoAtTime(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SetTempoAtTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double tempo, sec; int err = slotDoubleVal(b, &tempo); if (err) return errFailed; err = slotDoubleVal(c, &sec); if (err) return errFailed; clock->SetTempoAtTime(tempo, sec); return errNone; } int prTempoClock_BeatsToSecs(struct VMGlobals *g, int numArgsPushed); int prTempoClock_BeatsToSecs(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double beats; int err = slotDoubleVal(b, &beats); if (err) return errFailed; SetFloat(a, clock->BeatsToSecs(beats)); return errNone; } int prTempoClock_SecsToBeats(struct VMGlobals *g, int numArgsPushed); int prTempoClock_SecsToBeats(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; TempoClock *clock = (TempoClock*)slotRawPtr(&slotRawObject(a)->slots[1]); if (!clock) { error("clock is not running.\n"); return errFailed; } double secs; int err = slotDoubleVal(b, &secs); if (err) return errFailed; SetFloat(a, clock->SecsToBeats(secs)); return errNone; } int prSystemClock_Clear(struct VMGlobals *g, int numArgsPushed); int prSystemClock_Clear(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp; schedClearUnsafe(); return errNone; } int prSystemClock_Sched(struct VMGlobals *g, int numArgsPushed); int prSystemClock_Sched(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double delta, seconds; int err = slotDoubleVal(b, &delta); if (err) return errNone; // return nil OK, just don't schedule err = slotDoubleVal(&g->thread->seconds, &seconds); if (err) return errNone; // return nil OK, just don't schedule seconds += delta; if (seconds == dInfinity) return errNone; // return nil OK, just don't schedule PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); schedAdd(g, inQueue, seconds, c); return errNone; } int prSystemClock_SchedAbs(struct VMGlobals *g, int numArgsPushed); int prSystemClock_SchedAbs(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; double time; int err = slotDoubleVal(b, &time) || (time == dInfinity); if (err) return errNone; // return nil OK, just don't schedule PyrObject* inQueue = slotRawObject(&g->process->sysSchedulerQueue); schedAdd(g, inQueue, time, c); return errNone; } int prElapsedTime(struct VMGlobals *g, int numArgsPushed) { SetFloat(g->sp, elapsedTime()); return errNone; } int prmonotonicClockTime(struct VMGlobals *g, int numArgsPushed) { SetFloat(g->sp, monotonicClockTime()); return errNone; } void initSchedPrimitives() { int base, index=0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_TempoClock_New", prTempoClock_New, 4, 0); definePrimitive(base, index++, "_TempoClock_Free", prTempoClock_Free, 1, 0); definePrimitive(base, index++, "_TempoClock_Clear", prTempoClock_Clear, 1, 0); definePrimitive(base, index++, "_TempoClock_Dump", prTempoClock_Dump, 1, 0); definePrimitive(base, index++, "_TempoClock_Sched", prTempoClock_Sched, 3, 0); definePrimitive(base, index++, "_TempoClock_SchedAbs", prTempoClock_SchedAbs, 3, 0); definePrimitive(base, index++, "_TempoClock_Tempo", prTempoClock_Tempo, 1, 0); definePrimitive(base, index++, "_TempoClock_BeatDur", prTempoClock_BeatDur, 1, 0); definePrimitive(base, index++, "_TempoClock_ElapsedBeats", prTempoClock_ElapsedBeats, 1, 0); definePrimitive(base, index++, "_TempoClock_Beats", prTempoClock_Beats, 1, 0); definePrimitive(base, index++, "_TempoClock_SetBeats", prTempoClock_SetBeats, 2, 0); definePrimitive(base, index++, "_TempoClock_SetTempoAtBeat", prTempoClock_SetTempoAtBeat, 3, 0); definePrimitive(base, index++, "_TempoClock_SetTempoAtTime", prTempoClock_SetTempoAtTime, 3, 0); definePrimitive(base, index++, "_TempoClock_SetAll", prTempoClock_SetAll, 4, 0); definePrimitive(base, index++, "_TempoClock_BeatsToSecs", prTempoClock_BeatsToSecs, 2, 0); definePrimitive(base, index++, "_TempoClock_SecsToBeats", prTempoClock_SecsToBeats, 2, 0); definePrimitive(base, index++, "_SystemClock_Clear", prSystemClock_Clear, 1, 0); definePrimitive(base, index++, "_SystemClock_Sched", prSystemClock_Sched, 3, 0); definePrimitive(base, index++, "_SystemClock_SchedAbs", prSystemClock_SchedAbs, 3, 0); definePrimitive(base, index++, "_ElapsedTime", prElapsedTime, 1, 0); definePrimitive(base, index++, "_monotonicClockTime", prmonotonicClockTime, 1, 0); } SuperCollider-Source/lang/LangPrimSource/PyrSerialPrim.cpp000644 000765 000024 00000034460 12756531745 024764 0ustar00crucialstaff000000 000000 /* Serial port support. Copyright (c) 2006 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrSched.h" #include "SCBase.h" #include "SC_FIFO.h" #include "SC_Lock.h" class SerialPort { public: enum Parity { kNoParity, kEvenParity, kOddParity }; struct Options { Options() : exclusive(false), baudrate(9600), databits(8), stopbit(true), parity(kNoParity), crtscts(false), xonxoff(false) { } bool exclusive; size_t baudrate; size_t databits; bool stopbit; Parity parity; bool crtscts; bool xonxoff; }; static const int kNumOptions = 7; static const int kBufferSize = 8192; static const int kReadTimeoutMs = 1000; typedef SC_FIFO FIFO; struct Error : std::runtime_error { explicit Error(const char* what) : std::runtime_error(what) { } }; struct SysError : public Error { explicit SysError(int e=errno) : Error(strerror(e)) { } }; static PyrSymbol* s_dataAvailable; static PyrSymbol* s_doneAction; public: SerialPort(PyrObject* obj, const char* serialport, const Options& options); ~SerialPort(); bool isRunning() const { return m_running; } int fd() const { return m_fd; } const Options& options() const { return m_options; } bool put(uint8_t byte); bool get(uint8_t* byte); int rxErrors(); void stop(); void cleanup(); bool isCurrentThread() const; protected: void threadLoop(); void dataAvailable(); void doneAction(); private: // language interface PyrObject* m_obj; std::atomic m_dodone; // serial interface Options m_options; int m_fd; std::atomic m_open; struct termios m_termio; struct termios m_oldtermio; // rx buffers int m_rxErrors[2]; FIFO m_rxfifo; uint8_t m_rxbuffer[kBufferSize]; // rx thread std::atomic m_running; thread m_thread; }; PyrSymbol* SerialPort::s_dataAvailable = 0; PyrSymbol* SerialPort::s_doneAction = 0; SerialPort::SerialPort(PyrObject* obj, const char* serialport, const Options& options) : m_obj(obj), m_options(options), m_fd(-1) { // open non blocking m_fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY); if (m_fd == -1) { throw SysError(errno); } // exclusiveness #if defined(TIOCEXCL) if (m_options.exclusive) { if (ioctl(m_fd, TIOCEXCL) == -1) { throw SysError(errno); } } #endif // TIOCEXCL if (fcntl(m_fd, F_SETFL, O_NONBLOCK) == -1) { int e = errno; close(m_fd); throw SysError(e); } // initialize serial connection // get current settings and remember them struct termios toptions; if (tcgetattr(m_fd, &toptions) < 0) { int e = errno; close(m_fd); throw SysError(e); } memcpy(&m_oldtermio, &toptions, sizeof(toptions)); // baudrate speed_t brate; switch (m_options.baudrate) { case 1200: brate = B1200; break; case 1800: brate = B1800; break; case 2400: brate = B2400; break; case 4800: brate = B4800; break; case 9600: brate = B9600; break; case 19200: brate = B19200; break; case 38400: brate = B38400; break; // #ifndef _POSIX_C_SOURCE #if defined(B7200) case 7200: brate = B7200; break; #endif #if defined(B7200) case 14400: brate = B14400; break; #endif #if defined(B28800) case 28800: brate = B28800; break; #endif #if defined(B57600) case 57600: brate = B57600; break; #endif #if defined(B76800) case 76800: brate = B76800; break; #endif #if defined(B115200) case 115200: brate = B115200; break; #endif #if defined(B230400) case 230400: brate = B230400; break; #endif // #endif // !_POSIX_C_SOURCE default: close(m_fd); throw Error("unsupported baudrate"); } cfsetispeed(&toptions, brate); cfsetospeed(&toptions, brate); // data bits toptions.c_cflag &= ~CSIZE; switch (m_options.databits) { case 5: toptions.c_cflag |= CS5; break; case 6: toptions.c_cflag |= CS6; break; case 7: toptions.c_cflag |= CS7; break; default: m_options.databits = 8; toptions.c_cflag |= CS8; break; } // stop bit if (m_options.stopbit) { toptions.c_cflag |= CSTOPB; } else { toptions.c_cflag &= ~CSTOPB; } // parity switch (m_options.parity) { case kNoParity: toptions.c_cflag &= ~PARENB; break; case kEvenParity: toptions.c_cflag |= PARENB; toptions.c_cflag &= ~PARODD; break; case kOddParity: toptions.c_cflag |= (PARENB | PARODD); break; } // h/w flow control #if !defined(_POSIX_C_SOURCE) || defined(__USE_MISC) if (m_options.crtscts) { toptions.c_cflag &= ~CRTSCTS; } else { toptions.c_cflag |= CRTSCTS; } #endif // !_POSIX_C_SOURCE || __USE_MISC // s/w flow control if (m_options.xonxoff) { toptions.c_iflag |= (IXON | IXOFF | IXANY); } else { toptions.c_iflag &= ~(IXON | IXOFF | IXANY); } // (nescivi) by default carriage returns are translated to line feeds, // we don't want that toptions.c_iflag &= ~ICRNL; // enable READ & ignore ctrl lines toptions.c_cflag |= (CREAD | CLOCAL); // non-canonical (raw) i/o toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // disable post processing toptions.c_oflag &= ~OPOST; // see: http://unixwiz.net/techtips/termios-vmin-vtime.html // NOTE: unused for non-blocking reads // toptions.c_cc[VMIN] = 0; // toptions.c_cc[VTIME] = 20; if (tcsetattr(m_fd, TCSAFLUSH, &toptions) < 0) { int e = errno; close(m_fd); throw SysError(e); } memcpy(&m_termio, &toptions, sizeof(toptions)); m_rxErrors[0] = m_rxErrors[1] = 0; try { thread thread(std::bind(&SerialPort::threadLoop, this)); m_thread = std::move(thread); } catch(std::exception & e) { close(m_fd); throw e; } m_open = true; m_dodone = true; } SerialPort::~SerialPort() { m_running = false; if ( m_open ){ tcflush(m_fd, TCIOFLUSH); tcsetattr(m_fd, TCSANOW, &m_oldtermio); close(m_fd); m_open = false; } if (m_thread.joinable() && m_thread.get_id() != std::this_thread::get_id()) { m_thread.join(); } else { assert(0 && "We're about to destroy m_thread from it's own thread, and without first joining!"); } } void SerialPort::stop(){ m_running = false; } void SerialPort::cleanup(){ m_running = false; m_dodone = false; if ( m_open ){ tcflush(m_fd, TCIOFLUSH); tcsetattr(m_fd, TCSANOW, &m_oldtermio); close(m_fd); m_open = false; }; } bool SerialPort::isCurrentThread() const { return m_thread.get_id() == std::this_thread::get_id(); } bool SerialPort::put(uint8_t byte) { return write(m_fd, &byte, sizeof(byte)) == sizeof(byte); } bool SerialPort::get(uint8_t* byte) { if (m_rxfifo.IsEmpty()) return false; *byte = m_rxfifo.Get() & 0xFF; return true; } int SerialPort::rxErrors() { // errors since last query int x = m_rxErrors[1]; int res = x-m_rxErrors[0]; m_rxErrors[0] = x; return res; } void SerialPort::dataAvailable() { int status = lockLanguageOrQuit(m_running); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } PyrSymbol *method = s_dataAvailable; if (m_obj) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, method, 1); g->canCallOS = false; } gLangMutex.unlock(); } void SerialPort::doneAction() { int status = lockLanguageOrQuit(m_dodone); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } PyrSymbol *method = s_doneAction; if (m_obj) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, method, 1); g->canCallOS = false; } gLangMutex.unlock(); } void SerialPort::threadLoop() { const int fd = m_fd; const int max_fd = fd+1; m_running = true; m_rxErrors[1] = 0; while (true) { fd_set rfds; FD_ZERO( &rfds); FD_SET(fd, &rfds); struct timeval timeout; timeout.tv_sec = kReadTimeoutMs/1000; timeout.tv_usec = (kReadTimeoutMs%1000)*1000; int n = select(max_fd, &rfds, 0, 0, &timeout); // int fdset = FD_ISSET(fd, &rfds); // printf( "fdset %i, n %i, errno %i\n", fdset, n, errno ); if ( m_open ){ if ((n > 0) && FD_ISSET(fd, &rfds)) { // printf("poll input\n"); int nr = 0; // while (true) { if ( m_open ){ int n2 = read(fd, m_rxbuffer, kBufferSize); // printf("read %d, errno %i, errbadf %i, %i, %i\n", n2, errno, EBADF, EAGAIN, EIO); if (n2 > 0) { // write data to ringbuffer for (int i=0; i < n2; ++i) { if (!m_rxfifo.Put(m_rxbuffer[i])) { m_rxErrors[1]++; break; } } nr += n2; } else if ((n2 == 0) && (n == 1) ) { // added by nescivi, to check for disconnected device. In this case the read is 0 all the time and otherwise eats up the CPU // printf( "done\n" ); goto done; } else if ((n2 == 0) || ((n2 == -1) && (errno == EAGAIN))) { // printf( "break\n"); break; } else { #ifndef NDEBUG printf("SerialPort HUP\n"); #endif goto done; } } //} if (!m_running) { // close and cleanup goto done; } if (nr > 0) { dataAvailable(); } } else if (n == -1) { goto done; } } if (!m_running) { // close and cleanup goto done; } } done: // doneAction(); if ( m_open ){ tcflush(fd, TCIOFLUSH); tcsetattr(fd, TCSANOW, &m_oldtermio); close(fd); }; m_open = false; m_running = false; if ( m_dodone ) doneAction(); #ifndef NDEBUG printf("SerialPort closed\n"); #endif } // ===================================================================== // primitives static SerialPort* getSerialPort(PyrSlot* slot) { if (NotPtr(&slotRawObject(slot)->slots[0])) return NULL; return (SerialPort*)slotRawPtr(&slotRawObject(slot)->slots[0]); } static int prSerialPort_Open(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args = g->sp - 1 - SerialPort::kNumOptions; int err; PyrSlot* self = args+0; if (getSerialPort(self) != 0) return errFailed; char portName[PATH_MAX]; err = slotStrVal(args+1, portName, sizeof(portName)); printf("portName %s\n", portName); if (err) return err; SerialPort::Options options; SerialPort* port = 0; options.exclusive = IsTrue(args+2); int baudrate; err = slotIntVal(args+3, &baudrate); if (err) return err; options.baudrate = baudrate; int databits; err = slotIntVal(args+4, &databits); if (err) return err; options.databits = databits; options.stopbit = IsTrue(args+5); int parity; err = slotIntVal(args+6, &parity); if (err) return err; options.parity = (SerialPort::Parity)parity; options.crtscts = IsTrue(args+7); options.xonxoff = IsTrue(args+8); try { port = new SerialPort(slotRawObject(self), portName, options); } catch (SerialPort::Error& e) { std::ostringstream os; os << "SerialPort Error: " << e.what(); post(os.str().c_str()); return errFailed; } SetPtr(slotRawObject(self)->slots+0, port); return errNone; } static int prSerialPort_Close(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; port->stop(); return errNone; } static int prSerialPort_Cleanup(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; if (port->isCurrentThread()) { post("Cannot cleanup SerialPort from this thread. Call from AppClock thread."); return errFailed; } port->cleanup(); post("SerialPort Cleanup\n"); delete port; SetNil(slotRawObject(self)->slots+0); return errNone; } static int prSerialPort_Next(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); // printf( "port %i", port ); if (port == 0) return errFailed; uint8_t byte; if (port->get(&byte)) { SetInt(self, byte); } else { SetNil(self); } return errNone; } static int prSerialPort_Put(struct VMGlobals *g, int numArgsPushed) { PyrSlot *args = g->sp - 1; PyrSlot* self = args+0; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; PyrSlot* src = args+1; int val; if (IsChar(src)) { val = slotRawChar(src); } else { int err = slotIntVal(src, &val); if (err) return err; } bool res = port->put(val & 0xFF); SetBool(self, res); return errNone; } static int prSerialPort_RXErrors(struct VMGlobals *g, int numArgsPushed) { PyrSlot* self = g->sp; SerialPort* port = (SerialPort*)getSerialPort(self); if (port == 0) return errFailed; SetInt(self, port->rxErrors()); return errNone; } void initSerialPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_SerialPort_Open", prSerialPort_Open, 2+SerialPort::kNumOptions, 0); definePrimitive(base, index++, "_SerialPort_Close", prSerialPort_Close, 1, 0); definePrimitive(base, index++, "_SerialPort_Next", prSerialPort_Next, 1, 0); definePrimitive(base, index++, "_SerialPort_Put", prSerialPort_Put, 2, 0); definePrimitive(base, index++, "_SerialPort_RXErrors", prSerialPort_RXErrors, 1, 0); definePrimitive(base, index++, "_SerialPort_Cleanup", prSerialPort_Cleanup, 1, 0); SerialPort::s_dataAvailable = getsym("prDataAvailable"); SerialPort::s_doneAction = getsym("prDoneAction"); } // EOF SuperCollider-Source/lang/LangPrimSource/PyrSignalPrim.cpp000644 000765 000024 00000035112 12756531745 024755 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "PyrSymbol.h" #include "PyrKernel.h" #include "PyrObject.h" #include "PyrPrimitive.h" #include "PyrSignal.h" #include "PyrSignalPrim.h" #include "PyrMessage.h" #include "SC_Constants.h" #include "SCBase.h" #include "clz.h" extern "C" { #include "fftlib.h" } #include #include #include int prSignalFill(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err; float value; a = g->sp - 1; b = g->sp; err = slotFloatVal(b, &value); if (err != errNone) return err; signal_fill(slotRawObject(a), value); return errNone; } int prSignalScale(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err; float value; a = g->sp - 1; b = g->sp; err = slotFloatVal(b, &value); if (err != errNone) return err; signal_scale(slotRawObject(a), value); return errNone; } int prSignalOffset(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err; float value; a = g->sp - 1; b = g->sp; err = slotFloatVal(b, &value); if (err != errNone) return err; signal_offset(slotRawObject(a), value); return errNone; } int prSignalString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; PyrObject *signal; float *x; char str[128]; a = g->sp; slotString(a, str); signal = slotRawObject(a); if (signal->size) { x = (float*)(signal->slots); sprintf(str, "%s[%g .. %g]", slotRawSymbol(&signal->classptr->name)->name, x[0], x[signal->size-1]); } else { sprintf(str, "%s[none]", slotRawSymbol(&signal->classptr->name)->name); } string = newPyrString(g->gc, str, 0, true); SetObject(a, string); return errNone; } int prSignalPeak(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetFloat(a, signal_findpeak(slotRawObject(a))); return errNone; } int prSignalNormalize(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err, start, end; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(c)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } signal_normalize_range(slotRawObject(a), start, end); return errNone; } int prSignalNormalizeTransferFn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; signal_normalize_transfer_fn(slotRawObject(a)); return errNone; } int prSignalIntegral(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; SetFloat(a, signal_integral(slotRawObject(a))); return errNone; } int prSignalInvert(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err, start, end; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(c)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } signal_invert_range(slotRawObject(a), start, end); return errNone; } int prSignalReverse(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err, start, end; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(b)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } signal_reverse_range(slotRawObject(a), start, end); return errNone; } int prSignalRotate(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int err, rot; a = g->sp - 1; b = g->sp; err = slotIntVal(b, &rot); if (err) return err; SetRaw(a, signal_rotate(g, slotRawObject(a), rot)); return errNone; } int prSignalOverDub(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; int index; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(b) || !isKindOf(slotRawObject(b), class_signal)) return errWrongType; err = slotIntVal(c, &index); if (err) return errWrongType; signal_overdub(g, slotRawObject(a), slotRawObject(b), index); return errNone; } int prSignalOverWrite(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; int index; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(b) || !isKindOf(slotRawObject(b), class_signal)) return errWrongType; err = slotIntVal(c, &index); if (err) return errWrongType; signal_overwrite(g, slotRawObject(a), slotRawObject(b), index); return errNone; } int prSignalFade(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d, *e; int err; int start, end; float lvl0, lvl1; a = g->sp - 4; b = g->sp - 3; c = g->sp - 2; d = g->sp - 1; e = g->sp; err = slotIntVal(b, &start); if (err) { if (IsNil(b)) start = 0; else return err; } err = slotIntVal(c, &end); if (err) { if (IsNil(c)) end = slotRawObject(a)->size; else return err; } err = slotFloatVal(d, &lvl0); if (err) return err; err = slotFloatVal(e, &lvl1); if (err) return err; signal_fade_range(slotRawObject(a), start, end, lvl0, lvl1); return errNone; } int prSignalAddHarmonic(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c, *d; int err; float harmonic, amp; double phase, step; PyrObject *signal; float *out; a = g->sp - 3; b = g->sp - 2; c = g->sp - 1; d = g->sp; err = slotFloatVal(b, &harmonic); if (err) return errWrongType; err = slotFloatVal(c, &); if (err) return errWrongType; err = slotDoubleVal(d, &phase); if (err) return errWrongType; signal = slotRawObject(a); out = (float*)(signal->slots) - 1; step = twopi * harmonic / signal->size; UNROLL_CODE(signal->size, out, *++out += sin(phase) * amp; phase += step; ); return errNone; } int prSignalAddChebyshev(struct VMGlobals *g, int numArgsPushed); int prSignalAddChebyshev(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int err; float harmonic, amp; double x, step; PyrObject *signal; float *out; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotFloatVal(b, &harmonic); if (err) return errWrongType; err = slotFloatVal(c, &); if (err) return errWrongType; signal = slotRawObject(a); out = (float*)(signal->slots) - 1; x = -1.0; step = 2.0 / (signal->size - 1); UNROLL_CODE(signal->size, out, *++out += cos(harmonic * acos(sc_min(x, 1.0))) * amp; x += step; ); return errNone; } ////////////////////////////////////////////////////////////////////////////// void signalAsWavetable(float *signal, float *wavetable, int size) { int i, imax; float *in, *out; float val1, val2; in = signal; out = wavetable - 1; imax = size-1; for (i=0; isp; signal = slotRawObject(a); size = signal->size; if ((size & (size - 1)) != 0) { error("Signal size not a power of two.\n"); return errFailed; } wavetable = newPyrSignal(g, signal->size * 2); wavetable->classptr = class_wavetable; signalAsWavetable((float*)signal->slots, (float*)wavetable->slots, signal->size); SetObject(a, wavetable); return errNone; } int prWavetableAsSignal(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrObject *signal, *wavetable; a = g->sp; wavetable = slotRawObject(a); signal = newPyrSignal(g, wavetable->size / 2); wavetableAsSignal((float*)wavetable->slots, (float*)signal->slots, signal->size); SetObject(a, signal); return errNone; } //class_signal #if 1 int prSignal_FFT(struct VMGlobals *g, int numArgsPushed); int prSignal_FFT(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int i, M, fftsize, fftbufsize, asize; float *inreal, *inimag, *fftbuf, *costable, *outreal, *outimag; PyrObject *fftoutobj, *complexobj, *realobj, *imagobj; a = g->sp - 2; b = g->sp - 1; c = g->sp; asize = slotRawObject(a)->size; if (NotNil(b) && !(isKindOfSlot(b, class_signal) && slotRawObject(b)->size == asize)) { error("Signal::fft imaginary part wrong type or length.\n"); return errFailed; } M = LOG2CEIL(asize); fftsize = 1L << M; if (!(isKindOfSlot(c, class_floatarray))) { error("Signal::fft must be provided a table containing 1/4 cycle of a cosine.\n"); return errFailed; } if (slotRawObject(c)->size != fftsize/4+1) { error("Signal::fft cosine table wrong size (%d), expected %d.\n", slotRawObject(c)->size, fftsize/4+1); return errFailed; } costable = (float*)slotRawObject(c)->slots; fftbufsize = fftsize * 2; fftoutobj = newPyrSignal(g, fftbufsize); fftoutobj->size = fftbufsize; ++g->sp; SetObject(g->sp, fftoutobj); complexobj = instantiateObject(g->gc, s_complex->u.classobj, 0, false, true); ++g->sp; SetObject(g->sp, complexobj); realobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 0, realobj); g->gc->GCWriteNew(complexobj, realobj); imagobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 1, imagobj); g->gc->GCWriteNew(complexobj, imagobj); inreal = (float*)slotRawObject(a)->slots - 1; if (IsNil(b)) { fftbuf = (float*)fftoutobj->slots - 1; for (i=0; islots; rffts(fftbuf, M, 1, costable); } else { inimag = (float*)slotRawObject(b)->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; islots; ffts(fftbuf, M, 1, costable); } outreal = (float*)realobj->slots - 1; outimag = (float*)imagobj->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; isize = fftsize; imagobj->size = fftsize; g->sp -= 2; SetRaw(a, complexobj); return errNone; } int prSignal_IFFT(struct VMGlobals *g, int numArgsPushed); int prSignal_IFFT(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int i, M, fftsize, fftbufsize, asize; float *inreal, *inimag, *fftbuf, *costable, *outreal, *outimag; PyrObject *fftoutobj, *complexobj, *realobj, *imagobj; a = g->sp - 2; b = g->sp - 1; c = g->sp; asize = slotRawObject(a)->size; if (!(isKindOfSlot(b, class_signal) && slotRawObject(b)->size == asize)) { error("Signal::ifft imaginary part wrong type or length.\n"); return errFailed; } M = LOG2CEIL(asize); fftsize = 1L << M; if (!(isKindOfSlot(c, class_floatarray))) { error("Signal::ifft must be provided a table containing 1/4 cycle of a cosine.\n"); return errFailed; } if (slotRawObject(c)->size != fftsize/4+1) { error("Signal::ifft cosine table wrong size (%d), expected %d.\n", slotRawObject(c)->size, fftsize/4+1); return errFailed; } costable = (float*)slotRawObject(c)->slots; fftbufsize = fftsize * 2; fftoutobj = newPyrSignal(g, fftbufsize); fftoutobj->size = fftbufsize; ++g->sp; SetObject(g->sp, fftoutobj); complexobj = instantiateObject(g->gc, s_complex->u.classobj, 0, false, true); ++g->sp; SetObject(g->sp, complexobj); realobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 0, realobj); g->gc->GCWriteNew(complexobj, realobj); imagobj = newPyrSignal(g, fftbufsize); SetObject(complexobj->slots + 1, imagobj); g->gc->GCWriteNew(complexobj, imagobj); inreal = (float*)slotRawObject(a)->slots - 1; inimag = (float*)slotRawObject(b)->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; islots; iffts(fftbuf, M, 1, costable); outreal = (float*)realobj->slots - 1; outimag = (float*)imagobj->slots - 1; fftbuf = (float*)fftoutobj->slots - 1; for (i=0; isize = fftsize; imagobj->size = fftsize; g->sp -= 2; SetRaw(a, complexobj); return errNone; } #endif void initSignalPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_SignalPeak", prSignalPeak, 1, 0); definePrimitive(base, index++, "_SignalNormalize", prSignalNormalize, 3, 0); definePrimitive(base, index++, "_SignalNormalizeTransferFn", prSignalNormalizeTransferFn, 1, 0); definePrimitive(base, index++, "_SignalIntegral", prSignalIntegral, 1, 0); definePrimitive(base, index++, "_SignalReverse", prSignalReverse, 3, 0); definePrimitive(base, index++, "_SignalInvert", prSignalInvert, 3, 0); definePrimitive(base, index++, "_SignalRotate", prSignalRotate, 2, 0); definePrimitive(base, index++, "_SignalFill", prSignalFill, 2, 0); definePrimitive(base, index++, "_SignalScale", prSignalScale, 2, 0); definePrimitive(base, index++, "_SignalOffset", prSignalOffset, 2, 0); definePrimitive(base, index++, "_SignalOverDub", prSignalOverDub, 3, 0); definePrimitive(base, index++, "_SignalOverWrite", prSignalOverWrite, 3, 0); definePrimitive(base, index++, "_SignalFade", prSignalFade, 5, 0); definePrimitive(base, index++, "_SignalAddHarmonic", prSignalAddHarmonic, 4, 0); definePrimitive(base, index++, "_SignalAddChebyshev", prSignalAddChebyshev, 3, 0); definePrimitive(base, index++, "_SignalString", prSignalString, 1, 0); definePrimitive(base, index++, "_SignalAsWavetable", prSignalAsWavetable, 1, 0); definePrimitive(base, index++, "_WavetableAsSignal", prWavetableAsSignal, 1, 0); definePrimitive(base, index++, "_Signal_FFT", prSignal_FFT, 3, 0); definePrimitive(base, index++, "_Signal_IFFT", prSignal_IFFT, 3, 0); } SuperCollider-Source/lang/LangPrimSource/PyrSignalPrim.h000644 000765 000024 00000004234 12321461511 024400 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PYRSIGNALPRIM_H_ #define _PYRSIGNALPRIM_H_ extern PyrSymbol *s_wavetable; extern struct PyrClass *class_wavetable; void initSignalPrimitives(); int prSignalCat(VMGlobals *g, int numArgsPushed); int prSignalFill(VMGlobals *g, int numArgsPushed); int prSignalRamp(VMGlobals *g, int numArgsPushed); int prSignalScale(VMGlobals *g, int numArgsPushed); int prSignalOffset(VMGlobals *g, int numArgsPushed); int prSignalString(VMGlobals *g, int numArgsPushed); int prSignalPeak(VMGlobals *g, int numArgsPushed); int prSignalNormalize(VMGlobals *g, int numArgsPushed); int prSignalNormalizeTransferFn(VMGlobals *g, int numArgsPushed); int prSignalIntegral(VMGlobals *g, int numArgsPushed); int prSignalOverDub(VMGlobals *g, int numArgsPushed); int prSignalOverWrite(VMGlobals *g, int numArgsPushed); int prSignalFade(VMGlobals *g, int numArgsPushed); int prSignalAddHarmonic(VMGlobals *g, int numArgsPushed); int prSignalAsWavetable(VMGlobals *g, int numArgsPushed); int prWavetableAsSignal(VMGlobals *g, int numArgsPushed); int prSignalInvert(VMGlobals *g, int numArgsPushed); int prSignalReverse(VMGlobals *g, int numArgsPushed); int prSignalRotate(VMGlobals *g, int numArgsPushed); void signalAsWavetable(float *signal, float *wavetable, int size); void wavetableAsSignal(float *wavetable, float *signal, int size); #endif SuperCollider-Source/lang/LangPrimSource/PyrStringPrim.cpp000644 000765 000024 00000070725 12756531745 025017 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for String. */ #include "PyrPrimitive.h" #include "PyrKernel.h" #include "GC.h" #include "Hash.h" #include #include #include #include "PyrLexer.h" #include "SC_DirUtils.h" #ifdef _WIN32 # include # include "SC_Win32Utils.h" #else # include #endif #include #include #include #include #include "yaml-cpp/yaml.h" #include #include using namespace std; int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed); int prStringAsSymbol(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char str[1024], *strp=0; int len; a = g->sp; len = slotRawObject(a)->size; strp = len > 1023 ? (char*)malloc(len+1) : str; memcpy(strp, slotRawString(a)->s, len); strp[len] = 0; SetSymbol(a, getsym(strp)); if (len > 1023) free(strp); return errNone; } int prString_AsInteger(struct VMGlobals *g, int numArgsPushed); int prString_AsInteger(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char str[256]; int err = slotStrVal(a, str, 255); if (err) return err; SetInt(a, atoi(str)); return errNone; } int prString_AsFloat(struct VMGlobals *g, int numArgsPushed); int prString_AsFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char str[256]; int err = slotStrVal(a, str, 255); if (err) return err; SetFloat(a, atof(str)); return errNone; } int prString_AsCompileString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrString* scstr = slotRawString(a); char *chars1 = scstr->s; int newSize = scstr->size + 2; for (int i=0; isize; ++i) { if (chars1[i] == '"' || chars1[i] == '\\') newSize++; } PyrString *newString = newPyrStringN(g->gc, newSize, 0, true); char *chars2 = newString->s; chars2[0] = '"'; chars2[newSize - 1] = '"'; int k = 1; for (int i=0; isize; ++i) { int c = chars1[i]; if (c == '"' || c == '\\') chars2[k++] = '\\'; chars2[k++] = c; } SetObject(a, newString); return errNone; } int prString_Format(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(b, class_array)) return errWrongType; char *fmt = slotRawString(a)->s; int asize = slotRawObject(a)->size; int bsize = slotRawObject(b)->size; int csize = asize; PyrSlot *slots = slotRawObject(b)->slots; for (int i=0; isize; } PyrString *newString = newPyrStringN(g->gc, csize, 0, true); char* buf = newString->s; int k=0; int index = 0; for (int i=0; is, bstring->size); k += bstring->size; index++; } } else if (ch == '\\') { if (i >= asize) break; ch = fmt[i++]; if (ch == '%') { buf[k++] = '%'; } else { i--; buf[k++] = '\\'; } } else { buf[k++] = ch; } } newString->size = k; SetObject(a, newString); return errNone; }; namespace detail { namespace bin = boost::intrusive; class regex_lru_cache { int regex_flags; struct regex_node: bin::list_base_hook<>, bin::unordered_set_base_hook<> { public: regex_node(const char * str, size_t size, int regex_flags): pattern(str, size, regex_flags) {} boost::regex const & get (void) const { return pattern; } private: boost::regex pattern; }; struct regex_equal { bool operator()(regex_node const & lhs, regex_node const & rhs) const { return lhs.get() == rhs.get(); } bool operator()(const char * lhs, regex_node const & rhs) const { return strcmp(lhs, rhs.get().str().c_str()) == 0; } }; static inline std::size_t string_hash(const char * str) { std::size_t ret = 0; // sdbm hash int c; while ((c = *str++)) ret = c + (ret << 6) + (ret << 16) - ret; return ret; } struct regex_hash { size_t operator()(regex_node const & arg) const { return string_hash(arg.get().str().c_str()); } size_t operator()(const char * arg) const { return string_hash(arg); } }; typedef bin::unordered_set, bin::hash, bin::power_2_buckets, bin::constant_time_size > re_set_t; typedef re_set_t::bucket_type bucket_type; typedef re_set_t::bucket_traits bucket_traits; bucket_type buckets[128]; re_set_t re_set; bin::list re_list; void pop_lru() { regex_node & rlu = re_list.back(); re_list.pop_back(); re_set.erase(rlu); delete &rlu; } public: regex_lru_cache(int regex_flags = boost::regex_constants::ECMAScript): re_set(bucket_traits(buckets, 128)), re_list() {} ~regex_lru_cache() { while (!re_list.empty()) { pop_lru(); } } boost::regex const & get_regex(const char * str, size_t size) { re_set_t::iterator re_in_cache = re_set.find(str, regex_hash(), regex_equal()); if (re_in_cache != re_set.end()) { regex_node & node = *re_in_cache; bin::list::iterator re_in_list = bin::list::s_iterator_to(node); re_list.splice(re_list.begin(), re_list, re_in_list); // move to the begin of the list assert(&re_list.front() == &node); return node.get(); } if (re_list.size() >= 64) pop_lru(); regex_node * new_node = new regex_node(str, size, regex_flags); re_set.insert(*new_node); re_list.push_front(*new_node); return new_node->get(); } }; } int prString_Regexp(struct VMGlobals *g, int numArgsPushed) { /* not reentrant */ static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript | boost::regex_constants::nosubs); using namespace boost; int start, end, len; PyrSlot *a = g->sp - 3; PyrSlot *b = g->sp - 2; PyrSlot *c = g->sp - 1; PyrSlot *d = g->sp; if (!isKindOfSlot(b, class_string)) return errWrongType; if (NotInt(c) || (NotInt(d) && NotNil(d))) return errWrongType; start = slotRawInt(c); len = slotRawObject(b)->size; // last char index instead of size if(IsNil(d)) { end = len; } else { end = slotRawInt(d); } if(end > len) end = len; if(end - start <= 0) { SetFalse(a); return errNone; } int stringlen = end - start; try { regex const & pattern = regex_lru_cache.get_regex(slotRawString(a)->s, slotRawObject(a)->size); match_flag_type flags = match_nosubs | match_any; const char * stringStart = slotRawString(b)->s + start; const char * stringEnd = stringStart + stringlen; bool res = regex_search(stringStart, stringEnd, pattern, flags); if(res) SetTrue(a); else SetFalse(a); return errNone; } catch (std::exception const & e) { postfl("Warning: Exception in _String_Regexp - %s\n", e.what()); return errFailed; } } struct sc_regexp_match { int pos; int len; }; static int prString_FindRegexp(struct VMGlobals *g, int numArgsPushed) { /* not reentrant */ static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript); using namespace boost; PyrSlot *a = g->sp - 2; // source string PyrSlot *b = g->sp - 1; // pattern PyrSlot *c = g->sp; // offset if (!isKindOfSlot(b, class_string) || (NotInt(c))) { SetNil(a); return errWrongType; } int offset = slotRawInt(c); int stringlen = std::max(slotRawObject(a)->size - offset, 0); std::vector matches; const char* const stringBegin = slotRawString(a)->s + offset; try { regex const & pattern = regex_lru_cache.get_regex(slotRawString(b)->s, slotRawObject(b)->size); match_flag_type flags = match_default; match_results what; const char* start = stringBegin; const char* end = start + stringlen; while (start <= end && regex_search(start, end, what, pattern, flags)) { for (int i = 0; i < what.size(); ++i ) { sc_regexp_match match; if (what[i].matched) { match.pos = what[i].first - stringBegin; match.len = what[i].second - what[i].first; } else { match.pos = 0; match.len = 0; } matches.push_back(match); } start = what[0].second; if(what[0].first == what[0].second) ++start; } } catch (std::exception const & e) { postfl("Warning: Exception in _String_FindRegexp - %s\n", e.what()); SetNil(a); return errFailed; } int match_count = matches.size(); PyrObject *result_array = newPyrArray(g->gc, match_count, 0, true); SetObject(a, result_array); if( !match_count ) return errNone; for (int i = 0; i < match_count; ++i ) { int pos = matches[i].pos; int len = matches[i].len; PyrObject *array = newPyrArray(g->gc, 2, 0, true); SetObject(result_array->slots + i, array); result_array->size++; g->gc->GCWriteNew(result_array, array); // we know array is white so we can use GCWriteNew PyrString *matched_string = newPyrStringN(g->gc, len, 0, true); memcpy(matched_string->s, stringBegin + pos, len); array->size = 2; SetInt(array->slots, pos + offset); SetObject(array->slots+1, matched_string); g->gc->GCWrite(array, matched_string); // we know matched_string is white so we can use GCWriteNew }; return errNone; } static int prString_FindRegexpAt(struct VMGlobals *g, int numArgsPushed) { /* not reentrant */ static detail::regex_lru_cache regex_lru_cache(boost::regex_constants::ECMAScript); using namespace boost; PyrSlot *a = g->sp - 2; // source string PyrSlot *b = g->sp - 1; // pattern PyrSlot *c = g->sp; // offset if (!isKindOfSlot(b, class_string) || (NotInt(c))) { SetNil(a); return errWrongType; } int offset = slotRawInt(c); int stringlen = std::max(slotRawObject(a)->size - offset, 0); int matched_len = 0; const char* const stringBegin = slotRawString(a)->s + offset; try { regex const & pattern = regex_lru_cache.get_regex(slotRawString(b)->s, slotRawObject(b)->size); // match_continuous: the match must begin at the offset start match_flag_type flags = match_continuous; match_results what; const char* start = stringBegin; const char* end = start + stringlen; if (regex_search(start, end, what, pattern, flags)) { assert(what[0].first == stringBegin); matched_len = what[0].second - what[0].first; } else { SetNil(a); return errNone; } } catch (std::exception const & e) { postfl("Warning: Exception in _String_FindRegexpAt - %s\n", e.what()); return errFailed; } PyrObject *array = newPyrArray(g->gc, 2, 0, true); SetObject(a, array); PyrString *matched_string = newPyrStringN(g->gc, matched_len, 0, true); memcpy(matched_string->s, stringBegin, (size_t) matched_len); array->size = 2; SetInt(array->slots+1, matched_len); SetObject(array->slots, matched_string); g->gc->GCWriteNew(array, matched_string); // we know matched_string is white so we can use GCWriteNew return errNone; } int memcmpi(char *a, char *b, int len) { for (int i=0; i bb) return 1; } return 0; } int prStringCompare(struct VMGlobals *g, int numArgsPushed); int prStringCompare(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b, *c; int cmp, length; a = g->sp - 2; b = g->sp - 1; c = g->sp; if (NotObj(b) || !isKindOf(slotRawObject(b), class_string)) return errWrongType; length = sc_min(slotRawObject(a)->size, slotRawObject(b)->size); if (IsTrue(c)) cmp = memcmpi(slotRawString(a)->s, slotRawString(b)->s, length); else cmp = memcmp(slotRawString(a)->s, slotRawString(b)->s, length); if (cmp == 0) { if (slotRawObject(a)->size < slotRawObject(b)->size) cmp = -1; else if (slotRawObject(a)->size > slotRawObject(b)->size) cmp = 1; } SetInt(a, cmp); return errNone; } int prStringHash(struct VMGlobals *g, int numArgsPushed); int prStringHash(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int hash = Hash(slotRawString(a)->s, slotRawString(a)->size); SetInt(a, hash); return errNone; } #ifndef _WIN32 #include int prStringPathMatch(struct VMGlobals *g, int numArgsPushed); int prStringPathMatch(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char pattern[1024]; int err = slotStrVal(a, pattern, 1023); if (err) return err; glob_t pglob; int gflags = GLOB_MARK | GLOB_TILDE; #ifdef __APPLE__ gflags |= GLOB_QUOTE; #endif int gerr = glob(pattern, gflags, NULL, &pglob); if (gerr) { pglob.gl_pathc = 0; } PyrObject* array = newPyrArray(g->gc, pglob.gl_pathc, 0, true); SetObject(a, array); if (gerr) return errNone; for (unsigned int i=0; igc, pglob.gl_pathv[i], 0, true); SetObject(array->slots+i, string); g->gc->GCWriteNew(array, string); // we know string is white so we can use GCWriteNew array->size++; } globfree(&pglob); return errNone; } #else //#ifndef _WIN32 int prStringPathMatch(struct VMGlobals *g, int numArgsPushed); int prStringPathMatch(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char pattern[1024]; int err = slotStrVal(a, pattern, 1023); if (err) return err; win32_ReplaceCharInString(pattern,1024,'/','\\'); // Remove trailing slash if found, to allow folders to be matched if(pattern[strlen(pattern)-1]=='\\'){ pattern[strlen(pattern)-1] = 0; } // extract the containing folder, including backslash char folder[1024]; win32_ExtractContainingFolder(folder,pattern,1024); ///////// PASS 1 WIN32_FIND_DATA findData; HANDLE hFind; int nbPaths = 0; hFind = ::FindFirstFile(pattern, &findData); if (hFind == INVALID_HANDLE_VALUE) { nbPaths = 0; } if (hFind == INVALID_HANDLE_VALUE) { // This is what happens when no matches. So we create an empty array to return. PyrObject* array = newPyrArray(g->gc, 0, 0, true); SetObject(a, array); return errNone; } do { if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, "..")!=0){ nbPaths++; } } while( ::FindNextFile(hFind, &findData)); ::FindClose(hFind); // PASS 2 hFind = ::FindFirstFile(pattern, &findData); if (hFind == INVALID_HANDLE_VALUE) { nbPaths = 0; } PyrObject* array = newPyrArray(g->gc, nbPaths , 0, true); SetObject(a, array); if (hFind == INVALID_HANDLE_VALUE) { return errNone; } int i = 0; do { if(strcmp(findData.cFileName, "..")!=0 && strcmp(findData.cFileName, ".")!=0){ std::string strPath(folder); strPath += std::string(findData.cFileName); if(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){ strPath += std::string("\\"); // Append trailing slash, to match behaviour on unix (used by sclang to detect folderness) } const char* fullPath = strPath.c_str(); PyrObject *string = (PyrObject*)newPyrString(g->gc, fullPath, 0, true); SetObject(array->slots+i, string); g->gc->GCWriteNew(array, string); // we know string is white so we can use GCWriteNew array->size++; i++; } } while( ::FindNextFile(hFind, &findData)); ::FindClose(hFind); return errNone; } #endif //#ifndef _WIN32 int prString_Getenv(struct VMGlobals* g, int numArgsPushed); int prString_Getenv(struct VMGlobals* g, int /* numArgsPushed */) { PyrSlot* arg = g->sp; char key[256]; char* value; int err; err = slotStrVal(arg, key, 256); if (err) return err; #ifdef _WIN32 char buf[1024]; DWORD size = GetEnvironmentVariable(key, buf, 1024); if (size == 0 || size > 1024) value = 0; else value = buf; #else value = getenv(key); #endif if (value) { PyrString* pyrString = newPyrString(g->gc, value, 0, true); if (!pyrString) return errFailed; SetObject(arg, pyrString); } else { SetNil(arg); } return errNone; } int prString_Setenv(struct VMGlobals* g, int numArgsPushed); int prString_Setenv(struct VMGlobals* g, int /* numArgsPushed */) { PyrSlot* args = g->sp - 1; char key[256]; int err; err = slotStrVal(args+0, key, 256); if (err) return err; if (IsNil(args+1)) { #ifdef _WIN32 SetEnvironmentVariable(key,NULL); #else unsetenv(key); #endif } else { char value[1024]; err = slotStrVal(args+1, value, 1024); if (err) return err; #ifdef _WIN32 SetEnvironmentVariable(key, value); #else setenv(key, value, 1); #endif } return errNone; } int prStripRtf(struct VMGlobals *g, int numArgsPushed); int prStripRtf(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int len = slotRawObject(a)->size; char * chars = (char*)malloc(len + 1); memcpy(chars, slotRawString(a)->s, len); chars[len] = 0; rtf2txt(chars); PyrString* string = newPyrString(g->gc, chars, 0, false); SetObject(a, string); free(chars); return errNone; } int prStripHtml(struct VMGlobals *g, int numArgsPushed); int prStripHtml(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; int len = slotRawObject(a)->size; char * chars = (char*)malloc(len + 1); memcpy(chars, slotRawString(a)->s, len); chars[len] = 0; html2txt(chars); PyrString* string = newPyrString(g->gc, chars, 0, false); SetObject(a, string); free(chars); return errNone; } int prString_Find(struct VMGlobals *g, int numArgsPushed); int prString_Find(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; // source string PyrSlot *b = g->sp - 2; // search string PyrSlot *c = g->sp - 1; // ignoreCase PyrSlot *d = g->sp; // offset int offset; int err = slotIntVal(d, &offset); if (err) return err; int alength = slotRawObject(a)->size - offset; if (alength <= 0) { SetNil(a); return errNone; } if (isKindOfSlot(b, class_string)) { int blength = slotRawObject(b)->size; if ((blength == 0) // should also return nil if search string is longer than source || (blength > alength)) { SetNil(a); return errNone; } int cmp = 1; // assume contains will be false char *achar = slotRawString(a)->s + offset; char *bchar = slotRawString(b)->s; char bchar0 = bchar[0]; int scanlength = alength - blength; if (IsTrue(c)) { bchar0 = toupper(bchar0); for (int i=0; i <= scanlength; ++i, ++achar) { if (toupper(*achar) == bchar0) { cmp = memcmpi(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } else { for (int i=0; i <= scanlength; ++i, ++achar) { if (*achar == bchar0) { cmp = memcmp(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } if (cmp == 0) { SetInt(a, achar - slotRawString(a)->s); } else { SetNil(a); } return errNone; } else if (IsChar(b)) { char *achar = slotRawString(a)->s + offset; char bchar = slotRawChar(b); int scanlength = alength - 1; if (IsTrue(c)) { bchar = toupper(bchar); for (int i=0; i <= scanlength; ++i, ++achar) { if (toupper(*achar) == bchar) { SetInt(a, achar - slotRawString(a)->s); return errNone; } } } else { for (int i=0; i <= scanlength; ++i, ++achar) { if (*achar == bchar) { SetInt(a, achar - slotRawString(a)->s); return errNone; } } } SetNil(a); return errNone; } else return errWrongType; } int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed); int prString_FindBackwards(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 3; // source string PyrSlot *b = g->sp - 2; // search string PyrSlot *c = g->sp - 1; // ignoreCase PyrSlot *d = g->sp; // offset int offset; int err = slotIntVal(d, &offset); if (err) return err; int alength = sc_min(offset + 1, slotRawObject(a)->size); if (alength <= 0) { SetNil(a); return errNone; } if (isKindOfSlot(b, class_string)) { int blength = slotRawObject(b)->size; if ((blength == 0) // should also return nil if search string is longer than source || (blength > alength)) { SetNil(a); return errNone; } int cmp = 1; // assume contains will be false char *achar = slotRawString(a)->s + (alength - blength); char *bchar = slotRawString(b)->s; char bchar0 = bchar[0]; int scanlength = alength - blength; if (IsTrue(c)) { bchar0 = toupper(bchar0); for (int i=scanlength; i >= 0; --i, --achar) { if (toupper(*achar) == bchar0) { cmp = memcmpi(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } else { for (int i=scanlength; i >= 0; --i, --achar) { if (*achar == bchar0) { cmp = memcmp(achar+1, bchar+1, blength-1); if (cmp == 0) break; } } } if (cmp == 0) { SetInt(a, achar - slotRawString(a)->s); } else { SetNil(a); } return errNone; } else if (IsChar(b)) { char *achar = slotRawString(a)->s + (alength - 1); char bchar = slotRawChar(b); int scanlength = alength - 1; if (IsTrue(c)) { bchar = toupper(bchar); for (int i=scanlength; i >= 0; --i, --achar) { if (toupper(*achar) == bchar) { SetInt(a, achar - slotRawString(a)->s); return errNone; } } } else { for (int i=scanlength; i >= 0; --i, --achar) { if (*achar == bchar) { SetInt(a, achar - slotRawString(a)->s); return errNone; } } } SetNil(a); return errNone; } else return errWrongType; } #if __APPLE__ # include #endif // __APPLE__ int prString_StandardizePath(struct VMGlobals* g, int numArgsPushed); int prString_StandardizePath(struct VMGlobals* g, int /* numArgsPushed */) { PyrSlot* arg = g->sp; char ipath[PATH_MAX]; char opathbuf[PATH_MAX]; char* opath = opathbuf; int err; err = slotStrVal(arg, ipath, PATH_MAX); if (err) return err; if (!sc_StandardizePath(ipath, opath)) { opath = ipath; } #if __APPLE__ CFStringRef cfstring = CFStringCreateWithCString(NULL, opath, kCFStringEncodingUTF8); err = !CFStringGetFileSystemRepresentation(cfstring, opath, PATH_MAX); CFRelease(cfstring); if (err) return errFailed; #endif // __APPLE__ PyrString* pyrString = newPyrString(g->gc, opath, 0, true); SetObject(arg, pyrString); return errNone; } int prString_EscapeChar(struct VMGlobals* g, int numArgsPushed) { PyrSlot* arg = g->sp - 1; PyrSlot* charToEscapeSlot = g->sp; assert (isKindOfSlot(arg, class_string)); if (!IsChar(charToEscapeSlot)) return errWrongType; char charToEscape = slotRawChar(charToEscapeSlot); PyrString* argString = slotRawString(arg); int length = argString->size; PyrString* resultString = newPyrStringN(g->gc, length*2 + 1, 0, 1); // pressimize char * original = argString->s; char * result = resultString->s; int resultLength = length; for (int i = 0; i != length; ++i) { char current = *original++; if (current == charToEscape) { *result++ = '\\'; resultLength += 1; } *result++ = current; } *result = 0; resultString->size = resultLength; SetRaw(arg, (PyrObject*)resultString); return errNone; } static void yaml_traverse(struct VMGlobals* g, const YAML::Node & node, PyrObject *parent, PyrSlot *slot) { YAML::NodeType::value type = node.Type(); string out; PyrObject *result = NULL; switch (type) { case YAML::NodeType::Scalar: node >> out; result = (PyrObject*)newPyrString(g->gc, out.c_str(), 0, true); SetObject(slot, result); if(parent) g->gc->GCWriteNew(parent, result); // we know result is white so we can use GCWriteNew break; case YAML::NodeType::Sequence: result = newPyrArray(g->gc, node.size(), 0, true); SetObject(slot, result); if(parent) g->gc->GCWriteNew(parent, result); // we know result is white so we can use GCWriteNew for (unsigned int i = 0; i < node.size(); i++) { const YAML::Node & subnode = node[i]; result->size++; yaml_traverse(g, subnode, result, result->slots+i); } break; case YAML::NodeType::Map: { result = instantiateObject( g->gc, s_dictionary->u.classobj, 0, false, true ); SetObject(slot, result); if(parent) g->gc->GCWriteNew(parent, result); // we know result is white so we can use GCWriteNew PyrObject *array = newPyrArray(g->gc, node.size()*2, 0, true); result->size = 2; SetObject(result->slots, array); // array SetInt(result->slots+1, node.size()); // size g->gc->GCWriteNew(result, array); // we know array is white so we can use GCWriteNew int j = 0; for (YAML::Iterator i = node.begin(); i != node.end(); ++i) { const YAML::Node & key = i.first(); const YAML::Node & value = i.second(); key >> out; PyrObject *pkey = (PyrObject*)newPyrString(g->gc, out.c_str(), 0, true); SetObject(array->slots+j, pkey); array->size++; g->gc->GCWriteNew(array, pkey); // we know pkey is white so we can use GCWriteNew array->size++; yaml_traverse(g, value, array, array->slots+j+1); j += 2; } break; } case YAML::NodeType::Null: SetNil(slot); break; default: postfl("WARNING: yaml_traverse(): unknown/unsupported node type\n"); SetNil(slot); } } int prString_ParseYAML(struct VMGlobals* g, int numArgsPushed) { PyrSlot* arg = g->sp; if (!isKindOfSlot(arg, class_string)) return errWrongType; string str((const char*)slotRawString(arg)->s,slotRawString(arg)->size); std::istringstream fin(str); YAML::Parser parser(fin); YAML::Node doc; // while(parser.GetNextDocument(doc)) { // yaml_traverse(doc, 0); // } parser.GetNextDocument(doc); yaml_traverse(g, doc, NULL, arg); return errNone; } int prString_ParseYAMLFile(struct VMGlobals* g, int numArgsPushed) { PyrSlot* arg = g->sp; if (!isKindOfSlot(arg, class_string)) return errWrongType; string str((const char*)slotRawString(arg)->s,slotRawString(arg)->size); std::ifstream fin(str.c_str()); YAML::Parser parser(fin); YAML::Node doc; // while(parser.GetNextDocument(doc)) { // yaml_traverse(doc, 0); // } parser.GetNextDocument(doc); yaml_traverse(g, doc, NULL, arg); return errNone; } void initStringPrimitives(); void initStringPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_StringCompare", prStringCompare, 3, 0); definePrimitive(base, index++, "_StringHash", prStringHash, 1, 0); definePrimitive(base, index++, "_StringPathMatch", prStringPathMatch, 1, 0); definePrimitive(base, index++, "_StringAsSymbol", prStringAsSymbol, 1, 0); definePrimitive(base, index++, "_String_AsInteger", prString_AsInteger, 1, 0); definePrimitive(base, index++, "_String_AsFloat", prString_AsFloat, 1, 0); definePrimitive(base, index++, "_String_AsCompileString", prString_AsCompileString, 1, 0); definePrimitive(base, index++, "_String_Getenv", prString_Getenv, 1, 0); definePrimitive(base, index++, "_String_Setenv", prString_Setenv, 2, 0); definePrimitive(base, index++, "_String_Find", prString_Find, 4, 0); definePrimitive(base, index++, "_String_FindBackwards", prString_FindBackwards, 4, 0); definePrimitive(base, index++, "_String_Format", prString_Format, 2, 0); definePrimitive(base, index++, "_String_Regexp", prString_Regexp, 4, 0); definePrimitive(base, index++, "_String_FindRegexp", prString_FindRegexp, 3, 0); definePrimitive(base, index++, "_String_FindRegexpAt", prString_FindRegexpAt, 3, 0); definePrimitive(base, index++, "_StripRtf", prStripRtf, 1, 0); definePrimitive(base, index++, "_StripHtml", prStripHtml, 1, 0); definePrimitive(base, index++, "_String_StandardizePath", prString_StandardizePath, 1, 0); definePrimitive(base, index++, "_String_EscapeChar", prString_EscapeChar, 2, 0); definePrimitive(base, index++, "_String_ParseYAML", prString_ParseYAML, 1, 0); definePrimitive(base, index++, "_String_ParseYAMLFile", prString_ParseYAMLFile, 1, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initStringPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-Source/lang/LangPrimSource/PyrSymbolPrim.cpp000644 000765 000024 00000036203 12321461511 024764 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Symbol. */ #include #include #include "PyrPrimitive.h" #include "PyrSymbol.h" #include "VMGlobals.h" #include "PyrKernel.h" #include "SCBase.h" /* int prSymbolString(struct VMGlobals *g, int numArgsPushed); int prSymbolString(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrString *string; a = g->sp; if (NotSym(a)) return errWrongType; string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true); SetObject(a, string); return errNone; } */ int prSymbolIsPrefix(struct VMGlobals *g, int numArgsPushed); int prSymbolIsPrefix(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; int length; a = g->sp - 1; b = g->sp; if (!IsSym(a) || !IsSym(b)) return errWrongType; int32 alen = slotRawSymbol(a)->length; int32 blen = slotRawSymbol(b)->length; length = sc_min(alen, blen); if (memcmp(slotRawSymbol(a)->name, slotRawSymbol(b)->name, length) == 0) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbolClass(struct VMGlobals *g, int numArgsPushed); int prSymbolClass(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; PyrClass *classobj; //char firstChar; a = g->sp; if (slotRawSymbol(a)->flags & sym_Class) { //firstChar = slotRawSymbol(a)->name[0]; //if (firstChar >= 'A' && firstChar <= 'Z') { classobj = slotRawSymbol(a)->u.classobj; if (classobj) { SetObject(a, classobj); } else { SetNil(a); } } else { SetNil(a); } return errNone; } int prSymbolIsSetter(struct VMGlobals *g, int numArgsPushed); int prSymbolIsSetter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (slotRawSymbol(a)->flags & sym_Setter) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbolAsSetter(struct VMGlobals *g, int numArgsPushed); int prSymbolAsSetter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char str[256]; int len; a = g->sp; if (!(slotRawSymbol(a)->flags & sym_Setter)) { if ((slotRawSymbol(a)->flags & sym_Class) || (slotRawSymbol(a)->flags & sym_Primitive)) { error("Cannot convert class names or primitive names to setters.\n"); return errFailed; } if (strlen(slotRawSymbol(a)->name)>255) { error("symbol name too long.\n"); return errFailed; } strcpy(str, slotRawSymbol(a)->name); len = strlen(str); str[len] = '_'; str[len+1] = 0; //postfl("prSymbolAsSetter %s\n", str); SetRaw(a, getsym(str)); } return errNone; } int prSymbolAsGetter(struct VMGlobals *g, int numArgsPushed); int prSymbolAsGetter(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; char str[256]; a = g->sp; if ((slotRawSymbol(a)->flags & sym_Setter)) { if ((slotRawSymbol(a)->flags & sym_Class) || (slotRawSymbol(a)->flags & sym_Primitive)) { error("Cannot convert class names or primitive names to getters.\n"); return errFailed; } strcpy(str, slotRawSymbol(a)->name); str[strlen(str)-1] = 0; //postfl("prSymbolAsGetter %s\n", str); SetRaw(a, getsym(str)); } return errNone; } int prSymbolIsClassName(struct VMGlobals *g, int numArgsPushed); int prSymbolIsClassName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (slotRawSymbol(a)->flags & sym_Class) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbolIsMetaClassName(struct VMGlobals *g, int numArgsPushed); int prSymbolIsMetaClassName(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; if (slotRawSymbol(a)->flags & sym_MetaClass) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbol_AsInteger(struct VMGlobals *g, int numArgsPushed); int prSymbol_AsInteger(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char *str = slotRawSymbol(a)->name; SetInt(a, atoi(str)); return errNone; } int prSymbol_PrimitiveIndex(struct VMGlobals *g, int numArgsPushed); int prSymbol_PrimitiveIndex(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, slotRawSymbol(a)->u.index); return errNone; } int prSymbol_SpecialIndex(struct VMGlobals *g, int numArgsPushed); int prSymbol_SpecialIndex(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, slotRawSymbol(a)->specialIndex); return errNone; } int prSymbol_AsFloat(struct VMGlobals *g, int numArgsPushed); int prSymbol_AsFloat(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char *str = slotRawSymbol(a)->name; SetFloat(a, atof(str)); return errNone; } // following function lifted from liblo: http://sourceforge.net/projects/liblo/ /* Open SoundControl kit in C++ */ /* Copyright (C) 2002-2004 libOSC++ contributors. See AUTHORS */ /* */ /* This library is free software; you can redistribute it and/or */ /* modify it under the terms of the GNU Lesser General Public */ /* License as published by the Free Software Foundation; either */ /* version 2.1 of the License, or (at your option) any later version. */ /* */ /* This library is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ /* Lesser General Public License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public */ /* License along with this library; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* */ /* For questions regarding this program contact */ /* Daniel Holth or visit */ /* http://wiretap.stetson.edu/ */ /* In the sprit of the public domain, my modifications to this file are also */ /* dedicated to the public domain. Daniel Holth, Oct. 2004 */ /* ChangeLog: * * 2004-10-29 Import, convert to C++, begin OSC syntax changes. -dwh * OSC syntax changes are now working, needs more testing. * */ // Original header and syntax: /* * robust glob pattern matcher * ozan s. yigit/dec 1994 * public domain * * glob patterns: * * matches zero or more characters * ? matches any single character * [set] matches any character in the set * [^set] matches any character NOT in the set * where a set is a group of characters or ranges. a range * is written as two characters seperated with a hyphen: a-z denotes * all characters between a to z inclusive. * [-set] set matches a literal hypen and any character in the set * []set] matches a literal close bracket and any character in the set * * char matches itself except where char is '*' or '?' or '[' * \char matches char, including any pattern character * * examples: * a*c ac abc abbc ... * a?c acc abc aXc ... * a[a-z]c aac abc acc ... * a[-a-z]c a-c aac abc ... * * $Log$ * Revision 1.1 2004/11/19 23:00:57 theno23 * Added lo_send_timestamped * * Revision 1.3 1995/09/14 23:24:23 oz * removed boring test/main code. * * Revision 1.2 94/12/11 10:38:15 oz * cset code fixed. it is now robust and interprets all * variations of cset [i think] correctly, including [z-a] etc. * * Revision 1.1 94/12/08 12:45:23 oz * Initial revision */ #ifndef lo_NEGATE #define lo_NEGATE '!' #endif #ifndef lo_true #define lo_true 1 #endif #ifndef lo_false #define lo_false 0 #endif inline int lo_pattern_match(const char *str, const char *p) { int negate; int match; char c; while (*p) { if (!*str && *p != '*') return lo_false; switch (c = *p++) { case '*': while (*p == '*' && *p != '/') p++; if (!*p) return lo_true; // if (*p != '?' && *p != '[' && *p != '\\') if (*p != '?' && *p != '[' && *p != '{') while (*str && *p != *str) str++; while (*str) { if (lo_pattern_match(str, p)) return lo_true; str++; } return lo_false; case '?': if (*str) break; return lo_false; /* * set specification is inclusive, that is [a-z] is a, z and * everything in between. this means [z-a] may be interpreted * as a set that contains z, a and nothing in between. */ case '[': if (*p != lo_NEGATE) negate = lo_false; else { negate = lo_true; p++; } match = lo_false; while (!match && (c = *p++)) { if (!*p) return lo_false; if (*p == '-') { /* c-c */ if (!*++p) return lo_false; if (*p != ']') { if (*str == c || *str == *p || (*str > c && *str < *p)) match = lo_true; } else { /* c-] */ if (*str >= c) match = lo_true; break; } } else { /* cc or c] */ if (c == *str) match = lo_true; if (*p != ']') { if (*p == *str) match = lo_true; } else break; } } if (negate == match) return lo_false; /* * if there is a match, skip past the cset and continue on */ while (*p && *p != ']') p++; if (!*p++) /* oops! */ return lo_false; break; /* * {astring,bstring,cstring} */ case '{': { // *p is now first character in the {brace list} const char *place = str; // to backtrack const char *remainder = p; // to forwardtrack // find the end of the brace list while (*remainder && *remainder != '}') remainder++; if (!*remainder++) /* oops! */ return lo_false; c = *p++; while (c) { if (c == ',') { if (lo_pattern_match(str, remainder)) { return lo_true; } else { // backtrack on test string str = place; // continue testing, // skip comma if (!*p++) // oops return lo_false; } } else if (c == '}') { // continue normal pattern matching if (!*p && !*str) return lo_true; str--; // str is incremented again below break; } else if (c == *str) { str++; if (!*str && *remainder) return lo_false; } else { // skip to next comma str = place; while (*p != ',' && *p != '}' && *p) p++; if (*p == ',') p++; else if (*p == '}') { return lo_false; } } c = *p++; } } break; /* Not part of OSC pattern matching case '\\': if (*p) c = *p++; */ default: if (c != *str) return lo_false; break; } str++; } return !*str; } // end: following function lifted from liblo int prSymbol_matchOSCPattern(struct VMGlobals *g, int numArgsPushed); int prSymbol_matchOSCPattern(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a, *b; a = g->sp - 1; b = g->sp; if (!IsSym(a) || !IsSym(b)) return errWrongType; // int32 alen = slotRawSymbol(a)->length; // int32 blen = slotRawSymbol(b)->length; // length = sc_min(alen, blen); if (lo_pattern_match(slotRawSymbol(a)->name, slotRawSymbol(b)->name)) { SetTrue(a); } else { SetFalse(a); } return errNone; } int prSymbol_isMap(struct VMGlobals *g, int numArgsPushed); int prSymbol_isMap(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char *str = slotRawSymbol(a)->name; if(strlen(str)>1 && (str[0]=='a' || str[0]=='c') && str[1]>='0' && str[1]<='9') SetTrue(a); else SetFalse(a); return errNone; } void initSymbolPrimitives(); void initSymbolPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); definePrimitive(base, index++, "_SymbolIsPrefix", prSymbolIsPrefix, 2, 0); //definePrimitive(base, index++, "_SymbolString", prSymbolString, 1, 0); definePrimitive(base, index++, "_SymbolClass", prSymbolClass, 1, 0); definePrimitive(base, index++, "_SymbolIsClassName", prSymbolIsClassName, 1, 0); definePrimitive(base, index++, "_SymbolIsMetaClassName", prSymbolIsMetaClassName, 1, 0); definePrimitive(base, index++, "_SymbolIsSetter", prSymbolIsSetter, 1, 0); definePrimitive(base, index++, "_SymbolAsSetter", prSymbolAsSetter, 1, 0); definePrimitive(base, index++, "_SymbolAsGetter", prSymbolAsGetter, 1, 0); definePrimitive(base, index++, "_Symbol_AsInteger", prSymbol_AsInteger, 1, 0); definePrimitive(base, index++, "_Symbol_PrimitiveIndex", prSymbol_PrimitiveIndex, 1, 0); definePrimitive(base, index++, "_Symbol_SpecialIndex", prSymbol_SpecialIndex, 1, 0); definePrimitive(base, index++, "_Symbol_AsFloat", prSymbol_AsFloat, 1, 0); definePrimitive(base, index++, "_Symbol_matchOSCPattern", prSymbol_matchOSCPattern, 2, 0); definePrimitive(base, index++, "_Symbol_IsMap", prSymbol_isMap, 1, 0); } #if _SC_PLUGINS_ #include "SCPlugin.h" // export the function that SC will call to load the plug in. #pragma export on extern "C" { SCPlugIn* loadPlugIn(void); } #pragma export off // define plug in object class APlugIn : public SCPlugIn { public: APlugIn(); virtual ~APlugIn(); virtual void AboutToCompile(); }; APlugIn::APlugIn() { // constructor for plug in } APlugIn::~APlugIn() { // destructor for plug in } void APlugIn::AboutToCompile() { // this is called each time the class library is compiled. initSymbolPrimitives(); } // This function is called when the plug in is loaded into SC. // It returns an instance of APlugIn. SCPlugIn* loadPlugIn() { return new APlugIn(); } #endif SuperCollider-Source/lang/LangPrimSource/PyrUnixPrim.cpp000644 000765 000024 00000026301 12756531745 024463 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Primitives for Unix. */ #include #include #include #include "PyrPrimitive.h" #include "PyrObject.h" #include "PyrKernel.h" #include "PyrSched.h" #include "VMGlobals.h" #include "GC.h" #include "SC_RGen.h" #include "SC_DirUtils.h" #include "sc_popen.h" #include "SCBase.h" #include "SC_Lock.h" #include #include #ifdef _WIN32 #include "SC_Win32Utils.h" #else #include #endif using namespace boost::filesystem; extern bool compiledOK; PyrSymbol* s_unixCmdAction; int prString_System(struct VMGlobals *g, int numArgsPushed); int prString_System(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char cmdline[1024]; int err = slotStrVal(a, cmdline, 1023); if (err) return err; int res = system(cmdline); SetInt(a, res); return errNone; } int prString_Basename(struct VMGlobals *g, int numArgsPushed); int prString_Basename(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char path[PATH_MAX]; int err = slotStrVal(a, path, PATH_MAX); if (err) return err; char *basename0 = basename(path); int size = strlen(basename0); PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, basename0, size); SetObject(a, strobj); return errNone; } int prString_Dirname(struct VMGlobals *g, int numArgsPushed); int prString_Dirname(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; char path[PATH_MAX]; int err = slotStrVal(a, path, PATH_MAX); if (err) return err; char *dirname0 = dirname(path); int size = strlen(dirname0); PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, dirname0, size); SetObject(a, strobj); return errNone; } struct sc_process { pid_t pid; FILE *stream; bool postOutput; }; static void string_popen_thread_func(struct sc_process *process) { FILE *stream = process->stream; pid_t pid = process->pid; char buf[1024]; while (process->postOutput) { char *string = fgets(buf, 1024, stream); if (!string) break; postText(string, strlen(string)); } int res; res = sc_pclose(stream, pid); res = WEXITSTATUS(res); if(process->postOutput) postfl("RESULT = %d\n", res); delete process; gLangMutex.lock(); if(compiledOK) { VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, class_string); ++g->sp; SetInt(g->sp, res); ++g->sp; SetInt(g->sp, pid); runInterpreter(g, s_unixCmdAction, 3); g->canCallOS = false; } gLangMutex.unlock(); } int prString_POpen(struct VMGlobals *g, int numArgsPushed); int prString_POpen(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; if (!isKindOfSlot(a, class_string)) return errWrongType; char *cmdline = new char[slotRawObject(a)->size + 1]; slotStrVal(a, cmdline, slotRawObject(a)->size + 1); #ifdef SC_IPHONE SetInt(a, 0); return errNone; #endif sc_process *process = new sc_process; process->stream = sc_popen(cmdline, &process->pid, "r"); setvbuf(process->stream, 0, _IONBF, 0); pid_t pid = process->pid; process->postOutput = IsTrue(b); delete [] cmdline; if(process->stream == NULL) { delete process; return errFailed; } thread thread(std::bind(string_popen_thread_func, process)); thread.detach(); SetInt(a, pid); return errNone; } int prArrayPOpen(struct VMGlobals *g, int numArgsPushed); int prArrayPOpen(struct VMGlobals *g, int numArgsPushed) { PyrObject *obj; PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; #ifdef SC_IPHONE SetInt(a, 0); return errNone; #endif if (NotObj(a)) return errWrongType; obj = slotRawObject(a); if (!(slotRawInt(&obj->classptr->classFlags) & classHasIndexableInstances)) return errNotAnIndexableObject; if( obj->size < 1) return errFailed; PyrSlot filenameSlot; getIndexedSlot(obj, &filenameSlot, 0); if (!isKindOfSlot(&filenameSlot, class_string)) return errWrongType; char filename[PATH_MAX]; if (slotRawObject(&filenameSlot)->size > PATH_MAX - 1) return errFailed; slotStrVal(&filenameSlot, filename, slotRawObject(&filenameSlot)->size + 1); std::vector argv (obj->size + 1); path p; p /= filename; std::string filenameOnly = p.filename().string(); std::vector vfilenameOnly(filenameOnly.begin(), filenameOnly.end()); vfilenameOnly.push_back('\0'); argv[0] = vfilenameOnly.data(); argv[obj->size] = NULL; if(obj->size > 1) { for (int i=1; isize; ++i) { PyrSlot argSlot; getIndexedSlot(obj, &argSlot, i); if (!isKindOfSlot(&argSlot, class_string)) return errWrongType; char *arg = new char[slotRawObject(&argSlot)->size + 1]; slotStrVal(&argSlot, arg, slotRawObject(&argSlot)->size + 1); argv[i] = arg; } } sc_process *process = new sc_process; process->stream = sc_popen_argv(filename, argv.data(), &process->pid, "r"); setvbuf(process->stream, 0, _IONBF, 0); pid_t pid = process->pid; process->postOutput = IsTrue(b); if(process->stream == NULL) { delete process; return errFailed; } thread thread(std::bind(string_popen_thread_func, process)); thread.detach(); for (int i=1; isize; ++i) { delete [] argv[i]; } SetInt(a, pid); return errNone; } int prPidRunning(VMGlobals *g, int numArgsPushed); int prPidRunning(VMGlobals *g, int numArgsPushed) { PyrSlot *a; a = g->sp; #ifdef _WIN32 HANDLE handle; handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, slotRawInt(a)); if(handle) { unsigned long exitCode; if(GetExitCodeProcess(handle, &exitCode) == 0) SetFalse(a); else if(exitCode == STILL_ACTIVE) SetTrue(a); CloseHandle(handle); } else SetFalse(a); #else if(kill(slotRawInt(a), 0) == 0) SetTrue(a); else SetFalse(a); #endif return errNone; } int prUnix_Errno(struct VMGlobals *g, int numArgsPushed); int prUnix_Errno(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, errno); return errNone; } #include static void fillSlotsFromTime(PyrSlot * result, struct tm* tm, std::chrono::system_clock::time_point const & now) { PyrSlot *slots = slotRawObject(result)->slots; SetInt(slots+0, tm->tm_year + 1900); SetInt(slots+1, tm->tm_mon + 1); // 0 based month ?? SetInt(slots+2, tm->tm_mday); SetInt(slots+3, tm->tm_hour); SetInt(slots+4, tm->tm_min); SetInt(slots+5, tm->tm_sec); SetInt(slots+6, tm->tm_wday); SetFloat(slots+7, std::chrono::duration_cast(now.time_since_epoch()).count() * 1.0e-9); } int prLocalTime(struct VMGlobals *g, int numArgsPushed) { using namespace std::chrono; system_clock::time_point now = system_clock::now(); time_t now_time_t = system_clock::to_time_t(now); struct tm* tm = localtime(&now_time_t); fillSlotsFromTime(g->sp, tm, now); return errNone; } int prGMTime(struct VMGlobals *g, int numArgsPushed) { using namespace std::chrono; system_clock::time_point now = system_clock::now(); time_t now_time_t = system_clock::to_time_t(now); struct tm* tm = gmtime(&now_time_t); fillSlotsFromTime(g->sp, tm, now); return errNone; } int prAscTime(struct VMGlobals *g, int numArgsPushed); int prAscTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; PyrSlot *slots = slotRawObject(a)->slots; if (IsNil(slots + 0)) { SetNil(a); return errNone; } struct tm tm0; if (slotIntVal(slots+0, &tm0.tm_year)) return errWrongType; tm0.tm_year -= 1900; if (slotIntVal(slots+1, &tm0.tm_mon)) return errWrongType; tm0.tm_mon -- ; if (slotIntVal(slots+2, &tm0.tm_mday)) return errWrongType; if (slotIntVal(slots+3, &tm0.tm_hour)) return errWrongType; if (slotIntVal(slots+4, &tm0.tm_min)) return errWrongType; if (slotIntVal(slots+5, &tm0.tm_sec)) return errWrongType; if (slotIntVal(slots+6, &tm0.tm_wday)) return errWrongType; const char *text = asctime(&tm0); int size = strlen(text) - 1; // Discard trailing newline PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, text, size); SetObject(a, strobj); return errNone; } int prStrFTime(struct VMGlobals *g, int numArgsPushed); int prStrFTime(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp - 1; PyrSlot *b = g->sp; PyrSlot *slots = slotRawObject(a)->slots; if (IsNil(slots + 0)) { SetNil(a); return errNone; } struct tm tm0; if (slotIntVal(slots+0, &tm0.tm_year)) return errWrongType; tm0.tm_year -= 1900; if (slotIntVal(slots+1, &tm0.tm_mon)) return errWrongType; tm0.tm_mon --; if (slotIntVal(slots+2, &tm0.tm_mday)) return errWrongType; if (slotIntVal(slots+3, &tm0.tm_hour)) return errWrongType; if (slotIntVal(slots+4, &tm0.tm_min)) return errWrongType; if (slotIntVal(slots+5, &tm0.tm_sec)) return errWrongType; if (slotIntVal(slots+6, &tm0.tm_wday)) return errWrongType; char format[1024]; if (slotStrVal(b, format, 1024)) return errWrongType; char buffer[1024]; if (strftime(buffer, 1024, format, &tm0) != 0) { int size = strlen(buffer); PyrString *strobj = newPyrStringN(g->gc, size, 0, true); memcpy(strobj->s, buffer, size); SetObject(a, strobj); } else { error("could not convert the date to string with the give format"); return errFailed; } return errNone; } int32 timeseed(); int prTimeSeed(struct VMGlobals *g, int numArgsPushed); int prTimeSeed(struct VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, timeseed()); return errNone; } int prGetPid(VMGlobals *g, int numArgsPushed); int prGetPid(VMGlobals *g, int numArgsPushed) { PyrSlot *a = g->sp; SetInt(a, #ifndef _WIN32 getpid() #else GetCurrentProcessId() #endif ); return errNone; } void initUnixPrimitives(); void initUnixPrimitives() { int base, index = 0; base = nextPrimitiveIndex(); s_unixCmdAction = getsym("doUnixCmdAction"); definePrimitive(base, index++, "_String_System", prString_System, 1, 0); definePrimitive(base, index++, "_String_Basename", prString_Basename, 1, 0); definePrimitive(base, index++, "_String_Dirname", prString_Dirname, 1, 0); definePrimitive(base, index++, "_String_POpen", prString_POpen, 2, 0); definePrimitive(base, index++, "_Unix_Errno", prUnix_Errno, 1, 0); definePrimitive(base, index++, "_LocalTime", prLocalTime, 1, 0); definePrimitive(base, index++, "_GMTime", prGMTime, 1, 0); definePrimitive(base, index++, "_AscTime", prAscTime, 1, 0); definePrimitive(base, index++, "_prStrFTime", prStrFTime, 2, 0); definePrimitive(base, index++, "_TimeSeed", prTimeSeed, 1, 0); definePrimitive(base, index++, "_PidRunning", prPidRunning, 1, 0); definePrimitive(base, index++, "_GetPid", prGetPid, 1, 0); definePrimitive(base, index++, "_ArrayPOpen", prArrayPOpen, 2, 0); } SuperCollider-Source/lang/LangPrimSource/ReadWriteMacros.h000644 000765 000024 00000014271 12321461511 024675 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _ReadWriteMacros_ #define _ReadWriteMacros_ #include "SC_Types.h" #include "SC_Endian.h" #include #include #include template class SC_IOStream { protected: T s; public: SC_IOStream() : s(0) {} SC_IOStream(T inStream) : s(inStream) {} void SetStream(T inStream) { s = inStream; } T GetStream() { return s; } // core routines void readData(char *data, size_t size); uint8 readUInt8(); void writeData(char *data, size_t size); void writeUInt8(uint8 inInt); // built using core routines void writeInt8(int8 inInt) { writeUInt8((uint8)inInt); } void writeInt16_be(int16 inInt) { writeUInt8((uint8)(inInt >> 8)); writeUInt8(inInt); } void writeInt16_le(int16 inInt) { writeUInt8((uint8)inInt); writeUInt8((uint8)(inInt >> 8)); } void writeInt32_be(int32 inInt) { writeUInt8((uint8)(inInt >> 24)); writeUInt8((uint8)(inInt >> 16)); writeUInt8((uint8)(inInt >> 8)); writeUInt8((uint8)inInt); } void writeInt32_le(int32 inInt) { writeUInt8((uint8)inInt); writeUInt8((uint8)(inInt >> 8)); writeUInt8((uint8)(inInt >> 16)); writeUInt8((uint8)(inInt >> 24)); } #if BYTE_ORDER == BIG_ENDIAN void writeFloat_be(float inFloat) #else void writeFloat_le(float inFloat) #endif { union { float f; uint8 c[4]; } u; u.f = inFloat; writeUInt8(u.c[0]); writeUInt8(u.c[1]); writeUInt8(u.c[2]); writeUInt8(u.c[3]); } #if BYTE_ORDER == BIG_ENDIAN void writeFloat_le(float inFloat) #else void writeFloat_be(float inFloat) #endif { union { float f; uint8 c[4]; } u; u.f = inFloat; writeUInt8(u.c[3]); writeUInt8(u.c[2]); writeUInt8(u.c[1]); writeUInt8(u.c[0]); } #if BYTE_ORDER == BIG_ENDIAN void writeDouble_be(double inDouble) #else void writeDouble_le(double inDouble) #endif { union { double f; uint8 c[8]; } u; u.f = inDouble; writeUInt8(u.c[0]); writeUInt8(u.c[1]); writeUInt8(u.c[2]); writeUInt8(u.c[3]); writeUInt8(u.c[4]); writeUInt8(u.c[5]); writeUInt8(u.c[6]); writeUInt8(u.c[7]); } #if BYTE_ORDER == BIG_ENDIAN void writeDouble_le(double inDouble) #else void writeDouble_be(double inDouble) #endif { union { double f; uint8 c[8]; } u; u.f = inDouble; writeUInt8(u.c[7]); writeUInt8(u.c[6]); writeUInt8(u.c[5]); writeUInt8(u.c[4]); writeUInt8(u.c[3]); writeUInt8(u.c[2]); writeUInt8(u.c[1]); writeUInt8(u.c[0]); } int8 readInt8() { return (int8)readUInt8(); } int16 readInt16_be() { uint8 a = readUInt8(); uint8 b = readUInt8(); return (int16)((a << 8) | b); } int16 readInt16_le() { uint8 a = readUInt8(); uint8 b = readUInt8(); return (int16)((b << 8) | a); } int32 readInt32_be() { uint8 a = readUInt8(); uint8 b = readUInt8(); uint8 c = readUInt8(); uint8 d = readUInt8(); return (int32)((a << 24) | (b << 16) | (c << 8) | d); } int32 readInt32_le() { uint8 a = readUInt8(); uint8 b = readUInt8(); uint8 c = readUInt8(); uint8 d = readUInt8(); return (int32)((d << 24) | (c << 16) | (b << 8) | a); } #if BYTE_ORDER == BIG_ENDIAN float readFloat_be() #else float readFloat_le() #endif { union { float f; uint8 c[4]; } u; u.c[0] = readUInt8(); u.c[1] = readUInt8(); u.c[2] = readUInt8(); u.c[3] = readUInt8(); return u.f; } #if BYTE_ORDER == BIG_ENDIAN float readFloat_le() #else float readFloat_be() #endif { union { float f; uint8 c[4]; } u; u.c[3] = readUInt8(); u.c[2] = readUInt8(); u.c[1] = readUInt8(); u.c[0] = readUInt8(); return u.f; } #if BYTE_ORDER == BIG_ENDIAN double readDouble_be() #else double readDouble_le() #endif { union { double f; uint8 c[8]; } u; u.c[0] = readUInt8(); u.c[1] = readUInt8(); u.c[2] = readUInt8(); u.c[3] = readUInt8(); u.c[4] = readUInt8(); u.c[5] = readUInt8(); u.c[6] = readUInt8(); u.c[7] = readUInt8(); return u.f; } #if BYTE_ORDER == BIG_ENDIAN double readDouble_le() #else double readDouble_be() #endif { union { double f; uint8 c[8]; } u; u.c[7] = readUInt8(); u.c[6] = readUInt8(); u.c[5] = readUInt8(); u.c[4] = readUInt8(); u.c[3] = readUInt8(); u.c[2] = readUInt8(); u.c[1] = readUInt8(); u.c[0] = readUInt8(); return u.f; } void readSymbol(char *outString) { int length = readUInt8(); readData(outString, length); outString[length] = 0; } void writeSymbol(char *inString) { size_t length = strlen(inString); writeUInt8((uint8)length); writeData(inString, length); } }; // core routines template <> inline void SC_IOStream::readData(char *data, size_t size) { size_t read = fread(data, 1, size, s); if (read != size) throw std::runtime_error("SC_IOStream::readData: read != size"); } template <> inline uint8 SC_IOStream::readUInt8() { return (uint8)fgetc(s); } template <> inline void SC_IOStream::writeData(char *data, size_t size) { fwrite(data, 1, size, s); } template <> inline void SC_IOStream::writeUInt8(uint8 inInt) { fputc(inInt, s); } // core routines template <> inline void SC_IOStream::readData(char *data, size_t size) { memcpy(data, s, size); s += size; } template <> inline uint8 SC_IOStream::readUInt8() { return (uint8)*s++; } template <> inline void SC_IOStream::writeData(char *data, size_t size) { memcpy(s, data, size); s += size; } template <> inline void SC_IOStream::writeUInt8(uint8 inInt) { *s++ = (inInt & 255); } #endif SuperCollider-Source/lang/LangPrimSource/SC_AlsaMIDI.cpp000644 000765 000024 00000074311 12756531745 024131 0ustar00crucialstaff000000 000000 /* Alsa MIDI/Sequencer support. Copyright (c) 2004 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include "SC_LanguageClient.h" #include #include PyrSymbol* s_midiin; PyrSymbol* s_domidiaction; PyrSymbol* s_midiNoteOnAction; PyrSymbol* s_midiNoteOffAction; PyrSymbol* s_midiTouchAction; PyrSymbol* s_midiControlAction; PyrSymbol* s_midiPolyTouchAction; PyrSymbol* s_midiProgramAction; PyrSymbol* s_midiBendAction; PyrSymbol* s_midiSysexAction; PyrSymbol* s_midiSysrtAction; PyrSymbol* s_midiSMPTEAction; const int kMaxMidiPorts = 16; bool gMIDIInitialized = false; extern bool compiledOK; // ===================================================================== // Platform declarations (interface routines) // ===================================================================== static int initClient(); static int initMIDI(int numIn, int numOut); static int disposeMIDI(); static int restartMIDI(); static void cleanUpMIDI(); static int listMIDIEndpoints(struct VMGlobals *g, PyrSlot *a); static int connectMIDIIn(int inputIndex, int uid); static int disconnectMIDIIn(int inputIndex, int uid); static int connectMIDIOut(int outputIndex, int uid); static int disconnectMIDIOut(int outputIndex, int uid); static int sendMIDI(int port, int destId, int length, int hiStatus, int loStatus, int aval, int bval, float late); static int sendMIDISysex(int port, int destId, int length, uint8* data); // ===================================================================== // Platform declarations (ALSA) // ===================================================================== #include #include #include static const size_t kAlsaMaxPacketSize = 3; static const size_t kAlsaMaxPortNameLen = 256; // MIDI packet struct SC_AlsaMidiPacket { uint8 data[kAlsaMaxPacketSize]; }; // MIDI client state struct SC_AlsaMidiClient { snd_seq_t* mHandle; int mQueue; int mNumInPorts; int mInPorts[kMaxMidiPorts]; int mNumOutPorts; int mOutPorts[kMaxMidiPorts]; snd_midi_event_t* mEventToMidi; snd_midi_event_t* mMidiToEvent; std::thread mInputThread; std::atomic_bool mShouldBeRunning { false }; int startInputThread() { mShouldBeRunning = true; try { std::thread inputThread ( [this] { inputThreadFunc(); }); mInputThread = std::move( inputThread ); return errNone; } catch (...) { post("MIDI (ALSA): could not start input thread\n"); return errFailed; } } void joinInputThread() { mShouldBeRunning = false; if( mInputThread.joinable() ) mInputThread.join(); } void inputThreadFunc(); void processEvent(snd_seq_event_t* evt); int connectInput(int inputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName); int connectOutput(int outputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName); int sendEvent(int outputIndex, int uid, snd_seq_event_t* evt, float late=0.f); int mClientID; }; static SC_AlsaMidiClient gMIDIClient; // Port description struct SC_AlsaMidiPort { SC_AlsaMidiPort() : uid(0) { *name = 0; *device = 0; } char name[kAlsaMaxPortNameLen]; char device[kAlsaMaxPortNameLen]; int32 uid; }; // ===================================================================== // Platform implementation (ALSA) // ===================================================================== static inline int SC_AlsaMakeUID(int clientID, int portID) { return (clientID << 16) | (portID & 0xFFFF); } static inline void SC_AlsaParseUID(int uid, int& clientID, int& portID) { clientID = uid >> 16; portID = uid & 0xFFFF; } void SC_AlsaMidiClient::processEvent(snd_seq_event_t* evt) { int status = lockLanguageOrQuit(mShouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; PyrInt8Array* sysexArray; SC_AlsaMidiPacket pkt; g->canCallOS = false; // cannot call the OS // class MIDIIn ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // source ++g->sp; SetInt(g->sp, SC_AlsaMakeUID(evt->source.client, evt->source.port)); switch (evt->type) { // midi events case SND_SEQ_EVENT_NOTEOFF: // noteOff ++g->sp; SetInt(g->sp, evt->data.note.channel); ++g->sp; SetInt(g->sp, evt->data.note.note); ++g->sp; SetInt(g->sp, evt->data.note.velocity); runInterpreter(g, s_midiNoteOffAction, 5); break; case SND_SEQ_EVENT_NOTEON: // noteOn ++g->sp; SetInt(g->sp, evt->data.note.channel); ++g->sp; SetInt(g->sp, evt->data.note.note); ++g->sp; SetInt(g->sp, evt->data.note.velocity); // runInterpreter(g, evt->data.note.velocity ? s_midiNoteOnAction : s_midiNoteOffAction, 5); runInterpreter(g, s_midiNoteOnAction, 5); break; case SND_SEQ_EVENT_KEYPRESS: // polytouch ++g->sp; SetInt(g->sp, evt->data.note.channel); ++g->sp; SetInt(g->sp, evt->data.note.note); ++g->sp; SetInt(g->sp, evt->data.note.velocity); runInterpreter(g, s_midiPolyTouchAction, 5); break; case SND_SEQ_EVENT_CONTROLLER: // control ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.param); ++g->sp; SetInt(g->sp, evt->data.control.value); runInterpreter(g, s_midiControlAction, 5); break; case SND_SEQ_EVENT_PGMCHANGE: // program ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.value); runInterpreter(g, s_midiProgramAction, 4); break; case SND_SEQ_EVENT_CHANPRESS: // touch ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.value); runInterpreter(g, s_midiTouchAction, 4); break; case SND_SEQ_EVENT_PITCHBEND: // bend ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.value + 8192); runInterpreter(g, s_midiBendAction, 4); break; // system common events case SND_SEQ_EVENT_QFRAME: // mtc quarter frame { int index = evt->data.control.value >> 4; int data = evt->data.control.value & 0xf; #if 0 post( "mtc qframe: byte 0x%x index 0x%x data 0x%x\n", evt->data.control.value, index, data ); #endif switch (index) { case 1: case 3: case 5: case 7: data = data << 4; } ++g->sp; SetInt(g->sp, index); ++g->sp; SetInt(g->sp, data); } runInterpreter(g, s_midiSMPTEAction, 4); break; case SND_SEQ_EVENT_SONGPOS: // song ptr ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, (evt->data.control.value << 7) | evt->data.control.param); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_SONGSEL: // song sel ++g->sp; SetInt(g->sp, evt->data.control.channel); ++g->sp; SetInt(g->sp, evt->data.control.param); runInterpreter(g, s_midiSysrtAction, 4); break; // system realtime events case SND_SEQ_EVENT_TUNE_REQUEST: // tuning request ++g->sp; SetInt(g->sp, 0x6); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_CLOCK: // clock ++g->sp; SetInt(g->sp, 0x8); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_TICK: // tick ++g->sp; SetInt(g->sp, 0x9); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_START: // start ++g->sp; SetInt(g->sp, 0xA); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_CONTINUE: // continue ++g->sp; SetInt(g->sp, 0xB); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_STOP: // stop ++g->sp; SetInt(g->sp, 0xC); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_SENSING: // active sensing ++g->sp; SetInt(g->sp, 0xE); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; case SND_SEQ_EVENT_RESET: // system reset ++g->sp; SetInt(g->sp, 0xF); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); break; // sysex events case SND_SEQ_EVENT_SYSEX: // sysex sysexArray = newPyrInt8Array(g->gc, evt->data.ext.len, 0, true); memcpy(sysexArray->b, evt->data.ext.ptr, evt->data.ext.len); sysexArray->size = evt->data.ext.len; ++g->sp; SetObject(g->sp, (PyrObject*)sysexArray); runInterpreter(g, s_midiSysexAction, 3); break; default: // unknown: convert to midi packet snd_midi_event_reset_decode(mEventToMidi); memset(pkt.data, 0, kAlsaMaxPacketSize); if (snd_midi_event_decode(mEventToMidi, pkt.data, kAlsaMaxPacketSize, evt) > 0) { for (size_t i=0; i < kAlsaMaxPacketSize; i++) { ++g->sp; SetInt(g->sp, pkt.data[i]); } runInterpreter(g, s_domidiaction, 2+kAlsaMaxPacketSize); } else { g->sp -= 2; } } g->canCallOS = false; } gLangMutex.unlock(); } void SC_AlsaMidiClient::inputThreadFunc() { int npfd = snd_seq_poll_descriptors_count(mHandle, POLLIN); struct pollfd pfd[npfd]; snd_seq_poll_descriptors(mHandle, pfd, npfd, POLLIN); while (mShouldBeRunning.load( std::memory_order_relaxed )) { if (poll(pfd, npfd, 2000) > 0) { // 2s timeout for (int i=0; i < npfd; i++) { if (pfd[i].revents > 0) { do { snd_seq_event_t* evt = nullptr; int status = snd_seq_event_input(mHandle, &evt); if( status > 0 ) { assert( evt ); processEvent(evt); snd_seq_free_event(evt); } } while (snd_seq_event_input_pending(mHandle, 0) > 0); } } } } } int SC_AlsaMidiClient::connectInput(int inputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName) { snd_seq_t* seq = mHandle; snd_seq_client_info_t* cinfo; snd_seq_port_subscribe_t* subs; snd_seq_addr_t src, dst; int cid, pid; if ((inputIndex < 0) || (inputIndex >= mNumInPorts)) return errIndexOutOfRange; snd_seq_client_info_alloca(&cinfo); if (snd_seq_get_client_info(seq, cinfo) < 0) { post("MIDI (ALSA): could not get client info: %s\n", snd_strerror(errno)); return errFailed; } dst.client = snd_seq_client_info_get_client(cinfo); dst.port = mInPorts[inputIndex]; SC_AlsaParseUID(uid, cid, pid); src.client = cid; src.port = pid; //post("MIDI (ALSA): connect ndx %d uid %u dst %d:%d src %d:%d\n", inputIndex, uid, dst.client, dst.port, src.client, src.port); snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender(subs, &src); snd_seq_port_subscribe_set_dest(subs, &dst); if ((*action)(seq, subs) < 0) { post("MIDI (ALSA): %s failed (%s)\n", actionName, snd_strerror(errno)); return errFailed; } return errNone; } int SC_AlsaMidiClient::connectOutput(int outputIndex, int uid, int (*action)(snd_seq_t*, snd_seq_port_subscribe_t*), const char* actionName) { snd_seq_t* seq = mHandle; snd_seq_client_info_t* cinfo; snd_seq_port_subscribe_t* subs; snd_seq_addr_t src, dst; int cid, pid; if ((outputIndex < 0) || (outputIndex >= mNumOutPorts)) return errIndexOutOfRange; snd_seq_client_info_alloca(&cinfo); if (snd_seq_get_client_info(seq, cinfo) < 0) { post("MIDI (ALSA): could not get client info: %s\n", snd_strerror(errno)); return errFailed; } src.client = snd_seq_client_info_get_client(cinfo); src.port = mOutPorts[outputIndex]; SC_AlsaParseUID(uid, cid, pid); dst.client = cid; dst.port = pid; // post("MIDI (ALSA): connect ndx %d uid %u dst %d:%d src %d:%d\n", outputIndex, uid, dst.client, dst.port, src.client, src.port); snd_seq_port_subscribe_alloca(&subs); snd_seq_port_subscribe_set_sender(subs, &src); snd_seq_port_subscribe_set_dest(subs, &dst); if ((*action)(seq, subs) < 0) { post("MIDI (ALSA): %s failed (%s)\n", actionName, snd_strerror(errno)); return errFailed; } return errNone; } int SC_AlsaMidiClient::sendEvent(int outputIndex, int uid, snd_seq_event_t* evt, float late) { snd_seq_real_time time; if ((outputIndex < 0) || (outputIndex >= mNumOutPorts)) return errIndexOutOfRange; snd_seq_ev_set_source(evt, mOutPorts[outputIndex]); if (uid == 0) { // send to all subscribed ports snd_seq_ev_set_subs(evt); } else { // send to specific port int cid, pid; SC_AlsaParseUID(uid, cid, pid); snd_seq_ev_set_dest(evt, cid, pid); } // long latelong; if (late > 0.f) { // latelong = (long) (late * 1000000000); // new time calculation. The old one was not correct // time.tv_sec = (long)(latelong / 1000000000); // seconds // time.tv_nsec = (long)(latelong % 1000000000); // nanoseconds time.tv_sec = (long)(floorf (late)); time.tv_nsec = (long)((late - time.tv_sec) * 1e9f); } else { time.tv_sec = time.tv_nsec = 0; } // evt->flags = evt->flags | SND_SEQ_TIME_STAMP_REAL; // post("MIDI (ALSA): sending event, time %i, %i, late %f, latelong %i\n", time.tv_sec, time.tv_nsec, late, latelong); snd_seq_ev_schedule_real(evt, mQueue, 1, &time); snd_seq_event_output_direct(mHandle, evt); // snd_seq_event_output(mHandle, evt); // snd_seq_continue_queue(mHandle, mQueue, 0); // snd_seq_drain_output(mHandle); return errNone; } int initMIDI(int numIn, int numOut) { SC_AlsaMidiClient* client = &gMIDIClient; int i; if (client->mHandle) cleanUpMIDI(); numIn = sc_clip(numIn, 1, kMaxMidiPorts); numOut = sc_clip(numOut, 1, kMaxMidiPorts); // initialize client handle if (snd_seq_open(&client->mHandle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { client->mHandle = 0; post("MIDI (ALSA): could not open ALSA sequencer: %s\n", snd_strerror(errno)); return errFailed; } snd_seq_set_client_name(client->mHandle, "SuperCollider"); // allocate i/o ports for (i=0; i < numIn; i++) { char str[32]; int port; sprintf(str, "in%d", i); port = snd_seq_create_simple_port( client->mHandle, str, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION); if (port < 0) { post("MIDI (ALSA): could not create MIDI in port %d: %s\n", i, snd_strerror(errno)); break; } client->mInPorts[i] = port; } client->mNumInPorts = i; for (i=0; i < numOut; i++) { char str[32]; int port; sprintf(str, "out%d", i); port = snd_seq_create_simple_port( client->mHandle, str, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ, SND_SEQ_PORT_TYPE_APPLICATION); if (port < 0) { post("MIDI (ALSA): could not create MIDI out port %d: %s\n", i, snd_strerror(errno)); break; } client->mOutPorts[i] = port; } client->mNumOutPorts = i; // initialize queue client->mQueue = snd_seq_alloc_queue(client->mHandle); snd_seq_start_queue(client->mHandle, client->mQueue, 0); snd_seq_drain_output(client->mHandle); // snd_seq_set_client_pool_output(seqHandle, ??); // initialize event en-/decoders if (snd_midi_event_new(32, &client->mEventToMidi) < 0) { client->mEventToMidi = 0; post("MIDI (ALSA): could not create MIDI decoder\n"); return errFailed; } if (snd_midi_event_new(32, &client->mMidiToEvent) < 0) { client->mMidiToEvent = 0; post("MIDI (ALSA): could not create MIDI encoder\n"); return errFailed; } snd_midi_event_no_status(client->mEventToMidi, 1); snd_midi_event_no_status(client->mMidiToEvent, 1); // start input thread return client->startInputThread(); } int initMIDIClient() { SC_AlsaMidiClient* client = &gMIDIClient; if (client->mHandle) return errNone; // initialize client handle if (snd_seq_open(&client->mHandle, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0) { client->mHandle = 0; post("MIDI (ALSA): could not open ALSA sequencer: %s\n", snd_strerror(errno)); return errFailed; } snd_seq_set_client_name(client->mHandle, "SuperCollider"); client->mClientID = snd_seq_client_id( client->mHandle ); // initialize queue client->mQueue = snd_seq_alloc_queue(client->mHandle); snd_seq_start_queue(client->mHandle, client->mQueue, 0); snd_seq_drain_output(client->mHandle); // snd_seq_set_client_pool_output(seqHandle, ??); // initialize event en-/decoders if (snd_midi_event_new(32, &client->mEventToMidi) < 0) { client->mEventToMidi = 0; post("MIDI (ALSA): could not create MIDI decoder\n"); return errFailed; } if (snd_midi_event_new(32, &client->mMidiToEvent) < 0) { client->mMidiToEvent = 0; post("MIDI (ALSA): could not create MIDI encoder\n"); return errFailed; } snd_midi_event_no_status(client->mEventToMidi, 1); snd_midi_event_no_status(client->mMidiToEvent, 1); return client->startInputThread(); } int disposeMIDI() { cleanUpMIDI(); return errNone; } int restartMIDI() { return errNone; } void cleanUpMIDI() { SC_AlsaMidiClient* client = &gMIDIClient; if (client->mHandle) { client->joinInputThread(); snd_seq_remove_events_t *revt; snd_seq_remove_events_malloc(&revt); snd_seq_remove_events_set_queue(revt, client->mQueue); snd_seq_remove_events_set_condition(revt, SND_SEQ_REMOVE_OUTPUT|SND_SEQ_REMOVE_IGNORE_OFF); snd_seq_remove_events(client->mHandle, revt); snd_seq_remove_events_free(revt); snd_seq_stop_queue(client->mHandle, client->mQueue, 0); snd_seq_free_queue(client->mHandle, client->mQueue); if (client->mEventToMidi) { snd_midi_event_free(client->mEventToMidi); } if (client->mMidiToEvent) { snd_midi_event_free(client->mMidiToEvent); } snd_seq_close(client->mHandle); client->mHandle = 0; } } inline static bool SC_AlsaCheckPerm(snd_seq_port_info_t* pinfo, int bits) { int cap = snd_seq_port_info_get_capability(pinfo); return ((cap & bits) == bits) && !(cap & SND_SEQ_PORT_CAP_NO_EXPORT); } int listMIDIEndpoints(struct VMGlobals *g, PyrSlot* a) { snd_seq_t* seq; snd_seq_client_info_t* cinfo; snd_seq_port_info_t* pinfo; if (!gMIDIClient.mHandle) return errFailed; seq = gMIDIClient.mHandle; snd_seq_client_info_alloca(&cinfo); snd_seq_port_info_alloca(&pinfo); snd_seq_client_info_set_client(cinfo, -1); std::vector srcPorts; std::vector dstPorts; while (snd_seq_query_next_client(seq, cinfo) >= 0) { int cid = snd_seq_client_info_get_client(cinfo); const char* cname = snd_seq_client_info_get_name(cinfo); if ((cid < 0) || (cid > 0xffff)) { post("MIDI (ALSA): client ID out of range.\n"); return errFailed; } snd_seq_port_info_set_client(pinfo, cid); snd_seq_port_info_set_port(pinfo, -1); while (snd_seq_query_next_port(seq, pinfo) >= 0) { int pid = snd_seq_port_info_get_port(pinfo); const char* pname = snd_seq_port_info_get_name(pinfo); if ((pid < 0) || (pid > 0xffff)) { post("MIDI (ALSA): port ID out of range.\n"); return errFailed; } if (SC_AlsaCheckPerm(pinfo, SND_SEQ_PORT_CAP_READ|SND_SEQ_PORT_CAP_SUBS_READ)) { // src port srcPorts.push_back(SC_AlsaMidiPort()); snprintf(srcPorts.back().name, kAlsaMaxPortNameLen, "%s", pname); snprintf(srcPorts.back().device, kAlsaMaxPortNameLen, "%s", cname); srcPorts.back().uid = SC_AlsaMakeUID(cid, pid); //post("MIDI (ALSA): src %s-%s %d:%d %u\n", cname, pname, cid, pid, srcPorts.back().uid); } if (SC_AlsaCheckPerm(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) { // dst port dstPorts.push_back(SC_AlsaMidiPort()); snprintf(dstPorts.back().name, kAlsaMaxPortNameLen, "%s", pname); snprintf(dstPorts.back().device, kAlsaMaxPortNameLen, "%s", cname); dstPorts.back().uid = SC_AlsaMakeUID(cid, pid); //post("MIDI (ALSA): dst %s-%s %d:%d %u\n", cname, pname, cid, pid, srcPorts.back().uid); } } } int numSrc = srcPorts.size(); int numDst = dstPorts.size(); PyrObject* idarray = newPyrArray(g->gc, 6 * sizeof(PyrObject), 0 , true); SetObject(a, idarray); PyrObject* idarraySo = newPyrArray(g->gc, numSrc * sizeof(int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarraySo); g->gc->GCWrite(idarray, idarraySo); PyrObject* devarraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarraySo); g->gc->GCWrite(idarray, devarraySo); PyrObject* namearraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearraySo); g->gc->GCWrite(idarray, namearraySo); PyrObject* idarrayDe = newPyrArray(g->gc, numDst * sizeof(int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarrayDe); g->gc->GCWrite(idarray, idarrayDe); PyrObject* namearrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearrayDe); g->gc->GCWrite(idarray, namearrayDe); PyrObject* devarrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarrayDe); g->gc->GCWrite(idarray, devarrayDe); for (int i=0; igc, name, 0, true); SetObject(namearraySo->slots+i, string); namearraySo->size++; g->gc->GCWrite(namearraySo, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, devicename, 0, true); SetObject(devarraySo->slots+i, devstring); devarraySo->size++; g->gc->GCWrite(devarraySo, (PyrObject*)devstring); SetInt(idarraySo->slots+i, srcPorts[i].uid); idarraySo->size++; } for (int i=0; igc, name, 0, true); SetObject(namearrayDe->slots+namearrayDe->size++, string); g->gc->GCWrite(namearrayDe, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, devicename, 0, true); SetObject(devarrayDe->slots+i, devstring); devarrayDe->size++; g->gc->GCWrite(devarrayDe, (PyrObject*)devstring); SetInt(idarrayDe->slots+i, dstPorts[i].uid); idarrayDe->size++; } return errNone; } int connectMIDIIn(int inputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectInput(inputIndex, uid, &snd_seq_subscribe_port, "connect"); } int disconnectMIDIIn(int inputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectInput(inputIndex, uid, &snd_seq_unsubscribe_port, "disconnect"); } int connectMIDIOut(int outputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectOutput(outputIndex, uid, &snd_seq_subscribe_port, "connect"); } int disconnectMIDIOut(int outputIndex, int uid) { if (!gMIDIClient.mHandle) return errFailed; return gMIDIClient.connectOutput(outputIndex, uid, &snd_seq_unsubscribe_port, "disconnect"); } int sendMIDI(int port, int uid, int length, int hiStatus, int loStatus, int aval, int bval, float late) { if (!gMIDIClient.mHandle) return errFailed; // post("MIDI (ALSA): send %x %x %d %d %i\n", hiStatus>>4, loStatus, aval, bval, gMIDIClient.mMidiToEvent); snd_seq_event_t evt; SC_AlsaMidiPacket pkt; snd_seq_ev_clear(&evt); pkt.data[0] = (hiStatus & 0xF0) | (loStatus & 0x0F); pkt.data[1] = (uint8)aval; pkt.data[2] = (uint8)bval; snd_midi_event_reset_encode(gMIDIClient.mMidiToEvent); if (snd_midi_event_encode(gMIDIClient.mMidiToEvent, pkt.data, length, &evt) < 0) { post("MIDI (ALSA): could not encode midi data: %s\n", snd_strerror(errno)); return errFailed; } return gMIDIClient.sendEvent(port, uid, &evt, late); } int sendMIDISysex(int port, int uid, int length, uint8* data) { if (!gMIDIClient.mHandle) return errFailed; snd_seq_event_t evt; evt.type = SND_SEQ_EVENT_SYSEX; // MIDIOut.sysex patch 2007-01-16 snd_seq_ev_set_variable(&evt, length, data); return gMIDIClient.sendEvent(port, uid, &evt, 0.f); } // ===================================================================== // Primitives // ===================================================================== int prInitMIDI(struct VMGlobals *g, int numArgsPushed); int prInitMIDI(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, numIn, numOut; err = slotIntVal(b, &numIn); if (err) return errWrongType; err = slotIntVal(c, &numOut); if (err) return errWrongType; return initMIDI(numIn, numOut); } int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed); int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed) { return initMIDIClient(); } int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed); int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed) { return disposeMIDI(); } int prRestartMIDI(VMGlobals *g, int numArgsPushed); int prRestartMIDI(VMGlobals *g, int numArgsPushed) { return restartMIDI(); } int prListMIDIEndpoints(struct VMGlobals *g, int numArgsPushed); int prListMIDIEndpoints(struct VMGlobals *g, int numArgsPushed) { return listMIDIEndpoints(g, g->sp); } int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return connectMIDIIn(inputIndex, uid); } int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return disconnectMIDIIn(inputIndex, uid); } int prConnectMIDIOut(struct VMGlobals *g, int numArgsPushed); int prConnectMIDIOut(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return connectMIDIOut(inputIndex, uid); } int prDisconnectMIDIOut(struct VMGlobals *g, int numArgsPushed); int prDisconnectMIDIOut(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; err = slotIntVal(c, &uid); if (err) return err; return disconnectMIDIOut(inputIndex, uid); } int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed); int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed) { //port, uid, len, hiStatus, loStatus, a, b, latency //PyrSlot *m = g->sp - 8; PyrSlot *p = g->sp - 7; PyrSlot *u = g->sp - 6; PyrSlot *l = g->sp - 5; PyrSlot *his = g->sp - 4; PyrSlot *los = g->sp - 3; PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *plat = g->sp; int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval; float late; err = slotIntVal(p, &outputIndex); if (err) return err; err = slotIntVal(u, &uid); if (err) return err; err = slotIntVal(l, &length); if (err) return err; err = slotIntVal(his, &hiStatus); if (err) return err; err = slotIntVal(los, &loStatus); if (err) return err; err = slotIntVal(a, &aval); if (err) return err; err = slotIntVal(b, &bval); if (err) return err; err = slotFloatVal(plat, &late); if (err) return err; return sendMIDI(outputIndex, uid, length, hiStatus, loStatus, aval, bval, late); } int prSendSysex(VMGlobals *g, int numArgsPushed) { int err, uid, outputIndex; PyrInt8Array* packet; // rcvr, uid, packet PyrSlot* args = g->sp - 2; int MIDIOut_port_index = instVarOffset("MIDIOut", "port"); err = slotIntVal(slotRawObject(args)->slots + MIDIOut_port_index, &outputIndex); if (err) return err; err = slotIntVal(args+1, &uid); if (err) return err; if( !isKindOfSlot(args+2, s_int8array->u.classobj) ) return errWrongType; packet = slotRawInt8Array(&args[2]); return sendMIDISysex(outputIndex, uid, packet->size, packet->b); } int prGetMIDIClientID(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; if (!gMIDIClient.mHandle) return errFailed; SetInt(args, gMIDIClient.mClientID ); return errNone; } void initMIDIPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; s_midiin = getsym("MIDIIn"); s_domidiaction = getsym("doAction"); s_midiNoteOnAction = getsym("doNoteOnAction"); s_midiNoteOffAction = getsym("doNoteOffAction"); s_midiTouchAction = getsym("doTouchAction"); s_midiControlAction = getsym("doControlAction"); s_midiPolyTouchAction = getsym("doPolyTouchAction"); s_midiProgramAction = getsym("doProgramAction"); s_midiBendAction = getsym("doBendAction"); s_midiSysexAction = getsym("doSysexAction"); s_midiSysrtAction = getsym("doSysrtAction"); s_midiSMPTEAction = getsym("doSMPTEaction"); definePrimitive(base, index++, "_InitMIDI", prInitMIDI, 3, 0); definePrimitive(base, index++, "_InitMIDIClient", prInitMIDIClient, 1, 0); definePrimitive(base, index++, "_RestartMIDI", prRestartMIDI, 1, 0); definePrimitive(base, index++, "_DisposeMIDIClient", prDisposeMIDIClient, 1, 0); definePrimitive(base, index++, "_ListMIDIEndpoints", prListMIDIEndpoints, 1, 0); definePrimitive(base, index++, "_ConnectMIDIIn", prConnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIIn", prDisconnectMIDIIn, 3, 0); definePrimitive(base, index++, "_ConnectMIDIOut", prConnectMIDIOut, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIOut", prDisconnectMIDIOut, 3, 0); definePrimitive(base, index++, "_SendMIDIOut", prSendMIDIOut, 9, 0); definePrimitive(base, index++, "_SendSysex", prSendSysex, 3, 0); // MIDIOut.sysex patch 2007-01-16 definePrimitive(base, index++, "_GetMIDIClientID", prGetMIDIClientID, 1, 0); cleanUpMIDI(); } void deinitMIDIPrimitives() { cleanUpMIDI(); } // EOF SuperCollider-Source/lang/LangPrimSource/SC_ComPort.cpp000644 000765 000024 00000021535 12766171707 024170 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_BoundsMacros.h" #include "SC_ComPort.h" #include "SC_Endian.h" #include #include #include #include "SCBase.h" #include #include "PyrSched.h" #include "SC_Lock.h" #include "SC_Msg.h" #include "SC_ReplyImpl.hpp" #include #include #include #define scprintf printf #include "SC_OscUtils.hpp" #undef scprintf void ProcessOSCPacket(OSC_Packet *inPacket, int inPortNum, double time); ////////////////////////////////////////////////////////////////////////////////////////////////////////// thread gAsioThread; boost::asio::io_service ioService; static void asioFunction() { boost::asio::io_service::work work(ioService); ioService.run(); } void startAsioThread() { thread asioThread (&asioFunction); gAsioThread = std::move(asioThread); } void stopAsioThread() { ioService.stop(); gAsioThread.join(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_UdpInPort::SC_UdpInPort(int inPortNum, int portsToCheck): mPortNum(inPortNum), udpSocket(ioService) { using namespace boost::asio; BOOST_AUTO(protocol, ip::udp::v4()); udpSocket.open(protocol); for (int offset = 0; offset != portsToCheck; ++offset) { try { udpSocket.bind(ip::udp::endpoint(protocol, inPortNum + offset)); mPortNum = inPortNum + offset; break; } catch (std::exception const & ) { if (offset == (portsToCheck - 1)) throw std::runtime_error("unable to bind udp socket\n"); } } boost::asio::socket_base::send_buffer_size option(65536); udpSocket.set_option(option); startReceiveUDP(); } SC_UdpInPort::~SC_UdpInPort() {} void SC_UdpInPort::startReceiveUDP() { using namespace boost; udpSocket.async_receive_from(asio::buffer(recvBuffer), remoteEndpoint, boost::bind(&SC_UdpInPort::handleReceivedUDP, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); } void SC_UdpInPort::handleReceivedUDP(const boost::system::error_code& error, std::size_t bytesTransferred) { double timeReceived = elapsedTime(); // get time now to minimize jitter due to lang load if (error == boost::asio::error::operation_aborted) return; /* we're done */ if (error == boost::asio::error::connection_refused) { // avoid windows error message startReceiveUDP(); return; } if (error) { printf("SC_UdpInPort: received error - %s\n", error.message().c_str()); startReceiveUDP(); return; } OSC_Packet * packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); packet->mReplyAddr.mProtocol = kUDP; packet->mReplyAddr.mAddress = remoteEndpoint.address(); packet->mReplyAddr.mPort = remoteEndpoint.port(); packet->mReplyAddr.mSocket = udpSocket.native_handle(); char *data = (char*)malloc(bytesTransferred); packet->mSize = bytesTransferred; packet->mData = data; memcpy(data, recvBuffer.data(), bytesTransferred); ProcessOSCPacket(packet, mPortNum, timeReceived); startReceiveUDP(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_UdpCustomInPort::SC_UdpCustomInPort(int inPortNum) : SC_UdpInPort(inPortNum, 1) {} SC_UdpCustomInPort::~SC_UdpCustomInPort() {} ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_TcpInPort::SC_TcpInPort(int inPortNum, int inMaxConnections, int inBacklog): acceptor(ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), inPortNum)), mPortNum(inPortNum) { // FIXME: handle max connections // FIXME: backlog??? startAccept(); } void SC_TcpInPort::startAccept() { SC_TcpConnection::pointer newConnection (new SC_TcpConnection(ioService, this)); acceptor.async_accept(newConnection->socket, boost::bind(&SC_TcpInPort::handleAccept, this, newConnection, boost::asio::placeholders::error)); } void SC_TcpInPort::handleAccept(SC_TcpConnection::pointer newConnection, const boost::system::error_code &error) { if (!error) newConnection->start(); startAccept(); } void SC_TcpConnection::start() { namespace ba = boost::asio; ba::async_read(socket, ba::buffer(&OSCMsgLength, sizeof(OSCMsgLength)), boost::bind(&SC_TcpConnection::handleLengthReceived, shared_from_this(), ba::placeholders::error, ba::placeholders::bytes_transferred)); } void SC_TcpConnection::handleLengthReceived(const boost::system::error_code &error, size_t bytes_transferred) { if (error) return; namespace ba = boost::asio; // msglen is in network byte order OSCMsgLength = sc_ntohl(OSCMsgLength); data = (char*)malloc(OSCMsgLength); ba::async_read(socket, ba::buffer(data, OSCMsgLength), boost::bind(&SC_TcpConnection::handleMsgReceived, shared_from_this(), ba::placeholders::error, ba::placeholders::bytes_transferred)); } void SC_TcpConnection::handleMsgReceived(const boost::system::error_code &error, size_t bytes_transferred) { double timeReceived = elapsedTime(); // get time now to minimize jitter due to lang load if (error) { free(data); return; } assert(bytes_transferred == OSCMsgLength); OSC_Packet * packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); packet->mReplyAddr.mProtocol = kTCP; packet->mReplyAddr.mSocket = socket.native_handle(); packet->mSize = OSCMsgLength; packet->mData = data; ProcessOSCPacket(packet, mParent->mPortNum, timeReceived); start(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SC_TcpClientPort::SC_TcpClientPort(unsigned long inAddress, int inPort, ClientNotifyFunc notifyFunc, void *clientData): socket(ioService), endpoint(boost::asio::ip::address_v4(inAddress), inPort), mClientNotifyFunc(notifyFunc), mClientData(clientData) { using namespace boost::asio; boost::system::error_code error; ip::tcp::no_delay noDelayOption(true); socket.set_option(noDelayOption, error); socket.connect(endpoint); startReceive(); } void SC_TcpClientPort::startReceive() { namespace ba = boost::asio; ba::async_read(socket, ba::buffer(&OSCMsgLength, sizeof(OSCMsgLength)), boost::bind(&SC_TcpClientPort::handleLengthReceived, this, ba::placeholders::error, ba::placeholders::bytes_transferred)); } void SC_TcpClientPort::handleLengthReceived(const boost::system::error_code &error, size_t bytes_transferred) { if (error == boost::asio::error::connection_aborted) { if (mClientNotifyFunc) (*mClientNotifyFunc)(mClientData); } if (error) return; // msglen is in network byte order OSCMsgLength = sc_ntohl(OSCMsgLength); data = (char*)malloc(OSCMsgLength); namespace ba = boost::asio; ba::async_read(socket, ba::buffer(data, OSCMsgLength), boost::bind(&SC_TcpClientPort::handleMsgReceived, this, ba::placeholders::error, ba::placeholders::bytes_transferred)); } void SC_TcpClientPort::handleMsgReceived(const boost::system::error_code &error, size_t bytes_transferred) { double timeReceived = elapsedTime(); // get time now to minimize jitter due to lang load if (error == boost::asio::error::connection_aborted) { if (mClientNotifyFunc) (*mClientNotifyFunc)(mClientData); } if (error) { free(data); return; } assert(bytes_transferred == OSCMsgLength); OSC_Packet * packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); packet->mReplyAddr.mProtocol = kTCP; packet->mReplyAddr.mSocket = socket.native_handle(); packet->mReplyAddr.mAddress = socket.remote_endpoint().address(); packet->mReplyAddr.mPort = socket.remote_endpoint().port(); packet->mSize = OSCMsgLength; packet->mData = data; ProcessOSCPacket(packet, socket.local_endpoint().port(), timeReceived); startReceive(); } int SC_TcpClientPort::Close() { boost::system::error_code error; socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, error); socket.close(); if (error) { if( error != boost::asio::error::not_connected ) { ::error("Socket shutdown failed, closed socket anyway. %s", error.message().c_str() ); return errFailed; } } return errNone; } SuperCollider-Source/lang/LangPrimSource/SC_ComPort.h000644 000765 000024 00000007165 12766171707 023640 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_ComPort_ #define _SC_ComPort_ #include "SC_Types.h" #include #include #include ////////////////////////////////////////////////////////////////////////////////////////////////////////// const int kTextBufSize = 65536; class SC_UdpInPort { int mPortNum; boost::array recvBuffer; boost::asio::ip::udp::endpoint remoteEndpoint; void handleReceivedUDP(const boost::system::error_code& error, std::size_t bytes_transferred); void startReceiveUDP(); public: boost::asio::ip::udp::socket udpSocket; int RealPortNum() const { return mPortNum; } boost::asio::ip::udp::socket & Socket () { return udpSocket; } SC_UdpInPort(int inPortNum, int portsToCheck = 10); ~SC_UdpInPort(); }; class SC_UdpCustomInPort : public SC_UdpInPort { public: SC_UdpCustomInPort(int inPortNum); ~SC_UdpCustomInPort(); }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// class SC_TcpConnection: public boost::enable_shared_from_this { public: typedef boost::shared_ptr pointer; boost::asio::ip::tcp::socket socket; SC_TcpConnection(boost::asio::io_service & ioService, class SC_TcpInPort * parent): socket(ioService), mParent(parent) {} void start(); private: int32 OSCMsgLength; char * data; class SC_TcpInPort * mParent; void handleLengthReceived(const boost::system::error_code& error, size_t bytes_transferred); void handleMsgReceived(const boost::system::error_code& error, size_t bytes_transferred); }; class SC_TcpInPort { boost::asio::ip::tcp::acceptor acceptor; public: const int mPortNum; SC_TcpInPort(int inPortNum, int inMaxConnections, int inBacklog); void startAccept(); void handleAccept(SC_TcpConnection::pointer new_connection, const boost::system::error_code& error); }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// class SC_TcpClientPort { public: typedef void (*ClientNotifyFunc)(void* clientData); public: SC_TcpClientPort(unsigned long inAddress, int inPort, ClientNotifyFunc notifyFunc=0, void* clientData=0); int Close(); boost::asio::ip::tcp::socket & Socket () { return socket; } private: int32 OSCMsgLength; char * data; void startReceive(); void handleLengthReceived(const boost::system::error_code& error, size_t bytes_transferred); void handleMsgReceived(const boost::system::error_code& error, size_t bytes_transferred); boost::asio::ip::tcp::socket socket; boost::asio::ip::tcp::endpoint endpoint; ClientNotifyFunc mClientNotifyFunc; void* mClientData; }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif SuperCollider-Source/lang/LangPrimSource/SC_CoreAudioPrim.cpp000755 000765 000024 00000010446 12756531745 025312 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "SCBase.h" #include "VMGlobals.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "GC.h" enum { OUT = 0, IN, BOTH }; int listDevices(struct VMGlobals *g, int type) { int numDevices, num = 0; PyrSlot *a = g->sp-2; AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; // unsigned long count; UInt32 count; // OSStatus err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0); OSStatus err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count); AudioDeviceID *devices = (AudioDeviceID*)malloc(count); // err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, devices); if (err!=kAudioHardwareNoError) { free(devices); return 0; } numDevices = count / sizeof(AudioDeviceID); int i; if (typegc, num * sizeof(PyrObject), 0, true); SetObject(a, devArray); int j = 0; for (i=0; igc, name, 0, true); SetObject(devArray->slots+j, string); devArray->size++; g->gc->GCWriteNew(devArray, (PyrObject*)string); // we know array is white so we can use GCWriteNew free(name); j++; } free(devices); return 1; } int prListAudioDevices(struct VMGlobals *g, int numArgsPushed) { int in = 0; int out = 0; slotIntVal(g->sp, &out); slotIntVal(g->sp-1, &in); int type; if (in && out) type = BOTH; else if (in) type = IN; else type = OUT; if (listDevices(g, type)) return errNone; return errFailed; } void initCoreAudioPrimitives() { definePrimitive(nextPrimitiveIndex(), 0, "_ListAudioDevices", prListAudioDevices, 3, 0); }SuperCollider-Source/lang/LangPrimSource/SC_CoreMIDI.cpp000644 000765 000024 00000060564 12756531745 024146 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* changes by charles picasso 14/april/2008 (sysex parsing + added running status) changes by jan trutzschler v. f. 9/9/2002 the midiReadProc calls doAction in the class MIDIIn. with the arguments: inUid, status, chan, val1, val2 added prDisposeMIDIClient added prRestartMIDI 19/9 call different actions,disconnect midiInPort, midiout: sendmidi 04/feb/03 prListMIDIEndpoints modification by Ron Kuivila added jt. */ #if SC_IPHONE #include #else #include #include #endif #include #include #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" PyrSymbol* s_domidiaction; PyrSymbol* s_midiNoteOnAction; PyrSymbol* s_midiNoteOffAction; PyrSymbol* s_midiTouchAction; PyrSymbol* s_midiControlAction; PyrSymbol* s_midiPolyTouchAction; PyrSymbol* s_midiProgramAction; PyrSymbol* s_midiBendAction; PyrSymbol* s_midiSysexAction; PyrSymbol* s_midiInvalidSysexAction; PyrSymbol* s_midiSysrtAction; PyrSymbol* s_midiSMPTEAction; //jt PyrSymbol * s_midiin; PyrSymbol * s_numMIDIDev; PyrSymbol * s_midiclient; const int kMaxMidiPorts = 16; MIDIClientRef gMIDIClient = 0; MIDIPortRef gMIDIInPort[kMaxMidiPorts], gMIDIOutPort[kMaxMidiPorts]; int gNumMIDIInPorts = 0, gNumMIDIOutPorts = 0; bool gMIDIInitialized = false; //cp static bool gSysexFlag = false; static Byte gRunningStatus = 0; std::vector gSysexData; void midiNotifyProc(const MIDINotification *msg, void* refCon) { } extern bool compiledOK; #if 0 static void dumpSysexData() { if(gSysexData.size() <= 0) return; std::vector::const_iterator iter = gSysexData.begin(), end = gSysexData.end(); int i=0; while(iter != end) { if((i % 16) == 0 && (i > 0)) printf("\n"); ++i; printf("%02X ", *iter++); } printf("\n"); printf("sysex data dump size: %i bytes.\n", gSysexData.size()); } #endif static void sysexBegin() { gRunningStatus = 0; // clear running status gSysexData.clear(); gSysexFlag = true; } static void scCallSysexAction(PyrSymbol* action, int recoverFromUID) { VMGlobals *g = gMainVMGlobals; if(recoverFromUID) { // rebuild the VM so sc won't crash with two following calls ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn ++g->sp; SetInt(g->sp, recoverFromUID); //src ++g->sp; } PyrInt8Array* sysexArray = newPyrInt8Array(g->gc, gSysexData.size(), 0, true); sysexArray->size = gSysexData.size(); std::copy(gSysexData.begin(), gSysexData.end(), sysexArray->b); SetObject(g->sp, (PyrObject*) sysexArray); // chan argument unneeded as there runInterpreter(g, action, 3 ); // special sysex action in the lang } static void sysexEnd(int lastUID) { gSysexFlag = false; scCallSysexAction(s_midiSysexAction, lastUID); } static void sysexEndInvalid() { gSysexFlag = false; scCallSysexAction(s_midiInvalidSysexAction, 0); } static int midiProcessSystemPacket(MIDIPacket *pkt, int chan) { int index, data; VMGlobals *g = gMainVMGlobals; switch (chan) { case 7: // added cp: Sysex EOX must be taken into account if first on data packet case 0: { int last_uid = 0; int m = pkt->length; Byte* p_pkt = pkt->data; Byte pktval; while(m--) { pktval = *p_pkt++; if(pktval & 0x80) { // status byte if(pktval == 0xF7) { // end packet gSysexData.push_back(pktval); // add EOX if(gSysexFlag) sysexEnd(last_uid); // if last_uid != 0 rebuild the VM. else sysexEndInvalid(); // invalid 1 byte with only EOX can happen break; } else if(pktval == 0xF0) { // new packet if(gSysexFlag) {// invalid new one/should not happen -- but handle in case // store the last uid value previous to invalid data to rebuild VM after sysexEndInvalid call // since it may call sysexEnd() just after it ! if(slotIntVal(g->sp-1, &last_uid)) { post("error: failed retrieving uid value !"); last_uid = -1; } sysexEndInvalid(); } sysexBegin(); // new sysex in gSysexData.push_back(pktval); // add SOX } else {// abnormal data in middle of sysex packet gSysexData.push_back(pktval); // add it as an abort message sysexEndInvalid(); // flush invalid m = 0; // discard all packet break; } } else if(gSysexFlag) gSysexData.push_back(pktval); // add Byte else // garbage - handle in case - discard it break; } return (pkt->length-m); } break; case 1 : index = pkt->data[1] >> 4; data = pkt->data[1] & 0xf; switch (index) { case 1: case 3: case 5: case 7: { data = data << 4; } } SetInt(g->sp, index); // chan unneeded ++g->sp; SetInt(g->sp, data); // special smpte action in the lang runInterpreter(g, s_midiSMPTEAction, 4 ); return 2; case 2 : //songptr ++g->sp; SetInt(g->sp, (pkt->data[2] << 7) | pkt->data[1]); //val1 runInterpreter(g, s_midiSysrtAction, 4); return 3; case 3 : // song select ++g->sp; SetInt(g->sp, pkt->data[1]); //val1 runInterpreter(g, s_midiSysrtAction, 4); return 2; case 6: //tunerequest case 8: //clock case 9: //tick case 10: //start case 11: //continue case 12: //stop case 14: //activeSense case 15: //reset gRunningStatus = 0; // clear running status runInterpreter(g, s_midiSysrtAction, 3); return 1; default: g->sp -= 3; // nevermind break; } return (1); } static void midiProcessPacket(MIDIPacket *pkt, size_t uid) { //jt if(pkt) { gLangMutex.lock(); //dont know if this is really needed/seems to be more stable.. // it is needed -jamesmcc if (compiledOK) { VMGlobals *g = gMainVMGlobals; int i = 0; //cp : changed uint8 to int if packet->length >= 256 bug:(infinite loop) while (i < pkt->length) { uint8 status = pkt->data[i] & 0xF0; uint8 chan = pkt->data[i] & 0x0F; g->canCallOS = false; // cannot call the OS ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn //set arguments: ++g->sp; SetInt(g->sp, uid); //src // ++g->sp; SetInt(g->sp, status); //status ++g->sp; SetInt(g->sp, chan); //chan if(status & 0x80) // set the running status for voice messages gRunningStatus = ((status >> 4) == 0xF) ? 0 : pkt->data[i]; // keep also additional info L: switch (status) { case 0x80 : //noteOff ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiNoteOffAction, 5); i += 3; break; case 0x90 : //noteOn ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 // runInterpreter(g, pkt->data[i+2] ? s_midiNoteOnAction : s_midiNoteOffAction, 5); runInterpreter(g, s_midiNoteOnAction, 5); i += 3; break; case 0xA0 : //polytouch ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiPolyTouchAction, 5); i += 3; break; case 0xB0 : //control ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 ++g->sp; SetInt(g->sp, pkt->data[i+2]); //val2 runInterpreter(g, s_midiControlAction, 5); i += 3; break; case 0xC0 : //program ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 runInterpreter(g, s_midiProgramAction, 4); i += 2; break; case 0xD0 : //touch ++g->sp; SetInt(g->sp, pkt->data[i+1]); //val1 runInterpreter(g, s_midiTouchAction, 4); i += 2; break; case 0xE0 : //bend ++g->sp; SetInt(g->sp, (pkt->data[i+2] << 7) | pkt->data[i+1]); //val1 runInterpreter(g, s_midiBendAction, 4); i += 3; break; case 0xF0 : i += midiProcessSystemPacket(pkt, chan); break; default : // data byte => continuing sysex message if(gRunningStatus && !gSysexFlag) { // modified cp: handling running status. may be we should here status = gRunningStatus & 0xF0; // accept running status only inside a packet beginning chan = gRunningStatus & 0x0F; // with a valid status byte ? SetInt(g->sp, chan); --i; goto L; // parse again with running status set } chan = 0; i += midiProcessSystemPacket(pkt, chan); break; } } g->canCallOS = false; } gLangMutex.unlock(); } } static void midiReadProc(const MIDIPacketList *pktlist, void* readProcRefCon, void* srcConnRefCon) { MIDIPacket *pkt = (MIDIPacket*)pktlist->packet; size_t uid = (size_t) srcConnRefCon; for (uint32 i=0; inumPackets; ++i) { midiProcessPacket(pkt, uid); pkt = MIDIPacketNext(pkt); } } int midiCleanUp(); int initMIDI(int numIn, int numOut) { OSStatus err; CFAllocatorRef alloc = CFAllocatorGetDefault(); int enc = kCFStringEncodingMacRoman; midiCleanUp(); numIn = sc_clip(numIn, 1, kMaxMidiPorts); numOut = sc_clip(numOut, 1, kMaxMidiPorts); if (!gMIDIClient) { CFStringRef clientName = CFStringCreateWithCString(alloc, "SuperCollider", enc); err = MIDIClientCreate(clientName, midiNotifyProc, nil, &gMIDIClient); if (err) { post("Could not create MIDI client. error: "); return errFailed; } CFRelease(clientName); } for (int i=0; isp; int numSrc = MIDIGetNumberOfSources(); int numDst = MIDIGetNumberOfDestinations(); PyrObject* idarray = newPyrArray(g->gc, 6 * sizeof(PyrObject), 0 , true); SetObject(a, idarray); PyrObject* idarraySo = newPyrArray(g->gc, numSrc * sizeof(SInt32), 0 , true); SetObject(idarray->slots+idarray->size++, idarraySo); g->gc->GCWriteNew(idarray, idarraySo); // we know idarraySo is white so we can use GCWriteNew PyrObject* devarraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarraySo); g->gc->GCWriteNew(idarray, devarraySo); // we know devarraySo is white so we can use GCWriteNew PyrObject* namearraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearraySo); g->gc->GCWriteNew(idarray, namearraySo); // we know namearraySo is white so we can use GCWriteNew PyrObject* idarrayDe = newPyrArray(g->gc, numDst * sizeof(SInt32), 0 , true); SetObject(idarray->slots+idarray->size++, idarrayDe); g->gc->GCWriteNew(idarray, idarrayDe); // we know idarrayDe is white so we can use GCWriteNew PyrObject* namearrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearrayDe); g->gc->GCWriteNew(idarray, namearrayDe); // we know namearrayDe is white so we can use GCWriteNew PyrObject* devarrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarrayDe); g->gc->GCWriteNew(idarray, devarrayDe); // we know devarrayDe is white so we can use GCWriteNew for (int i=0; igc, cendname, 0, true); SetObject(namearraySo->slots+i, string); namearraySo->size++; g->gc->GCWriteNew(namearraySo, (PyrObject*)string); // we know string is white so we can use GCWriteNew PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarraySo->slots+i, devstring); devarraySo->size++; g->gc->GCWriteNew(devarraySo, (PyrObject*)devstring); // we know devString is white so we can use GCWriteNew SetInt(idarraySo->slots+i, id); idarraySo->size++; if (devname) CFRelease(devname); if (endname) CFRelease(endname); } // post("numDst %d\n", numDst); for (int i=0; igc, cendname, 0, true); SetObject(namearrayDe->slots+namearrayDe->size++, string); g->gc->GCWriteNew(namearrayDe, (PyrObject*)string); // we know string is white so we can use GCWriteNew PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarrayDe->slots+devarrayDe->size++, devstring); g->gc->GCWriteNew(devarrayDe, (PyrObject*)devstring); // we know devstring is white so we can use GCWriteNew SetInt(idarrayDe->slots+idarrayDe->size++, id); if (devname) CFRelease(devname); if (endname) CFRelease(endname); } return errNone; } int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return errWrongType; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return errWrongType; MIDIEndpointRef src=0; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, &src, &mtype); if (mtype != kMIDIObjectType_Source) return errFailed; //pass the uid to the midiReadProc to identify the src MIDIPortConnectSource(gMIDIInPort[inputIndex], src, (void*)uid); return errNone; } int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed); int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return err; MIDIEndpointRef src=0; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, &src, &mtype); if (mtype != kMIDIObjectType_Source) return errFailed; MIDIPortDisconnectSource(gMIDIInPort[inputIndex], src); return errNone; } int prInitMIDI(struct VMGlobals *g, int numArgsPushed); int prInitMIDI(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, numIn, numOut; err = slotIntVal(b, &numIn); if (err) return errWrongType; err = slotIntVal(c, &numOut); if (err) return errWrongType; return initMIDI(numIn, numOut); } int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed); int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed) { return midiCleanUp(); } int prRestartMIDI(VMGlobals *g, int numArgsPushed); int prRestartMIDI(VMGlobals *g, int numArgsPushed) { MIDIRestart(); return errNone; } void freeSysex(MIDISysexSendRequest* pk); void freeSysex(MIDISysexSendRequest* pk) { free(pk); } int prSendSysex(VMGlobals *g, int numArgsPushed); int prSendSysex(VMGlobals *g, int numArgsPushed) { int err, uid, size; if( !isKindOfSlot(g->sp, s_int8array->u.classobj) ) return errWrongType; PyrInt8Array* packet = slotRawInt8Array(g->sp); size = packet->size; PyrSlot *u = g->sp - 1; err = slotIntVal(u, &uid); if (err) return err; MIDIEndpointRef dest; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&dest, &mtype); if (mtype != kMIDIObjectType_Destination) return errFailed; if (!dest) return errFailed; MIDISysexSendRequest *pk = (MIDISysexSendRequest*) malloc (sizeof(MIDISysexSendRequest) + size); Byte *data = (Byte *)pk + sizeof(MIDISysexSendRequest); memcpy(data,packet->b, size); pk->complete = false; pk -> destination = dest; pk -> data = data; pk -> bytesToSend = size; pk->completionProc = freeSysex; pk->completionRefCon = 0; return ((MIDISendSysex(pk) == (OSStatus)0) ? errNone : errFailed); } #if SC_IPHONE static struct mach_timebase_info machTimebaseInfo() { struct mach_timebase_info info; mach_timebase_info(&info); return info; } static MIDITimeStamp midiTime(float latencySeconds) { // add the latency expressed in seconds, to the current host time base. static struct mach_timebase_info info = machTimebaseInfo(); // cache the timebase info. Float64 latencyNanos = 1000000000 * latencySeconds; MIDITimeStamp latencyMIDI = (latencyNanos / (Float64)info.numer) * (Float64)info.denom; return (MIDITimeStamp)mach_absolute_time() + latencyMIDI; } #else static MIDITimeStamp midiTime(float latencySeconds) { // add the latency expressed in seconds, to the current host time base. UInt64 latencyNanos = 1000000000 * latencySeconds ; //secs to nano return (MIDITimeStamp)AudioGetCurrentHostTime() + AudioConvertNanosToHostTime(latencyNanos); } #endif void sendmidi(int port, MIDIEndpointRef dest, int length, int hiStatus, int loStatus, int aval, int bval, float late); void sendmidi(int port, MIDIEndpointRef dest, int length, int hiStatus, int loStatus, int aval, int bval, float late) { MIDIPacketList mpktlist; MIDIPacketList * pktlist = &mpktlist; MIDIPacket * pk = MIDIPacketListInit(pktlist); ByteCount nData = (ByteCount) length; pk->data[0] = (Byte) (hiStatus & 0xF0) | (loStatus & 0x0F); pk->data[1] = (Byte) aval; pk->data[2] = (Byte) bval; pk = MIDIPacketListAdd(pktlist, sizeof(struct MIDIPacketList) , pk, midiTime(late), nData, pk->data); /*OSStatus error =*/ MIDISend(gMIDIOutPort[port], dest, pktlist ); } int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed); int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed) { //port, uid, len, hiStatus, loStatus, a, b, latency //PyrSlot *m = g->sp - 8; PyrSlot *p = g->sp - 7; PyrSlot *u = g->sp - 6; PyrSlot *l = g->sp - 5; PyrSlot *his = g->sp - 4; PyrSlot *los = g->sp - 3; PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *plat = g->sp; int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval; float late; err = slotIntVal(p, &outputIndex); if (err) return err; if (outputIndex < 0 || outputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(u, &uid); if (err) return err; err = slotIntVal(l, &length); if (err) return err; err = slotIntVal(his, &hiStatus); if (err) return err; err = slotIntVal(los, &loStatus); if (err) return err; err = slotIntVal(a, &aval); if (err) return err; err = slotIntVal(b, &bval); if (err) return err; err = slotFloatVal(plat, &late); if (err) return err; MIDIEndpointRef dest; MIDIObjectType mtype; MIDIObjectFindByUniqueID(uid, (MIDIObjectRef*)&dest, &mtype); if (mtype != kMIDIObjectType_Destination) return errFailed; if (!dest) return errFailed; sendmidi(outputIndex, dest, length, hiStatus, loStatus, aval, bval, late); return errNone; } // not needed in CoreMIDI: int initMIDIClient() { return errNone; } int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed); int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed) { return initMIDIClient(); } //-------------- void initMIDIPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; gSysexData.reserve(1024); s_midiin = getsym("MIDIIn"); s_domidiaction = getsym("doAction"); s_midiNoteOnAction = getsym("doNoteOnAction"); s_midiNoteOffAction = getsym("doNoteOffAction"); s_midiTouchAction = getsym("doTouchAction"); s_midiControlAction = getsym("doControlAction"); s_midiPolyTouchAction = getsym("doPolyTouchAction"); s_midiProgramAction = getsym("doProgramAction"); s_midiBendAction = getsym("doBendAction"); s_midiSysexAction = getsym("doSysexAction"); s_midiInvalidSysexAction = getsym("doInvalidSysexAction"); // client can handle incorrect case s_midiSysrtAction = getsym("doSysrtAction"); s_midiSMPTEAction = getsym("doSMPTEaction"); s_numMIDIDev = getsym("prSetNumberOfDevices"); s_midiclient = getsym("MIDIClient"); definePrimitive(base, index++, "_ListMIDIEndpoints", prListMIDIEndpoints, 1, 0); definePrimitive(base, index++, "_InitMIDI", prInitMIDI, 3, 0); definePrimitive(base, index++, "_InitMIDIClient", prInitMIDIClient, 1, 0); definePrimitive(base, index++, "_ConnectMIDIIn", prConnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIIn", prDisconnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisposeMIDIClient", prDisposeMIDIClient, 1, 0); definePrimitive(base, index++, "_RestartMIDI", prRestartMIDI, 1, 0); definePrimitive(base, index++, "_SendMIDIOut", prSendMIDIOut, 9, 0); definePrimitive(base, index++, "_SendSysex", prSendSysex, 3, 0); if(gMIDIClient) midiCleanUp(); } SuperCollider-Source/lang/LangPrimSource/SC_FIFO.h000644 000765 000024 00000004723 12321461511 022753 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SC_FIFO_H_INCLUDED #define SC_FIFO_H_INCLUDED #ifdef __APPLE__ # include #endif #ifdef _WIN32 # include # include #endif template class SC_FIFO { public: SC_FIFO() : mMask(N - 1), mReadHead(0), mWriteHead(0) {} void MakeEmpty() { mReadHead = mWriteHead; } bool IsEmpty() { return mReadHead == mWriteHead; } bool HasData() { return mReadHead != mWriteHead; } bool Put(T data) { long next = NextPos(mWriteHead); if (next == mReadHead) return false; // fifo is full mItems[next] = data; #ifdef __APPLE__ // we don't really need a compare and swap, but this happens to call // the PowerPC memory barrier instruction lwsync. OSAtomicCompareAndSwap32Barrier(mWriteHead, next, &mWriteHead); #elif defined(_WIN32) InterlockedExchange(reinterpret_cast(&mWriteHead),next); #else mWriteHead = next; #endif return true; } T Get() { //assert(HasData()); long next = NextPos(mReadHead); T out = mItems[next]; #ifdef __APPLE__ // we don't really need a compare and swap, but this happens to call // the PowerPC memory barrier instruction lwsync. OSAtomicCompareAndSwap32Barrier(mReadHead, next, &mReadHead); #elif defined(_WIN32) InterlockedExchange(reinterpret_cast(&mReadHead),next); #else mReadHead = next; #endif return out; } int Capacity() const { return N; } private: int NextPos(int inPos) { return (inPos + 1) & mMask; } long mMask; #ifdef __APPLE__ int32_t mReadHead, mWriteHead; #else volatile int mReadHead, mWriteHead; #endif T mItems[N]; }; #endif // SC_FIFO_H_INCLUDED SuperCollider-Source/lang/LangPrimSource/SC_HID_api.cpp000644 000765 000024 00000071511 12756531745 024042 0ustar00crucialstaff000000 000000 /* HIDAPI based HID support. Copyright (c) 2013 Marije Baalman, Tim Blechmann ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include #include #include "SC_LanguageClient.h" extern bool compiledOK; #ifdef HAVE_HIDAPI #if 1 static inline void trace(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vpost(fmt, ap); } #else static inline void trace(...) {} #endif // needed for string conversions #include #include #include #include #include typedef std::map hid_map_t; // helper function to convert from unicode to ansi char * wchar_to_char( wchar_t * wchs ) { if (wchs == nullptr) return nullptr; int len = wcslen( wchs ) + 1; char * chs = (char*) malloc( sizeof(char) * len ); std::wcstombs( chs, wchs, len ); return chs; } wchar_t * char_to_wchar( char * chs ) { if (chs == nullptr) return nullptr; int len = std::strlen( chs ) + 1; wchar_t * wchs = (wchar_t*) malloc( sizeof( wchar_t ) * len ); std::mbstowcs( wchs, chs, len ); return wchs; } static PyrSymbol* s_hidapi = nullptr; static PyrSymbol* s_hidElementData = nullptr; static PyrSymbol* s_hidDeviceData = nullptr; static PyrSymbol* s_hidClosed = nullptr; class SC_HID_API_Threadpool { typedef std::map ThreadMap; public: void openDevice(hid_dev_desc * desc, std::atomic &shouldBeRunning) { trace("open device %p\n"); std::lock_guard lock(guard); if (map.find(desc) != map.end()) // thread already polling device return; std::thread deviceThread( [=, &shouldBeRunning] { trace("start polling thread for %d\n", desc); while( true ) { unsigned char buf[256]; int res = hid_read_timeout( desc->device, buf, sizeof(buf), 250); if ( res > 0 ) { hid_parse_input_report( buf, res, desc ); } else if (res == -1) { trace("device thread interrupted \n"); hid_throw_readerror( desc ); trace("device thread closed device \n"); return; } } std::lock_guard lock_(guard); auto it = map.find(desc); std::thread thisThread = std::move( it->second ); map.erase(it); thisThread.detach(); }); map.emplace( desc, std::move(deviceThread) ); } void closeDevice(hid_dev_desc * desc) { std::thread thread; { std::lock_guard lock(guard); auto it = map.find(desc); if (it == map.end()) { std::printf("device already closed %p\n", desc->device); return; } thread = std::move(it->second); } thread.detach(); hid_close_device( desc ); trace("close device: interrupted \n"); } private: ThreadMap map; std::mutex guard; }; struct SC_HID_APIManager { public: static SC_HID_APIManager& instance(); int init(); int closeAll(); int build_devicelist(); int free_devicelist(); int open_device_path( const char * path, int vendor, int product ); int open_device( int vendor, int product, char * serial_number=NULL ); int close_device( int joy_idx ); void close_all_devices(); struct hid_dev_desc * get_device( int joy_idx ); void setPyrObject( PyrObject * obj ); SC_HID_APIManager(); ~SC_HID_APIManager(); int initialize_hidapi(); void elementData( int, struct hid_device_element * ); void deviceData( int, struct hid_dev_desc * ); void deviceRepetitiveReadError( int, struct hid_dev_desc * ); struct hid_device_info *devinfos; protected: void handleDevice( int, struct hid_dev_desc *, std::atomic const & shouldBeRunning); void handleElement( int, struct hid_device_element *, std::atomic const & shouldBeRunning); void deviceClosed( int, struct hid_dev_desc *, std::atomic const & shouldBeRunning); private: hid_map_t hiddevices; // declares a vector of hiddevices int number_of_hids; // language interface PyrObject* m_obj; std::atomic m_running; std::atomic mShouldBeRunning; SC_HID_API_Threadpool mThreads; }; static void hid_element_cb( struct hid_device_element *el, void *data) { SC_HID_APIManager::instance().elementData( *((int*) data), el ); } static void hid_descriptor_cb( struct hid_dev_desc *dd, void *data) { SC_HID_APIManager::instance().deviceData( *((int*) data), dd ); } void hid_readerror_cb(hid_dev_desc* dd, void* data) { SC_HID_APIManager::instance().deviceRepetitiveReadError( *((int*) data), dd ); } void SC_HID_APIManager::deviceData( int id, struct hid_dev_desc * dd ){ handleDevice( id, dd, mShouldBeRunning ); } void SC_HID_APIManager::elementData( int id, struct hid_device_element * ele ) { handleElement( id, ele, mShouldBeRunning ); } void SC_HID_APIManager::deviceRepetitiveReadError( int id, struct hid_dev_desc * dd ){ deviceClosed( id, dd, mShouldBeRunning ); // hiddevices.erase( id ); } void SC_HID_APIManager::setPyrObject( PyrObject * obj ){ m_obj = obj; } void SC_HID_APIManager::close_all_devices() { for ( auto elem : hiddevices ) mThreads.closeDevice( elem.second ); hiddevices.clear(); } int SC_HID_APIManager::open_device_path( const char * path, int vendor, int product ){ // struct hid_dev_desc * newdevdesc; newdevdesc = hid_open_device_path( path, vendor, product ); if (!newdevdesc){ post( "HIDAPI : Unable to open device %s: %d, %d\n", path, vendor, product ); return -1; } else { hiddevices.insert( std::pair(number_of_hids, newdevdesc) ); newdevdesc->index = number_of_hids; hid_set_descriptor_callback( newdevdesc, (hid_descriptor_callback) hid_descriptor_cb, &newdevdesc->index ); hid_set_readerror_callback( newdevdesc, (hid_device_readerror_callback) hid_readerror_cb, &newdevdesc->index ); hid_set_element_callback( newdevdesc, (hid_element_callback) hid_element_cb, &newdevdesc->index ); number_of_hids++; mThreads.openDevice(newdevdesc, mShouldBeRunning); return newdevdesc->index; } } int SC_HID_APIManager::open_device( int vendor, int product, char* serial_number ){ // struct hid_dev_desc * newdevdesc; if ( serial_number != NULL ){ wchar_t * serialW = char_to_wchar( serial_number ); newdevdesc = hid_open_device( vendor, product, serialW ); free(serialW); } else { newdevdesc = hid_open_device( vendor, product, NULL ); } if (!newdevdesc){ post( "HIDAPI: Unable to open device %d, %d %s\n", vendor, product, serial_number ); return -1; } else { hiddevices.insert( std::pair(number_of_hids, newdevdesc) ); newdevdesc->index = number_of_hids; hid_set_descriptor_callback( newdevdesc, (hid_descriptor_callback) hid_descriptor_cb, &newdevdesc->index ); hid_set_readerror_callback( newdevdesc, (hid_device_readerror_callback) hid_readerror_cb, &newdevdesc->index ); hid_set_element_callback( newdevdesc, (hid_element_callback) hid_element_cb, &newdevdesc->index ); number_of_hids++; mThreads.openDevice(newdevdesc, mShouldBeRunning); return newdevdesc->index; } } int SC_HID_APIManager::close_device( int joy_idx ){ struct hid_dev_desc * hidtoclose = get_device( joy_idx ); if ( hidtoclose == NULL ){ post( "HIDAPI: could not find device to close %d\n", joy_idx); return 1; // not a fatal error } else { mThreads.closeDevice(hidtoclose); hiddevices.erase( joy_idx ); } return 1; } struct hid_dev_desc * SC_HID_APIManager::get_device( int joy_idx ){ auto iterator = hiddevices.find( joy_idx ); if (iterator == hiddevices.end()) { post( "HIDAPI : device was not open %d\n", joy_idx); return NULL; } return hiddevices.find( joy_idx )->second; } SC_HID_APIManager& SC_HID_APIManager::instance() { static SC_HID_APIManager instance; return instance; } SC_HID_APIManager::SC_HID_APIManager() : m_running(false) { number_of_hids = 0; } SC_HID_APIManager::~SC_HID_APIManager() { close_all_devices(); } int SC_HID_APIManager::init() { int result; number_of_hids = 0; mShouldBeRunning = true; if ( !m_running ){ result = initialize_hidapi(); } if ( !m_running ){ return errFailed; } return result; } int SC_HID_APIManager::closeAll() { m_running = false; mShouldBeRunning = false; close_all_devices(); return errNone; } int SC_HID_APIManager::initialize_hidapi(){ m_running = false; if (hid_init()){ post( "Unable to initialize hidapi\n"); return errFailed; } m_running = true; return errNone; } int SC_HID_APIManager::build_devicelist(){ struct hid_device_info *cur_dev; devinfos = hid_enumerate(0x0, 0x0); cur_dev = devinfos; int count = 0; while (cur_dev) { count++; cur_dev = cur_dev->next; } return count; } int SC_HID_APIManager::free_devicelist(){ hid_free_enumeration(devinfos); devinfos = NULL; return errNone; } void SC_HID_APIManager::deviceClosed( int joy_idx, struct hid_dev_desc * dd, std::atomic const & shouldBeRunning ){ int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { trace("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, s_hidapi->u.classobj ); // set the class HID_API ++g->sp; SetInt(g->sp, joy_idx ); runInterpreter(g, s_hidClosed, 2); g->canCallOS = false; } gLangMutex.unlock(); } void SC_HID_APIManager::handleElement( int joy_idx, struct hid_device_element * ele, std::atomic const & shouldBeRunning ){ int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, s_hidapi->u.classobj ); // set the class HID_API ++g->sp; SetInt(g->sp, joy_idx ); ++g->sp; SetInt(g->sp, ele->index ); ++g->sp; SetInt(g->sp, ele->usage_page ); ++g->sp; SetInt(g->sp, ele->usage ); ++g->sp; SetInt(g->sp, ele->value ); ++g->sp; SetFloat(g->sp, hid_element_map_logical( ele ) ); ++g->sp; SetFloat(g->sp, hid_element_map_physical( ele ) ); ++g->sp; SetInt(g->sp, ele->array_value ); runInterpreter(g, s_hidElementData, 9 ); g->canCallOS = false; } gLangMutex.unlock(); } void SC_HID_APIManager::handleDevice( int joy_idx, struct hid_dev_desc * devd, std::atomic const & shouldBeRunning ){ int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, s_hidapi->u.classobj ); // set the class HID_API ++g->sp; SetInt(g->sp, joy_idx ); ++g->sp; SetInt(g->sp, devd->device_collection->num_elements ); runInterpreter(g, s_hidDeviceData, 3); g->canCallOS = false; } gLangMutex.unlock(); } // ---------- primitive calls: --------------- int prHID_API_Initialize(VMGlobals* g, int numArgsPushed) { PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot *self = args + 0; SC_HID_APIManager::instance().setPyrObject( slotRawObject(self) ); // initialize HID_APIManager return SC_HID_APIManager::instance().init(); } int prHID_API_CloseAll(VMGlobals* g, int numArgsPushed) { // close all devices, and cleanup manager return SC_HID_APIManager::instance().closeAll(); } int prHID_API_BuildDeviceList(VMGlobals* g, int numArgsPushed){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot *self = args + 0; // no arguments int err; const char emptyString[] = ""; // iterate over available devices and return info to language to populate the list there int result = SC_HID_APIManager::instance().build_devicelist(); if ( result > 0 ){ PyrObject* allDevsArray = newPyrArray(g->gc, result * sizeof(PyrObject), 0 , true); SetObject( self, allDevsArray ); struct hid_device_info *cur_dev = SC_HID_APIManager::instance().devinfos; while( cur_dev ){ PyrObject* devInfo = newPyrArray(g->gc, 11 * sizeof(PyrObject), 0 , true); SetObject(allDevsArray->slots+allDevsArray->size++, devInfo ); g->gc->GCWriteNew(allDevsArray, devInfo); // we know devInfo is white so we can use GCWriteNew SetInt(devInfo->slots+devInfo->size++, cur_dev->vendor_id); SetInt(devInfo->slots+devInfo->size++, cur_dev->product_id); PyrString *dev_path_name = newPyrString(g->gc, cur_dev->path, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_path_name); g->gc->GCWriteNew(devInfo, dev_path_name); // we know dev_path_name is white so we can use GCWriteNew const char * mystring; if ( cur_dev->serial_number != NULL ) mystring = wchar_to_char( cur_dev->serial_number ); else mystring = emptyString; PyrString *dev_serial = newPyrString(g->gc, mystring, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_serial); g->gc->GCWriteNew(devInfo, dev_serial); // we know dev_serial is white so we can use GCWriteNew if (mystring != emptyString) free((void*)mystring); if ( cur_dev->manufacturer_string != NULL ) mystring = wchar_to_char( cur_dev->manufacturer_string ); else mystring = emptyString; PyrString *dev_man_name = newPyrString(g->gc, mystring, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_man_name); g->gc->GCWriteNew(devInfo, dev_man_name); // we know dev_man_name is white so we can use GCWriteNew if (mystring != emptyString) free((void*)mystring); if ( cur_dev->product_string != NULL ) mystring = wchar_to_char( cur_dev->product_string ); else mystring = emptyString; PyrString *dev_prod_name = newPyrString(g->gc, mystring, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_prod_name); g->gc->GCWriteNew(devInfo, dev_prod_name); // we know dev_prod_name is white so we can use GCWriteNew if (mystring != emptyString) free((void*)mystring); SetInt(devInfo->slots+devInfo->size++, cur_dev->release_number); SetInt(devInfo->slots+devInfo->size++, cur_dev->interface_number); SetInt(devInfo->slots+devInfo->size++, cur_dev->usage_page); SetInt(devInfo->slots+devInfo->size++, cur_dev->usage); cur_dev = cur_dev->next; } SC_HID_APIManager::instance().free_devicelist(); } else { // send back info that no devices were found, or empty array SetInt( self, 0 ); } return errNone; } int prHID_API_Open( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg1 = args + 1; PyrSlot* arg2 = args + 2; PyrSlot* arg3 = args + 3; int err; char path[256]; int vendorid; int productid; // char serial_number[256]; // could also use serial_number as specification to open device, but this is not working yet err = slotIntVal( arg1, &vendorid ); if ( err != errNone ) return err; err = slotIntVal( arg2, &productid ); if ( err != errNone ) return err; int result; err = slotStrVal(arg3, path, sizeof(path)); if (err) return err; result = SC_HID_APIManager::instance().open_device_path( path, vendorid, productid ); /* // could also use serial_number as specification to open device, but this is not working yet if ( NotNil( arg3 ) ){ err = slotStrVal(arg3, serial_number, sizeof(serial_number)); if (err) return err; // open device result = SC_HID_APIManager::instance().open_device( vendorid, productid, serial_number ); } else { // open device result = SC_HID_APIManager::instance().open_device( vendorid, productid, NULL ); } */ SetInt( self, result ); return errNone; } int prHID_API_Close( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg = args + 1; int err; int joyid; err = slotIntVal( arg, &joyid ); if ( err != errNone ) return err; int result = SC_HID_APIManager::instance().close_device( joyid ); SetInt( self, result ); return errNone; } int prHID_API_GetInfo( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg = args + 1; int err; int joyid; err = slotIntVal( arg, &joyid ); if ( err != errNone ) return err; const char emptyString[] = ""; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_info * cur_dev = devdesc->info; if ( cur_dev != NULL ){ PyrObject* devInfo = newPyrArray(g->gc, 9 * sizeof(PyrObject), 0 , true); SetObject( self, devInfo ); SetInt(devInfo->slots+devInfo->size++, cur_dev->vendor_id); SetInt(devInfo->slots+devInfo->size++, cur_dev->product_id); PyrString *dev_path_name = newPyrString(g->gc, cur_dev->path, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_path_name); g->gc->GCWriteNew(devInfo, dev_path_name); // we know dev_path_name is white so we can use GCWriteNew const char * mystring; if ( cur_dev->serial_number != NULL ){ mystring = wchar_to_char( cur_dev->serial_number ); } else { mystring = emptyString; } PyrString *dev_serial = newPyrString(g->gc, mystring, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_serial); g->gc->GCWriteNew(devInfo, dev_serial); // we know dev_serial is white so we can use GCWriteNew if (mystring != emptyString) free((void*)mystring); if ( cur_dev->manufacturer_string != NULL ){ mystring = wchar_to_char( cur_dev->manufacturer_string ); } else { mystring = emptyString; } PyrString *dev_man_name = newPyrString(g->gc, mystring, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_man_name); g->gc->GCWriteNew(devInfo, dev_man_name); // we know dev_man_name is white so we can use GCWriteNew if (mystring != emptyString) free((void*)mystring); if ( cur_dev->product_string != NULL ){ mystring = wchar_to_char( cur_dev->product_string ); } else { mystring = emptyString; } PyrString *dev_prod_name = newPyrString(g->gc, mystring, 0, true ); SetObject(devInfo->slots+devInfo->size++, dev_prod_name); g->gc->GCWriteNew(devInfo, dev_prod_name); // we know dev_prod_name is white so we can use GCWriteNew if (mystring != emptyString) free((void*)mystring); SetInt(devInfo->slots+devInfo->size++, cur_dev->release_number); SetInt(devInfo->slots+devInfo->size++, cur_dev->interface_number); } else { SetInt( self, 0 ); } return errNone; } int prHID_API_GetNumberOfCollections( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg = args + 1; int err; int joyid; err = slotIntVal( arg, &joyid ); if ( err != errNone ) return err; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_collection * cur_dev = devdesc->device_collection; if ( cur_dev != NULL ){ SetInt( self, cur_dev->num_collections ); } else { SetInt( self, 0 ); } return errNone; } int prHID_API_GetCollectionInfo( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg1 = args + 1; PyrSlot* arg2 = args + 2; int err; int joyid; int collectionid; err = slotIntVal( arg1, &joyid ); if ( err != errNone ) return err; err = slotIntVal( arg2, &collectionid ); if ( err != errNone ) return err; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_collection * curdev = devdesc->device_collection; struct hid_device_collection * curcollection = curdev->first_collection; struct hid_device_collection * thiscollection = NULL; bool found = curcollection->index == collectionid; if ( found ){ thiscollection = curcollection; } while( curcollection != NULL && !found ){ found = curcollection->index == collectionid; if ( found ){ thiscollection = curcollection; } curcollection = curcollection->next_collection; } if ( thiscollection != NULL ){ PyrObject* elInfo = newPyrArray(g->gc, 9 * sizeof(PyrObject), 0 , true); SetObject( self, elInfo ); SetInt(elInfo->slots+elInfo->size++, thiscollection->index ); SetInt(elInfo->slots+elInfo->size++, thiscollection->type ); SetInt(elInfo->slots+elInfo->size++, thiscollection->usage_page ); SetInt(elInfo->slots+elInfo->size++, thiscollection->usage_index ); if ( thiscollection->parent_collection != NULL ){ SetInt(elInfo->slots+elInfo->size++, thiscollection->parent_collection->index ); } else { SetInt(elInfo->slots+elInfo->size++, -2 ); } SetInt(elInfo->slots+elInfo->size++, thiscollection->num_collections ); if ( thiscollection->first_collection != NULL ){ SetInt(elInfo->slots+elInfo->size++, thiscollection->first_collection->index ); } else { SetInt(elInfo->slots+elInfo->size++, -1 ); } SetInt(elInfo->slots+elInfo->size++, thiscollection->num_elements ); if ( thiscollection->first_element != NULL ){ SetInt(elInfo->slots+elInfo->size++, thiscollection->first_element->index ); } else { SetInt(elInfo->slots+elInfo->size++, -1 ); } } else { SetInt( self, 0 ); } return errNone; } int prHID_API_GetNumberOfElements( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg = args + 1; int err; int joyid; err = slotIntVal( arg, &joyid ); if ( err != errNone ) return err; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_collection * cur_dev = devdesc->device_collection; if ( cur_dev != NULL ){ SetInt( self, cur_dev->num_elements ); } else { SetInt( self, 0 ); } return errNone; } int prHID_API_GetElementInfo( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg1 = args + 1; PyrSlot* arg2 = args + 2; int err; int joyid; int elementid; err = slotIntVal( arg1, &joyid ); if ( err != errNone ) return err; err = slotIntVal( arg2, &elementid ); if ( err != errNone ) return err; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_collection * curdev = devdesc->device_collection; struct hid_device_element * curelement = curdev->first_element; struct hid_device_element * thiselement = NULL; bool found = curelement->index == elementid; if ( found ){ thiselement = curelement; } while( curelement != NULL && !found ){ found = curelement->index == elementid; if ( found ){ thiselement = curelement; } curelement = curelement->next; } if ( thiselement != NULL ){ PyrObject* elInfo = newPyrArray(g->gc, 18 * sizeof(PyrObject), 0 , true); SetObject( self, elInfo ); SetInt(elInfo->slots+elInfo->size++, thiselement->index ); SetInt(elInfo->slots+elInfo->size++, thiselement->io_type ); SetInt(elInfo->slots+elInfo->size++, thiselement->type ); SetInt(elInfo->slots+elInfo->size++, thiselement->usage_page ); SetInt(elInfo->slots+elInfo->size++, thiselement->usage ); SetInt(elInfo->slots+elInfo->size++, thiselement->usage_min ); SetInt(elInfo->slots+elInfo->size++, thiselement->usage_max ); SetInt(elInfo->slots+elInfo->size++, thiselement->logical_min ); SetInt(elInfo->slots+elInfo->size++, thiselement->logical_max ); SetInt(elInfo->slots+elInfo->size++, thiselement->phys_min ); SetInt(elInfo->slots+elInfo->size++, thiselement->phys_max ); SetInt(elInfo->slots+elInfo->size++, thiselement->unit_exponent ); SetInt(elInfo->slots+elInfo->size++, thiselement->unit ); SetInt(elInfo->slots+elInfo->size++, thiselement->report_size ); SetInt(elInfo->slots+elInfo->size++, thiselement->report_id ); SetInt(elInfo->slots+elInfo->size++, thiselement->report_index ); SetInt(elInfo->slots+elInfo->size++, thiselement->value ); SetInt(elInfo->slots+elInfo->size++, thiselement->parent_collection->index ); } else { SetInt( self, 0 ); } return errNone; } int prHID_API_SetElementOutput( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg1 = args + 1; PyrSlot* arg2 = args + 2; PyrSlot* arg3 = args + 3; int err; int joyid; int elementid; int value; err = slotIntVal( arg1, &joyid ); if ( err != errNone ) return err; err = slotIntVal( arg2, &elementid ); if ( err != errNone ) return err; err = slotIntVal( arg3, &value ); if ( err != errNone ) return err; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_collection * curdev = devdesc->device_collection; struct hid_device_element * curelement = curdev->first_element; struct hid_device_element * thiselement = NULL; if ( devdesc != NULL ){ bool found = false; while( curelement != NULL && !found ){ found = (curelement->index == elementid) && ( curelement->io_type == 2 ); if ( found ){ thiselement = curelement; } curelement = hid_get_next_output_element( curelement ); } if ( thiselement != NULL ){ thiselement->value = value; hid_send_output_report( devdesc, thiselement->report_id ); } } return errNone; } int prHID_API_SetElementRepeat( VMGlobals* g, int numArgsPushed ){ PyrSlot *args = g->sp - numArgsPushed + 1; PyrSlot* self = args + 0; PyrSlot* arg1 = args + 1; PyrSlot* arg2 = args + 2; PyrSlot* arg3 = args + 3; int err; int joyid; int elementid; int value; err = slotIntVal( arg1, &joyid ); if ( err != errNone ) return err; err = slotIntVal( arg2, &elementid ); if ( err != errNone ) return err; err = slotIntVal( arg3, &value ); if ( err != errNone ) return err; struct hid_dev_desc * devdesc = SC_HID_APIManager::instance().get_device( joyid ); struct hid_device_collection * curdev = devdesc->device_collection; struct hid_device_element * curelement = curdev->first_element; struct hid_device_element * thiselement = NULL; if ( devdesc != NULL ){ bool found = false; while( curelement != NULL && !found ){ found = (curelement->index == elementid) && ( curelement->io_type == 1 ); if ( found ){ thiselement = curelement; } curelement = hid_get_next_input_element( curelement ); } if ( thiselement != NULL ){ thiselement->repeat = value; } } return errNone; } void close_HID_API_Devices(){ SC_HID_APIManager::instance().closeAll(); } void initHIDAPIPrimitives() { int base, index; close_HID_API_Devices(); s_hidapi = getsym("HID"); base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_HID_API_Initialize", prHID_API_Initialize, 1, 0); // this initializes the hid subsystem definePrimitive(base, index++, "_HID_API_CloseAll", prHID_API_CloseAll, 1, 0); // this also cleans up and closes devices definePrimitive(base, index++, "_HID_API_BuildDeviceList", prHID_API_BuildDeviceList, 1, 0); // this gets device info about the various devices that are attached definePrimitive(base, index++, "_HID_API_OpenDevice", prHID_API_Open, 3, 0); // opens a specific device definePrimitive(base, index++, "_HID_API_CloseDevice", prHID_API_Close, 2, 0); // closes a specific device definePrimitive(base, index++, "_HID_API_GetInfo", prHID_API_GetInfo, 2, 0); // gets info about a specific device definePrimitive(base, index++, "_HID_API_GetNumberOfCollections", prHID_API_GetNumberOfCollections, 2, 0); // gets number of elements of a device definePrimitive(base, index++, "_HID_API_GetCollectionInfo", prHID_API_GetCollectionInfo, 3, 0); // gets info about a specific device element definePrimitive(base, index++, "_HID_API_GetNumberOfElements", prHID_API_GetNumberOfElements, 2, 0); // gets number of elements of a device definePrimitive(base, index++, "_HID_API_GetElementInfo", prHID_API_GetElementInfo, 4, 0); // gets info about a specific device element definePrimitive(base, index++, "_HID_API_SetElementOutput", prHID_API_SetElementOutput, 3, 0); // sets the output value of a specific device element, and sends the report definePrimitive(base, index++, "_HID_API_SetElementRepeat", prHID_API_SetElementRepeat, 3, 0); // sets the repeat property of a specific device element s_hidElementData = getsym("prHIDElementData"); // send back element data s_hidDeviceData = getsym("prHIDDeviceData"); // send back device data s_hidClosed = getsym("prHIDDeviceClosed"); // send back that device was closed } void deinitHIDAPIPrimitives() { SC_HID_APIManager::instance().closeAll(); } #else // no HID API void initHIDAPIPrimitives() { //other platforms? } void deinitHIDAPIPrimitives() { } #endif /// HAVE_API_HID // EOF SuperCollider-Source/lang/LangPrimSource/SC_LID.cpp000644 000765 000024 00000045412 12524671173 023207 0ustar00crucialstaff000000 000000 /* Linux Input Device support. Copyright (c) 2004 stefan kersten. modifications by Marije Baalman 2006-9 ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Linux Input Device interface, 2004 */ #include #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include "SC_LanguageClient.h" #if HAVE_LID #include #include #include #include #include #include #include #include #define BITS_PER_LONG (sizeof(long) * 8) #define NBITS(x) ((((x) - 1) / BITS_PER_LONG) + 1) #define OFF(x) ((x) % BITS_PER_LONG) #define BIT(x) (1UL << OFF(x)) #define LONG(x) ((x) / BITS_PER_LONG) #define TEST_BIT(array, bit) (((array)[LONG(bit)] >> OFF(bit)) & 1) extern bool compiledOK; static PyrSymbol* s_inputDeviceClass = 0; static PyrSymbol* s_inputDeviceInfoClass = 0; static PyrSymbol* s_absInfoClass = 0; static PyrSymbol* s_handleEvent = 0; static PyrSymbol* s_readError = 0; // ===================================================================== // SC_LID struct SC_LID { SC_LID(PyrObject *obj); ~SC_LID(); int open(const char *path); int close(); bool isEventTypeSupported(int evtType); bool isEventCodeSupported(int evtType, int evtCode); int getName(char* buf, size_t size); int getInfo(struct input_id *info, char *bufPhys, size_t sizePhys, char *bufUniq, size_t sizeUniq); int getKeyState(int evtCode); int getAbsInfo(int evtCode, struct input_absinfo *info); int setLedState( int evtCode, int evtValue, int evtType ); int grab(int flag); void handleEvent(struct input_event& evt, std::atomic const & shouldBeRunning); void readError(std::atomic const & shouldBeRunning); static PyrObject* getObject(PyrSlot* slot) { return isKindOfSlot(slot, s_inputDeviceClass->u.classobj) ? slotRawObject(slot) : 0; } static SC_LID* getDevice(PyrObject* obj) { return (SC_LID*)slotRawPtr(&obj->slots[0]); } SC_LID* m_next; PyrObject* m_obj; int m_fd; int m_lastEventType; unsigned long m_eventTypeCaps[NBITS(EV_MAX)]; unsigned long m_eventCodeCaps[NBITS(KEY_MAX)]; unsigned long m_keyState[NBITS(KEY_MAX)]; }; // ===================================================================== // SC_LIDManager struct SC_LIDManager { public: static SC_LIDManager& instance(); int start(); int stop(); int add(SC_LID *dev); int remove(SC_LID *dev); private: SC_LIDManager(); ~SC_LIDManager(); enum { kStop, kAdd, kRemove }; struct Command { int id; union { SC_LID* dev; } arg; }; int sendCommand(const Command& cmd); void devicesChanged(); bool asyncAddDevice(SC_LID *dev); bool asyncRemoveDevice(SC_LID *dev); void loop(); static void* threadFunc(void*); pthread_t m_thread; pthread_mutex_t m_mutex; std::atomic m_running; std::atomic mShouldBeRunning; int m_cmdFifo[2]; int m_nfds; fd_set m_fds; SC_LID* m_devices; }; // ===================================================================== // SC_LID SC_LID::SC_LID(PyrObject* obj) : m_next(0), m_obj(obj), m_fd(-1), m_lastEventType(-1) { SetPtr(obj->slots+0, this); } SC_LID::~SC_LID() { if (m_fd != -1) ::close(m_fd); } int SC_LID::open(const char* path) { m_fd = ::open(path, O_RDWR); if (m_fd == -1) { error("LID (1): %s\n", strerror(errno)); return errFailed; } memset(m_eventTypeCaps, 0, sizeof(m_eventTypeCaps)); if (ioctl(m_fd, EVIOCGBIT(0, EV_MAX), m_eventTypeCaps) == -1) { error("LID (2): %s\n", strerror(errno)); return errFailed; } memset(m_keyState, 0, sizeof(m_keyState)); if (ioctl(m_fd, EVIOCGKEY(sizeof(m_keyState)), m_keyState) == -1) { error("LID (3): %s\n", strerror(errno)); return errFailed; } return SC_LIDManager::instance().add(this); } int SC_LID::close() { SetNil(m_obj->slots+0); return SC_LIDManager::instance().remove(this); } bool SC_LID::isEventTypeSupported(int evtType) { return TEST_BIT(m_eventTypeCaps, evtType); } bool SC_LID::isEventCodeSupported(int evtType, int evtCode) { if (evtType != m_lastEventType) { m_lastEventType = evtType; memset(m_eventCodeCaps, 0, sizeof(m_eventCodeCaps)); if (ioctl(m_fd, EVIOCGBIT(evtType, KEY_MAX), m_eventCodeCaps) == -1) { post("LID failed to check event code (error %s)\n", strerror(errno)); return false; } } return TEST_BIT(m_eventCodeCaps, evtCode); } int SC_LID::getName(char* buf, size_t size) { if (ioctl(m_fd, EVIOCGNAME(size), buf) == -1) { error("LID (5): %s\n", strerror(errno)); return errFailed; } return errNone; } int SC_LID::getInfo(struct input_id *info, char *bufPhys, size_t sizePhys, char *bufUniq, size_t sizeUniq) { if (ioctl(m_fd, EVIOCGID, info) == -1) { error("LID (6): %s\n", strerror(errno)); return errFailed; } if (ioctl(m_fd, EVIOCGPHYS(sizePhys), bufPhys) == -1) { // strcpy( sizePhys, strerror(errno)); post("LID could not retrieve physical location (error: %s)\n", strerror(errno)); // return errFailed; } if (ioctl(m_fd, EVIOCGUNIQ(sizeUniq), bufUniq) == -1) { // strcpy( strerror(errno), sizeof( strerror(errno)), sizeUniq ); post("LID could not get unique identifier (error: %s)\n", strerror(errno)); // return errFailed; } return errNone; } int SC_LID::getKeyState(int evtCode) { return TEST_BIT(m_keyState, evtCode); } int SC_LID::getAbsInfo(int evtCode, struct input_absinfo* info) { if (ioctl(m_fd, EVIOCGABS(evtCode), info) == -1) { error("LID (9): %s\n", strerror(errno)); return errFailed; } return errNone; } int SC_LID::setLedState( int evtCode, int evtValue, int evtType ) { // added by marije baalman struct input_event ev; // post( "set led state called, putting event" ); ev.code = evtCode; ev.value = evtValue; ev.type = evtType; // post( "m_fd %i", m_fd ); // post( "code %i, value %i ", evtCode, evtValue ); if ( write(m_fd, &ev, sizeof(struct input_event)) == -1 ) { // post( "error writing event" ); return errFailed; } return errNone; } int SC_LID::grab(int flag) { if (ioctl(m_fd, EVIOCGRAB, flag) == -1) { error("LID (10): %s\n", strerror(errno)); return errFailed; } return errNone; } void SC_LID::handleEvent(struct input_event& evt, std::atomic const & shouldBeRunning) { if (evt.type != EV_SYN) { int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, evt.type); ++g->sp; SetInt(g->sp, evt.code); ++g->sp; SetInt(g->sp, evt.value); runInterpreter(g, s_handleEvent, 4); g->canCallOS = false; } gLangMutex.unlock(); } } void SC_LID::readError(std::atomic const & shouldBeRunning) { int status = lockLanguageOrQuit(shouldBeRunning); if (status == EINTR) return; if (status) { postfl("error when locking language (%d)\n", status); return; } if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_readError, 1); g->canCallOS = false; } gLangMutex.unlock(); } // ===================================================================== // SC_LIDManager SC_LIDManager& SC_LIDManager::instance() { static SC_LIDManager instance; return instance; } SC_LIDManager::SC_LIDManager() : m_running(false), m_devices(0) { if (pipe(m_cmdFifo) == -1) { m_cmdFifo[0] = m_cmdFifo[1] = -1; } devicesChanged(); } SC_LIDManager::~SC_LIDManager() { close(m_cmdFifo[0]); close(m_cmdFifo[1]); } int SC_LIDManager::start() { mShouldBeRunning = true; int err = pthread_create(&m_thread, 0, &threadFunc, this); if (err != 0) return errFailed; return errNone; } int SC_LIDManager::stop() { if (m_running == false) return errNone; Command cmd; cmd.id = kStop; int err = sendCommand(cmd); if (err) return err; mShouldBeRunning = false; err = pthread_join(m_thread, 0); if (err != 0) return errFailed; return errNone; } int SC_LIDManager::add(SC_LID* dev) { Command cmd; cmd.id = kAdd; cmd.arg.dev = dev; return sendCommand(cmd); } int SC_LIDManager::remove(SC_LID* dev) { Command cmd; cmd.id = kRemove; cmd.arg.dev = dev; return sendCommand(cmd); } int SC_LIDManager::sendCommand(const Command& cmd) { return write(m_cmdFifo[1], &cmd, sizeof(cmd)) == sizeof(cmd) ? errNone : errFailed; } void SC_LIDManager::devicesChanged() { int fdMax = m_cmdFifo[0]; FD_ZERO(&m_fds); FD_SET(fdMax, &m_fds); SC_LID *dev = m_devices; while (dev) { int fd = dev->m_fd; if (fd != -1) { FD_SET(fd, &m_fds); if (fd > fdMax) fdMax = fd; } dev = dev->m_next; } m_nfds = fdMax + 1; } bool SC_LIDManager::asyncAddDevice(SC_LID* dev) { if (dev->m_next) return false; dev->m_next = m_devices; m_devices = dev; devicesChanged(); return true; } bool SC_LIDManager::asyncRemoveDevice(SC_LID* dev) { SC_LID *prev = 0, *cur = m_devices; while (cur) { if (cur == dev) { if (prev) prev->m_next = dev->m_next; else m_devices = dev->m_next; dev->m_next = 0; delete dev; devicesChanged(); return true; } prev = cur; cur = cur->m_next; } return false; } void* SC_LIDManager::threadFunc(void* arg) { ((SC_LIDManager*)arg)->loop(); return 0; } void SC_LIDManager::loop() { m_running = true; post("LID: event loop started\n"); while (true) { fd_set fds; memcpy(&fds, &m_fds, sizeof(fd_set)); int n = select(m_nfds, &fds, 0, 0, 0); if (n == -1) { if( errno == EINTR ) continue; post("LID: error in input handler: %s\n", strerror(errno)); goto quit; } else if (n > 0) { if (FD_ISSET(m_cmdFifo[0], &fds)) { Command cmd; --n; int err = read(m_cmdFifo[0], &cmd, sizeof(cmd)); if (err == -1) { if( errno != EINTR ) { post("LID: error in input handler: %s\n", strerror(errno)); goto quit; } } else { switch (cmd.id) { case kStop: goto quit; case kAdd: if (asyncAddDevice(cmd.arg.dev)) { post("LID: added device %p\n", cmd.arg); } else { post("LID: cannot add device\n"); } break; case kRemove: if (asyncRemoveDevice(cmd.arg.dev)) { post("LID: removed device %p\n", cmd.arg); } else { post("LID: couldn't remove device\n"); } break; default: post("LID: unknown command in input handler\n"); } } } if (n > 0) { SC_LID *dev = m_devices; while (dev) { int fd = dev->m_fd; if (FD_ISSET(fd, &fds)) { struct input_event evt; if (read(fd, &evt, sizeof(evt)) == sizeof(evt)) { dev->handleEvent(evt, mShouldBeRunning); } else { dev->readError(mShouldBeRunning); } } if (!mShouldBeRunning) goto quit; dev = dev->m_next; } } } } quit: m_running = false; post("LID: event loop stopped\n"); } // ===================================================================== // Primitive Interface int prLID_Open(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; char path[PATH_MAX]; err = slotStrVal(args+1, path, sizeof(path)); if (err) return err; SC_LID* dev = new SC_LID(obj); err = dev->open(path); if (err) { delete dev; return err; } return errNone; } int prLID_Close(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; return dev->close(); } int prLID_EventTypeSupported(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int evtType; int err; if (!g->canCallOS) return errCantCallOS; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtType); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetBool(args, dev->isEventTypeSupported(evtType)); return errNone; } int prLID_EventCodeSupported(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 2; int evtType, evtCode; int err; if (!g->canCallOS) return errCantCallOS; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtType); if (err) return err; err = slotIntVal(args+2, &evtCode); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetBool(args, dev->isEventCodeSupported(evtType, evtCode)); return errNone; } int prLID_GetInfo(VMGlobals* g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; if (!isKindOfSlot(args+1, s_inputDeviceInfoClass->u.classobj)) return errWrongType; PyrObject* infoObj = slotRawObject(&args[1]); SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; char name[128]; err = dev->getName(name, sizeof(name)); if (err) return err; struct input_id info; char namePhys[128]; char nameUniq[128]; err = dev->getInfo(&info, namePhys, sizeof( namePhys ), nameUniq, sizeof( nameUniq ) ); if (err) return err; SetSymbol(infoObj->slots+0, getsym(name)); SetInt(infoObj->slots+1, info.bustype); SetInt(infoObj->slots+2, info.vendor); SetInt(infoObj->slots+3, info.product); SetInt(infoObj->slots+4, info.version); SetSymbol(infoObj->slots+5, getsym(namePhys)); SetSymbol(infoObj->slots+6, getsym(nameUniq)); slotCopy(&args[0], &args[1]); return errNone; } int prLID_GetKeyState(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int evtCode; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetInt(args, dev->getKeyState(evtCode)); return errNone; } int prLID_GetAbsInfo(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 2; int evtCode; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; if (!isKindOfSlot(args+2, s_absInfoClass->u.classobj)) return errWrongType; PyrObject* infoObj = slotRawObject(&args[2]); SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; struct input_absinfo info; err = dev->getAbsInfo(evtCode, &info); if (err) return err; SetInt(infoObj->slots+0, info.value); SetInt(infoObj->slots+1, info.minimum); SetInt(infoObj->slots+2, info.maximum); SetInt(infoObj->slots+3, info.fuzz); SetInt(infoObj->slots+4, info.flat); slotCopy(&args[0], &args[2]); return errNone; } int prLID_Grab(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; return dev->grab(IsTrue(args+1)); } int prLID_Start(VMGlobals* g, int numArgsPushed) { // if (!g->canCallOS) return errCantCallOS; return SC_LIDManager::instance().start(); } int prLID_Stop(VMGlobals* g, int numArgsPushed) { // if (!g->canCallOS) return errCantCallOS; return SC_LIDManager::instance().stop(); } int prLID_SetLedState(VMGlobals *g, int numArgsPushed) { // post( "set led state primitive called" ); PyrSlot* args = g->sp - 2; int evtCode, evtValue; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; err = slotIntVal(args+2, &evtValue); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetInt(args, dev->setLedState(evtCode,evtValue, EV_LED)); return errNone; } int prLID_SetMscState(VMGlobals *g, int numArgsPushed) { // post( "set msc state primitive called\n" ); PyrSlot* args = g->sp - 2; int evtCode, evtValue; int err; PyrObject* obj = SC_LID::getObject(args+0); if (!obj) return errWrongType; err = slotIntVal(args+1, &evtCode); if (err) return err; err = slotIntVal(args+2, &evtValue); if (err) return err; SC_LID* dev = SC_LID::getDevice(obj); if (!dev) return errFailed; SetInt(args, dev->setLedState(evtCode,evtValue, EV_MSC)); return errNone; } void SC_LIDInit() { int base, index; s_inputDeviceClass = getsym("LID"); s_inputDeviceInfoClass = getsym("LIDInfo"); s_absInfoClass = getsym("LIDAbsInfo"); s_handleEvent = getsym("prHandleEvent"); s_readError = getsym("prReadError"); base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_LID_Open", prLID_Open, 2, 0); definePrimitive(base, index++, "_LID_Close", prLID_Close, 1, 0); definePrimitive(base, index++, "_LID_EventTypeSupported", prLID_EventTypeSupported, 2, 0); definePrimitive(base, index++, "_LID_EventCodeSupported", prLID_EventCodeSupported, 3, 0); definePrimitive(base, index++, "_LID_GetInfo", prLID_GetInfo, 2, 0); definePrimitive(base, index++, "_LID_GetKeyState", prLID_GetKeyState, 2, 0); definePrimitive(base, index++, "_LID_GetAbsInfo", prLID_GetAbsInfo, 3, 0); definePrimitive(base, index++, "_LID_Grab", prLID_Grab, 2, 0); definePrimitive(base, index++, "_LID_Start", prLID_Start, 1, 0); definePrimitive(base, index++, "_LID_Stop", prLID_Stop, 1, 0); definePrimitive(base, index++, "_LID_SetLedState", prLID_SetLedState, 3, 0); // added by Marije Baalman definePrimitive(base, index++, "_LID_SetMscState", prLID_SetMscState, 3, 0); } #else // !HAVE_LID int prLID_Start(VMGlobals* g, int numArgsPushed) { return errNone; } int prLID_Stop(VMGlobals* g, int numArgsPushed) { return errNone; } void SC_LIDInit() { int base, index; base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_LID_Start", prLID_Start, 1, 0); definePrimitive(base, index++, "_LID_Stop", prLID_Stop, 1, 0); } #endif // HAVE_LID void initLIDPrimitives() { SC_LIDInit(); } // EOF SuperCollider-Source/lang/LangPrimSource/SC_Msg.h000644 000765 000024 00000002463 12321461511 022755 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Msg_ #define _SC_Msg_ #include #include #include "SC_ReplyImpl.hpp" #include "sc_msg_iter.h" class SC_Msg; enum { // Handler IDs kUnknownAction = 0, kRealTimeAction = 1, kNonRealTimeAction = 2, kEitherTimeAction = 3 }; int32 Hash(ReplyAddress *inReplyAddress); struct OSC_Packet { char *mData; int32 mSize; bool mIsBundle; ReplyAddress mReplyAddr; }; void FreeOSCPacket(OSC_Packet *inPacket); #endif SuperCollider-Source/lang/LangPrimSource/SC_PortMIDI.cpp000644 000765 000024 00000055451 12760322424 024164 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* changes by jan trutzschler v. f. 9/9/2002 the midiReadProc calls doAction in the class MIDIIn. with the arguments: inUid, status, chan, val1, val2 added prDisposeMIDIClient added prRestartMIDI 19/9 call different actions,disconnect midiInPort, midiout: sendmidi 04/feb/03 prListMIDIEndpoints modification by Ron Kuivila added jt. */ #include "PortMIDI.h" #include "PortTime.h" #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #include "SC_Lock.h" #include #include #include using std::memset; // symbols to call back into lang PyrSymbol* s_domidiaction; PyrSymbol* s_midiNoteOnAction; PyrSymbol* s_midiNoteOffAction; PyrSymbol* s_midiTouchAction; PyrSymbol* s_midiControlAction; PyrSymbol* s_midiPolyTouchAction; PyrSymbol* s_midiProgramAction; PyrSymbol* s_midiBendAction; PyrSymbol* s_midiSysexAction; PyrSymbol* s_midiInvalidSysexAction; PyrSymbol* s_midiSysrtAction; PyrSymbol* s_midiSMPTEAction; PyrSymbol* s_midiin; PyrSymbol* s_numMIDIDev; PyrSymbol* s_midiclient; const int kMaxMidiPorts = 16; int gNumMIDIInPorts = 0, gNumMIDIOutPorts = 0; bool gMIDIInitialized = false; static std::vector gSysexData; static bool gSysexFlag = false; static uint8_t gRunningStatus = 0; PmStream* gMIDIInStreams[kMaxMidiPorts]; bool gMIDIInStreamUsed[kMaxMidiPorts]; PmStream* gMIDIOutStreams[kMaxMidiPorts]; std::map gMidiInputIndexToPmDevIndex; std::map gMidiOutputIndexToPmDevIndex; SC_Lock gPmStreamMutex; /* if INPUT_BUFFER_SIZE is 0, PortMidi uses a default value */ #define PMSTREAM_INPUT_BUFFER_SIZE 0 #define PMSTREAM_OUTPUT_BUFFER_SIZE 100 #define PMSTREAM_DRIVER_INFO NULL #define PMSTREAM_TIME_PROC NULL #define PMSTREAM_TIME_INFO NULL extern bool compiledOK; static void sysexBegin() { gRunningStatus = 0; // clear running status gSysexData.clear(); gSysexFlag = true; } static void scCallSysexAction(PyrSymbol* action) { VMGlobals *g = gMainVMGlobals; uint8_t *pSysexData = &gSysexData[0]; // Convert to array access PyrInt8Array* sysexArray = newPyrInt8Array(g->gc, gSysexData.size(), 0, true); sysexArray->size = gSysexData.size(); memcpy(sysexArray->b, pSysexData, gSysexData.size()); ++g->sp; SetObject(g->sp, (PyrObject*)sysexArray); // chan argument unneeded as there runInterpreter(g, action, 3); // special sysex action in the lang } static void sysexEnd() { gSysexFlag = false; scCallSysexAction(s_midiSysexAction); } static void sysexEndInvalid() { gSysexFlag = false; scCallSysexAction(s_midiInvalidSysexAction); } static int midiProcessPartialSystemPacket(uint32_t msg) { int index, data; VMGlobals *g = gMainVMGlobals; // to iterate over the contents of the message byte by byte uint8_t *p = reinterpret_cast(&msg); int i = 0; while (i < 4){ switch (p[i]){ /* SysEx start */ case 0xF0: if (gSysexFlag) { sysexEndInvalid(); } sysexBegin(); // new sysex in gSysexData.push_back(p[i]); // add SOX i++; break; /* SysEx end */ case 0xF7: gSysexData.push_back(p[i]); // add EOX if (gSysexFlag) sysexEnd(); // if last_uid != 0 rebuild the VM. else sysexEndInvalid(); // invalid 1 byte with only EOX can happen return 0; /* MIDI clock. Can only be received as the first byte */ case 0xF1: index = p[i + 1] >> 4; data = p[i + 1] & 0xf; if (index % 2) { data = data << 4; } SetInt(g->sp, index); // chan unneeded ++g->sp; SetInt(g->sp, data); // special smpte action in the lang runInterpreter(g, s_midiSMPTEAction, 4); return 0; /* Song pointer. Can only be received as the first byte */ case 0xF2: ++g->sp; SetInt(g->sp, (p[i + 2] << 7) | p[i + 1]); runInterpreter(g, s_midiSysrtAction, 4); return 0; /* Song select. Can only be received as the first byte */ case 0xF3: ++g->sp; SetInt(g->sp, p[i + 1]); runInterpreter(g, s_midiSysrtAction, 4); return 0; /* Realtime messages. Can be anywhere within a message */ case 0xF6: case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFE: gRunningStatus = 0; // clear running status ++g->sp; SetInt(g->sp, p[i] & 0xF); ++g->sp; SetInt(g->sp, 0); runInterpreter(g, s_midiSysrtAction, 4); i++; break; default: // This should be data if (p[i] & 0x80){ // if it a command byte, it is an error gSysexData.push_back(p[i]); // add it as an abort message sysexEndInvalid(); // flush invalid return 0; } else if (gSysexFlag){ gSysexData.push_back(p[i]); // add Byte i++; } else{ // garbage - handle in case - discard it i++; break; } } } return 0; } /* timer "interrupt" for processing midi data */ static void PMProcessMidi(PtTimestamp timestamp, void *userData) { PmEvent buffer; /* just one message at a time */ for( int i = 0 ; i < gNumMIDIInPorts; ++i ) { for (;;){ long Tstatus, data1, data2; // Only lock the PM mutex while accessing the PortMidi functionality. It is very important to not acquire the lang mutex while holding // the PM mutex to avoid a deadlock, since the laguage may try to acquire the PM mutex for a MIDIOut operation { lock_guard mulo(gPmStreamMutex); PmStream* midi_in = gMIDIInStreams[i]; if (!midi_in) { break; } const PmError result = Pm_Poll(midi_in); if (result == pmNoData){ break; } else if (result != pmGotData) { std::printf("errrr %s\n", Pm_GetErrorText(result)); continue; } if (Pm_Read(midi_in, &buffer, 1) == pmBufferOverflow) continue; // unless there was overflow, we should have a message now Tstatus = Pm_MessageStatus(buffer.message); // The PM mutex is released here } // +---------------------------------------------+ // | Lock the interp. mutex and dispatch message | // +---------------------------------------------+ gLangMutex.lock(); if (compiledOK) { VMGlobals *g = gMainVMGlobals; uint8 status = static_cast(Tstatus & 0xF0); uint8 chan = static_cast(Tstatus & 0x0F); g->canCallOS = false; // cannot call the OS // Do not put the data in the stack again if we are in the middle of processing a System Message, if (!gSysexFlag){ ++g->sp; SetObject(g->sp, s_midiin->u.classobj); // Set the class MIDIIn ++g->sp; SetInt(g->sp, i); //src } if(status & 0x80) // set the running status for voice messages gRunningStatus = ((status >> 4) == 0xF) ? 0 : Tstatus; // keep also additional info L: switch (status) { case 0x80: //noteOff ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, Pm_MessageData1(buffer.message)); ++g->sp; SetInt(g->sp, Pm_MessageData2(buffer.message)); runInterpreter(g, s_midiNoteOffAction, 5); break; case 0x90: //noteOn ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, Pm_MessageData1(buffer.message)); ++g->sp; SetInt(g->sp, Pm_MessageData2(buffer.message)); // runInterpreter(g, data2 ? s_midiNoteOnAction : s_midiNoteOffAction, 5); runInterpreter(g, s_midiNoteOnAction, 5); break; case 0xA0: //polytouch ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, Pm_MessageData1(buffer.message)); ++g->sp; SetInt(g->sp, Pm_MessageData2(buffer.message)); runInterpreter(g, s_midiPolyTouchAction, 5); break; case 0xB0: //control ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, Pm_MessageData1(buffer.message)); ++g->sp; SetInt(g->sp, Pm_MessageData2(buffer.message)); runInterpreter(g, s_midiControlAction, 5); break; case 0xC0: //program ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, Pm_MessageData1(buffer.message)); runInterpreter(g, s_midiProgramAction, 4); break; case 0xD0: //touch ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, Pm_MessageData1(buffer.message)); runInterpreter(g, s_midiTouchAction, 4); break; case 0xE0: //bend ++g->sp; SetInt(g->sp, chan); //chan ++g->sp; SetInt(g->sp, (Pm_MessageData2(buffer.message) << 7) | Pm_MessageData1(buffer.message)); runInterpreter(g, s_midiBendAction, 4); break; case 0xF0: // only the first Pm_Event will carry the 0xF0 byte // we pass the messages to the processing function, which will take care of assembling the, midiProcessPartialSystemPacket(buffer.message); break; default : // data byte => continuing sysex message ir running status if(gRunningStatus && !gSysexFlag) { // handle running status status = gRunningStatus & 0xF0; // accept running status only inside a packet beginning chan = gRunningStatus & 0x0F; // with a valid status byte SetInt(g->sp, chan); goto L; // parse again with running status set // mv - get next byte } if (gSysexFlag){ midiProcessPartialSystemPacket(buffer.message); // process sysex packet } break; } g->canCallOS = false; } gLangMutex.unlock(); } // if (midi_in) } // for loop until numMIDIInPorts } /* ------------------------------------------------------------- */ static void midiCleanUp(); static int initMIDI(int numIn, int numOut) { midiCleanUp(); lock_guard mulo(gPmStreamMutex); const PmError initializationError = Pm_Initialize(); if (initializationError) { std::printf("MIDI: cannot open midi backend %s\n", Pm_GetErrorText(initializationError)); return errFailed; } /* Here, numIn and numOut are 0, even if the inputs to lang (MIDIClient init) were nil, but according to the documentation, it should be the number of inputs or outputs. That matches what I see in MIDIOut.sc -> MIDIClient *init, in which it is setting that to sources.size, and destinations.size, so I guess that the problem is that this information is not known at this point, or there is something missing. */ numIn = sc_clip(numIn, 1, kMaxMidiPorts); numOut = sc_clip(numOut, 1, kMaxMidiPorts); int inIndex = 0; int outIndex = 0; for (int i = 0; i < Pm_CountDevices(); ++i) { const PmDeviceInfo* devInfo = Pm_GetDeviceInfo(i); if( devInfo->input ) { gNumMIDIInPorts++; gMidiInputIndexToPmDevIndex[inIndex++] = i; } /* Ignore the MIDI Mapper. Otherwise, if it is allocated, we get "already allocated" errors */ if ((devInfo->output) && (strnicmp(devInfo->name, "Microsoft MIDI Mapper", 50) != 0)) { gNumMIDIOutPorts++; gMidiOutputIndexToPmDevIndex[outIndex++] = i; } } if (gNumMIDIInPorts > numIn) gNumMIDIInPorts = numIn; if (gNumMIDIOutPorts > numOut) gNumMIDIOutPorts = numOut; for (int i = 0; i < gNumMIDIOutPorts; i++) { const int pmdid = gMidiOutputIndexToPmDevIndex[i]; const PmDeviceInfo* devInfo = Pm_GetDeviceInfo(pmdid); const PmError error = Pm_OpenOutput(&gMIDIOutStreams[i], pmdid, NULL, 512L, NULL, NULL, 0); std::printf("MIDI: device %d %d %d %s (%s)\n", i, pmdid, &gMIDIOutStreams[i], Pm_GetErrorText(error), devInfo->name); if( error ) { std::printf("MIDI: cannot open device %d %d %s (%s)\n", i, pmdid, Pm_GetErrorText(error), devInfo->name); int hostError; if( (hostError = Pm_HasHostError(nullptr)) ) { char hostErrorString[PM_HOST_ERROR_MSG_LEN]; Pm_GetHostErrorText(hostErrorString, PM_HOST_ERROR_MSG_LEN); std::printf("MIDI: Host error %s\n", hostErrorString); } } } /* will call our function, PMProcessMidi() every millisecond */ Pt_Start(1, &PMProcessMidi, 0); /* start a timer with millisecond accuracy */ gMIDIInitialized = true; return errNone; } static int getNumSources() { int n = 0; for (int i = 0; i < Pm_CountDevices(); ++i) { const PmDeviceInfo* devInfo = Pm_GetDeviceInfo(i); if (devInfo->input){ n++; } } return n; } static int getNumDestinations() { int n = 0; for (int i = 0; i < Pm_CountDevices(); ++i) { const PmDeviceInfo* devInfo = Pm_GetDeviceInfo(i); if ((devInfo->output) && (strnicmp(devInfo->name, "Microsoft MIDI Mapper", 50) != 0)){ n++; } } return n; } /* ------------------------------------------------------------- */ static void midiCleanUp() { lock_guard mulo(gPmStreamMutex); if(gMIDIInitialized) { for (int i=0; isp; int numSrc = getNumSources(); int numDst = getNumDestinations(); PyrObject* idarray = newPyrArray(g->gc, 6 * sizeof(PyrObject), 0 , true); SetObject(a, idarray); // 0 PyrObject* idarraySo = newPyrArray(g->gc, numSrc * sizeof(__int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarraySo); g->gc->GCWrite(idarray, idarraySo); // 1 PyrObject* devarraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarraySo); g->gc->GCWrite(idarray, devarraySo); // 2 PyrObject* namearraySo = newPyrArray(g->gc, numSrc * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearraySo); g->gc->GCWrite(idarray, namearraySo); // 3 PyrObject* idarrayDe = newPyrArray(g->gc, numDst * sizeof(__int32), 0 , true); SetObject(idarray->slots+idarray->size++, idarrayDe); g->gc->GCWrite(idarray, idarrayDe); // 4 PyrObject* namearrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, namearrayDe); g->gc->GCWrite(idarray, namearrayDe); // 5 PyrObject* devarrayDe = newPyrArray(g->gc, numDst * sizeof(PyrObject), 0 , true); SetObject(idarray->slots+idarray->size++, devarrayDe); g->gc->GCWrite(idarray, devarrayDe); for (int i=0; iname,1023); cendname[1023] = 0; strncpy(cdevname,devInfo->name,1023); cdevname[1023] = 0; PyrString *string = newPyrString(g->gc, cendname, 0, true); SetObject(namearraySo->slots+i, string); namearraySo->size++; g->gc->GCWrite(namearraySo, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarraySo->slots+i, devstring); devarraySo->size++; g->gc->GCWrite(devarraySo, (PyrObject*)devstring); SetInt(idarraySo->slots+i, i); idarraySo->size++; } // post("numDst %d\n", numDst); for (int i=0; iname,1023); cendname[1023] = 0; strncpy(cdevname,devInfo->name,1023); cdevname[1023] = 0; PyrString *string = newPyrString(g->gc, cendname, 0, true); SetObject(namearrayDe->slots+namearrayDe->size++, string); g->gc->GCWrite(namearrayDe, (PyrObject*)string); PyrString *devstring = newPyrString(g->gc, cdevname, 0, true); SetObject(devarrayDe->slots+devarrayDe->size++, devstring); g->gc->GCWrite(devarrayDe, (PyrObject*)devstring); SetInt(idarrayDe->slots+idarrayDe->size++, i); } return errNone; } /* ------------------------------------------------------------- */ int prConnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { lock_guard mulo(gPmStreamMutex); //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return errWrongType; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return errWrongType; PmStream* inStream = NULL; int pmdid = gMidiInputIndexToPmDevIndex[uid]; const PmError error = Pm_OpenInput( &inStream, pmdid, PMSTREAM_DRIVER_INFO, PMSTREAM_INPUT_BUFFER_SIZE, PMSTREAM_TIME_PROC, PMSTREAM_TIME_INFO ); if(error) { std::printf("cannot open MIDI input: %s\n", Pm_GetErrorText(error)); int hostError; if( (hostError = Pm_HasHostError(nullptr)) ) { char hostErrorString[PM_HOST_ERROR_MSG_LEN]; Pm_GetHostErrorText(hostErrorString, PM_HOST_ERROR_MSG_LEN); std::printf("MIDI: Host error %s\n", hostErrorString); } return errFailed; } gMIDIInStreams[uid] = inStream; gMIDIInStreamUsed[uid] = true; return errNone; } /* ------------------------------------------------------------- */ int prDisconnectMIDIIn(struct VMGlobals *g, int numArgsPushed) { lock_guard mulo(gPmStreamMutex); PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, inputIndex, uid; err = slotIntVal(b, &inputIndex); if (err) return err; if (inputIndex < 0 || inputIndex >= gNumMIDIInPorts) return errIndexOutOfRange; err = slotIntVal(c, &uid); if (err) return err; if (gMIDIInStreamUsed[uid]){ const PmError error = Pm_Close(gMIDIInStreams[uid]); if (error) { std::printf("cannot close MIDI device: %s\n", Pm_GetErrorText(error)); return errFailed; } gMIDIInStreamUsed[uid] = false; gMIDIInStreams[uid] = NULL; } return errNone; } /* ------------------------------------------------------------- */ int prInitMIDI(struct VMGlobals *g, int numArgsPushed) { //PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *c = g->sp; int err, numIn, numOut; err = slotIntVal(b, &numIn); if (err) return errWrongType; err = slotIntVal(c, &numOut); if (err) return errWrongType; return initMIDI(numIn, numOut); } int prDisposeMIDIClient(VMGlobals *g, int numArgsPushed) { midiCleanUp(); return errNone; } int prRestartMIDI(VMGlobals *g, int numArgsPushed) { /* Do nothing */ return errNone; } /* void freeSysex(MIDISysexSendRequest* pk) { free(pk->data); free(pk); } */ int prSendSysex(VMGlobals *g, int numArgsPushed) { lock_guard mulo(gPmStreamMutex); int err, uid; PyrSlot* args = g->sp - 2; // args[1] contains the uid and args[2] contains the array err = slotIntVal(&args[1], &uid); if (err) return err; if (!isKindOfSlot(&args[2], s_int8array->u.classobj)) return errWrongType; PyrInt8Array *packet = slotRawInt8Array(&args[2]); if (gMIDIOutStreams[uid]){ PmError result = Pm_WriteSysEx(gMIDIOutStreams[uid], 0, packet->b); if (result != pmNoError) return errFailed; else return errNone; } return errFailed; } /* ------------------------------------------------------------- */ int prSendMIDIOut(struct VMGlobals *g, int numArgsPushed) { lock_guard mulo(gPmStreamMutex); //port, uid, len, hiStatus, loStatus, a, b, latency //PyrSlot *m = g->sp - 8; PyrSlot *p = g->sp - 7; PyrSlot *u = g->sp - 6; PyrSlot *l = g->sp - 5; PyrSlot *his = g->sp - 4; PyrSlot *los = g->sp - 3; PyrSlot *a = g->sp - 2; PyrSlot *b = g->sp - 1; PyrSlot *plat = g->sp; int err, outputIndex, uid, length, hiStatus, loStatus, aval, bval; float late; err = slotIntVal(p, &outputIndex); if (err) return err; if (outputIndex < 0 || outputIndex >= gNumMIDIOutPorts) return errIndexOutOfRange; err = slotIntVal(u, &uid); if (err) return err; err = slotIntVal(l, &length); if (err) return err; err = slotIntVal(his, &hiStatus); if (err) return err; err = slotIntVal(los, &loStatus); if (err) return err; err = slotIntVal(a, &aval); if (err) return err; err = slotIntVal(b, &bval); if (err) return err; err = slotFloatVal(plat, &late); if (err) return err; Pm_WriteShort(gMIDIOutStreams[uid], 0, Pm_Message((hiStatus & 0xF0) | (loStatus & 0x0F) , aval, bval)); return errNone; } // not needed in PortMIDI: int initMIDIClient() { return errNone; } int prInitMIDIClient(struct VMGlobals *g, int numArgsPushed) { return initMIDIClient(); } void initMIDIPrimitives() { int base, index; base = nextPrimitiveIndex(); index = 0; s_midiin = getsym("MIDIIn"); s_domidiaction = getsym("doAction"); s_midiNoteOnAction = getsym("doNoteOnAction"); s_midiNoteOffAction = getsym("doNoteOffAction"); s_midiTouchAction = getsym("doTouchAction"); s_midiControlAction = getsym("doControlAction"); s_midiPolyTouchAction = getsym("doPolyTouchAction"); s_midiProgramAction = getsym("doProgramAction"); s_midiBendAction = getsym("doBendAction"); s_midiSysexAction = getsym("doSysexAction"); s_midiInvalidSysexAction = getsym("doInvalidSysexAction"); // client can handle incorrect case s_midiSysrtAction = getsym("doSysrtAction"); s_midiSMPTEAction = getsym("doSMPTEaction"); s_numMIDIDev = getsym("prSetNumberOfDevices"); s_midiclient = getsym("MIDIClient"); definePrimitive(base, index++, "_ListMIDIEndpoints", prListMIDIEndpoints, 1, 0); definePrimitive(base, index++, "_InitMIDI", prInitMIDI, 3, 0); definePrimitive(base, index++, "_InitMIDIClient", prInitMIDIClient, 1, 0); definePrimitive(base, index++, "_ConnectMIDIIn", prConnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisconnectMIDIIn", prDisconnectMIDIIn, 3, 0); definePrimitive(base, index++, "_DisposeMIDIClient", prDisposeMIDIClient, 1, 0); definePrimitive(base, index++, "_RestartMIDI", prRestartMIDI, 1, 0); definePrimitive(base, index++, "_SendMIDIOut", prSendMIDIOut, 9, 0); definePrimitive(base, index++, "_SendSysex", prSendSysex, 3, 0); midiCleanUp(); } void deinitMIDIPrimitives() { midiCleanUp(); } SuperCollider-Source/lang/LangPrimSource/SC_Speech.cpp000644 000765 000024 00000023162 12321461511 023770 0ustar00crucialstaff000000 000000 /* * SC_Speech.h * SC3lang * * Created by jan truetzschler v. falkenstein on Wed Apr 16 2003. * Copyright (c) 2003 sampleAndHold.org. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "InitAlloc.h" #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" ///////////////////// const int kMaxSpeechChannels = 32; PyrSymbol * s_speech; PyrSymbol * s_speechwordAction; PyrSymbol * s_speechdoneAction; SpeechChannel fCurSpeechChannel[kMaxSpeechChannels]; char *speechStrings[kMaxSpeechChannels]; pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ); pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ) { //call action here; // post("text done"); gLangMutex.lock(); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); // Set the class //set arguments: ++g->sp;SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechdoneAction, 2); if(speechStrings[(int) inRefCon] != NULL){ free(speechStrings[(int) inRefCon]); speechStrings[(int) inRefCon] = NULL; } g->canCallOS = false; gLangMutex.unlock(); } pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen); pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen) { //post("word done"); gLangMutex.lock(); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); //set arguments: ++g->sp; SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechwordAction, 2); g->canCallOS = false; gLangMutex.unlock(); } int prInitSpeech(struct VMGlobals *g, int numArgsPushed); int prInitSpeech(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-1; PyrSlot *b = g->sp; int chan; slotIntVal(b, &chan); if (chan < 0 || chan >= kMaxSpeechChannels) return errIndexOutOfRange; for (int i=0; isp-2; PyrSlot *a = g->sp-1; PyrSlot *str = g->sp; int chan; slotIntVal(a, &chan); chan = sc_clip(chan, 0, kMaxSpeechChannels); if(speechStrings[chan] != NULL) { post("voice %i already speaking\n", chan); return errNone; } else { // speechStrings[chan] = (char*)pyr_pool_compile->Alloc((slotRawObject(a)->size + 1)* sizeof(char)); speechStrings[chan] = (char*) malloc((slotRawObject(str)->size + 1)* sizeof(char)); MEMFAIL(speechStrings[chan]); slotStrVal(str, speechStrings[chan], slotRawObject(str)->size+1); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SpeakText( fCurSpeechChannel[chan], speechStrings[chan], strlen(speechStrings[chan])); //should be freed only after the text was spoken! // todo move this bit to the callback! // pyr_pool_compile->Free(theTextToSpeak); } return errNone; } int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed); int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newRate = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soRate, &newRate); return errNone; } int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newVal = (Fixed)(val * 65536.0); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechPitch (fCurSpeechChannel[chan], newVal); return errNone; } int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soPitchMod, &newVal); return errNone; } int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed) { OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan; slotIntVal(b, &chan); slotDoubleVal(c, &val); Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soVolume, &newVal); return errNone; } // theErr = PauseSpeechAt (fCurSpeechChannel, kImmediate); // theErr = ContinueSpeech (fCurSpeechChannel); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); //Fixed newVal = (Fixed)(val * 65536.0); if(val) { theErr = ContinueSpeech(fCurSpeechChannel[chan] ); } else { theErr = PauseSpeechAt(fCurSpeechChannel[chan], kImmediate); } return errNone; } int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed); int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int selector [3] = {kImmediate, kEndOfWord, kEndOfWord}; int val; int chan; slotIntVal(b, &chan); slotIntVal(c, &val); StopSpeechAt(fCurSpeechChannel[chan], selector[val]); if(speechStrings[chan] != NULL) { free(speechStrings[chan]); speechStrings[chan] = NULL; } return errNone; } int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan; VoiceSpec theVoiceSpec; slotIntVal(b, &chan); slotIntVal(c, &val); theErr = GetIndVoice (val, &theVoiceSpec); if (SetSpeechInfo (fCurSpeechChannel[chan], soCurrentVoice, &theVoiceSpec) == incompatibleVoice) return (!errNone); return errNone; } int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed); int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed){ PyrSlot *out = g->sp-1; PyrSlot *b = g->sp; int chan; slotIntVal(b, &chan); if(speechStrings[chan] != NULL) SetTrue(out); else SetFalse(out); return errNone; } void initSpeechPrimitives () { int base, index; base = nextPrimitiveIndex(); index = 0; s_speechwordAction = getsym("doWordAction"); s_speechdoneAction = getsym("doSpeechDoneAction"); s_speech = getsym("Speech"); definePrimitive(base, index++, "_SpeakText", prSpeakText, 3, 0); definePrimitive(base, index++, "_InitSpeech", prInitSpeech, 2, 0); definePrimitive(base, index++, "_SetSpeechRate", prSetSpeechRate, 3, 0); definePrimitive(base, index++, "_SetSpeechPitch", prSetSpeechPitch, 3, 0); definePrimitive(base, index++, "_SetSpeechPitchMod", prSetSpeechPitchMod, 3, 0); definePrimitive(base, index++, "_SetSpeechVoice", prSetSpeechVoice, 3, 0); definePrimitive(base, index++, "_SetSpeechVolume", prSetSpeechVolume, 3, 0); definePrimitive(base, index++, "_SetSpeechPause", prSetSpeechPause, 3, 0); //0 pause, 1 continue definePrimitive(base, index++, "_SetSpeechStopAt", prSetSpeechStop, 3, 0); //0 kImmediate, 1 kEndOfWord, 2 kEndOfSentence definePrimitive(base, index++, "_SpeechVoiceIsSpeaking", prSpeechVoiceIsSpeaking, 2, 0); for(int i=0; i #include "InitAlloc.h" #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #import #import #import #import #import #import //comment the following line to use cocoa speech #define useCarbonSpeech ///////////////////// const int kMaxSpeechChannels = 32; PyrSymbol * s_speech; PyrSymbol * s_speechwordAction; PyrSymbol * s_speechdoneAction; #ifdef useCarbonSpeech SpeechChannel fCurSpeechChannel[kMaxSpeechChannels]; char *speechStrings[kMaxSpeechChannels]; #else //NSSpeechSynthesizer* speechSynths[kMaxSpeechChannels]; NSArray * speechSynthsArray; #endif pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ); pascal void OurSpeechDoneCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon ) { //call action here; // post("text done"); #ifdef useCarbonSpeech gLangMutex.lock(); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); // Set the class //set arguments: ++g->sp;SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechdoneAction, 2); if(speechStrings[(int) inRefCon] != NULL){ free(speechStrings[(int) inRefCon]); speechStrings[(int) inRefCon] = NULL; } g->canCallOS = false; gLangMutex.unlock(); #endif } pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen); pascal void OurWordCallBackProc ( SpeechChannel inSpeechChannel, long inRefCon, long inWordPos, short inWordLen) { //post("word done"); #ifdef useCarbonSpeech gLangMutex.lock(); VMGlobals *g = gMainVMGlobals; g->canCallOS = true; ++g->sp; SetObject(g->sp, s_speech->u.classobj); //set arguments: ++g->sp; SetInt(g->sp, (int) inRefCon); //src runInterpreter(g, s_speechwordAction, 2); g->canCallOS = false; gLangMutex.unlock(); #endif } int prInitSpeech(struct VMGlobals *g, int numArgsPushed); int prInitSpeech(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-1; PyrSlot *b = g->sp; int chan, err; err = slotIntVal(b, &chan); if (err) return err; if (chan < 0 || chan >= kMaxSpeechChannels) return errIndexOutOfRange; #ifdef useCarbonSpeech for (int i=0; isp-1; PyrSlot *str = g->sp; int chan, err; err = slotIntVal(a, &chan); if (err) return err; chan = sc_clip(chan, 0, kMaxSpeechChannels); #ifdef useCarbonSpeech chan = sc_clip(chan, 0, kMaxSpeechChannels); if(speechStrings[chan] != NULL) { post("voice %i already speaking\n", chan); return errNone; } else { // speechStrings[chan] = (char*)pyr_pool_compile->Alloc((a->uo->size + 1)* sizeof(char)); speechStrings[chan] = (char*) malloc((slotRawObject(str)->size + 1)* sizeof(char)); MEMFAIL(speechStrings[chan]); slotStrVal(str, speechStrings[chan], slotRawObject(str)->size+1); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SpeakText( fCurSpeechChannel[chan], speechStrings[chan], strlen(speechStrings[chan])); } #else // gLangMutex.lock(); NSAutoreleasePool *autoreleasepool= [[NSAutoreleasePool alloc] init]; NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; char cstr [str->uo->size+1]; slotStrVal(str, cstr, str->uo->size+1); // if([spsynth isSpeaking]) [spsynth stopSpeaking]; // NSString * nsstring = [NSString stringWithCString: cstr encoding: NSASCIIStringEncoding]; [spsynth startSpeakingString: [NSString stringWithCString: cstr encoding: NSASCIIStringEncoding]]; // [nsstring release]; // [nsstring release]; [autoreleasepool release]; // gLangMutex.unlock(); #endif return errNone; } int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed); int prSetSpeechRate(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotDoubleVal(c, &val); if (err) return err; #ifdef useCarbonSpeech Fixed newRate = (Fixed)(val * 65536.0); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soRate, &newRate); #else // NSSpeechSynthesizer * spsynth = speechSynths[chan]; // if(!spsynth) return errNone; // [spsynth setRate: val]; #endif return errNone; } int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitch(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotDoubleVal(c, &val); if (err) return err; #ifdef useCarbonSpeech Fixed newVal = (Fixed)(val * 65536.0); //if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechPitch (fCurSpeechChannel[chan], newVal); #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; // 10.5 only ... ;-( // [spsynth setObject: val forProperty: NSSpeechPitchBaseProperty error: &err]; #endif return errNone; } int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPitchMod(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotDoubleVal(c, &val); if (err) return err; #ifdef useCarbonSpeech Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soPitchMod, &newVal); #endif return errNone; } int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVolume(struct VMGlobals *g, int numArgsPushed) { OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; double val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotDoubleVal(c, &val); if (err) return err; #ifdef useCarbonSpeech Fixed newVal = (Fixed)(val * 65536.0); // if(!fCurSpeechChannel) theErr = NewSpeechChannel( NULL, &fCurSpeechChannel ); theErr = SetSpeechInfo (fCurSpeechChannel[chan], soVolume, &newVal); #else // 10.5 :-( // NSSpeechSynthesizer * spsynth = speechSynths[chan]; // if(!spsynth) return errNone; // [spsynth setVolume: val]; #endif return errNone; } // theErr = PauseSpeechAt (fCurSpeechChannel, kImmediate); // theErr = ContinueSpeech (fCurSpeechChannel); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed); int prSetSpeechPause(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotIntVal(c, &val); if (err) return err; #ifdef useCarbonSpeech if(val) { theErr = ContinueSpeech(fCurSpeechChannel[chan] ); } else { theErr = PauseSpeechAt(fCurSpeechChannel[chan], kImmediate); } #else // NSSpeechSynthesizer * spsynth = speechSynths[chan]; // if(!spsynth) return errNone; // [spsynth setRate: val]; #endif return errNone; } int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed); int prSetSpeechStop(struct VMGlobals *g, int numArgsPushed){ //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int selector [3] = {kImmediate, kEndOfWord, kEndOfWord}; int val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotIntVal(c, &val); if (err) return err; #ifdef useCarbonSpeech StopSpeechAt(fCurSpeechChannel[chan], selector[val]); if(speechStrings[chan] != NULL) { free(speechStrings[chan]); speechStrings[chan] = NULL; } #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; [spsynth stopSpeaking]; #endif return errNone; } int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed); int prSetSpeechVoice(struct VMGlobals *g, int numArgsPushed){ OSErr theErr = noErr; //PyrSlot *a = g->sp-2; PyrSlot *b = g->sp-1; PyrSlot *c = g->sp; int val; int chan, err; err = slotIntVal(b, &chan); if (err) return err; err = slotIntVal(c, &val); if (err) return err; #ifdef useCarbonSpeech VoiceSpec theVoiceSpec; theErr = GetIndVoice (val, &theVoiceSpec); if (SetSpeechInfo (fCurSpeechChannel[chan], soCurrentVoice, &theVoiceSpec) == incompatibleVoice) { post("ERROR: Incompatible Voice\n"); return errFailed; } #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; [spsynth setVoice: [[NSSpeechSynthesizer availableVoices] objectAtIndex: val]]; #endif return errNone; } #ifndef useCarbonSpeech int prGetSpeechVoiceNames(struct VMGlobals *g, int numArgsPushed); int prGetSpeechVoiceNames(struct VMGlobals *g, int numArgsPushed){ PyrSlot *a = g->sp-1; PyrSlot *b = g->sp; NSAutoreleasePool *autoreleasepool= [[NSAutoreleasePool alloc] init]; NSString * aVoice = NULL; NSEnumerator * voiceEnumerator = [[NSSpeechSynthesizer availableVoices] objectEnumerator]; PyrObject* allVoices = newPyrArray(g->gc, (int) [[NSSpeechSynthesizer availableVoices] count] * sizeof(PyrObject), 0 , true); SetObject(a, allVoices); while(aVoice = [voiceEnumerator nextObject]) { NSDictionary * dictionaryOfVoiceAttributes = [NSSpeechSynthesizer attributesForVoice:aVoice]; NSString * voiceDisplayName = [dictionaryOfVoiceAttributes objectForKey:NSVoiceName]; PyrString *namestring = newPyrString(g->gc, [voiceDisplayName cStringUsingEncoding:[NSString defaultCStringEncoding]], 0, true); SetObject(allVoices->slots+allVoices->size++, namestring); g->gc->GCWriteNew(allVoices, (PyrObject*) namestring); // we know namestring is white so we can use GCWriteNew } [autoreleasepool release]; return errNone; } #endif int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed); int prSpeechVoiceIsSpeaking(struct VMGlobals *g, int numArgsPushed){ PyrSlot *out = g->sp-1; PyrSlot *b = g->sp; int chan, err; err = slotIntVal(b, &chan); if (err) return err; #ifdef useCarbonSpeech if(speechStrings[chan] != NULL) SetTrue(out); else SetFalse(out); #else NSSpeechSynthesizer * spsynth = [speechSynthsArray objectAtIndex: chan]; if(!spsynth) return errNone; if([spsynth isSpeaking]) SetTrue(out); else SetFalse(out); #endif return errNone; } void initSpeechPrimitives () { int base, index; base = nextPrimitiveIndex(); index = 0; s_speechwordAction = getsym("doWordAction"); s_speechdoneAction = getsym("doSpeechDoneAction"); s_speech = getsym("Speech"); definePrimitive(base, index++, "_SpeakText", prSpeakText, 3, 0); definePrimitive(base, index++, "_InitSpeech", prInitSpeech, 2, 0); definePrimitive(base, index++, "_SetSpeechRate", prSetSpeechRate, 3, 0); definePrimitive(base, index++, "_SetSpeechPitch", prSetSpeechPitch, 3, 0); definePrimitive(base, index++, "_SetSpeechPitchMod", prSetSpeechPitchMod, 3, 0); definePrimitive(base, index++, "_SetSpeechVoice", prSetSpeechVoice, 3, 0); definePrimitive(base, index++, "_SetSpeechVolume", prSetSpeechVolume, 3, 0); definePrimitive(base, index++, "_SetSpeechPause", prSetSpeechPause, 3, 0); //0 pause, 1 continue definePrimitive(base, index++, "_SetSpeechStopAt", prSetSpeechStop, 3, 0); //0 kImmediate, 1 kEndOfWord, 2 kEndOfSentence definePrimitive(base, index++, "_SpeechVoiceIsSpeaking", prSpeechVoiceIsSpeaking, 2, 0); #ifndef useCarbonSpeech definePrimitive(base, index++, "_GetSpeechVoiceNames", prGetSpeechVoiceNames, 2, 0); #endif #ifdef useCarbonSpeech for(int i=0; i #endif #include "SCBase.h" #include "VMGlobals.h" #include "PyrSymbolTable.h" #include "PyrInterpreter.h" #include "PyrKernel.h" #include "PyrObjectProto.h" #include "PyrPrimitiveProto.h" #include "PyrKernelProto.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "PyrSched.h" #include "GC.h" #ifdef HAVE_WII #ifdef __APPLE__ #include #include extern "C"{ #include "WiiMote_OSX/wiiremote.h" } #endif // __APPLE__ #ifdef __linux__ #include #include #include #include extern "C"{ #include // #include // #include // #include // #include } #endif // __linux__ // common: #include #include //--------- PyrSymbols ------------ PyrSymbol * s_wiiDisconnected; PyrSymbol * s_wiiConnected; PyrSymbol * s_handleEvent; PyrSymbol * s_handleBatteryEvent; PyrSymbol * s_handleExtensionEvent; PyrSymbol * s_handleNunchukEvent; PyrSymbol * s_handleClassicEvent; PyrSymbol * s_handleIREvent; PyrSymbol * s_handleAccEvent; PyrSymbol * s_handleButtonEvent; static PyrSymbol* s_wii = 0; static PyrSymbol* s_wiiCalibrationInfoClass = 0; static PyrSymbol* s_wiiLEDStateClass = 0; static PyrSymbol* s_readError = 0; extern bool compiledOK; //int gNumberOfWiiDevices = 0; #ifdef __APPLE__ EventLoopTimerRef gWiiTimer = NULL; // timer for element data updates #endif // --------------- SC_WII structure -------------- struct SC_WII { SC_WII(PyrObject *obj); ~SC_WII(); bool open(); bool close(); bool wii_connect(); bool wii_disconnect(); int enable( bool enab ); void disconnected(); void connected(); void get_address(); // void set_address( char * addr ); // void speaker_init( int format ); bool update(); #ifdef __linux__ void handleBatteryEvent( uint8_t battery ); void handleButtonEvent( uint16_t buttons ); void handleAccEvent( uint8_t acc[3] ); void handleIREvent( int id, cwiid_ir_src ir ); void handleNunchukEvent( struct cwiid_nunchuk_mesg nunchuk ); void handleClassicEvent( struct cwiid_classic_mesg classic ); void handleExtensionEvent( int ext_type ); #endif #ifdef __APPLE__ // void handleBatteryEvent( ); // void handleButtonEvent( ); // void handleAccEvent( ); // void handleIREvent( ); // void handleNunchukEvent( ); // void handleClassicEvent( ); void handleEvent(); #endif void readError(); static PyrObject* getObject(PyrSlot* slot) { return isKindOfSlot(slot, s_wii->u.classobj) ? slotRawObject(slot) : 0; } static SC_WII* getDevice(PyrObject* obj) { return (SC_WII*)slotRawPtr(obj->slots); } #ifdef __APPLE__ WiiRemoteRef m_wiiremote; char m_address[32]; #endif #ifdef __linux__ cwiid_wiimote_t *m_wiiremote; int id; unsigned char rpt_mode; unsigned char led_state; char m_address[19]; #endif bool m_connected; int m_searching; SC_WII* m_next; PyrObject* m_obj; }; // ---------------- SC_WIIManager structure -------------- struct SC_WIIManager { public: static SC_WIIManager& instance(); int start( float updtime ); int stop(); #ifdef __linux__ cwiid_wiimote_t * discover(); #endif #ifdef __APPLE__ WiiRemoteRef discover(); #endif int add(SC_WII *dev); int remove(SC_WII *dev); /// kind of private, but used in callback function and getWiiData SC_WII* m_devices; private: SC_WIIManager(); ~SC_WIIManager(); void loop(); bool m_running; float m_updatetime; }; #ifdef __linux__ /// linux specific cwiid functions #define toggle_bit(bf,b) \ (bf) = ((bf) & b) \ ? ((bf) & ~(b)) \ : ((bf) | (b)) void set_bit( unsigned char * bf, unsigned char b ) { if (!(*bf & b) ) toggle_bit( *bf, b ); } void clear_bit( unsigned char * bf, unsigned char b ) { if ((*bf & b) ) toggle_bit( *bf, b ); } cwiid_mesg_callback_t cwiid_callback; void set_led_state(cwiid_wiimote_t *wiimote, unsigned char led_state); void set_rpt_mode(cwiid_wiimote_t *wiimote, unsigned char rpt_mode); cwiid_err_t err; void err(cwiid_wiimote_t *wiimote, const char *s, va_list ap) { if (wiimote) printf("%d:", cwiid_get_id(wiimote)); else printf("-1:"); vprintf(s, ap); printf("\n"); } void set_led_state(cwiid_wiimote_t *wiimotet, unsigned char led_state) { // printf( "set_led_state %i\n", led_state ); if (cwiid_set_led(wiimotet, led_state)) { post( "WII Error: Unable to set led state\n"); } } void set_rpt_mode(cwiid_wiimote_t *wiimotet, unsigned char rpt_mode) { if (cwiid_set_rpt_mode(wiimotet, rpt_mode)) { post( "WII Error: Unable to set report mode\n"); } } #endif #ifdef __APPLE__ void GetWii_Events(); static pascal void IdleTimerWii (EventLoopTimerRef inTimer, void* userData); static EventLoopTimerUPP GetTimerUPPWii (void); static pascal void IdleTimerWii (EventLoopTimerRef inTimer, void* userData) { #pragma unused (inTimer, userData) GetWii_Events (); } static EventLoopTimerUPP GetTimerUPPWii (void) { static EventLoopTimerUPP sTimerUPP = NULL; if (sTimerUPP == NULL) sTimerUPP = NewEventLoopTimerUPP (IdleTimerWii); return sTimerUPP; } #endif //------------ SC_WIIManager functions -------- SC_WIIManager& SC_WIIManager::instance() { static SC_WIIManager instance; return instance; } SC_WIIManager::SC_WIIManager() : m_running(false), m_devices(0) { #ifdef __linux__ cwiid_set_err(err); #endif #ifdef __APPLE__ NumVersion outSoftwareVersion; BluetoothHCIVersionInfo outHardwareVersion; // post("aka.wiiremote 1.0B6-UB by Masayuki Akamatsu"); if (IOBluetoothGetVersion(&outSoftwareVersion, &outHardwareVersion)==kIOReturnSuccess) { if (outSoftwareVersion.majorRev < 1 && outSoftwareVersion.minorAndBugRev < 0x63) { error("WII: requires Bluetooth version 1.6.3 or later."); return; } } else { error("WII: can't get Bluetooth version."); return; } #endif } SC_WIIManager::~SC_WIIManager() { #ifdef __APPLE__ if (gWiiTimer) { RemoveEventLoopTimer(gWiiTimer); gWiiTimer = NULL; } #endif } int SC_WIIManager::start( float updtime ) { /// nothing to do for Linux #ifdef __APPLE__ m_updatetime = (updtime / 1000); // convert to seconds post( "WII: eventloop updatetime %f\n", m_updatetime ); //double eventtime = (double) updtime; if(gWiiTimer) { RemoveEventLoopTimer(gWiiTimer); gWiiTimer = NULL; } InstallEventLoopTimer (GetCurrentEventLoop(), 0, (EventTimerInterval) m_updatetime, GetTimerUPPWii (), 0, &gWiiTimer); #endif return errNone; } #ifdef __linux__ cwiid_wiimote_t * SC_WIIManager::discover() { bdaddr_t bdaddr = {0, 0, 0, 0, 0, 0}; cwiid_wiimote_t* wiimotediscovered; if ( (wiimotediscovered = cwiid_open(&bdaddr, 0)) == NULL ) { return NULL; } if (cwiid_set_mesg_callback(wiimotediscovered, cwiid_callback)) { post("ERROR: WII: Unable to set message callback\n"); if ( cwiid_close(wiimotediscovered) ){ post("ERROR: WII: Unable to close Wii\n"); } return NULL; } /// adding these as devices in the primitive! this is the only way to be able to connect, as the connection uses much more info than I thought! return( wiimotediscovered ); } #endif #ifdef __APPLE__ WiiRemoteRef SC_WIIManager::discover() { /* WiiRemoteRef newwii; char address[32]; newwii = (WiiRemoteRef)malloc(sizeof(WiiRemoteRec)); if (newwii != NULL) { wiiremote_init(newwii); bool result; result = wiiremote_search( newwii, address); // start searching the device // m_searching++; post("WII: searching wiimote %i\n",result); } return( newwii ); */ } #endif int SC_WIIManager::stop() { /// nothing to do on LINUX #ifdef __APPLE__ if (gWiiTimer) { RemoveEventLoopTimer(gWiiTimer); gWiiTimer = NULL; } #endif return errNone; } int SC_WIIManager::add(SC_WII* dev) { // post("WII: SC_WIIManager::add\n"); if (dev->m_next) return false; if (m_devices == dev ) { m_devices = dev; } else { dev->m_next = m_devices; m_devices = dev; } #ifdef __linux__ dev->id = cwiid_get_id( dev->m_wiiremote ); if (cwiid_enable(dev->m_wiiremote, CWIID_FLAG_MESG_IFC)) { post("ERROR: WII: Unable to enable Wii\n"); } dev->rpt_mode = CWIID_RPT_STATUS; dev->led_state = 0; set_rpt_mode( dev->m_wiiremote, dev->rpt_mode ); set_led_state( dev->m_wiiremote, dev->led_state ); #endif //#ifdef __APPLE__ // dev->wii_connect(); //#endif return true; } int SC_WIIManager::remove(SC_WII* dev) { SC_WII *prev = 0, *cur = m_devices; while (cur) { if (cur == dev) { if (prev) prev->m_next = dev->m_next; else m_devices = dev->m_next; dev->m_next = 0; delete dev; return errNone; } prev = cur; cur = cur->m_next; } return errFailed; } #ifdef __linux__ void cwiid_callback(cwiid_wiimote_t *wiimotet, int mesg_count, union cwiid_mesg mesg[], struct timespec *timestamp) { int i, j; int valid_source; int thisid, id; SC_WII *dev = SC_WIIManager::instance().m_devices; id = 0; thisid = cwiid_get_id( wiimotet ); while (dev) { if ( thisid == dev->id ) { break; } dev = dev->m_next; } for (i=0; i < mesg_count; i++) { switch (mesg[i].type) { case CWIID_MESG_STATUS: dev->handleBatteryEvent( mesg[i].status_mesg.battery ); dev->handleExtensionEvent( mesg[i].status_mesg.ext_type ); break; case CWIID_MESG_BTN: dev->handleButtonEvent( mesg[i].btn_mesg.buttons ); break; case CWIID_MESG_ACC: dev->handleAccEvent( mesg[i].acc_mesg.acc ); break; case CWIID_MESG_IR: for (j = 0; j < CWIID_IR_SRC_COUNT; j++) { dev->handleIREvent( j, mesg[i].ir_mesg.src[j] ); } break; case CWIID_MESG_NUNCHUK: dev->handleNunchukEvent( mesg[i].nunchuk_mesg ); break; case CWIID_MESG_CLASSIC: dev->handleClassicEvent( mesg[i].classic_mesg ); break; case CWIID_MESG_ERROR: dev->disconnected(); dev->readError(); break; default: post("WII: Unknown Report"); break; } } } #endif #ifdef __APPLE__ void GetWii_Events (){ SC_WII *dev = SC_WIIManager::instance().m_devices; // m_devices; int debugcnt = 0; while (dev) { bool connection; // post( "WII: device %i, t %p, w %p, n %p\n", debugcnt, dev, dev->m_wiiremote, dev->m_next); debugcnt++; if ( dev->m_wiiremote != NULL ) { connection = wiiremote_isconnected(dev->m_wiiremote); if ( dev->m_connected == false && connection == true) // if the device is connected, but wasn't before { // post( "WII: wiimote got connected\n"); wiiremote_getstatus(dev->m_wiiremote); dev->connected(); } else if (dev->m_connected == true && connection == false) // if device was disconnected { // post( "WII: wiimote got disconnected\n"); dev->disconnected(); } else if ( dev->m_searching > 0 ) { dev->wii_connect(); } if ( dev->m_connected ) { // post( "WII: wiimote is connected\n"); wiiremote_getstatus(dev->m_wiiremote); dev->handleEvent(); } else { // post("WII: wiimote not connected\n"); } } else { // post("WII: read error\n"); dev->readError(); } dev = dev->m_next; } } #endif //---------------- SC_WII functions ----------------- SC_WII::SC_WII(PyrObject* obj) : m_next(0), m_obj(obj) { // #ifdef __linux__ // m_report = nil; // #endif m_wiiremote = NULL; m_searching = 0; m_connected = false; // m_address; SetPtr(obj->slots+0, this); } SC_WII::~SC_WII() { close(); } bool SC_WII::open() { #ifdef __APPLE__ m_wiiremote = (WiiRemoteRef)malloc(sizeof(WiiRemoteRec)); if (m_wiiremote != NULL) { wiiremote_init(m_wiiremote); m_wiiremote->isMotionSensorEnabled = true; m_wiiremote->isIRSensorEnabled = false; m_wiiremote->isVibrationEnabled = false; m_wiiremote->isExpansionPortEnabled = false; m_wiiremote->isLED1Illuminated = false; m_wiiremote->isLED2Illuminated = false; m_wiiremote->isLED3Illuminated = false; m_wiiremote->isLED4Illuminated = false; m_connected = false; // return SC_WIIManager::instance().add(this); } #endif #ifdef __linux__ // m_wiiremote = (wiimote_t*)malloc(sizeof(wiimote_t)); // m_report = (wiimote_report_t)malloc(sizeof(wiimote_report_t)); // if ( m_wiiremote != NULL ) // { // *m_wiiremote = WIIMOTE_INIT; // m_report = WIIMOTE_REPORT_INIT; // m_connected = false; // return SC_WIIManager::instance().add(this); // } #endif return( false ); } bool SC_WII::close() { if (m_wiiremote != NULL) { #ifdef __APPLE__ if (wiiremote_isconnected(m_wiiremote)) wiiremote_disconnect(m_wiiremote); ; //m_wiiremote, sizeof(WiiRemoteRec)); m_wiiremote = NULL; m_searching = 0; #endif #ifdef __linux__ if ( cwiid_close( m_wiiremote ) ){ // m_wiiremote = NULL; post( "error closing device\n" ); fflush( stdout ); return errFailed; } m_wiiremote = NULL; // return errNone; // if (wiimote_is_open(m_wiiremote)) // wiimote_disconnect(m_wiiremote); #endif } // SetNil(m_obj->slots+0); return SC_WIIManager::instance().remove(this); } bool SC_WII::wii_connect() { #ifdef __APPLE__ if (wiiremote_isconnected(m_wiiremote)) { post("WII: wiimote is already connected\n"); m_connected = true; } else { bool result; result = wiiremote_search( m_wiiremote, m_address); // start searching the device m_searching++; post("WII: searching wiimote %i\n",result); if ( result ) m_connected = true; else m_connected = false; } #endif #ifdef __linux__ // if (wiimote_connect(m_wiiremote, m_address) < 0) { // post("WII: unable to open wiimote: %s at address %s\n", wiimote_get_error(), m_address); // post("WII: unable to open wiimote at address %s\n",m_address); // m_connected = false; // } // else m_connected = true; #endif return( m_connected ); } void SC_WII::connected() { bool result; m_connected = true; m_searching = 0; #ifdef __APPLE__ result = wiiremote_led( m_wiiremote, 0, 0, 0, 0); // if ( !result ) // wii_disconnect(); #endif // post("WII: wiiremote connected\n"); gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_wiiConnected, 1); g->canCallOS = false; } gLangMutex.unlock(); } bool SC_WII::wii_disconnect() { bool result; m_searching = 0; /// TODO: remove from wii_manager #ifdef __APPLE__ wiiremote_stopsearch( m_wiiremote ); result = wiiremote_disconnect( m_wiiremote); #endif #ifdef __linux__ // result = wiimote_disconnect(m_wiiremote); #endif // call disconnect action if ( result ) disconnected(); return( result ); } int SC_WII::enable( bool enab ) { #ifdef __linux__ if ( enab ) { if (cwiid_enable(m_wiiremote, CWIID_FLAG_MESG_IFC)) { return errFailed; } } else { if (cwiid_disable(m_wiiremote, CWIID_FLAG_MESG_IFC)) { return errFailed; } } return errNone; #endif return errNone; } void SC_WII::disconnected() { m_connected = false; m_searching = 0; gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_wiiDisconnected, 1); g->canCallOS = false; } gLangMutex.unlock(); } // void SC_WII::speaker_init( int format ) // { // if ( format == 4 ) // wiimote_speaker_init(m_wiiremote, WIIMOTE_FMT_S4, 0xff); // else if ( format == 8 ) // wiimote_speaker_init(m_wiiremote, WIIMOTE_FMT_S8, 0xff); // } void SC_WII::get_address() { #ifdef __APPLE__ if (m_wiiremote->device == NULL) { return; } else { char str[32]; wiiremote_getaddress(m_wiiremote, str); strcpy(m_address, str); } #endif } // bool SC_WII::update() // { // if (wiimote_update(m_wiiremote) < 0) { // wiimote_disconnect(m_wiiremote); // post( "WII: wiimote got disconnected\n"); // disconnected(); // return( false ); // } // return( true ); // } // void SC_WII::set_address( char * addr ) // { // strcpy( m_address, addr ); // // post( "WII: addr %s, m_address %s\n", addr, m_address ); // } #ifdef __APPLE__ void SC_WII::handleEvent() { if (m_wiiremote->device == NULL) return; // do nothing gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); // buttons // post( "buttondata %i\n", m_wiiremote->buttonData); // ++g->sp; SetInt(g->sp, m_wiiremote->buttonData); PyrObject *butArray = newPyrArray(g->gc, 11 * sizeof(int), 0, true); PyrSlot *butArraySlots = butArray->slots; SetInt(butArray->slots+butArray->size++, (int) ((0x0008 & m_wiiremote->buttonData) > 0) ); //A SetInt(butArray->slots+butArray->size++, (int) ((0x0004 & m_wiiremote->buttonData) > 0) ); //B SetInt(butArray->slots+butArray->size++, (int) ((0x0002 & m_wiiremote->buttonData) > 0) ); //1 SetInt(butArray->slots+butArray->size++, (int) ((0x0001 & m_wiiremote->buttonData) > 0) ); //2 SetInt(butArray->slots+butArray->size++, (int) ((0x0010 & m_wiiremote->buttonData) > 0) ); //minus SetInt(butArray->slots+butArray->size++, (int) ((0x0080 & m_wiiremote->buttonData) > 0) ); //home SetInt(butArray->slots+butArray->size++, (int) ((0x1000 & m_wiiremote->buttonData) > 0) ); // plus SetInt(butArray->slots+butArray->size++, (int) ((0x0800 & m_wiiremote->buttonData) > 0) ); // up SetInt(butArray->slots+butArray->size++, (int) ((0x0400 & m_wiiremote->buttonData) > 0) ); // down SetInt(butArray->slots+butArray->size++, (int) ((0x0100 & m_wiiremote->buttonData) > 0) ); // left SetInt(butArray->slots+butArray->size++, (int) ((0x0200 & m_wiiremote->buttonData) > 0) ); // right butArray->size = 11; ++g->sp; SetObject(g->sp, butArray); if (m_wiiremote->isIRSensorEnabled) {// IR sensor ++g->sp; SetFloat(g->sp, m_wiiremote->posX); ++g->sp; SetFloat(g->sp, m_wiiremote->posY); ++g->sp; SetFloat(g->sp, m_wiiremote->angle); ++g->sp; SetInt(g->sp, m_wiiremote->tracking); } else { ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } if (m_wiiremote->isMotionSensorEnabled) { // motion sensor ++g->sp; SetFloat(g->sp, (float) m_wiiremote->accX / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->accY / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->accZ / 256); ++g->sp; SetInt(g->sp, m_wiiremote->orientation); } else { ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } if (m_wiiremote->isExpansionPortAttached && m_wiiremote->isExpansionPortEnabled) { ++g->sp; SetInt(g->sp, m_wiiremote->expType); // Classic Controller if (m_wiiremote->expType == WiiClassicController) { // buttons //++g->sp; SetInt(g->sp, m_wiiremote->cButtonData); PyrObject *outArray = newPyrArray(g->gc, 15 * sizeof(char), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((0x0008 & m_wiiremote->cButtonData) > 0) ); //X SetInt(outArray->slots+outArray->size++, (int) ((0x0020 & m_wiiremote->cButtonData) > 0) ); //Y SetInt(outArray->slots+outArray->size++, (int) ((0x0010 & m_wiiremote->cButtonData) > 0) ); //A SetInt(outArray->slots+outArray->size++, (int) ((0x0040 & m_wiiremote->cButtonData) > 0) ); //B SetInt(outArray->slots+outArray->size++, (int) ((0x2000 & m_wiiremote->cButtonData) > 0) ); //L SetInt(outArray->slots+outArray->size++, (int) ((0x0200 & m_wiiremote->cButtonData) > 0) ); //R SetInt(outArray->slots+outArray->size++, (int) ((0x0080 & m_wiiremote->cButtonData) > 0) ); //ZL SetInt(outArray->slots+outArray->size++, (int) ((0x0004 & m_wiiremote->cButtonData) > 0) ); //ZR SetInt(outArray->slots+outArray->size++, (int) ((0x0001 & m_wiiremote->cButtonData) > 0) ); //Up SetInt(outArray->slots+outArray->size++, (int) ((0x4000 & m_wiiremote->cButtonData) > 0) ); //Down SetInt(outArray->slots+outArray->size++, (int) ((0x0002 & m_wiiremote->cButtonData) > 0) ); //Left SetInt(outArray->slots+outArray->size++, (int) ((0x8000 & m_wiiremote->cButtonData) > 0) );//Right SetInt(outArray->slots+outArray->size++, (int) ((0x1000 & m_wiiremote->cButtonData) > 0) );//Minus SetInt(outArray->slots+outArray->size++, (int) ((0x0800 & m_wiiremote->cButtonData) > 0) );//Home SetInt(outArray->slots+outArray->size++, (int) ((0x0400 & m_wiiremote->cButtonData) > 0) );//Plus outArray->size = 15; ++g->sp; SetObject(g->sp, outArray); // Joystick 1 ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickX1 / 0x3F); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickY1 / 0x3F); // Joystick 2 ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickX2 / 0x1F); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cStickY2 / 0x1F); // Analog ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cAnalogL / 0x1F); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->cAnalogR / 0x1F); } // Nunchuk if (m_wiiremote->expType == WiiNunchuk) { // Buttons //++g->sp; SetInt(g->sp, m_wiiremote->nButtonData); PyrObject *butArrayN = newPyrArray(g->gc, 2 * sizeof(int), 0, true); PyrSlot *butArraySlotsN = butArrayN->slots; SetInt(butArrayN->slots+butArrayN->size++, (int) ((0x01 & m_wiiremote->nButtonData) < 1) ); SetInt(butArrayN->slots+butArrayN->size++, (int) ((0x02 & m_wiiremote->nButtonData) < 1) ); butArrayN->size = 2; ++g->sp; SetObject(g->sp, butArrayN); // Joystick ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nStickX / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nStickY / 256); // Motion Sensor if (m_wiiremote->isMotionSensorEnabled) { ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nAccX / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nAccY / 256); ++g->sp; SetFloat(g->sp, (float) m_wiiremote->nAccZ / 256); ++g->sp; SetInt(g->sp, m_wiiremote->nOrientation); } else { ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetFloat(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } } } else { ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); ++g->sp; SetInt(g->sp, 0); } ++g->sp; SetFloat(g->sp, m_wiiremote->batteryLevel); runInterpreter(g, s_handleEvent, 19); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleBatteryEvent( uint8_t battery ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetFloat(g->sp, (float) battery / CWIID_BATTERY_MAX ); runInterpreter(g, s_handleBatteryEvent, 2); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleExtensionEvent( int ext_type ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, ext_type ); runInterpreter(g, s_handleExtensionEvent, 2); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleButtonEvent( uint16_t buttons ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); // post( "handle Button Event\n" ); // fflush( stdout ); // ++g->sp; SetInt(g->sp, (int) buttons ); PyrObject *outArray = newPyrArray(g->gc, 11 * sizeof(int), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_A & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_B & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_1 & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_2 & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_MINUS & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_HOME & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_PLUS & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_UP & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_DOWN & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_LEFT & buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_BTN_RIGHT & buttons) > 0) ); outArray->size = 11; ++g->sp; SetObject(g->sp, outArray); runInterpreter(g, s_handleButtonEvent, 2); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleAccEvent( uint8_t acc[3] ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetFloat(g->sp, (float) acc[CWIID_X]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) acc[CWIID_Y]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) acc[CWIID_Z]/CWIID_ACC_MAX ); runInterpreter(g, s_handleAccEvent, 4); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleNunchukEvent( struct cwiid_nunchuk_mesg nunchuk ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); PyrObject *outArray = newPyrArray(g->gc, 2 * sizeof(int), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((CWIID_NUNCHUK_BTN_Z & nunchuk.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_NUNCHUK_BTN_C & nunchuk.buttons) > 0) ); outArray->size = 2; ++g->sp; SetObject(g->sp, outArray); // ++g->sp; SetInt(g->sp, (int) nunchuk.buttons); ++g->sp; SetFloat(g->sp, (float) nunchuk.stick[CWIID_X]/256); ++g->sp; SetFloat(g->sp, (float) nunchuk.stick[CWIID_Y]/256); ++g->sp; SetFloat(g->sp, (float) nunchuk.acc[CWIID_X]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) nunchuk.acc[CWIID_Y]/CWIID_ACC_MAX ); ++g->sp; SetFloat(g->sp, (float) nunchuk.acc[CWIID_Z]/CWIID_ACC_MAX ); runInterpreter(g, s_handleNunchukEvent, 7); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleClassicEvent( struct cwiid_classic_mesg classic ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); PyrObject *outArray = newPyrArray(g->gc, 15 * sizeof(char), 0, true); PyrSlot *outArraySlots = outArray->slots; SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_X & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_Y & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_A & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_B & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_L & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_R & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_ZL & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_ZR & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_UP & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_DOWN & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_LEFT & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_RIGHT & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_MINUS & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_HOME & classic.buttons) > 0) ); SetInt(outArray->slots+outArray->size++, (int) ((CWIID_CLASSIC_BTN_PLUS & classic.buttons) > 0) ); outArray->size = 15; ++g->sp; SetObject(g->sp, outArray); // ++g->sp; SetInt(g->sp, (int) classic.buttons); ++g->sp; SetFloat(g->sp, (float) classic.l_stick[CWIID_X]/CWIID_CLASSIC_L_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.l_stick[CWIID_Y]/CWIID_CLASSIC_L_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.r_stick[CWIID_X]/CWIID_CLASSIC_R_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.r_stick[CWIID_Y]/CWIID_CLASSIC_R_STICK_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.l/CWIID_CLASSIC_LR_MAX ); ++g->sp; SetFloat(g->sp, (float) classic.r/CWIID_CLASSIC_LR_MAX ); runInterpreter(g, s_handleClassicEvent, 8); g->canCallOS = false; } gLangMutex.unlock(); } #endif #ifdef __linux__ void SC_WII::handleIREvent( int id, cwiid_ir_src ir ){ gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); ++g->sp; SetInt(g->sp, id); ++g->sp; SetInt(g->sp, ir.valid); ++g->sp; SetFloat(g->sp, (float) ir.pos[CWIID_X]/CWIID_IR_X_MAX); ++g->sp; SetFloat(g->sp, (float) ir.pos[CWIID_Y]/CWIID_IR_Y_MAX); ++g->sp; SetFloat(g->sp, (float) ir.size/256); runInterpreter(g, s_handleIREvent, 6); g->canCallOS = false; } gLangMutex.unlock(); } #endif void SC_WII::readError() { gLangMutex.lock(); if (compiledOK) { VMGlobals* g = gMainVMGlobals; g->canCallOS = false; ++g->sp; SetObject(g->sp, m_obj); runInterpreter(g, s_readError, 1); g->canCallOS = false; } gLangMutex.unlock(); // SC_WIIManager::instance().remove( this ); } //------------ primitives --------------- int prWii_Start(VMGlobals* g, int numArgsPushed) { float updtime; int err; PyrSlot* args = g->sp - 1; // PyrSlot* args = g->sp; err = slotFloatVal(args+1, &updtime); if (err) return err; post( "update time %f", updtime ); // if (!g->canCallOS) return errCantCallOS; // return SC_WIIManager::instance().start(); return SC_WIIManager::instance().start(updtime); } int prWii_Stop(VMGlobals* g, int numArgsPushed) { // if (!g->canCallOS) return errCantCallOS; return SC_WIIManager::instance().stop(); } int prWii_Discover(VMGlobals* g, int numArgsPushed) { int curid, nmotes; int err; PyrSlot* args = g->sp - 1; err = slotIntVal(args, &curid); if (err) return err; if (!isKindOfSlot(args+1, class_array)) return errWrongType; PyrObject* allDevsArray = slotRawObject(&args[1]); PyrSlot* slotsArray = allDevsArray->slots; #ifdef __linux__ cwiid_wiimote_t * thiswii; thiswii = SC_WIIManager::instance().discover(); if ( thiswii == NULL ){ SetFalse(g->sp-2); post( "no device found\n" ); return errNone; } #endif if ( !isKindOfSlot(slotsArray+curid, s_wii->u.classobj ) ) { SetFalse(g->sp-2); return errWrongType; } PyrObject* obj = SC_WII::getObject(slotsArray+curid); SC_WII* dev = SC_WII::getDevice(obj); #ifdef __APPLE__ dev->wii_connect(); #endif // post( "dev %p, wii %p\n", dev, dev->m_wiiremote ); // if (!dev) return errFailed; // free( dev->m_wiiremote ); #ifdef __linux__ dev->m_wiiremote = thiswii; #endif if ( SC_WIIManager::instance().add( dev ) ) { post( "device added\n" ); SetTrue(g->sp-2); } else { SetFalse(g->sp-2); post( "device was already added\n" ); } return errNone; } int prWii_Open(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = new SC_WII(obj); err = dev->open(); if (err) { delete dev; return err; } return errNone; } int prWii_Close(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; return dev->close(); } int prWiiAddress(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; dev->get_address(); SetSymbol(args, getsym(dev->m_address)); return errNone; } // int prWiiSetAddress(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // #ifdef __linux__ // char path[19]; // #endif // #ifdef __APPLE__ // char path[32]; // #endif // err = slotStrVal(args+1, path, sizeof(path)); // if (err) return err; // // post( "WII: address %s\n", path ); // // dev->set_address( path ); // // return errNone; // } int prWiiConnect(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; dev->wii_connect(); return errNone; } int prWiiDisconnect(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; dev->wii_disconnect(); return errNone; } int prWiiCalibration(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; if (!isKindOfSlot(args+1, s_wiiCalibrationInfoClass->u.classobj)) return errWrongType; PyrObject* infoObj = slotRawObject(&args[1]); SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ SetFloat(infoObj->slots+0, dev->m_wiiremote->wiiCalibData.accX_zero); SetFloat(infoObj->slots+1, dev->m_wiiremote->wiiCalibData.accY_zero); SetFloat(infoObj->slots+2, dev->m_wiiremote->wiiCalibData.accZ_zero); SetFloat(infoObj->slots+3, dev->m_wiiremote->wiiCalibData.accX_1g); SetFloat(infoObj->slots+4, dev->m_wiiremote->wiiCalibData.accY_1g); SetFloat(infoObj->slots+5, dev->m_wiiremote->wiiCalibData.accZ_1g); if (dev->m_wiiremote->isExpansionPortAttached) { SetFloat(infoObj->slots+6, dev->m_wiiremote->nunchukCalibData.accX_zero); SetFloat(infoObj->slots+7, dev->m_wiiremote->nunchukCalibData.accY_zero); SetFloat(infoObj->slots+8, dev->m_wiiremote->nunchukCalibData.accZ_zero); SetFloat(infoObj->slots+9, dev->m_wiiremote->nunchukCalibData.accX_1g); SetFloat(infoObj->slots+10, dev->m_wiiremote->nunchukCalibData.accY_1g); SetFloat(infoObj->slots+11, dev->m_wiiremote->nunchukCalibData.accZ_1g); SetFloat(infoObj->slots+12, dev->m_wiiremote->nunchukJoyStickCalibData.x_max); SetFloat(infoObj->slots+13, dev->m_wiiremote->nunchukJoyStickCalibData.x_min); SetFloat(infoObj->slots+14, dev->m_wiiremote->nunchukJoyStickCalibData.x_center); SetFloat(infoObj->slots+15, dev->m_wiiremote->nunchukJoyStickCalibData.y_max); SetFloat(infoObj->slots+16, dev->m_wiiremote->nunchukJoyStickCalibData.y_min); SetFloat(infoObj->slots+17, dev->m_wiiremote->nunchukJoyStickCalibData.y_center); } #endif #ifdef __linux__ /* SetInt(infoObj->slots+0, dev->m_wiiremote->cal.x_zero); SetInt(infoObj->slots+1, dev->m_wiiremote->cal.y_zero); SetInt(infoObj->slots+2, dev->m_wiiremote->cal.z_zero); SetInt(infoObj->slots+3, dev->m_wiiremote->cal.x_scale); SetInt(infoObj->slots+4, dev->m_wiiremote->cal.y_scale); SetInt(infoObj->slots+5, dev->m_wiiremote->cal.z_scale); if (dev->m_wiiremote->mode.ext == 1) { SetInt(infoObj->slots+6, dev->m_wiiremote->ext.nunchuk.cal.x_zero); SetInt(infoObj->slots+7, dev->m_wiiremote->ext.nunchuk.cal.y_zero); SetInt(infoObj->slots+8, dev->m_wiiremote->ext.nunchuk.cal.z_zero); SetInt(infoObj->slots+9, dev->m_wiiremote->ext.nunchuk.cal.x_scale); SetInt(infoObj->slots+10, dev->m_wiiremote->ext.nunchuk.cal.y_scale); SetInt(infoObj->slots+11, dev->m_wiiremote->ext.nunchuk.cal.z_scale); SetInt(infoObj->slots+12, dev->m_wiiremote->ext.nunchuk.cal.joyx_max); SetInt(infoObj->slots+13, dev->m_wiiremote->ext.nunchuk.cal.joyx_min); SetInt(infoObj->slots+14, dev->m_wiiremote->ext.nunchuk.cal.joyx_center); SetInt(infoObj->slots+15, dev->m_wiiremote->ext.nunchuk.cal.joyy_max); SetInt(infoObj->slots+16, dev->m_wiiremote->ext.nunchuk.cal.joyy_min); SetInt(infoObj->slots+17, dev->m_wiiremote->ext.nunchuk.cal.joyy_center); }*/ #endif } slotCopy(&args[0], &args[1]); return errNone; } // int prWiiGetLED(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* leds = slotRawObject(&args[1]); // PyrSlot* bslots = leds->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->led.one); // SetInt(bslots+1, dev->m_wiiremote->led.two); // SetInt(bslots+2, dev->m_wiiremote->led.three); // SetInt(bslots+3, dev->m_wiiremote->led.four); // #endif // } // // return errNone; // } // // int prWiiGetButtons(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->keys.left); // SetInt(bslots+1, dev->m_wiiremote->keys.right); // SetInt(bslots+2, dev->m_wiiremote->keys.down); // SetInt(bslots+3, dev->m_wiiremote->keys.up); // SetInt(bslots+4, dev->m_wiiremote->keys.plus); // SetInt(bslots+5, dev->m_wiiremote->keys.two); // SetInt(bslots+6, dev->m_wiiremote->keys.one); // SetInt(bslots+7, dev->m_wiiremote->keys.b); // SetInt(bslots+8, dev->m_wiiremote->keys.a); // SetInt(bslots+9, dev->m_wiiremote->keys.minus); // SetInt(bslots+10, dev->m_wiiremote->keys.home); // #endif // } // // return errNone; // } // // int prWiiGetMotion(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->axis.x); // SetInt(bslots+1, dev->m_wiiremote->axis.y); // SetInt(bslots+2, dev->m_wiiremote->axis.z); // #endif // } // // return errNone; // } // // int prWiiGetIR(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ir1.x); // SetInt(bslots+1, dev->m_wiiremote->ir1.y); // SetInt(bslots+2, dev->m_wiiremote->ir1.size); // #endif // } // // return errNone; // } // // int prWiiGetNunchukButtons(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ext.nunchuk.keys.z); // SetInt(bslots+1, dev->m_wiiremote->ext.nunchuk.keys.c); // #endif // } // // return errNone; // } // // int prWiiGetNunchukJoy(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ext.nunchuk.joyx); // SetInt(bslots+1, dev->m_wiiremote->ext.nunchuk.joyy); // #endif // } // // return errNone; // } // // int prWiiGetNunchukMotion(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // // if (!isKindOfSlot(args+1, s_wiiLEDStateClass->u.classobj)) // // return errWrongType; // // PyrObject* infoObj = slotRawObject(&args[1]); // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (!isKindOfSlot(args+1, class_array)) // return errWrongType; // PyrObject* buttons = slotRawObject(&args[1]); // PyrSlot* bslots = buttons->slots; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // // SetInt(bslots+0, dev->m_wiiremote->isLED1Illuminated); // // SetInt(bslots+1, dev->m_wiiremote->isLED2Illuminated); // // SetInt(bslots+2, dev->m_wiiremote->isLED3Illuminated); // // SetInt(bslots+3, dev->m_wiiremote->isLED4Illuminated); // #endif // #ifdef __linux__ // SetInt(bslots+0, dev->m_wiiremote->ext.nunchuk.axis.x); // SetInt(bslots+1, dev->m_wiiremote->ext.nunchuk.axis.y); // SetInt(bslots+2, dev->m_wiiremote->ext.nunchuk.axis.z); // #endif // } // // return errNone; // } // // int prWiiGetExpansion(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // if (dev->m_wiiremote->isExpansionPortAttached) // SetInt( args, dev->m_wiiremote->expType ); // else // SetInt( args, 0 ); // #endif // // #ifdef __linux__ // // if ( dev->m_wiiremote->mode.ext == 1 ) // // SetInt( args, dev->m_wiiremote->ext.id ); // // else // // SetInt( args, 0 ); // // #endif // } // // return errNone; // } // // int prWiiGetBattery(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp; // int err; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // #ifdef __APPLE__ // if (dev->m_wiiremote->batteryLevel) // SetFloat( args, dev->m_wiiremote->batteryLevel ); // else // SetFloat( args, 0 ); // #endif // // #ifdef __linux__ // // SetFloat( args, dev->m_wiiremote->battery ); // // #endif // } // // return errNone; // } int prWiiSetLED(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; bool result; int enable1, enable2, enable3, enable4; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; if (!isKindOfSlot(args+1, class_array)) return errWrongType; PyrObject* leds = slotRawObject(&args[1]); PyrSlot* bslots = leds->slots; err = slotIntVal( bslots+0, &enable1 ); if (err) return err; err = slotIntVal( bslots+1, &enable2 ); if (err) return err; err = slotIntVal( bslots+2, &enable3 ); if (err) return err; err = slotIntVal( bslots+3, &enable4 ); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ result = wiiremote_led( dev->m_wiiremote, enable1, enable2, enable3, enable4); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->led_state, CWIID_LED1_ON); else clear_bit(&dev->led_state, CWIID_LED1_ON); if ( enable2 ) set_bit(&dev->led_state, CWIID_LED2_ON); else clear_bit(&dev->led_state, CWIID_LED2_ON); if ( enable3 ) set_bit(&dev->led_state, CWIID_LED3_ON); else clear_bit(&dev->led_state, CWIID_LED3_ON); if ( enable4 ) set_bit(&dev->led_state, CWIID_LED4_ON); else clear_bit(&dev->led_state, CWIID_LED4_ON); set_led_state(dev->m_wiiremote, dev->led_state); // post( "WII: led %i %i %i %i", dev->m_wiiremote->led.one, dev->m_wiiremote->led.two, dev->m_wiiremote->led.three, dev->m_wiiremote->led.four ); // dev->update(); #endif } return errNone; } int prWiiSetVibration(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ result = wiiremote_vibration( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); // post( "WII: rumble %i %i", enable1, result ); #endif #ifdef __linux__ if (cwiid_set_rumble(dev->m_wiiremote, (unsigned char) enable1)) { return errFailed; } // post( "WII: rumble %i %i", dev->m_wiiremote->rumble, enable1 ); #endif } return errNone; } int prWiiSetExpansion(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ result = wiiremote_expansion( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_EXT); else clear_bit(&dev->rpt_mode, CWIID_RPT_EXT); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); // post( "WII: expansion %i %i", dev->m_wiiremote->mode.ext, enable1 ); #endif } return errNone; } int prWiiSetIRSensor(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ result = wiiremote_irsensor( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_IR); else clear_bit(&dev->rpt_mode, CWIID_RPT_IR); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); // post( "WII: ir sensor %i %i", dev->m_wiiremote->mode.ir, enable1 ); #endif } return errNone; } int prWiiSetMotionSensor(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // if ( !result ) // dev->wii_disconnect(); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_ACC); else clear_bit(&dev->rpt_mode, CWIID_RPT_ACC); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); #endif } return errNone; } int prWiiSetButtons(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ // buttons are always enabled // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); #endif #ifdef __linux__ if ( enable1 ) set_bit(&dev->rpt_mode, CWIID_RPT_BTN); else clear_bit(&dev->rpt_mode, CWIID_RPT_BTN); set_rpt_mode(dev->m_wiiremote, dev->rpt_mode); #endif } return errNone; } int prWiiEnable(VMGlobals *g, int numArgsPushed) { PyrSlot* args = g->sp - 1; int err; int enable1; bool result; PyrObject* obj = SC_WII::getObject(args+0); if (!obj) return errWrongType; SC_WII* dev = SC_WII::getDevice(obj); if (!dev) return errFailed; err = slotIntVal(args+1, &enable1); if (err) return err; if (dev->m_wiiremote == NULL) { return errFailed; } else { #ifdef __APPLE__ // is always enabled // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); #endif #ifdef __linux__ dev->enable( enable1 ); #endif } return errNone; } // int prWiiPlaySpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 4; // int err; // int enable1; // int freq, vol; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // err = slotIntVal(args+2, &freq); // if (err) return err; // // err = slotIntVal(args+3, &vol); // if (err) return err; // // // err = slotIntVal(args+4, &sample); // // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef __APPLE__ // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // uint8_t sample[20] = { // 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c, // 0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c,0x3c // }; // wiimote_speaker_freq( dev->m_wiiremote, (uint8_t) freq); // wiimote_speaker_volume( dev->m_wiiremote, (uint8_t) vol ); // if ( enable1 ) // wiimote_speaker_play( dev->m_wiiremote, sample, 20); // // // post( "WII: speaker %i %i", freq, vol ); // #endif // } // // return errNone; // } // int prWiiEnableSpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // int enable1; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef __APPLE__ // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // if ( enable1 ) // wiimote_speaker_enable(dev->m_wiiremote); // else // wiimote_speaker_disable(dev->m_wiiremote); // // // post( "WII: speaker enable %i", enable1 ); // // #endif // } // // return errNone; // } // // int prWiiInitSpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // int enable1; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef __APPLE__ // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // if ( enable1 ) // dev->speaker_init( 4 ); // else // dev->speaker_init( 8 ); // // // post( "WII: speaker init %i", enable1 ); // // #endif // } // // return errNone; // } // // int prWiiMuteSpeaker(VMGlobals *g, int numArgsPushed) // { // PyrSlot* args = g->sp - 1; // int err; // int enable1; // bool result; // // PyrObject* obj = SC_WII::getObject(args+0); // if (!obj) return errWrongType; // // SC_WII* dev = SC_WII::getDevice(obj); // if (!dev) return errFailed; // // err = slotIntVal(args+1, &enable1); // if (err) return err; // // if (dev->m_wiiremote == NULL) // { // return errFailed; // } // else // { // // #ifdef __APPLE__ // // result = wiiremote_motionsensor( dev->m_wiiremote, enable1 ); // // #endif // #ifdef __linux__ // if ( enable1 ) // wiimote_speaker_mute(dev->m_wiiremote); // else // wiimote_speaker_unmute(dev->m_wiiremote); // // // post( "WII: mute %i", enable1 ); // #endif // } // // return errNone; // } void initWiiPrimitives() { int base, index; s_wii = getsym("WiiMote"); s_wiiCalibrationInfoClass = getsym("WiiCalibrationInfo"); // has calibration date for all axes // s_wiiLEDStateClass = getsym("WiiLEDState"); // has the four LED states // s_wiiRemoteClass = getsym("WiiRemote"); // Remote // s_wiiNunChuckClass = getsym("WiiNunChuck"); // NunChuck // s_wiiClassicClass = getsym("WiiClassic"); // Classic // s_wiiAction = getsym("prWiiMoteAction"); s_wiiDisconnected = getsym("prDisconnectAction"); s_wiiConnected = getsym("prConnectAction"); s_readError = getsym("prReadError"); /// general event on MacOSX s_handleEvent = getsym("prHandleEvent"); /// separate events on Linux: s_handleBatteryEvent = getsym("prHandleBatteryEvent"); s_handleExtensionEvent = getsym("prHandleExtensionEvent"); s_handleButtonEvent = getsym("prHandleButtonEvent"); s_handleNunchukEvent = getsym("prHandleNunchukEvent"); s_handleClassicEvent = getsym("prHandleClassicEvent"); s_handleIREvent = getsym("prHandleIREvent"); s_handleAccEvent = getsym("prHandleAccEvent"); base = nextPrimitiveIndex(); index = 0; definePrimitive(base, index++, "_Wii_Start", prWii_Start, 2, 0); // starts the eventloop definePrimitive(base, index++, "_Wii_Discover", prWii_Discover, 3, 0); // discovers a new device definePrimitive(base, index++, "_Wii_Stop", prWii_Stop, 1, 0); // stops the eventloop definePrimitive(base, index++, "_Wii_Open", prWii_Open, 1, 0 ); // definePrimitive(base, index++, "_Wii_Update", prWii_Update, 1, 0 ); // definePrimitive(base, index++, "_Wii_UpdateData", prWii_UpdateData, 9, 0 ); definePrimitive(base, index++, "_Wii_Close", prWii_Close, 1, 0 ); definePrimitive(base, index++, "_Wii_Address", prWiiAddress, 1, 0); // definePrimitive(base, index++, "_Wii_SetAddress", prWiiSetAddress, 2, 0); definePrimitive(base, index++, "_Wii_Connect", prWiiConnect, 1, 0); definePrimitive(base, index++, "_Wii_Disconnect", prWiiDisconnect, 1, 0); definePrimitive(base, index++, "_Wii_Calibration", prWiiCalibration, 2, 0); // definePrimitive(base, index++, "_Wii_GetExpansion", prWiiGetExpansion, 1, 0); // definePrimitive(base, index++, "_Wii_GetBattery", prWiiGetBattery, 1, 0); // // definePrimitive(base, index++, "_Wii_GetButtons", prWiiGetButtons, 2, 0); // definePrimitive(base, index++, "_Wii_GetMotion", prWiiGetMotion, 2, 0); // definePrimitive(base, index++, "_Wii_GetIR", prWiiGetIR, 2, 0); // // definePrimitive(base, index++, "_Wii_GetNunchukButtons", prWiiGetNunchukButtons, 2, 0); // definePrimitive(base, index++, "_Wii_GetNunchukJoy", prWiiGetNunchukJoy, 2, 0); // definePrimitive(base, index++, "_Wii_GetNunchukMotion", prWiiGetNunchukMotion, 2, 0); // definePrimitive(base, index++, "_Wii_GetClassicButtons", prWiiGetClassicButtons, 2, 0); // definePrimitive(base, index++, "_Wii_GetClassicJoy", prWiiGetClassicJoy, 2, 0); // definePrimitive(base, index++, "_Wii_GetClassicAnalog", prWiiGetClassicAnalog, 2, 0); // definePrimitive(base, index++, "_Wii_GetLED", prWiiGetLED, 2, 0); definePrimitive(base, index++, "_Wii_SetLED", prWiiSetLED, 2, 0); definePrimitive(base, index++, "_Wii_SetVibration", prWiiSetVibration, 2, 0); // definePrimitive(base, index++, "_Wii_InitSpeaker", prWiiInitSpeaker, 2, 0); // definePrimitive(base, index++, "_Wii_PlaySpeaker", prWiiPlaySpeaker, 5, 0); // definePrimitive(base, index++, "_Wii_MuteSpeaker", prWiiMuteSpeaker, 2, 0); // definePrimitive(base, index++, "_Wii_EnableSpeaker", prWiiEnableSpeaker, 2, 0); definePrimitive(base, index++, "_Wii_Enable", prWiiEnable, 2, 0); definePrimitive(base, index++, "_Wii_EnableButtons", prWiiSetButtons, 2, 0); definePrimitive(base, index++, "_Wii_EnableIRSensor", prWiiSetIRSensor, 2, 0); definePrimitive(base, index++, "_Wii_EnableMotionSensor", prWiiSetMotionSensor, 2, 0); definePrimitive(base, index++, "_Wii_EnableExpansion", prWiiSetExpansion, 2, 0); } #else // NOT HAVE_WII void initWiiPrimitives() { //other platforms? } #endif SuperCollider-Source/include/common/000755 000765 000024 00000000000 13007315613 020567 5ustar00crucialstaff000000 000000 SuperCollider-Source/include/lang/000755 000765 000024 00000000000 13007315613 020220 5ustar00crucialstaff000000 000000 SuperCollider-Source/include/plugin_interface/000755 000765 000024 00000000000 13007315613 022615 5ustar00crucialstaff000000 000000 SuperCollider-Source/include/server/000755 000765 000024 00000000000 13007315613 020605 5ustar00crucialstaff000000 000000 SuperCollider-Source/include/server/SC_OSC_Commands.h000644 000765 000024 00000004245 12321461511 023612 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_OSC_Commands_ #define _SC_OSC_Commands_ // command numbers: enum { cmd_none = 0, cmd_notify = 1, cmd_status = 2, cmd_quit = 3, cmd_cmd = 4, cmd_d_recv = 5, cmd_d_load = 6, cmd_d_loadDir = 7, cmd_d_freeAll = 8, cmd_s_new = 9, cmd_n_trace = 10, cmd_n_free = 11, cmd_n_run = 12, cmd_n_cmd = 13, cmd_n_map = 14, cmd_n_set = 15, cmd_n_setn = 16, cmd_n_fill = 17, cmd_n_before = 18, cmd_n_after = 19, cmd_u_cmd = 20, cmd_g_new = 21, cmd_g_head = 22, cmd_g_tail = 23, cmd_g_freeAll = 24, cmd_c_set = 25, cmd_c_setn = 26, cmd_c_fill = 27, cmd_b_alloc = 28, cmd_b_allocRead = 29, cmd_b_read = 30, cmd_b_write = 31, cmd_b_free = 32, cmd_b_close = 33, cmd_b_zero = 34, cmd_b_set = 35, cmd_b_setn = 36, cmd_b_fill = 37, cmd_b_gen = 38, cmd_dumpOSC = 39, cmd_c_get = 40, cmd_c_getn = 41, cmd_b_get = 42, cmd_b_getn = 43, cmd_s_get = 44, cmd_s_getn = 45, cmd_n_query = 46, cmd_b_query = 47, cmd_n_mapn = 48, cmd_s_noid = 49, cmd_g_deepFree = 50, cmd_clearSched = 51, cmd_sync = 52, cmd_d_free = 53, cmd_b_allocReadChannel = 54, cmd_b_readChannel = 55, cmd_g_dumpTree = 56, cmd_g_queryTree = 57, cmd_error = 58, cmd_s_newargs = 59, cmd_n_mapa = 60, cmd_n_mapan = 61, cmd_n_order = 62, cmd_p_new = 63, NUMBER_OF_COMMANDS = 64 }; #endif /* _SC_OSC_Commands_ */ SuperCollider-Source/include/server/SC_WorldOptions.h000644 000765 000024 00000006537 12766171707 024040 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_WorldOptions_ #define _SC_WorldOptions_ #include #include "SC_Reply.h" #include "SC_Types.h" #include "SC_Export.h" typedef int (*PrintFunc)(const char *format, va_list ap); struct WorldOptions { const char* mPassword; uint32 mNumBuffers; uint32 mMaxLogins; uint32 mMaxNodes; uint32 mMaxGraphDefs; uint32 mMaxWireBufs; uint32 mNumAudioBusChannels; uint32 mNumInputBusChannels; uint32 mNumOutputBusChannels; uint32 mNumControlBusChannels; uint32 mBufLength; uint32 mRealTimeMemorySize; int mNumSharedControls; float *mSharedControls; bool mRealTime; bool mMemoryLocking; const char *mNonRealTimeCmdFilename; const char *mNonRealTimeInputFilename; const char *mNonRealTimeOutputFilename; const char *mNonRealTimeOutputHeaderFormat; const char *mNonRealTimeOutputSampleFormat; uint32 mPreferredSampleRate; uint32 mNumRGens; uint32 mPreferredHardwareBufferFrameSize; uint32 mLoadGraphDefs; const char *mInputStreamsEnabled; const char *mOutputStreamsEnabled; const char *mInDeviceName; int mVerbosity; bool mRendezvous; const char *mUGensPluginPath; const char *mOutDeviceName; const char *mRestrictedPath; int mSharedMemoryID; }; const struct WorldOptions kDefaultWorldOptions = { 0,1024,64,1024,1024,64,1024,8,8,16384,64,8192, 0,0, 1, 0, 0,0,0,0,0 #if defined(_WIN32) ,44100 #else ,0 #endif ,64, 0, 1 ,0, 0, 0 ,0 ,1 ,0 ,0 ,0 ,0 }; struct SndBuf; SCSYNTH_DLLEXPORT_C void SetPrintFunc(PrintFunc func); SCSYNTH_DLLEXPORT_C struct World* World_New(struct WorldOptions *inOptions); SCSYNTH_DLLEXPORT_C void World_Cleanup(struct World *inWorld, bool unload_plugins = false); SCSYNTH_DLLEXPORT_C void World_NonRealTimeSynthesis(struct World *inWorld, struct WorldOptions *inOptions); SCSYNTH_DLLEXPORT_C int World_OpenUDP(struct World *inWorld, const char *bindTo, int inPort); SCSYNTH_DLLEXPORT_C int World_OpenTCP(struct World *inWorld, const char *bindTo, int inPort, int inMaxConnections, int inBacklog); SCSYNTH_DLLEXPORT_C void World_WaitForQuit(struct World *inWorld, bool unload_plugins = false); SCSYNTH_DLLEXPORT_C bool World_SendPacket(struct World *inWorld, int inSize, char *inData, ReplyFunc inFunc); SCSYNTH_DLLEXPORT_C bool World_SendPacketWithContext(struct World *inWorld, int inSize, char *inData, ReplyFunc inFunc, void *inContext); SCSYNTH_DLLEXPORT_C int World_CopySndBuf(struct World *world, uint32 index, struct SndBuf *outBuf, bool onlyIfChanged, bool *didChange); SCSYNTH_DLLEXPORT_C int scprintf(const char *fmt, ...); #endif // _SC_WorldOptions_ SuperCollider-Source/include/plugin_interface/FFT_UGens.h000644 000765 000024 00000007405 12321461511 024511 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FFT_UGENS_H #define FFT_UGENS_H #include "SC_PlugIn.h" #include "SCComplex.h" #include struct SCComplexBuf { float dc, nyq; SCComplex bin[1]; }; struct SCPolarBuf { float dc, nyq; SCPolar bin[1]; }; static inline SCPolarBuf* ToPolarApx(SndBuf *buf) { if (buf->coord == coord_Complex) { SCComplexBuf* p = (SCComplexBuf*)buf->data; int numbins = (buf->samples - 2) >> 1; for (int i=0; ibin[i].ToPolarApxInPlace(); } buf->coord = coord_Polar; } return (SCPolarBuf*)buf->data; } static inline SCComplexBuf* ToComplexApx(SndBuf *buf) { if (buf->coord == coord_Polar) { SCPolarBuf* p = (SCPolarBuf*)buf->data; int numbins = (buf->samples - 2) >> 1; for (int i=0; ibin[i].ToComplexApxInPlace(); } buf->coord = coord_Complex; } return (SCComplexBuf*)buf->data; } struct PV_Unit : Unit { }; #define sc_clipbuf(x, hi) ((x) >= (hi) ? 0 : ((x) < 0 ? 0 : (x))) // for operation on one buffer #define PV_GET_BUF \ float fbufnum = ZIN0(0); \ if (fbufnum < 0.f) { ZOUT0(0) = -1.f; return; } \ ZOUT0(0) = fbufnum; \ uint32 ibufnum = (uint32)fbufnum; \ World *world = unit->mWorld; \ SndBuf *buf; \ if (ibufnum >= world->mNumSndBufs) { \ int localBufNum = ibufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ buf = world->mSndBufs; \ } \ } else { \ buf = world->mSndBufs + ibufnum; \ } \ LOCK_SNDBUF(buf); \ int numbins = (buf->samples - 2) >> 1; \ // for operation on two input buffers, result goes in first one. #define PV_GET_BUF2 \ float fbufnum1 = ZIN0(0); \ float fbufnum2 = ZIN0(1); \ if (fbufnum1 < 0.f || fbufnum2 < 0.f) { ZOUT0(0) = -1.f; return; } \ ZOUT0(0) = fbufnum1; \ uint32 ibufnum1 = (int)fbufnum1; \ uint32 ibufnum2 = (int)fbufnum2; \ World *world = unit->mWorld; \ SndBuf *buf1; \ SndBuf *buf2; \ if (ibufnum1 >= world->mNumSndBufs) { \ int localBufNum = ibufnum1 - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf1 = parent->mLocalSndBufs + localBufNum; \ } else { \ buf1 = world->mSndBufs; \ } \ } else { \ buf1 = world->mSndBufs + ibufnum1; \ } \ if (ibufnum2 >= world->mNumSndBufs) { \ int localBufNum = ibufnum2 - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf2 = parent->mLocalSndBufs + localBufNum; \ } else { \ buf2 = world->mSndBufs; \ } \ } else { \ buf2 = world->mSndBufs + ibufnum2; \ } \ LOCK_SNDBUF2(buf1, buf2); \ if (buf1->samples != buf2->samples) return; \ int numbins = (buf1->samples - 2) >> 1; #define MAKE_TEMP_BUF \ if (!unit->m_tempbuf) { \ unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, buf->samples * sizeof(float)); \ unit->m_numbins = numbins; \ } else if (numbins != unit->m_numbins) return; extern InterfaceTable *ft; #endif SuperCollider-Source/include/plugin_interface/Hash.h000644 000765 000024 00000007672 12321461511 023662 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _Hash_ #define _Hash_ #include "SC_Types.h" #include "SC_Endian.h" // These hash functions are among the best there are in terms of both speed and quality. // A good hash function makes a lot of difference. // I have not used Bob Jenkins own hash function because the keys I use are relatively short. // hash function for a string inline int32 Hash(const char *inKey) { // the one-at-a-time hash. // a very good hash function. ref: a web page by Bob Jenkins. // http://www.burtleburtle.net/bob/hash/doobs.html int32 hash = 0; while (*inKey) { hash += *inKey++; hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash; } // hash function for a string that also returns the length inline int32 Hash(const char *inKey, size_t *outLength) { // the one-at-a-time hash. // a very good hash function. ref: a web page by Bob Jenkins. const char *origKey = inKey; int32 hash = 0; while (*inKey) { hash += *inKey++; hash += hash << 10; hash ^= hash >> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; *outLength = inKey - origKey; return hash; } // hash function for an array of char inline int32 Hash(const char *inKey, int32 inLength) { // the one-at-a-time hash. // a very good hash function. ref: a web page by Bob Jenkins. int32 hash = 0; for (int i=0; i> 6; } hash += hash << 3; hash ^= hash >> 11; hash += hash << 15; return hash; } // hash function for integers inline int32 Hash(int32 inKey) { // Thomas Wang's integer hash. // http://www.concentric.net/~Ttwang/tech/inthash.htm // a faster hash for integers. also very good. uint32 hash = (uint32)inKey; hash += ~(hash << 15); hash ^= hash >> 10; hash += hash << 3; hash ^= hash >> 6; hash += ~(hash << 11); hash ^= hash >> 16; return (int32)hash; } inline int64 Hash64(int64 inKey) { // Thomas Wang's 64 bit integer hash. uint64 hash = (uint64)inKey; hash += ~(hash << 32); hash ^= (hash >> 22); hash += ~(hash << 13); hash ^= (hash >> 8); hash += (hash << 3); hash ^= (hash >> 15); hash += ~(hash << 27); hash ^= (hash >> 31); return (int64)hash; } inline int32 Hash(const int32 *inKey, int32 inLength) { // one-at-a-time hashing of a string of int32's. // uses Thomas Wang's integer hash for the combining step. int32 hash = 0; for (int i=0; i #include "SC_Types.h" #include "SC_Constants.h" #include "float.h" #ifdef _MSC_VER // hypotf is c99, but not c++ #define hypotf _hypotf #endif //////////////////////////////////////////////////////////////////////////////// namespace detail { const int kSineSize = 8192; const int kSineMask = kSineSize - 1; const double kSinePhaseScale = kSineSize / twopi; const int32 kPolarLUTSize = 2049; const int32 kPolarLUTSize2 = kPolarLUTSize >> 1; /* each object file that is including this header will have separate lookup tables */ namespace { float gMagLUT[kPolarLUTSize]; float gPhaseLUT[kPolarLUTSize]; float gSine[kSineSize+1]; static bool initTables(void) { double sineIndexToPhase = twopi / kSineSize; for (int i=0; i <= kSineSize; ++i) { double phase = i * sineIndexToPhase; float32 d = sin(phase); gSine[i] = d; } double rPolarLUTSize2 = 1. / kPolarLUTSize2; for (int i=0; i < kPolarLUTSize; ++i) { double slope = (i - kPolarLUTSize2) * rPolarLUTSize2; double angle = atan(slope); gPhaseLUT[i] = (float)angle; gMagLUT[i] = (float)(1.f / cos(angle)); } return true; } bool dummy = initTables(); } struct Polar; struct Complex { Complex() {} Complex(float r, float i) : real(r), imag(i) {} void Set(float r, float i) { real = r; imag = i; } Complex& operator=(Complex b) { real = b.real; imag = b.imag; return *this; } Complex& operator=(float b) { real = b; imag = 0.; return *this; } Polar ToPolar(); /** * Converts cartesian to polar representation, using lookup tables. * Note: in this implementation the phase values returned lie in the range [-pi/4, 7pi/4] * rather than the more conventional [0, 2pi] or [-pi, pi]. */ Polar ToPolarApx(); void ToPolarInPlace(); void ToPolarApxInPlace(); float real, imag; }; struct Polar { Polar() {} Polar(float m, float p) : mag(m), phase(p) {} void Set(float m, float p) { mag = m; phase = p; } Complex ToComplex() { return Complex(mag * std::cos(phase), mag * std::sin(phase)); } Complex ToComplexApx() { uint32 sinindex = (int32)(kSinePhaseScale * phase) & kSineMask; uint32 cosindex = (sinindex + (kSineSize>>2)) & kSineMask; return Complex(mag * gSine[cosindex], mag * gSine[sinindex]); } void ToComplexInPlace() { Complex complx = ToComplex(); mag = complx.real; phase = complx.imag; } void ToComplexApxInPlace() { Complex complx = ToComplexApx(); mag = complx.real; phase = complx.imag; } float mag, phase; }; inline Polar Complex::ToPolar() { return Polar(hypotf(imag, real), std::atan2(imag, real)); } inline Polar Complex::ToPolarApx() { int32 index; float absreal = fabs(real); float absimag = fabs(imag); float mag, phase, slope; if (absreal > absimag) { slope = imag/real; index = (int32)(kPolarLUTSize2 + kPolarLUTSize2 * slope); mag = gMagLUT[index] * absreal; phase = gPhaseLUT[index]; if (real > 0) { return Polar(mag, phase); } else { return Polar(mag, (float)(pi + phase)); } } else if (absimag > 0) { slope = real/imag; index = (int32)(kPolarLUTSize2 + kPolarLUTSize2 * slope); mag = gMagLUT[index] * absimag; phase = gPhaseLUT[index]; if (imag > 0) { return Polar(mag, (float)(pi2 - phase)); } else { return Polar(mag, (float)(pi32 - phase)); } } else return Polar(0, 0); } inline void Complex::ToPolarInPlace() { Polar polar = ToPolar(); real = polar.mag; imag = polar.phase; } inline void Complex::ToPolarApxInPlace() { Polar polar = ToPolarApx(); real = polar.mag; imag = polar.phase; } } using detail::Polar; using detail::Complex; struct ComplexFT { float dc, nyq; Complex complex[1]; }; struct PolarFT { float dc, nyq; Polar polar[1]; }; void ToComplex(Polar in, Complex& out); inline Complex operator+(Complex a, Complex b) { return Complex(a.real + b.real, a.imag + b.imag); } inline Complex operator+(Complex a, float b) { return Complex(a.real + b, a.imag); } inline Complex operator+(float a, Complex b) { return Complex(a + b.real, b.imag); } inline Complex& operator+=(Complex& a, const Complex& b) { a.real += b.real, a.imag += b.imag; return a; } inline Complex& operator+=(Complex& a, float b) { a.real += b; return a; } inline Complex operator-(Complex a, Complex b) { return Complex(a.real - b.real, a.imag - b.imag); } inline Complex operator-(Complex a, float b) { return Complex(a.real - b, a.imag); } inline Complex operator-(float a, Complex b) { return Complex(a - b.real, b.imag); } inline Complex operator-=(Complex a, Complex b) { a.real -= b.real, a.imag -= b.imag; return a; } inline Complex operator-=(Complex a, float b) { a.real -= b; return a; } inline Complex operator*(Complex a, Complex b) { return Complex(a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real); } inline Complex operator*(Complex a, float b) { return Complex(a.real * b, a.imag * b); } inline Complex operator*(float a, Complex b) { return Complex(b.real * a, b.imag * a); } inline Complex operator*=(Complex a, Complex b) { a.Set( a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real ); return a; } inline Complex operator*=(Complex a, float b) { a.real *= b; a.imag *= b; return a; } inline Polar operator*(Polar a, float b) { return Polar(a.mag * b, a.phase); } inline Polar operator*(float a, Polar b) { return Polar(a * b.mag, b.phase); } inline Polar operator*=(Polar a, float b) { a.mag *= b; return a; } #endif SuperCollider-Source/include/plugin_interface/SC_Constants.h000644 000765 000024 00000003572 12756531745 025356 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Constants_ #define _SC_Constants_ #include #ifndef __FP__ const double pi = std::acos(-1.); #else const double sc_pi = std::acos(-1.); #define pi sc_pi // hack to avoid osx warning about deprecated pi #endif const double pi2 = pi * .5; const double pi32 = pi * 1.5; const double twopi = pi * 2.; const double rtwopi = 1. / twopi; const double log001 = std::log(0.001); const double log01 = std::log(0.01); const double log1 = std::log(0.1); const double rlog2 = 1./std::log(2.); const double sqrt2 = std::sqrt(2.); const double rsqrt2 = 1. / sqrt2; const float pi_f = std::acos(-1.f); const float pi2_f = pi_f * 0.5f; const float pi32_f = pi_f * 1.5f; const float twopi_f = pi_f * 2.f; const float sqrt2_f = std::sqrt(2.f); const float rsqrt2_f= 1.f/std::sqrt(2.f); // used to truncate precision const float truncFloat = (float)(3. * std::pow(2.0,22)); const double truncDouble = 3. * std::pow(2.0,51); const float kBadValue = 1e20f; // used in the secant table for values very close to 1/0 #endif SuperCollider-Source/include/plugin_interface/SC_DemandUnit.h000644 000765 000024 00000004543 12321461511 025406 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_DemandUnit_ #define _SC_DemandUnit_ #include "SC_Unit.h" #include "SC_Wire.h" // demand rate unit support. inline bool IsDemandInput(Unit* unit, int index) { Unit* fromUnit = unit->mInput[index]->mFromUnit; return fromUnit && fromUnit->mCalcRate == calc_DemandRate; } inline float DemandInput(Unit* unit, int index) { Unit* fromUnit = unit->mInput[index]->mFromUnit; if (fromUnit && fromUnit->mCalcRate == calc_DemandRate) (fromUnit->mCalcFunc)(fromUnit, 1); return IN0(index); } // support for audio rate input to demand UGens // offset comes in as inNumSamples, so is in the range 1..size ! inNumSamples = 0 has a special meaning (reset). // it is converted to a buffer index here. inline float DemandInputA(Unit* unit, int index, int offset) { Unit* fromUnit = unit->mInput[index]->mFromUnit; if(!fromUnit) { return IN0(index); } if (fromUnit->mCalcRate == calc_DemandRate) { (fromUnit->mCalcFunc)(fromUnit, offset); return IN0(index); } else if (fromUnit->mCalcRate == calc_FullRate) { return IN(index)[offset - 1]; } else { return IN0(index); } } inline void ResetInput(Unit* unit, int index) { Unit* fromUnit = unit->mInput[index]->mFromUnit; if (fromUnit && fromUnit->mCalcRate == calc_DemandRate) (fromUnit->mCalcFunc)(fromUnit, 0); } #define ISDEMANDINPUT(index) IsDemandInput(unit, (index)) #define DEMANDINPUT(index) DemandInput(unit, (index)) #define DEMANDINPUT_A(index, offset) DemandInputA(unit, (index), (offset)) #define RESETINPUT(index) ResetInput(unit, (index)) #endif SuperCollider-Source/include/plugin_interface/SC_FifoMsg.h000644 000765 000024 00000003070 12321461511 024702 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _FifoMsg_ #define _FifoMsg_ typedef void (*FifoMsgFunc)(struct FifoMsg*); struct FifoMsg { FifoMsg() : mPerformFunc(0), mFreeFunc(0), mData(0), mWorld(0) {} void Set(struct World *inWorld, FifoMsgFunc inPerform, FifoMsgFunc inFree, void* inData); void Perform(); void Free(); FifoMsgFunc mPerformFunc; FifoMsgFunc mFreeFunc; void* mData; struct World *mWorld; }; inline void FifoMsg::Set(World *inWorld, FifoMsgFunc inPerform, FifoMsgFunc inFree, void* inData) { mWorld = inWorld; mPerformFunc = inPerform; mFreeFunc = inFree; mData = inData; } inline void FifoMsg::Perform() { if (mPerformFunc) (mPerformFunc)(this); } inline void FifoMsg::Free() { if (mFreeFunc) (mFreeFunc)(this); } #endif SuperCollider-Source/include/plugin_interface/SC_Graph.h000644 000765 000024 00000003002 12321461511 024404 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Graph_ #define _SC_Graph_ #include "SC_Node.h" #include "SC_Rate.h" #include "SC_SndBuf.h" struct Graph { Node mNode; uint32 mNumWires; struct Wire *mWire; uint32 mNumControls; float *mControls; float **mMapControls; // try this for setting the rate of a control int *mControlRates; uint32 mNumUnits; struct Unit **mUnits; uint32 mNumCalcUnits; struct Unit **mCalcUnits; // excludes i-rate units. int mSampleOffset; struct RGen* mRGen; struct Unit *mLocalAudioBusUnit; struct Unit *mLocalControlBusUnit; float mSubsampleOffset; SndBuf *mLocalSndBufs; int localBufNum; int localMaxBufNum; }; typedef struct Graph Graph; #endif SuperCollider-Source/include/plugin_interface/SC_InlineBinaryOp.h000644 000765 000024 00000026260 12524671173 026254 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _BinaryOpUGen_ #define _BinaryOpUGen_ #include "SC_BoundsMacros.h" #include "SC_InlineUnaryOp.h" #include inline float sc_mod(float in, float hi) { // avoid the divide if possible const float lo = (float)0.; if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < lo) { in += hi; if (in >= lo) return in; } else return in; if (hi == lo) return lo; return in - hi*sc_floor(in/hi); } inline double sc_mod(double in, double hi) { // avoid the divide if possible const double lo = (double)0.; if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < lo) { in += hi; if (in >= lo) return in; } else return in; if (hi == lo) return lo; return in - hi*sc_floor(in/hi); } inline float sc_wrap(float in, float lo, float hi) { float range; // avoid the divide if possible if (in >= hi) { range = hi - lo; in -= range; if (in < hi) return in; } else if (in < lo) { range = hi - lo; in += range; if (in >= lo) return in; } else return in; if (hi == lo) return lo; return in - range * sc_floor((in - lo)/range); } inline double sc_wrap(double in, double lo, double hi) { double range; // avoid the divide if possible if (in >= hi) { range = hi - lo; in -= range; if (in < hi) return in; } else if (in < lo) { range = hi - lo; in += range; if (in >= lo) return in; } else return in; if (hi == lo) return lo; return in - range * sc_floor((in - lo)/range); } inline double sc_wrap(double in, double lo, double hi, double range) { // avoid the divide if possible if (in >= hi) { in -= range; if (in < hi) return in; } else if (in < lo) { in += range; if (in >= lo) return in; } else return in; if (hi == lo) return lo; return in - range * sc_floor((in - lo)/range); } inline double sc_wrap(float in, float lo, float hi, float range) { // avoid the divide if possible if (in >= hi) { in -= range; if (in < hi) return in; } else if (in < lo) { in += range; if (in >= lo) return in; } else return in; if (hi == lo) return lo; return in - range * sc_floor((in - lo)/range); } inline float sc_fold(float in, float lo, float hi) { float x, c, range, range2; x = in - lo; // avoid the divide if possible if (in >= hi) { in = hi + hi - in; if (in >= lo) return in; } else if (in < lo) { in = lo + lo - in; if (in < hi) return in; } else return in; if (hi == lo) return lo; // ok do the divide range = hi - lo; range2 = range + range; c = x - range2 * sc_floor(x / range2); if (c>=range) c = range2 - c; return c + lo; } inline double sc_fold(double in, double lo, double hi) { double x, c, range, range2; x = in - lo; // avoid the divide if possible if (in >= hi) { in = hi + hi - in; if (in >= lo) return in; } else if (in < lo) { in = lo + lo - in; if (in < hi) return in; } else return in; if (hi == lo) return lo; // ok do the divide range = hi - lo; range2 = range + range; c = x - range2 * sc_floor(x / range2); if (c>=range) c = range2 - c; return c + lo; } inline double sc_fold(float in, float lo, float hi, float range, float range2) { float x, c; x = in - lo; // avoid the divide if possible if (in >= hi) { in = hi + hi - in; if (in >= lo) return in; } else if (in < lo) { in = lo + lo - in; if (in < hi) return in; } else return in; if (hi == lo) return lo; // ok do the divide c = x - range2 * sc_floor(x / range2); if (c>=range) c = range2 - c; return c + lo; } inline double sc_fold(double in, double lo, double hi, double range, double range2) { double x, c; x = in - lo; // avoid the divide if possible if (in >= hi) { in = hi + hi - in; if (in >= lo) return in; } else if (in < lo) { in = lo + lo - in; if (in < hi) return in; } else return in; if (hi == lo) return lo; // ok do the divide c = x - range2 * sc_floor(x / range2); if (c>=range) c = range2 - c; return c + lo; } inline float sc_pow(float a, float b) { return a >= 0.f ? std::pow(a, b) : -std::pow(-a, b); } inline double sc_pow(double a, double b) { return a >= 0.f ? std::pow(a, b) : -std::pow(-a, b); } inline float sc_round(float x, float quant) { return quant==0. ? x : sc_floor(x/quant + .5f) * quant; } inline double sc_round(double x, double quant) { return quant==0. ? x : sc_floor(x/quant + .5) * quant; } inline float sc_roundUp(float x, float quant) { return quant==0. ? x : sc_ceil(x/quant) * quant; } inline double sc_roundUp(double x, double quant) { return quant==0. ? x : sc_ceil(x/quant) * quant; } inline float sc_trunc(float x, float quant) { return quant==0. ? x : sc_floor(x/quant) * quant; } inline double sc_trunc(double x, double quant) { return quant==0. ? x : sc_floor(x/quant) * quant; } inline float sc_atan2(float a, float b) { return std::atan2(a, b); } const float kFSQRT2M1 = static_cast(sqrt(2.) - 1.); const double kDSQRT2M1 = sqrt(2.) - 1.; inline float sc_hypotx(float x, float y) { float minxy; x = std::abs(x); y = std::abs(y); minxy = sc_min(x,y); return x + y - kFSQRT2M1 * minxy; } inline double sc_hypotx(double x, double y) { double minxy; x = std::abs(x); y = std::abs(y); minxy = sc_min(x,y); return x + y - kDSQRT2M1 * minxy; } inline int sc_div(int a, int b) { int c; if (b) { if (a<0) c = (a+1)/b - 1; else c = a/b; } else c = a; return c; } /* inline int sc_mod(int a, int b) { long c; c = a % b; if (c<0) c += b; return c; } */ inline int sc_mod(int in, int hi) { // avoid the divide if possible const int lo = 0; if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < lo) { in += hi; if (in >= lo) return in; } else return in; if (hi == lo) return lo; int c; c = in % hi; if (c<0) c += hi; return c; } inline int sc_wrap(int in, int lo, int hi) { return sc_mod(in - lo, hi - lo + 1) + lo; } inline int sc_fold(int in, int lo, int hi) { int b = hi - lo; int b2 = b+b; int c = sc_mod(in - lo, b2); if (c>b) c = b2-c; return c + lo; } inline int sc_gcd(int a, int b) { int t; const bool negative = (a <= 0 && b <= 0); a = sc_abs(a); b = sc_abs(b); if (a == 0) return b; if (b == 0) return a; if (a == 1 || b == 1) { if(negative) { return -1; } else { return 1; } } if (a < b) { t = a; a = b; b = t; } while (b > 0) { t = a % b; a = b; b = t; } if(negative) { a = 0 - a; } return a; } inline int sc_lcm(int a, int b) { if (a == 0 || b == 0) return 0; else return (a * b) / sc_gcd(a, b); } inline long sc_gcd(long a, long b) { long t; const bool negative = (a <= 0 && b <= 0); a = sc_abs(a); b = sc_abs(b); if (a == 0) return b; if (b == 0) return a; if (a == 1 || b == 1) { if(negative) { return (long)-1; } else { return (long)1; } } if (a < b) { t = a; a = b; b = t; } while (b > 0) { t = a % b; a = b; b = t; } if(negative) { a = 0 - a; } return a; } inline long sc_lcm(long a, long b) { if (a == 0 || b == 0) return (long)0; else return (a * b) / sc_gcd(a, b); } inline float sc_gcd(float u, float v) { return (float) sc_gcd((long) std::trunc(u), (long) std::trunc(v)); } inline float sc_lcm(float u, float v) { return (float) sc_lcm((long) std::trunc(u), (long) std::trunc(v)); } inline int sc_bitAnd(int a, int b) { return a & b; } inline int sc_bitOr(int a, int b) { return a | b; } inline int sc_leftShift(int a, int b) { return a << b; } inline int sc_rightShift(int a, int b) { return a >> b; } inline int sc_unsignedRightShift(int a, int b) { return (uint32)a >> b; } inline int sc_round(int x, int quant) { return quant==0 ? x : sc_div(x + quant/2, quant) * quant; } inline int sc_roundUp(int x, int quant) { return quant==0 ? x : sc_div(x + quant - 1, quant) * quant; } inline int sc_trunc(int x, int quant) { return quant==0 ? x : sc_div(x, quant) * quant; } template inline F sc_powi (F x, unsigned int n) { F z = 1; while (n != 0) { if ((n & 1) != 0) { z *= x; } n >>= 1; x *= x; } return z; } template inline T sc_thresh(T a, U b) { return a < b ? (T)0 : a; } template inline T sc_clip2(T a, T b) { return sc_clip(a, -b, b); } template inline T sc_wrap2(T a, T b) { return sc_wrap(a, -b, b); } template inline T sc_fold2(T a, T b) { return sc_fold(a, -b, b); } template inline T sc_excess(T a, T b) { return a - sc_clip(a, -b, b); } template inline T sc_scaleneg(T a, T b) { if (a < 0) return a*b; else return a; } template <> inline float sc_scaleneg(float a, float b) { b = 0.5f * b + 0.5f; return (std::abs(a) - a) * b + a; } template <> inline double sc_scaleneg(double a, double b) { b = 0.5 * b + 0.5; return (std::abs(a) - a) * b + a; } template inline T sc_amclip(T a, T b) { if (b < 0) return 0; else return a*b; } template <> inline float sc_amclip(float a, float b) { return a * 0.5f * (b + std::abs(b)); } template <> inline double sc_amclip(double a, double b) { return a * 0.5 * (b + std::abs(b)); } template inline T sc_ring1(T a, T b) { return a *b + a; } template inline T sc_ring2(T a, T b) { return a*b + a + b; } template inline T sc_ring3(T a, T b) { return a*a*b; } template inline T sc_ring4(T a, T b) { return a*a*b - a*b*b; } template inline T sc_difsqr(T a, T b) { return a*a - b*b; } template inline T sc_sumsqr(T a, T b) { return a*a + b*b; } template inline T sc_sqrsum(T a, T b) { T z = a+b; return z*z; } template inline T sc_sqrdif(T a, T b) { T z = a-b; return z*z; } #if 0 inline long sc_div(long a, long b) { int c; if (b) { if (a<0) c = (a+1)/b - 1; else c = a/b; } else c = a; return c; } inline long sc_wrap(long in, long lo, long hi) { return sc_mod(in - lo, hi - lo + 1) + lo; } inline long sc_fold(long in, long lo, long hi) { long b = hi - lo; int b2 = b+b; long c = sc_mod(in - lo, b2); if (c>b) c = b2-c; return c + lo; } inline long sc_bitAnd(long a, long b) { return a & b; } inline long sc_bitOr(long a, long b) { return a | b; } inline long sc_leftShift(long a, long b) { return a << b; } inline long sc_rightShift(long a, long b) { return a >> b; } inline long sc_unsignedRightShift(long a, long b) { return (unsigned long)a >> b; } inline long sc_round(long x, long quant) { return quant==0 ? x : sc_div(x + quant/2, quant) * quant; } #endif #endif SuperCollider-Source/include/plugin_interface/SC_InlineUnaryOp.h000644 000765 000024 00000030260 12756531745 026130 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _UnaryOpUGen_ #define _UnaryOpUGen_ #include "SC_Types.h" #include "SC_Constants.h" #include #include #ifdef __SSE__ #include #endif #ifdef __SSE4_1__ #include #endif /////////////////////////////////////////////////////////////////////////////////////// inline bool sc_isnan(float x) { return std::isnan(x); } inline bool sc_isnan(double x) { return std::isnan(x); } inline bool sc_isfinite(float x) { return std::isfinite(x); } inline bool sc_isfinite(double x) { return std::isfinite(x); } /////////////////////////////////////////////////////////////////////////////////////// // versions provided for float32 and float64 // did not supply template because do not want to instantiate for integers. // all constants explicitly cast to prevent PowerPC frsp instruction generation. /////////////////////////////////////////////////////////////////////////////////////// // this is a function for preventing pathological math operations in ugens. // can be used at the end of a block to fix any recirculating filter values. inline float32 zapgremlins(float32 x) { float32 absx = std::abs(x); // very small numbers fail the first test, eliminating denormalized numbers // (zero also fails the first test, but that is OK since it returns zero.) // very large numbers fail the second test, eliminating infinities // Not-a-Numbers fail both tests and are eliminated. return (absx > (float32)1e-15 && absx < (float32)1e15) ? x : (float32)0.; } inline float32 sc_log2(float32 x) { return std::log2(x); } inline float32 sc_log10(float32 x) { return std::log10(std::abs(x)); } inline float32 sc_midicps(float32 note) { return (float32)440. * std::pow((float32)2., (note - (float32)69.) * (float32)0.083333333333); } inline float32 sc_cpsmidi(float32 freq) { return sc_log2(freq * (float32)0.0022727272727) * (float32)12. + (float32)69.; } inline float32 sc_midiratio(float32 midi) { return std::pow((float32)2. , midi * (float32)0.083333333333); } inline float32 sc_ratiomidi(float32 ratio) { return (float32)12. * sc_log2(ratio); } inline float32 sc_octcps(float32 note) { return (float32)440. * std::pow((float32)2., note - (float32)4.75); } inline float32 sc_cpsoct(float32 freq) { return sc_log2(freq * (float32)0.0022727272727) + (float32)4.75; } inline float32 sc_ampdb(float32 amp) { return std::log10(amp) * (float32)20.; } inline float32 sc_dbamp(float32 db) { return std::pow((float32)10., db * (float32).05); } inline float32 sc_squared(float32 x) { return x * x; } inline float32 sc_cubed(float32 x) { return x * x * x; } inline float32 sc_sqrt(float32 x) { return x < (float32)0. ? -sqrt(-x) : sqrt(x); } inline float32 sc_hanwindow(float32 x) { if (x < (float32)0. || x > (float32)1.) return (float32)0.; return (float32)0.5 - (float32)0.5 * static_cast(cos(x * (float32)twopi)); } inline float32 sc_welwindow(float32 x) { if (x < (float32)0. || x > (float32)1.) return (float32)0.; return static_cast(sin(x * pi)); } inline float32 sc_triwindow(float32 x) { if (x < (float32)0. || x > (float32)1.) return (float32)0.; if (x < (float32)0.5) return (float32)2. * x; else return (float32)-2. * x + (float32)2.; } inline float32 sc_bitriwindow(float32 x) { float32 ax = (float32)1. - std::abs(x); if (ax <= (float32)0.) return (float32)0.; return ax; } inline float32 sc_rectwindow(float32 x) { if (x < (float32)0. || x > (float32)1.) return (float32)0.; return (float32)1.; } inline float32 sc_scurve(float32 x) { if (x <= (float32)0.) return (float32)0.; if (x >= (float32)1.) return (float32)1.; return x * x * ((float32)3. - (float32)2. * x); } inline float32 sc_scurve0(float32 x) { // assumes that x is in range return x * x * ((float32)3. - (float32)2. * x); } inline float32 sc_ramp(float32 x) { if (x <= (float32)0.) return (float32)0.; if (x >= (float32)1.) return (float32)1.; return x; } inline float32 sc_sign(float32 x) { return x < (float32)0. ? (float32)-1. : (x > (float32)0. ? (float32)1.f : (float32)0.f); } inline float32 sc_distort(float32 x) { return x / ((float32)1. + std::abs(x)); } inline float32 sc_distortneg(float32 x) { if (x < (float32)0.) return x/((float32)1. - x); else return x; } inline float32 sc_softclip(float32 x) { float32 absx = std::abs(x); if (absx <= (float32)0.5) return x; else return (absx - (float32)0.25) / x; } // Taylor expansion out to x**9/9! factored into multiply-adds // from Phil Burk. inline float32 taylorsin(float32 x) { // valid range from -pi/2 to +3pi/2 x = static_cast((float32)pi2 - std::abs(pi2 - x)); float32 x2 = x * x; return static_cast(x*(x2*(x2*(x2*(x2*(1.0/362880.0) - (1.0/5040.0)) + (1.0/120.0)) - (1.0/6.0)) + 1.0)); } inline float32 sc_trunc(float32 x) { return std::trunc(x); } inline float32 sc_ceil(float32 x) { #ifdef __SSE4_1__ __m128 a = _mm_set_ss(x); __m128 b = _mm_round_ss(a, a, _MM_FROUND_TO_POS_INF); return _mm_cvtss_f32(b); #else return std::ceil(x); #endif } inline float32 sc_floor(float32 x) { #ifdef __SSE4_1__ __m128 a = _mm_set_ss(x); __m128 b = _mm_round_ss(a, a, _MM_FROUND_TO_NEG_INF); return _mm_cvtss_f32(b); #else return std::floor(x); #endif } inline float32 sc_reciprocal(float32 x) { #ifdef __SSE__ // adapted from AP-803 Newton-Raphson Method with Streaming SIMD Extensions // 23 bit accuracy (out of 24bit) const __m128 arg = _mm_set_ss(x); const __m128 approx = _mm_rcp_ss(arg); const __m128 muls = _mm_mul_ss(_mm_mul_ss(arg, approx), approx); const __m128 doubleApprox = _mm_add_ss(approx, approx); const __m128 result = _mm_sub_ss(doubleApprox, muls); return _mm_cvtss_f32(result); #else return 1.f/x; #endif } inline float32 sc_frac(float32 x) { return x - sc_floor(x); } inline float32 sc_lg3interp(float32 x1, float32 a, float32 b, float32 c, float32 d) { // cubic lagrange interpolator float32 x0 = x1 + 1.f; float32 x2 = x1 - 1.f; float32 x3 = x1 - 2.f; float32 x03 = x0 * x3 * 0.5f; float32 x12 = x1 * x2 * 0.16666666666666667f; return x12 * (d * x0 - a * x3) + x03 * (b * x2 - c * x1); } inline float32 sc_CalcFeedback(float32 delaytime, float32 decaytime) { if (delaytime == 0.f || decaytime == 0.f) return 0.f; float32 absret = static_cast( std::exp(log001 * delaytime / std::abs(decaytime))); float32 ret = std::copysign(absret, decaytime); return ret; } inline float32 sc_wrap1(float32 x) { if (x >= (float32) 1.) return x + (float32)-2.; if (x < (float32)-1.) return x + (float32) 2.; return x; } inline float32 sc_fold1(float32 x) { if (x >= (float32) 1.) return (float32) 2. - x; if (x < (float32)-1.) return (float32)-2. - x; return x; } /////////////////////////////////////////////////////////////////////////////////////// inline float64 zapgremlins(float64 x) { float64 absx = std::abs(x); // very small numbers fail the first test, eliminating denormalized numbers // (zero also fails the first test, but that is OK since it returns zero.) // very large numbers fail the second test, eliminating infinities // Not-a-Numbers fail both tests and are eliminated. return (absx > (float64)1e-15 && absx < (float64)1e15) ? x : (float64)0.; } inline float64 sc_log2(float64 x) { return std::log2(std::abs(x)); } inline float64 sc_log10(float64 x) { return std::log10(std::abs(x)); } inline float64 sc_midicps(float64 note) { return (float64)440. * std::pow((float64)2., (note - (float64)69.) * (float64)0.08333333333333333333333333); } inline float64 sc_cpsmidi(float64 freq) { return sc_log2(freq * (float64)0.002272727272727272727272727) * (float64)12. + (float64)69.; } inline float64 sc_midiratio(float64 midi) { return std::pow((float64)2. , midi * (float64)0.083333333333); } inline float64 sc_ratiomidi(float64 ratio) { return (float64)12. * sc_log2(ratio); } inline float64 sc_octcps(float64 note) { return (float64)440. * std::pow((float64)2., note - (float64)4.75); } inline float64 sc_cpsoct(float64 freq) { return sc_log2(freq * (float64)0.0022727272727) + (float64)4.75; } inline float64 sc_ampdb(float64 amp) { return std::log10(amp) * (float64)20.; } inline float64 sc_dbamp(float64 db) { return std::pow((float64)10., db * (float64).05); } inline float64 sc_squared(float64 x) { return x * x; } inline float64 sc_cubed(float64 x) { return x * x * x; } inline float64 sc_sqrt(float64 x) { return x < (float64)0. ? -sqrt(-x) : sqrt(x); } inline float64 sc_hanwindow(float64 x) { if (x < (float64)0. || x > (float64)1.) return (float64)0.; return (float64)0.5 - (float64)0.5 * cos(x * twopi); } inline float64 sc_welwindow(float64 x) { if (x < (float64)0. || x > (float64)1.) return (float64)0.; return sin(x * pi); } inline float64 sc_triwindow(float64 x) { if (x < (float64)0. || x > (float64)1.) return (float64)0.; if (x < (float64)0.5) return (float64)2. * x; else return (float64)-2. * x + (float64)2.; } inline float64 sc_bitriwindow(float64 x) { float64 ax = std::abs(x); if (ax > (float64)1.) return (float64)0.; return (float64)1. - ax; } inline float64 sc_rectwindow(float64 x) { if (x < (float64)0. || x > (float64)1.) return (float64)0.; return (float64)1.; } inline float64 sc_scurve(float64 x) { if (x <= (float64)0.) return (float64)0.; if (x >= (float64)1.) return (float64)1.; return x * x * ((float64)3. - (float64)2. * x); } inline float64 sc_scurve0(float64 x) { // assumes that x is in range return x * x * ((float64)3. - (float64)2. * x); } inline float64 sc_ramp(float64 x) { if (x <= (float64)0.) return (float64)0.; if (x >= (float64)1.) return (float64)1.; return x; } inline float64 sc_sign(float64 x) { return x < (float64)0. ? (float64)-1. : (x > (float64)0. ? (float64)1.f : (float64)0.f); } inline float64 sc_distort(float64 x) { return x / ((float64)1. + std::abs(x)); } inline float64 sc_distortneg(float64 x) { if (x < (float64)0.) return x/((float64)1. - x); else return x; } inline float64 sc_softclip(float64 x) { float64 absx = std::abs(x); if (absx <= (float64)0.5) return x; else return (absx - (float64)0.25) / x; } // Taylor expansion out to x**9/9! factored into multiply-adds // from Phil Burk. inline float64 taylorsin(float64 x) { x = pi2 - std::abs(pi2 - x); float64 x2 = x * x; return x*(x2*(x2*(x2*(x2*(1.0/362880.0) - (1.0/5040.0)) + (1.0/120.0)) - (1.0/6.0)) + 1.0); } inline float64 sc_trunc(float64 x) { return std::trunc(x); } inline float64 sc_ceil(float64 x) { #ifdef __SSE4_1__ __m128d a = _mm_set_sd(x); const int cntrl = _MM_FROUND_TO_POS_INF; __m128d b = _mm_round_sd(a, a, cntrl); return _mm_cvtsd_f64(b); #else return std::ceil(x); #endif } inline float64 sc_floor(float64 x) { #ifdef __SSE4_1__ __m128d a = _mm_set_sd(x); const int cntrl = _MM_FROUND_TO_NEG_INF; __m128d b = _mm_round_sd(a, a, cntrl); return _mm_cvtsd_f64(b); #else return std::floor(x); #endif } inline float64 sc_reciprocal(float64 x) { return 1. / x; } inline float64 sc_frac(float64 x) { return x - sc_floor(x); } inline float64 sc_wrap1(float64 x) { if (x >= (float64) 1.) return x + (float64)-2.; if (x < (float64)-1.) return x + (float64) 2.; return x; } inline float64 sc_fold1(float64 x) { if (x >= (float64) 1.) return (float64) 2. - x; if (x < (float64)-1.) return (float64)-2. - x; return x; } inline int32 sc_grayCode(int32 x) { return x ^ (x >> 1); } /////////////////////////////////////////////////////////////////////////////////////// #endif SuperCollider-Source/include/plugin_interface/SC_InterfaceTable.h000644 000765 000024 00000020074 12321461511 026223 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_SynthInterfaceTable_ #define _SC_SynthInterfaceTable_ static const int sc_api_version = 2; #include "SC_Types.h" #include "SC_SndBuf.h" #include "SC_Unit.h" #include "SC_BufGen.h" #include "SC_FifoMsg.h" #include "SC_fftlib.h" #include "SC_Export.h" typedef struct SF_INFO SF_INFO ; struct World; typedef bool (*AsyncStageFn)(World *inWorld, void* cmdData); typedef void (*AsyncFreeFn)(World *inWorld, void* cmdData); struct ScopeBufferHnd { void *internalData; float *data; uint32 channels; uint32 maxFrames; float *channel_data( uint32 channel ) { return data + (channel * maxFrames); } operator bool () { return internalData != 0; } }; struct InterfaceTable { unsigned int mSineSize; float32 *mSineWavetable; float32 *mSine; float32 *mCosecant; // call printf for debugging. should not use in finished code. int (*fPrint)(const char *fmt, ...); // get a seed for a random number generator int32 (*fRanSeed)(); // define a unit def bool (*fDefineUnit)(const char *inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags); // define a command /cmd bool (*fDefinePlugInCmd)(const char *inCmdName, PlugInCmdFunc inFunc, void* inUserData); // define a command for a unit generator /u_cmd bool (*fDefineUnitCmd)(const char *inUnitClassName, const char *inCmdName, UnitCmdFunc inFunc); // define a buf gen bool (*fDefineBufGen)(const char *inName, BufGenFunc inFunc); // clear all of the unit's outputs. void (*fClearUnitOutputs)(Unit *inUnit, int inNumSamples); // non real time memory allocation void* (*fNRTAlloc)(size_t inSize); void* (*fNRTRealloc)(void *inPtr, size_t inSize); void (*fNRTFree)(void *inPtr); // real time memory allocation void* (*fRTAlloc)(World *inWorld, size_t inSize); void* (*fRTRealloc)(World *inWorld, void *inPtr, size_t inSize); void (*fRTFree)(World *inWorld, void *inPtr); // call to set a Node to run or not. void (*fNodeRun)(struct Node* node, int run); // call to stop a Graph after the next buffer. void (*fNodeEnd)(struct Node* graph); // send a trigger from a Node to clients void (*fSendTrigger)(struct Node* inNode, int triggerID, float value); // send a reply message from a Node to clients void (*fSendNodeReply)(struct Node* inNode, int replyID, const char* cmdName, int numArgs, const float* values); // sending messages between real time and non real time levels. bool (*fSendMsgFromRT)(World *inWorld, struct FifoMsg& inMsg); bool (*fSendMsgToRT)(World *inWorld, struct FifoMsg& inMsg); // libsndfile support int (*fSndFileFormatInfoFromStrings)(SF_INFO *info, const char *headerFormatString, const char *sampleFormatString); // get nodes by id struct Node* (*fGetNode)(World *inWorld, int inID); struct Graph* (*fGetGraph)(World *inWorld, int inID); void (*fNRTLock)(World *inWorld); void (*fNRTUnlock)(World *inWorld); bool mUnused0; void (*fGroup_DeleteAll)(struct Group* group); void (*fDoneAction)(int doneAction, struct Unit *unit); int (*fDoAsynchronousCommand) ( World *inWorld, void* replyAddr, const char* cmdName, void *cmdData, AsyncStageFn stage2, // stage2 is non real time AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData ); // fBufAlloc should only be called within a BufGenFunc int (*fBufAlloc)(SndBuf *inBuf, int inChannels, int inFrames, double inSampleRate); // To initialise a specific FFT, ensure your input and output buffers exist. Internal data structures // will be allocated using the alloc object, // Both "fullsize" and "winsize" should be powers of two (this is not checked internally). struct scfft * (*fSCfftCreate)(size_t fullsize, size_t winsize, SCFFT_WindowFunction wintype, float *indata, float *outdata, SCFFT_Direction forward, SCFFT_Allocator & alloc); void (*fSCfftDoFFT)(scfft *f); void (*fSCfftDoIFFT)(scfft *f); // destroy any resources held internally. void (*fSCfftDestroy)(scfft *f, SCFFT_Allocator & alloc); // Get scope buffer. Returns the maximum number of possile frames. bool (*fGetScopeBuffer)(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &); void (*fPushScopeBuffer)(World *inWorld, ScopeBufferHnd &, int frames); void (*fReleaseScopeBuffer)(World *inWorld, ScopeBufferHnd &); }; typedef struct InterfaceTable InterfaceTable; #define Print (*ft->fPrint) #define RanSeed (*ft->fRanSeed) #define NodeEnd (*ft->fNodeEnd) #define NodeRun (*ft->fNodeRun) #define DefineUnit (*ft->fDefineUnit) #define DefinePlugInCmd (*ft->fDefinePlugInCmd) #define DefineUnitCmd (*ft->fDefineUnitCmd) #define DefineBufGen (*ft->fDefineBufGen) #define ClearUnitOutputs (*ft->fClearUnitOutputs) #define SendTrigger (*ft->fSendTrigger) #define SendNodeReply (*ft->fSendNodeReply) #define SendMsgFromRT (*ft->fSendMsgFromRT) #define SendMsgToRT (*ft->fSendMsgToRT) #define DoneAction (*ft->fDoneAction) #define NRTAlloc (*ft->fNRTAlloc) #define NRTRealloc (*ft->fNRTRealloc) #define NRTFree (*ft->fNRTFree) #define RTAlloc (*ft->fRTAlloc) #define RTRealloc (*ft->fRTRealloc) #define RTFree (*ft->fRTFree) #define SC_GetNode (*ft->fGetNode) #define SC_GetGraph (*ft->fGetGraph) #define NRTLock (*ft->fNRTLock) #define NRTUnlock (*ft->fNRTUnlock) #define BufAlloc (*ft->fBufAlloc) #define GroupDeleteAll (*ft->fGroup_DeleteAll) #define SndFileFormatInfoFromStrings (*ft->fSndFileFormatInfoFromStrings) #define DoAsynchronousCommand (*ft->fDoAsynchronousCommand) #define DefineSimpleUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)&name##_Ctor, 0, 0); #define DefineDtorUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)&name##_Ctor, \ (UnitDtorFunc)&name##_Dtor, 0); #define DefineSimpleCantAliasUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)&name##_Ctor, 0, kUnitDef_CantAliasInputsToOutputs); #define DefineDtorCantAliasUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)&name##_Ctor, \ (UnitDtorFunc)&name##_Dtor, kUnitDef_CantAliasInputsToOutputs); typedef enum { sc_server_scsynth = 0, sc_server_supernova = 1 } SC_ServerType; #ifdef STATIC_PLUGINS #define PluginLoad(name) void name##_Load(InterfaceTable *inTable) #else #ifdef SUPERNOVA #define SUPERNOVA_CHECK C_LINKAGE SC_API_EXPORT int server_type(void) { return sc_server_supernova; } #else #define SUPERNOVA_CHECK C_LINKAGE SC_API_EXPORT int server_type(void) { return sc_server_scsynth; } #endif #define PluginLoad(name) \ C_LINKAGE SC_API_EXPORT int api_version(void) { return sc_api_version; } \ SUPERNOVA_CHECK \ C_LINKAGE SC_API_EXPORT void load(InterfaceTable *inTable) #endif #define scfft_create (*ft->fSCfftCreate) #define scfft_dofft (*ft->fSCfftDoFFT) #define scfft_doifft (*ft->fSCfftDoIFFT) #define scfft_destroy (*ft->fSCfftDestroy) class SCWorld_Allocator: public SCFFT_Allocator { InterfaceTable * ft; World * world; public: SCWorld_Allocator(InterfaceTable * ft, World * world): ft(ft), world(world) {} virtual void* alloc(size_t size) { return RTAlloc(world, size); } virtual void free(void* ptr) { RTFree(world, ptr); } }; #endif SuperCollider-Source/include/plugin_interface/sc_msg_iter.h000644 000765 000024 00000016200 12321461511 025260 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _sc_msg_iter_ #define _sc_msg_iter_ #include "SC_Endian.h" #include "SC_Types.h" #include // return the ptr to the byte after the OSC string. inline const char* OSCstrskip(const char *str) { // while (str[3]) { str += 4; } // return str + 4; do { str += 4; } while (str[-1]); return str; } // returns the number of bytes (including padding) for an OSC string. inline size_t OSCstrlen(const char *strin) { return OSCstrskip(strin) - strin; } // returns a float, converting an int if necessary inline float32 OSCfloat(const char* inData) { elem32 elem; elem.u = sc_ntohl(*(uint32*)inData); return elem.f; } inline int32 OSCint(const char* inData) { return (int32)sc_ntohl(*(uint32*)inData); } inline int64 OSCtime(const char* inData) { return ((int64)sc_ntohl(*(uint32*)inData) << 32) + (sc_ntohl(*(uint32*)(inData + 4))); } inline float64 OSCdouble(const char* inData) { elem64 slot; slot.i = ((int64)sc_ntohl(*(uint32*)inData) << 32) + (sc_ntohl(*(uint32*)(inData + 4))); return slot.f; } struct sc_msg_iter { const char *data, *rdpos, *endpos, *tags; int size, count; sc_msg_iter(); sc_msg_iter(int inSize, const char* inData); void init(int inSize, const char* inData); int64 gett(int64 defaultValue = 1); int32 geti(int32 defaultValue = 0); float32 getf(float32 defaultValue = 0.f); float64 getd(float64 defaultValue = 0.f); const char *gets(const char* defaultValue = 0); int32 *gets4(char* defaultValue = 0); size_t getbsize(); void getb(char* outData, size_t inSize); void skipb(); size_t remain() { return endpos - rdpos; } char nextTag(char defaultTag = 'f') { return tags ? tags[count] : defaultTag; } }; inline sc_msg_iter::sc_msg_iter() { } inline sc_msg_iter::sc_msg_iter(int inSize, const char* inData) { init(inSize, inData); } inline void sc_msg_iter::init(int inSize, const char* inData) { data = inData; size = inSize; endpos = data + size; count = 0; if (data[0] == ',') { tags = data+1; rdpos = OSCstrskip(data); } else { tags = 0; rdpos = data; } } inline int64 sc_msg_iter::gett(int64 defaultValue) { int64 value; if (remain() <= 0) return defaultValue; if (tags) { if (tags[count] == 't') { value = OSCtime(rdpos); rdpos += sizeof(int64); } else { /* this is dangerous, as rdpos is not advanced accordingly while count++ takes place */ value = defaultValue; } } else { value = OSCtime(rdpos); rdpos += sizeof(int64); } count++; return value; } inline int32 sc_msg_iter::geti(int32 defaultValue) { int value; if (remain() <= 0) return defaultValue; if (tags) { if (tags[count] == 'i') { value = OSCint(rdpos); rdpos += sizeof(int32); } else if (tags[count] == 'f') { value = (int32)OSCfloat(rdpos); rdpos += sizeof(float32); } else if (tags[count] == 's') { /* value = atoi(rdpos); */ value = defaultValue; rdpos = OSCstrskip(rdpos); } else if (tags[count] == 'b') { value = defaultValue; skipb(); } else { /* this is dangerous, as rdpos is not advanced accordingly while count++ takes place */ value = defaultValue; } } else { value = (int)OSCint(rdpos); rdpos += sizeof(int32); } count ++; return value; } inline float32 sc_msg_iter::getf(float32 defaultValue) { float32 value; if (remain() <= 0) return defaultValue; if (tags) { if (tags[count] == 'f') { value = OSCfloat(rdpos); rdpos += sizeof(float32); } else if (tags[count] == 'd') { value = static_cast(OSCdouble(rdpos)); rdpos += sizeof(float64); } else if (tags[count] == 'i') { value = static_cast(OSCint(rdpos)); rdpos += sizeof(int32); } else if (tags[count] == 's') { /* value = atof(rdpos); */ value = defaultValue; rdpos = OSCstrskip(rdpos); } else if (tags[count] == 'b') { value = defaultValue; skipb(); } else { /* this is dangerous, as rdpos is not advanced accordingly while count++ takes place */ value = defaultValue; } } else { value = OSCfloat(rdpos); rdpos += sizeof(float32); } count ++; return value; } inline float64 sc_msg_iter::getd(float64 defaultValue) { float64 value; if (remain() <= 0) return defaultValue; if (tags) { if (tags[count] == 'f') { value = (float64)OSCfloat(rdpos); rdpos += sizeof(float32); } else if (tags[count] == 'd') { value = OSCdouble(rdpos); rdpos += sizeof(float64); } else if (tags[count] == 'i') { value = (float64)OSCint(rdpos); rdpos += sizeof(int32); } else if (tags[count] == 's') { /* value = atof(rdpos); */ value = defaultValue; rdpos = OSCstrskip(rdpos); } else if (tags[count] == 'b') { value = defaultValue; skipb(); } else { /* this is dangerous, as rdpos is not advanced accordingly while count++ takes place */ value = defaultValue; } } else { value = OSCdouble(rdpos); rdpos += sizeof(float64); } count ++; return value; } inline const char* sc_msg_iter::gets(const char* defaultValue) { const char* value; if (remain() <= 0) return 0; if (tags) { if (tags[count] == 's') { value = rdpos; rdpos = OSCstrskip(rdpos); } else { value = defaultValue; } } else { value = rdpos; rdpos = OSCstrskip(rdpos); } count ++; return value; } inline int32* sc_msg_iter::gets4(char* defaultValue) { int32* value; if (remain() <= 0) return 0; if (tags) { if (tags[count] == 's') { value = (int32*)rdpos; rdpos = OSCstrskip(rdpos); } else { value = (int32*)defaultValue; } } else { value = (int32*)rdpos; rdpos = OSCstrskip(rdpos); } count ++; return value; } inline size_t sc_msg_iter::getbsize() { size_t len = 0; if (remain() <= 0) return 0; if (tags) { if (tags[count] == 'b') len = OSCint(rdpos); else if (tags[count] == 'm') len = 4; } return len; } inline void sc_msg_iter::getb(char* outArray, size_t size) { size_t len = 0; if (tags[count] == 'b') { len = OSCint(rdpos); if (size < len) return; rdpos += sizeof(int32); } else if (tags[count] == 'm') { len = 4; if (size < len) return; } size_t len4 = (len + 3) & (size_t)-4; memcpy(outArray, rdpos, size); rdpos += len4; count ++; } inline void sc_msg_iter::skipb() { size_t len = 0; if (tags[count] == 'b') { len = OSCint(rdpos); rdpos += sizeof(int32); } else if (tags[count] == 'm') len = 4; size_t len4 = (len + 3) & (size_t)-4; rdpos += len4; count ++; } #endif SuperCollider-Source/include/plugin_interface/SC_Node.h000644 000765 000024 00000002377 12321461511 024246 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Node_ #define _SC_Node_ #include "SC_Types.h" typedef void (*NodeCalcFunc)(struct Node *inNode); struct Node { int32 mID; int32 mHash; struct World *mWorld; struct NodeDef *mDef; NodeCalcFunc mCalcFunc; struct Node *mPrev, *mNext; struct Group *mParent; int32 mIsGroup; }; typedef struct Node Node; enum { kNode_Go, kNode_End, kNode_On, kNode_Off, kNode_Move, kNode_Info }; #endif SuperCollider-Source/include/plugin_interface/SC_PlugIn.h000644 000765 000024 00000003250 12321461511 024546 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SC_PLUGIN_H #define SC_PLUGIN_H #include "SC_World.h" #include "SC_Graph.h" #include "SC_Unit.h" #include "SC_Wire.h" #include "SC_InterfaceTable.h" #include "Unroll.h" #include "SC_InlineUnaryOp.h" #include "SC_InlineBinaryOp.h" #include "SC_BoundsMacros.h" #include "SC_RGen.h" #include "SC_DemandUnit.h" #include "clz.h" #include "sc_msg_iter.h" #include #include "SC_Alloca.h" #ifdef _WIN32 // temporarily override __attribute__ for (unused), later we'll remove it #ifndef __GNUC__ #define __attribute__(x) #endif #ifndef NAN // NAN is c99 #include #define NAN std::numeric_limits::quiet_NaN() #endif // windows.h defines min() and max() macros which break things such as // std::numeric_limits::max() - so let's undefine them #undef max #undef min #endif #endif /* SC_PLUGIN_H */ SuperCollider-Source/include/plugin_interface/SC_PlugIn.hpp000644 000765 000024 00000016453 12756531745 025142 0ustar00crucialstaff000000 000000 /* * SuperCollider real time audio synthesis system * Copyright (c) 2002 James McCartney. All rights reserved. * Copyright (c) 2011 Tim Blechmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SC_PLUGIN_HPP #define SC_PLUGIN_HPP #include #include "SC_PlugIn.h" #include "function_attributes.h" #include /// c++ wrapper for Unit struct class SCUnit: public Unit { public: ///@{ /// generic signal wrappers template struct ScalarSignal { explicit ScalarSignal(FloatType value): value(value) {} FloatType consume() const { return value; } FloatType value; }; template struct SlopeSignal { SlopeSignal(FloatType value, FloatType slope): value(value), slope(slope) {} FloatType consume() { FloatType ret = value; value += slope; return ret; } FloatType value, slope; }; template struct AudioSignal { explicit AudioSignal(const FloatType * pointer): pointer(pointer) {} FloatType consume() { return *pointer++; } const FloatType * pointer; }; template inline ScalarSignal makeScalar(FloatType value) const { return ScalarSignal(value); } template inline SlopeSignal makeSlope(FloatType next, FloatType last) const { return SlopeSignal(last, calcSlope(next, last)); } inline AudioSignal makeSignal(int index) const { const float * input = in(index); return AudioSignal(input); } ///@} /// get input signal at index const float * in(int index) const { assert( index < mNumInputs ); const Unit * unit = this; return IN(index); } /// get input signal at index (to be used with ZXP) const float * zin(int index) const { assert( index < mNumInputs ); const Unit * unit = this; return ZIN(index); } /// get first sample of input signal const float in0(int index) const { assert( index < mNumInputs ); const Unit * unit = this; return IN0(index); } /// get output signal at index float * out(int index) const { assert( index < mNumOutputs ); const Unit * unit = this; return OUT(index); } /// get output signal at index (to be used with ZXP) float * zout(int index) const { assert( index < mNumOutputs ); const Unit * unit = this; return ZOUT(index); } /// get reference to first sample of output signal float & out0(int index) const { assert( index < mNumOutputs ); const Unit * unit = this; return OUT0(index); } /// get rate of input signal int inRate(int index) const { assert( index < mNumInputs ); const Unit * unit = this; return INRATE(index); } /// get number of inputs int numInputs() const { return mNumInputs; } /// get number of outputs int numOutputs() const { return mNumOutputs; } /// test if input signal at index is scalar rate bool isScalarRateIn(int index) const { assert( index < mNumInputs ); return inRate(index) == calc_ScalarRate; } /// test if input signal at index is demand rate bool isDemandRateIn(int index) const { assert( index < mNumInputs ); return inRate(index) == calc_DemandRate; } /// test if input signal at index is control rate bool isControlRateIn(int index) const { assert( index < mNumInputs ); return inRate(index) == calc_BufRate; } /// test if input signal at index is audio rate bool isAudioRateIn(int index) const { assert( index < mNumInputs ); return inRate(index) == calc_FullRate; } /// get the blocksize of the input int inBufferSize(int index) const { assert( index < mNumInputs ); const Unit * unit = this; return INBUFLENGTH(index); } /// get sample rate of ugen double sampleRate() const { const Unit * unit = this; return SAMPLERATE; } /// get sample duration double sampleDur() const { const Unit * unit = this; return SAMPLEDUR; } /// get buffer size of ugen int bufferSize() const { return mBufLength; } /// get control rate double controlRate() const { const Unit * unit = this; return BUFRATE; } /// get duration of a control block double controlDur() const { const Unit * unit = this; return BUFDUR; } /// get sampling rate of audio signal double fullSampleRate() const { const Unit * unit = this; return FULLRATE; } /// get buffer size of audio signals int fullBufferSize() const { const Unit * unit = this; return FULLBUFLENGTH; } /// calculate slope value template FloatType calcSlope(FloatType next, FloatType prev) const { const Unit * unit = this; return CALCSLOPE(next, prev); } template static UnitCalcFunc make_calc_function(void) { return &run_member_function; } /// set calc function & compute initial sample template void set_calc_function(void) { mCalcFunc = make_calc_function(); (mCalcFunc)(this, 1); } /// set calc function & compute initial sample template void set_vector_calc_function(void) { mCalcFunc = make_calc_function(); make_calc_function()(this, 1); } /// @} private: template HOT static void run_member_function(struct Unit * unit, int inNumSamples) { UnitType * realUnit = static_cast(unit); ((realUnit)->*(PointerToMember))(inNumSamples); } }; /// define Ctor/Dtor functions for a class #define DEFINE_XTORS(CLASSNAME) \ void CLASSNAME##_Ctor(CLASSNAME * unit) \ { \ new(unit) CLASSNAME(); \ } \ \ void CLASSNAME##_Dtor(CLASSNAME * unit) \ { \ unit->~CLASSNAME(); \ } namespace detail { template void constructClass( Unit * unit ) { new( static_cast(unit) ) UGenClass(); } template void destroyClass( Unit * unit ) { static_cast(unit)->~UGenClass(); } } template void registerUnit( InterfaceTable * ft, const char * name ) { UnitCtorFunc ctor = detail::constructClass; UnitDtorFunc dtor = std::is_trivially_destructible::value ? nullptr : detail::destroyClass; (*ft->fDefineUnit)( name, sizeof(Unit), ctor, dtor, 0 ); } #endif /* SC_PLUGIN_HPP */ SuperCollider-Source/include/plugin_interface/SC_Rate.h000644 000765 000024 00000002632 12321461511 024246 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _Rate_ #define _Rate_ enum { calc_ScalarRate, calc_BufRate, calc_FullRate, calc_DemandRate }; struct Rate { double mSampleRate; // samples per second double mSampleDur; // seconds per sample double mBufDuration; // seconds per buffer double mBufRate; // buffers per second double mSlopeFactor; // 1. / NumSamples double mRadiansPerSample; // 2pi / SampleRate int mBufLength; // length of the buffer // second order filter loops are often unrolled by 3 int mFilterLoops, mFilterRemain; double mFilterSlope; }; typedef struct Rate Rate; #endif SuperCollider-Source/include/plugin_interface/SC_RGen.h000644 000765 000024 00000017772 12524671173 024235 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //----------------------------------------------------------------------------// // Ran088: L'Ecuyer's 1996 three-component Tausworthe generator "taus88" //----------------------------------------------------------------------------// // // Returns an integer random number uniformly distributed within [0,4294967295] // // The period length is approximately 2^88 (which is 3*10^26). // This generator is very fast and passes all standard statistical tests. // // Reference: // (1) P. L'Ecuyer, Maximally equidistributed combined Tausworthe generators, // Mathematics of Computation, 65, 203-213 (1996), see Figure 4. // (2) recommended in: // P. L'Ecuyer, Random number generation, chapter 4 of the // Handbook on Simulation, Ed. Jerry Banks, Wiley, 1997. // //----------------------------------------------------------------------------// //----------------------------------------------------------------------------// // I chose this random number generator for the following reasons: // fast. // easier and faster to seed than other high quality rng's such as Mersenne Twister. // the internal state is only 12 bytes. // the period is long enough for music/audio. // possible to code in altivec in future if needed. // - James McCartney //----------------------------------------------------------------------------// #ifndef _SC_RGen_ #define _SC_RGen_ #include "SC_Endian.h" #include "SC_Types.h" #include "SC_BoundsMacros.h" #include "Hash.h" #include struct RGen { void init(uint32 seed); uint32 trand(); int32 irand(int32 scale); int32 irand2(int32 scale); int32 ilinrand(int32 scale); int32 ibilinrand(int32 scale); float fcoin(); float frand(); float frand2(); float frand0(); float frand8(); float flinrand(); float fbilinrand(); float fsum3rand(); double drand(); double drand2(double scale); double linrand(double scale); double bilinrand(double scale); double exprandrng(double lo, double hi); double exprand(double scale); double biexprand(double scale); double sum3rand(double scale); uint32 s1, s2, s3; // random generator state }; inline void RGen::init(uint32 seed) { // humans tend to use small seeds - mess up the bits seed = (uint32)Hash((int)seed); // initialize seeds using the given seed value taking care of // the requirements. The constants below are arbitrary otherwise s1 = 1243598713U ^ seed; if (s1 < 2) s1 = 1243598713U; s2 = 3093459404U ^ seed; if (s2 < 8) s2 = 3093459404U; s3 = 1821928721U ^ seed; if (s3 < 16) s3 = 1821928721U; } inline uint32 trand( uint32& s1, uint32& s2, uint32& s3 ) { // This function is provided for speed in inner loops where the // state variables are loaded into registers. // Thus updating the instance variables can // be postponed until the end of the loop. s1 = ((s1 & (uint32)-2) << 12) ^ (((s1 << 13) ^ s1) >> 19); s2 = ((s2 & (uint32)-8) << 4) ^ (((s2 << 2) ^ s2) >> 25); s3 = ((s3 & (uint32)-16) << 17) ^ (((s3 << 3) ^ s3) >> 11); return s1 ^ s2 ^ s3; } inline uint32 RGen::trand() { // generate a random 32 bit number return ::trand(s1, s2, s3); } inline double RGen::drand() { // return a double from 0.0 to 0.999... #if BYTE_ORDER == BIG_ENDIAN union { struct { uint32 hi, lo; } i; double f; } du; #else union { struct { uint32 lo, hi; } i; double f; } du; #endif du.i.hi = 0x41300000; du.i.lo = trand(); return du.f - 1048576.; } inline float RGen::frand() { // return a float from 0.0 to 0.999... union { uint32 i; float f; } u; // union for floating point conversion of result u.i = 0x3F800000 | (trand() >> 9); return u.f - 1.f; } inline float RGen::frand0() { // return a float from +1.0 to +1.999... union { uint32 i; float f; } u; // union for floating point conversion of result u.i = 0x3F800000 | (trand() >> 9); return u.f; } inline float RGen::frand2() { // return a float from -1.0 to +0.999... union { uint32 i; float f; } u; // union for floating point conversion of result u.i = 0x40000000 | (trand() >> 9); return u.f - 3.f; } inline float RGen::frand8() { // return a float from -0.125 to +0.124999... union { uint32 i; float f; } u; // union for floating point conversion of result u.i = 0x3E800000 | (trand() >> 9); return u.f - 0.375f; } inline float RGen::fcoin() { // only return one of the two values -1.0 or +1.0 union { uint32 i; float f; } u; // union for floating point conversion of result u.i = 0x3F800000 | (0x80000000 & trand()); return u.f; } inline float RGen::flinrand() { float a = frand(); float b = frand(); return sc_min(a,b); } inline float RGen::fbilinrand() { float a = frand(); float b = frand(); return a - b; } inline float RGen::fsum3rand() { // larry polansky's poor man's gaussian generator return (frand() + frand() + frand() - 1.5) * 0.666666667; } inline int32 RGen::irand(int32 scale) { // return an int from 0 to scale - 1 return (int32)floor(scale * drand()); } inline int32 RGen::irand2(int32 scale) { // return a int from -scale to +scale return (int32)floor((2. * scale + 1.) * drand() - scale); } inline int32 RGen::ilinrand(int32 scale) { int32 a = irand(scale); int32 b = irand(scale); return sc_min(a,b); } inline double RGen::linrand(double scale) { double a = drand(); double b = drand(); return sc_min(a,b) * scale; } inline int32 RGen::ibilinrand(int32 scale) { int32 a = irand(scale); int32 b = irand(scale); return a - b; } inline double RGen::bilinrand(double scale) { double a = drand(); double b = drand(); return (a - b) * scale; } inline double RGen::exprandrng(double lo, double hi) { return lo * exp(log(hi / lo) * drand()); } inline double RGen::exprand(double scale) { double z; while ((z = drand()) == 0.0) {} return -log(z) * scale; } inline double RGen::biexprand(double scale) { double z; while ((z = drand2(1.)) == 0.0 || z == -1.0) {} if (z > 0.0) z = log(z); else z = -log(-z); return z * scale; } inline double RGen::sum3rand(double scale) { // larry polansky's poor man's gaussian generator return (drand() + drand() + drand() - 1.5) * 0.666666667 * scale; } inline double drand( uint32& s1, uint32& s2, uint32& s3 ) { union { struct { uint32 hi, lo; } i; double f; } u; u.i.hi = 0x41300000; u.i.lo = trand(s1,s2,s3); return u.f - 1048576.; } inline float frand( uint32& s1, uint32& s2, uint32& s3 ) { // return a float from 0.0 to 0.999... union { uint32 i; float f; } u; u.i = 0x3F800000 | (trand(s1,s2,s3) >> 9); return u.f - 1.f; } inline float frand0( uint32& s1, uint32& s2, uint32& s3 ) { // return a float from +1.0 to +1.999... union { uint32 i; float f; } u; u.i = 0x3F800000 | (trand(s1,s2,s3) >> 9); return u.f; } inline float frand2( uint32& s1, uint32& s2, uint32& s3 ) { // return a float from -1.0 to +0.999... union { uint32 i; float f; } u; u.i = 0x40000000 | (trand(s1,s2,s3) >> 9); return u.f - 3.f; } inline float frand8( uint32& s1, uint32& s2, uint32& s3 ) { // return a float from -0.125 to +0.124999... union { uint32 i; float f; } u; u.i = 0x3E800000 | (trand(s1,s2,s3) >> 9); return u.f - 0.375f; } inline float fcoin( uint32& s1, uint32& s2, uint32& s3 ) { // only return one of the two values -1.0 or +1.0 union { uint32 i; float f; } u; u.i = 0x3F800000 | (0x80000000 & trand(s1,s2,s3)); return u.f; } #endif SuperCollider-Source/include/plugin_interface/SC_SndBuf.h000644 000765 000024 00000013651 12756531745 024562 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SndBuf_ #define _SndBuf_ #include typedef struct SNDFILE_tag SNDFILE; #ifdef SUPERNOVA #include #include #ifdef __SSE2__ #include #endif class rw_spinlock { static const uint32_t unlocked_state = 0; static const uint32_t locked_state = 0x80000000; static const uint32_t reader_mask = 0x7fffffff; #ifdef __SSE2__ static inline void pause() { _mm_pause(); } #else static inline void pause() { } #endif public: struct unique_lock { explicit unique_lock(rw_spinlock & sl) : sl_(sl) { sl_.lock(); } ~unique_lock() { sl_.unlock(); } private: rw_spinlock & sl_; }; typedef unique_lock unique_lock; struct shared_lock { explicit shared_lock(rw_spinlock & sl): sl_(sl) { sl_.lock_shared(); } ~shared_lock() { sl_.unlock_shared(); } private: rw_spinlock & sl_; }; rw_spinlock() = default; rw_spinlock(rw_spinlock const & rhs) = delete; rw_spinlock & operator=(rw_spinlock const & rhs) = delete; rw_spinlock(rw_spinlock && rhs) = delete; rw_spinlock & operator=(rw_spinlock & rhs) = delete; ~rw_spinlock() { assert(state == unlocked_state); } void lock() { for (;;) { while( state.load(std::memory_order_relaxed) != unlocked_state ) pause(); uint32_t expected = unlocked_state; if( state.compare_exchange_weak(expected, locked_state, std::memory_order_acquire) ) break; } } bool try_lock() { uint32_t expected = unlocked_state; if( state.compare_exchange_strong(expected, locked_state, std::memory_order_acquire) ) return true; else return false; } void unlock() { assert( state.load(std::memory_order_relaxed) == locked_state) ; state.store( unlocked_state, std::memory_order_release ); } void lock_shared() { for(;;) { /* with the mask, the cas will fail, locked exclusively */ uint32_t current_state = state.load( std::memory_order_acquire ) & reader_mask; const uint32_t next_state = current_state + 1; if( state.compare_exchange_weak(current_state, next_state, std::memory_order_acquire) ) break; pause(); } } bool try_lock_shared() { /* with the mask, the cas will fail, locked exclusively */ uint32_t current_state = state.load(std::memory_order_acquire) & reader_mask; const uint32_t next_state = current_state + 1; if( state.compare_exchange_strong(current_state, next_state, std::memory_order_acquire) ) return true; else return false; } void unlock_shared() { for(;;) { uint32_t current_state = state.load(std::memory_order_relaxed); /* we don't need the reader_mask */ const uint32_t next_state = current_state - 1; if( state.compare_exchange_weak(current_state, uint32_t(next_state)) ) break; pause(); } } private: std::atomic state {unlocked_state}; }; #endif struct SndBuf { double samplerate; double sampledur; // = 1/ samplerate float *data; int channels; int samples; int frames; int mask; // for delay lines int mask1; // for interpolating oscillators. int coord; // used by fft ugens SNDFILE *sndfile; // used by disk i/o // SF_INFO fileinfo; // used by disk i/o #ifdef SUPERNOVA bool isLocal; mutable rw_spinlock lock; #endif }; typedef struct SndBuf SndBuf; struct SndBufUpdates { int reads; int writes; }; typedef struct SndBufUpdates SndBufUpdates; enum { coord_None, coord_Complex, coord_Polar }; inline float PhaseFrac(uint32_t inPhase) { union { uint32_t itemp; float ftemp; } u; u.itemp = 0x3F800000 | (0x007FFF80 & ((inPhase)<<7)); return u.ftemp - 1.f; } inline float PhaseFrac1(uint32_t inPhase) { union { uint32_t itemp; float ftemp; } u; u.itemp = 0x3F800000 | (0x007FFF80 & ((inPhase)<<7)); return u.ftemp; } inline float lookup(const float *table, int32_t phase, int32_t mask) { return table[(phase >> 16) & mask]; } #define xlobits 14 #define xlobits1 13 inline float lookupi(const float *table, uint32_t phase, uint32_t mask) { float frac = PhaseFrac(phase); const float *tbl = table + ((phase >> 16) & mask); float a = tbl[0]; float b = tbl[1]; return a + frac * (b - a); } inline float lookupi2(const float *table, uint32_t phase, uint32_t mask) { float frac = PhaseFrac1(phase); const float *tbl = table + ((phase >> 16) & mask); float a = tbl[0]; float b = tbl[1]; return a + frac * b; } inline float lookupi1(const float* table0, const float* table1, uint32_t pphase, int32_t lomask) { float pfrac = PhaseFrac1(pphase); uint32_t index = ((pphase >> xlobits1) & lomask); float val1 = *(const float*)((const char*)table0 + index); float val2 = *(const float*)((const char*)table1 + index); return val1 + val2 * pfrac; } inline float lininterp(float x, float a, float b) { return a + x * (b - a); } inline float cubicinterp(float x, float y0, float y1, float y2, float y3) { // 4-point, 3rd-order Hermite (x-form) float c0 = y1; float c1 = 0.5f * (y2 - y0); float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3; float c3 = 0.5f * (y3 - y0) + 1.5f * (y1 - y2); return ((c3 * x + c2) * x + c1) * x + c0; } #endif SuperCollider-Source/include/plugin_interface/SC_sndfile_stub.h000644 000765 000024 00000003546 12321461511 026041 0ustar00crucialstaff000000 000000 /* ** Copyright (C) 1999-2009 Erik de Castro Lopo ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU Lesser General Public License as published by ** the Free Software Foundation; either version 2.1 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* ** SC_sndfile_stub.h -- stub of libsndfile definitions, used to preserve binary compatibility when libsndfile unavailable ** taken from sndfile.h **/ /* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */ typedef struct SNDFILE_tag SNDFILE ; #if (defined (_MSCVER) || defined (_MSC_VER)) typedef __int64_t sf_count_t ; #define SF_COUNT_MAX 0x7fffffffffffffffi64 #else typedef off_t sf_count_t ; #define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFLL #endif /* A pointer to a SF_INFO structure is passed to sf_open_read () and filled in. ** On write, the SF_INFO structure is filled in by the user and passed into ** sf_open_write (). */ struct SF_INFO { sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */ int samplerate ; int channels ; int format ; int sections ; int seekable ; } ; typedef struct SF_INFO SF_INFO ; SuperCollider-Source/include/plugin_interface/SC_Unit.h000644 000765 000024 00000023175 12321461511 024277 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Unit_ #define _SC_Unit_ #include "SC_Types.h" #include "SC_SndBuf.h" typedef void (*UnitCtorFunc)(struct Unit* inUnit); typedef void (*UnitDtorFunc)(struct Unit* inUnit); typedef void (*UnitCalcFunc)(struct Unit *inThing, int inNumSamples); struct SC_Unit_Extensions { float * todo; }; struct Unit { struct World *mWorld; struct UnitDef *mUnitDef; struct Graph *mParent; uint32 mNumInputs, mNumOutputs; // changed from uint16 for synthdef ver 2 int16 mCalcRate; int16 mSpecialIndex; // used by unary and binary ops int16 mParentIndex; int16 mDone; struct Wire **mInput, **mOutput; struct Rate *mRate; SC_Unit_Extensions* mExtensions; //future proofing and backwards compatibility; used to be SC_Dimension struct pointer float **mInBuf, **mOutBuf; UnitCalcFunc mCalcFunc; int mBufLength; }; typedef struct Unit Unit; enum { kUnitDef_CantAliasInputsToOutputs = 1 }; #ifdef _WIN32 // Win32 headers (included by C std library headers) define IN and OUT macros // for their own purposes. #undef IN #undef OUT #endif // These return float* pointers to input and output buffers. #define IN(index) (unit->mInBuf[index]) #define OUT(index) (unit->mOutBuf[index]) // These return a float value. Used for control rate inputs and outputs. #define IN0(index) (IN(index)[0]) #define OUT0(index) (OUT(index)[0]) // get the rate of the input. #define INRATE(index) (unit->mInput[index]->mCalcRate) // get the blocksize of the input #define INBUFLENGTH(index) (unit->mInput[index]->mFromUnit->mBufLength) // set the calculation function #define SETCALC(func) (unit->mCalcFunc = (UnitCalcFunc)&func) // calculate a slope for control rate interpolation to audio rate. #define CALCSLOPE(next,prev) ((next - prev) * sc_typeof_cast(next)unit->mRate->mSlopeFactor) // get useful values #define SAMPLERATE (unit->mRate->mSampleRate) #define SAMPLEDUR (unit->mRate->mSampleDur) #define BUFLENGTH (unit->mBufLength) #define BUFRATE (unit->mRate->mBufRate) #define BUFDUR (unit->mRate->mBufDuration) #define FULLRATE (unit->mWorld->mFullRate.mSampleRate) #define FULLBUFLENGTH (unit->mWorld->mFullRate.mBufLength) #ifdef SUPERNOVA template struct buffer_lock2 { buffer_lock2(const SndBuf * buf1, const SndBuf * buf2): buf1_(buf1), buf2_(buf2) { if (buf1 == buf2) { lock1(); return; } for(;;) { lock1(); if (lock2()) return; unlock1(); } } ~buffer_lock2(void) { unlock1(); if (buf1_ != buf2_) unlock2(); } private: void lock1(void) { if (buf1_->isLocal) return; if (!shared1) buf1_->lock.lock(); else buf1_->lock.lock_shared(); } bool lock2(void) { if (buf2_->isLocal) return true; if (!shared2) return buf2_->lock.try_lock(); else return buf2_->lock.try_lock_shared(); } void unlock1(void) { if (buf1_->isLocal) return; if (!shared1) buf1_->lock.unlock(); else buf1_->lock.unlock_shared(); } void unlock2(void) { if (buf2_->isLocal) return; if (!shared2) buf2_->lock.unlock(); else buf2_->lock.unlock_shared(); } const SndBuf * buf1_; const SndBuf * buf2_; }; template struct buffer_lock { buffer_lock(const SndBuf * buf): buf_(buf) { if (!buf->isLocal) { if (shared) buf->lock.lock_shared(); else buf->lock.lock(); } } ~buffer_lock(void) { if (!buf_->isLocal) { if (shared) buf_->lock.unlock_shared(); else buf_->lock.unlock(); } } const SndBuf * buf_; }; #define ACQUIRE_BUS_AUDIO(index) unit->mWorld->mAudioBusLocks[index].lock() #define ACQUIRE_BUS_AUDIO_SHARED(index) unit->mWorld->mAudioBusLocks[index].lock_shared() #define RELEASE_BUS_AUDIO(index) unit->mWorld->mAudioBusLocks[index].unlock() #define RELEASE_BUS_AUDIO_SHARED(index) unit->mWorld->mAudioBusLocks[index].unlock_shared() #define LOCK_SNDBUF(buf) buffer_lock lock_##buf(buf) #define LOCK_SNDBUF_SHARED(buf) buffer_lock lock_##buf(buf); #define LOCK_SNDBUF2(buf1, buf2) buffer_lock2 lock_##buf1##_##buf2(buf1, buf2); #define LOCK_SNDBUF2_SHARED(buf1, buf2) buffer_lock2 lock_##buf1##_##buf2(buf1, buf2); #define LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2) buffer_lock2 lock_##buf1##_##buf2(buf1, buf2); #define LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2) buffer_lock2 lock_##buf1##_##buf2(buf1, buf2); #define ACQUIRE_SNDBUF(buf) do { if (!buf->isLocal) buf->lock.lock(); } while (false) #define ACQUIRE_SNDBUF_SHARED(buf) do { if (!buf->isLocal) buf->lock.lock_shared(); } while (false) #define RELEASE_SNDBUF(buf) do { if (!buf->isLocal) buf->lock.unlock(); } while (false) #define RELEASE_SNDBUF_SHARED(buf) do { if (!buf->isLocal) buf->lock.unlock_shared(); } while (false) #define ACQUIRE_BUS_CONTROL(index) unit->mWorld->mControlBusLock->lock() #define RELEASE_BUS_CONTROL(index) unit->mWorld->mControlBusLock->unlock() #else #define ACQUIRE_BUS_AUDIO(index) #define ACQUIRE_BUS_AUDIO_SHARED(index) #define RELEASE_BUS_AUDIO(index) #define RELEASE_BUS_AUDIO_SHARED(index) #define LOCK_SNDBUF(buf) #define LOCK_SNDBUF_SHARED(buf) #define LOCK_SNDBUF2(buf1, buf2) #define LOCK_SNDBUF2_SHARED(buf1, buf2) #define LOCK_SNDBUF2_EXCLUSIVE_SHARED(buf1, buf2) #define LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2) #define ACQUIRE_SNDBUF(buf) #define ACQUIRE_SNDBUF_SHARED(buf) #define RELEASE_SNDBUF(buf) #define RELEASE_SNDBUF_SHARED(buf) #define ACQUIRE_BUS_CONTROL(index) #define RELEASE_BUS_CONTROL(index) #endif // macros to grab a Buffer reference from the buffer indicated by the UGen's FIRST input #define GET_BUF \ float fbufnum = ZIN0(0); \ if (fbufnum < 0.f) { fbufnum = 0.f; } \ if (fbufnum != unit->m_fbufnum) { \ uint32 bufnum = (int)fbufnum; \ World *world = unit->mWorld; \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ unit->m_buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ unit->m_buf = world->mSndBufs + bufnum; \ } \ } else { \ unit->m_buf = world->mSndBufs + bufnum; \ } \ unit->m_fbufnum = fbufnum; \ } \ SndBuf *buf = unit->m_buf; \ LOCK_SNDBUF(buf); \ float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples __attribute__((__unused__)) = buf->samples; \ uint32 bufFrames = buf->frames; \ int mask __attribute__((__unused__)) = buf->mask; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; #define GET_BUF_SHARED \ float fbufnum = ZIN0(0); \ if (fbufnum < 0.f) { fbufnum = 0.f; } \ if (fbufnum != unit->m_fbufnum) { \ uint32 bufnum = (int)fbufnum; \ World *world = unit->mWorld; \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ unit->m_buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ unit->m_buf = world->mSndBufs + bufnum; \ } \ } else { \ unit->m_buf = world->mSndBufs + bufnum; \ } \ unit->m_fbufnum = fbufnum; \ } \ const SndBuf *buf = unit->m_buf; \ LOCK_SNDBUF_SHARED(buf); \ const float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples __attribute__((__unused__)) = buf->samples; \ uint32 bufFrames = buf->frames; \ int mask __attribute__((__unused__)) = buf->mask; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; #define SIMPLE_GET_BUF \ float fbufnum = ZIN0(0); \ fbufnum = sc_max(0.f, fbufnum); \ if (fbufnum != unit->m_fbufnum) { \ uint32 bufnum = (int)fbufnum; \ World *world = unit->mWorld; \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ unit->m_buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ unit->m_buf = world->mSndBufs + bufnum; \ } \ } else { \ unit->m_buf = world->mSndBufs + bufnum; \ } \ unit->m_fbufnum = fbufnum; \ } \ SndBuf *buf = unit->m_buf; \ #define SIMPLE_GET_BUF_EXCLUSIVE \ SIMPLE_GET_BUF; \ LOCK_SNDBUF(buf); #define SIMPLE_GET_BUF_SHARED \ SIMPLE_GET_BUF; \ LOCK_SNDBUF_SHARED(buf); // macros to get pseudo-random number generator, and put its state in registers #define RGET \ RGen& rgen = *unit->mParent->mRGen; \ uint32 s1 = rgen.s1; \ uint32 s2 = rgen.s2; \ uint32 s3 = rgen.s3; #define RPUT \ rgen.s1 = s1; \ rgen.s2 = s2; \ rgen.s3 = s3; typedef void (*UnitCmdFunc)(struct Unit *unit, struct sc_msg_iter *args); typedef void (*PlugInCmdFunc)(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr); #endif SuperCollider-Source/include/plugin_interface/SC_Wire.h000644 000765 000024 00000002051 12321461511 024254 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Wire_ #define _SC_Wire_ #include "SC_Types.h" struct Wire { struct Unit *mFromUnit; int32 mCalcRate; float32 *mBuffer; float32 mScalarValue; }; typedef struct Wire Wire; #endif SuperCollider-Source/include/plugin_interface/SC_World.h000644 000765 000024 00000006164 12756531745 024471 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_World_ #define _SC_World_ #include "SC_Types.h" #include "SC_Rate.h" #include "SC_SndBuf.h" #include "SC_RGen.h" #ifdef SUPERNOVA namespace nova { class spin_lock; class padded_rw_spinlock; } #endif struct World { // a pointer to private implementation, not available to plug-ins. struct HiddenWorld *hw; // a pointer to the table of function pointers that implement the plug-ins' // interface to the server. struct InterfaceTable *ft; // data accessible to plug-ins : double mSampleRate; int mBufLength; int mBufCounter; uint32 mNumAudioBusChannels; uint32 mNumControlBusChannels; uint32 mNumInputs; uint32 mNumOutputs; // vector of samples for all audio busses float *mAudioBus; // vector of samples for all control busses float *mControlBus; // these tell if a buss has been written to during a control period // if the value is equal to mBufCounter then the buss has been touched // this control period. int32 *mAudioBusTouched; int32 *mControlBusTouched; uint32 mNumSndBufs; SndBuf *mSndBufs; SndBuf *mSndBufsNonRealTimeMirror; SndBufUpdates *mSndBufUpdates; struct Group *mTopGroup; Rate mFullRate, mBufRate; uint32 mNumRGens; RGen *mRGen; uint32 mNumUnits, mNumGraphs, mNumGroups; int mSampleOffset; // offset in the buffer of current event time. void * mNRTLock; uint32 mNumSharedControls; float *mSharedControls; bool mRealTime; bool mRunning; int mDumpOSC; void* mDriverLock; float mSubsampleOffset; // subsample accurate offset in the buffer of current event time. int mVerbosity; int mErrorNotification; int mLocalErrorNotification; bool mRendezvous; // Allow user to disable Rendezvous const char* mRestrictedPath; // OSC commands to read/write data can only do it within this path, if specified #ifdef SUPERNOVA nova::padded_rw_spinlock * mAudioBusLocks; nova::spin_lock * mControlBusLock; #endif }; inline SndBuf* World_GetBuf(struct World *inWorld, uint32 index) { if (index > inWorld->mNumSndBufs) index = 0; return inWorld->mSndBufs + index; } inline SndBuf* World_GetNRTBuf(struct World *inWorld, uint32 index) { if (index > inWorld->mNumSndBufs) index = 0; return inWorld->mSndBufsNonRealTimeMirror + index; } typedef void (*LoadPlugInFunc)(struct InterfaceTable *); typedef void (*UnLoadPlugInFunc)(); #endif SuperCollider-Source/include/plugin_interface/SCComplex.h000644 000765 000024 00000002105 12321461511 024616 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SCComplex_ #define _SCComplex_ #include "SC_Complex.h" /** wrapper for backwards compatibility */ typedef Polar SCPolar; typedef Complex SCComplex; inline void init_SCComplex(InterfaceTable *inTable) {} #endif SuperCollider-Source/include/plugin_interface/Unroll.h000644 000765 000024 00000014306 12321461511 024242 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* These macros allow one to write code which can be compiled optimally depending on what loop constructs the compiler can best generate code. */ #ifndef _Unroll_ #define _Unroll_ #include #include #if 1 // loop type #define FOR_IS_FASTER 1 #define WHILE_IS_FASTER 0 // indexing type #define PREINCREMENT_IS_FASTER 1 #define POSTINCREMENT_IS_FASTER 0 #else // loop type #define FOR_IS_FASTER 1 #define WHILE_IS_FASTER 0 // indexing type #define PREINCREMENT_IS_FASTER 0 #define POSTINCREMENT_IS_FASTER 1 #endif // LOOPING MACROS : #if FOR_IS_FASTER #define LOOP(length, stmt) for (int xxi=0; xxi<(length); ++xxi) { stmt; } #elif WHILE_IS_FASTER #define LOOP(length, stmt) \ { int xxn = (length); \ while (--xxn) { \ stmt; \ } \ } #endif // above macros are not friendly to the debugger #if FOR_IS_FASTER #define LooP(length) for (int xxi=0; xxi<(length); ++xxi) #elif WHILE_IS_FASTER #define LooP(length) for (int xxi=(length); --xxi;) #endif /* faster loop macro, length is required to be larger than 0 */ #define LOOP1(length, stmt) \ { int xxn = (length); \ assert(length); \ do { \ stmt; \ } while (--xxn); \ } // LOOP INDEXING : /* meanings of the indexing macros: ZXP = dereference and pre or post increment ZX = dereference PZ = preincrement (if applicable) ZP = postincrement (if applicable) ZOFF = offset from the pointer of the first element of the array (preincrement requires a ZOFF of 1 which is pre-subtracted from the base pointer. For other indexing types ZOFF is zero) */ #if PREINCREMENT_IS_FASTER #define ZXP(z) (*++(z)) #define ZX(z) (*(z)) #define PZ(z) (++(z)) #define ZP(z) (z) #define ZOFF (1) #elif POSTINCREMENT_IS_FASTER #define ZXP(z) (*(z)++) #define ZX(z) (*(z)) #define PZ(z) (z) #define ZP(z) ((z)++) #define ZOFF (0) #endif // ACCESSING INLETS AND OUTLETS : // unit inputs #define ZIN(i) (IN(i) - ZOFF) // get buffer pointer offset for iteration #define ZIN0(i) (IN(i)[0]) // get first sample // unit outputs #define ZOUT(i) (OUT(i) - ZOFF) // get buffer pointer offset for iteration #define ZOUT0(i) (OUT(i)[0]) // get first sample #include "SC_BoundsMacros.h" #include // Efficiency notes: Clear and Copy was benchmarked in October 2008. // See http://www.mcld.co.uk/blog/blog.php?217 and http://www.mcld.co.uk/blog/blog.php?218 // Set floating-point data to all zeros inline void Clear(int numSamples, float *out) { // The memset approach is valid on any system using IEEE floating-point. On other systems, please check... memset(out, 0, numSamples * sizeof(float)); } inline void Clear(int numSamples, double *out) { // The memset approach is valid on any system using IEEE floating-point. On other systems, please check... memset(out, 0, numSamples * sizeof(double)); } inline void Copy(int numSamples, float *out, float *in) { memcpy(out, in, numSamples * sizeof(float)); } inline void Fill(int numSamples, float *out, float level) { out -= ZOFF; LOOP(numSamples, ZXP(out) = level; ); } inline void Fill(int numSamples, float *out, float level, float slope) { out -= ZOFF; LOOP(numSamples, ZXP(out) = level; level += slope; ); } inline void Accum(int numSamples, float *out, float *in) { in -= ZOFF; out -= ZOFF; LOOP(numSamples, ZXP(out) += ZXP(in); ); } inline void Scale(int numSamples, float *out, float level) { out -= ZOFF; LOOP(numSamples, ZXP(out) *= level;); } inline float Scale(int numSamples, float *out, float level, float slope) { out -= ZOFF; LOOP(numSamples, ZXP(out) *= level; level += slope;); return level; } inline float Scale(int numSamples, float *out, float *in, float level, float slope) { in -= ZOFF; out -= ZOFF; LOOP(numSamples, ZXP(out) = ZXP(in) * level; level += slope;); return level; } inline float ScaleMix(int numSamples, float *out, float *in, float level, float slope) { in -= ZOFF; out -= ZOFF; LOOP(numSamples, ZXP(out) += ZXP(in) * level; level += slope;); return level; } inline void Scale(int numSamples, float *out, float *in, float level) { in -= ZOFF; out -= ZOFF; LOOP(numSamples, ZXP(out) = ZXP(in) * level; ); } // in these the pointers are assumed to already have been pre-offset. inline void ZCopy(int numSamples, float *out, const float *in) { // pointers must be 8 byte aligned //assert((((long)(out+ZOFF) & 7) == 0) && (((long)(in+ZOFF) & 7) == 0)); if (in == out) return; if ((numSamples & 1) == 0) { // copying doubles is faster on powerpc. double *outd = (double*)(out + ZOFF) - ZOFF; double *ind = (double*)(in + ZOFF) - ZOFF; LOOP(numSamples >> 1, ZXP(outd) = ZXP(ind); ); } else { LOOP(numSamples, ZXP(out) = ZXP(in); ); } } inline void ZClear(int numSamples, float *out) { // pointers must be 8 byte aligned //assert((((long)(out+ZOFF) & 7) == 0) && (((long)(in+ZOFF) & 7) == 0)); if ((numSamples & 1) == 0) { // copying doubles is faster on powerpc. double *outd = (double*)(out + ZOFF) - ZOFF; LOOP(numSamples >> 1, ZXP(outd) = 0.; ); } else { LOOP(numSamples, ZXP(out) = 0.f; ); } } inline void ZAccum(int numSamples, float *out, float *in) { LOOP(numSamples, ZXP(out) += ZXP(in); ); } template inline void loop(int length, Functor const & f) { for (int i=0; i < length; ++i) f(); } template inline void loop1(int length, Functor const & f) { assert(length > 0); int i = length; do { f(); } while (--i); } #endif SuperCollider-Source/include/lang/SC_LanguageClient.h000644 000765 000024 00000012146 12756531745 023664 0ustar00crucialstaff000000 000000 /* -*- c++ -*- Abstract interpreter interface. Copyright (c) 2003 2004 stefan kersten. Copyright (c) 2013 tim blechmann. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SC_LANGUAGECLIENT_H_INCLUDED #define SC_LANGUAGECLIENT_H_INCLUDED #include "SC_Export.h" #include #include // ===================================================================== // SC_LanguageClient - abstract sclang client. // ===================================================================== SCLANG_DLLEXPORT class SC_LanguageClient * createLanguageClient(const char * name); SCLANG_DLLEXPORT void destroyLanguageClient(class SC_LanguageClient *); class SCLANG_DLLEXPORT SC_LanguageClient { public: struct Options { Options() : mMemSpace(2*1024*1024), mMemGrow(256*1024), mPort(57120), mRuntimeDir(0) { } int mMemSpace; // memory space in bytes int mMemGrow; // memory growth in bytes int mPort; // network port number char* mRuntimeDir; // runtime directory }; protected: // create singleton instance SC_LanguageClient(const char* name); virtual ~SC_LanguageClient(); friend void destroyLanguageClient(class SC_LanguageClient *); public: // singleton instance access locking static void lockInstance(); static void unlockInstance(); // return the singleton instance static SC_LanguageClient* instance(); static SC_LanguageClient* lockedInstance() { lockInstance(); return instance(); } // initialize language runtime void initRuntime(const Options& opt=Options()); void shutdownRuntime(); // return application name const char* getName() const; // library startup/shutdown bool isLibraryCompiled(); void compileLibrary(bool standalone); void shutdownLibrary(); void recompileLibrary(bool standalone); // interpreter access void lock(); bool trylock(); void unlock(); struct VMGlobals* getVMGlobals(); void setCmdLine(const char* buf, size_t size); void setCmdLine(const char* str); void setCmdLinef(const char* fmt, ...); void runLibrary(const char* methodName); void interpretCmdLine(); void interpretPrintCmdLine(); void executeFile(const char* fileName); void runMain(); void stopMain(); // post file access FILE* getPostFile(); void setPostFile(FILE* file); // run (in case of a terminal client) virtual int run(int argc, char** argv); // post buffer output (subclass responsibility) // should be thread-save. virtual void postText(const char* str, size_t len) = 0; virtual void postFlush(const char* str, size_t len) = 0; virtual void postError(const char* str, size_t len) = 0; // flush post buffer contents to screen. // only called from the main language thread. virtual void flush() = 0; // command line argument handling utilities static void snprintMemArg(char* dst, size_t size, int arg); static bool parseMemArg(const char* arg, int* res); static bool parsePortArg(const char* arg, int* res); // AppClock driver // to be called from client mainloop. void tick(); // AppClock driver. WARNING: Must be called locked! // Returns whether there is anything scheduled, // and writes the scheduled absolute time, if any, into nextTime. bool tickLocked( double * nextTime ); protected: // language notifications, subclasses can override // called after language runtime has been initialized virtual void onInitRuntime(); // called after the library has been compiled virtual void onLibraryStartup(); // called before the library is shut down virtual void onLibraryShutdown(); // called after the interpreter has been started virtual void onInterpStartup(); void runLibrary(struct PyrSymbol* pyrSymbol); private: friend void closeAllGUIScreens(); friend void initGUIPrimitives(); friend void initGUI(); private: class HiddenLanguageClient * mHiddenClient; }; // ===================================================================== // library functions // ===================================================================== extern void setPostFile(FILE* file); extern "C" int vpost(const char *fmt, va_list vargs); extern void post(const char *fmt, ...); extern void postfl(const char *fmt, ...); extern void postText(const char *text, long length); extern void postChar(char c); extern void error(const char *fmt, ...); extern void flushPostBuf(); #endif // SC_LANGUAGECLIENT_H_INCLUDED SuperCollider-Source/include/common/clz.h000644 000765 000024 00000010411 12321461511 021522 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* count leading zeroes function and those that can be derived from it */ #ifndef _CLZ_ #define _CLZ_ #include "SC_Types.h" #ifdef __MWERKS__ #define __PPC__ 1 #define __X86__ 0 // powerpc native count leading zeroes instruction: #define CLZ(x) ((int)__cntlzw((unsigned int)x)) #elif defined(__GNUC__) /* use gcc's builtins */ static __inline__ int32 CLZ(int32 arg) { if (arg) return __builtin_clz(arg); else return 32; } #elif defined(_MSC_VER) #include #pragma intrinsic(_BitScanReverse) __forceinline static int32 CLZ( int32 arg ) { unsigned long idx; if (_BitScanReverse(&idx, (unsigned long)arg)) { return (int32)(31-idx); } return 32; } #elif defined(__ppc__) || defined(__powerpc__) || defined(__PPC__) static __inline__ int32 CLZ(int32 arg) { __asm__ volatile("cntlzw %0, %1" : "=r" (arg) : "r" (arg)); return arg; } #elif defined(__i386__) || defined(__x86_64__) static __inline__ int32 CLZ(int32 arg) { if (arg) { __asm__ volatile("bsrl %0, %0\nxorl $31, %0\n" : "=r" (arg) : "0" (arg)); } else { arg = 32; } return arg; } #elif defined(SC_IPHONE) static __inline__ int32 CLZ(int32 arg) { return __builtin_clz(arg); } #else # error "clz.h: Unsupported architecture" #endif // count trailing zeroes inline int32 CTZ(int32 x) { return 32 - CLZ(~x & (x-1)); } // count leading ones inline int32 CLO(int32 x) { return CLZ(~x); } // count trailing ones inline int32 CTO(int32 x) { return 32 - CLZ(x & (~x-1)); } // number of bits required to represent x. inline int32 NUMBITS(int32 x) { return 32 - CLZ(x); } // log2 of the next power of two greater than or equal to x. inline int32 LOG2CEIL(int32 x) { return 32 - CLZ(x - 1); } // is x a power of two inline bool ISPOWEROFTWO(int32 x) { return (x & (x-1)) == 0; } // next power of two greater than or equal to x inline int32 NEXTPOWEROFTWO(int32 x) { return (int32)1L << LOG2CEIL(x); } // previous power of two less than or equal to x inline int32 PREVIOUSPOWEROFTWO(int32 x) { if (ISPOWEROFTWO(x)) return x; return (int32)1L << (LOG2CEIL(x) - 1); } // input a series of counting integers, outputs a series of gray codes . inline int32 GRAYCODE(int32 x) { return x ^ (x>>1); } // find least significant bit inline int32 LSBit(int32 x) { return x & -x; } // find least significant bit position inline int32 LSBitPos(int32 x) { return CTZ(x & -x); } // find most significant bit position inline int32 MSBitPos(int32 x) { return 31 - CLZ(x); } // find most significant bit inline int32 MSBit(int32 x) { return (int32)1L << MSBitPos(x); } // count number of one bits inline uint32 ONES(uint32 x) { uint32 t; x = x - ((x >> 1) & 0x55555555); t = ((x >> 2) & 0x33333333); x = (x & 0x33333333) + t; x = (x + (x >> 4)) & 0x0F0F0F0F; x = x + (x << 8); x = x + (x << 16); return x >> 24; } // count number of zero bits inline uint32 ZEROES(uint32 x) { return ONES(~x); } // reverse bits in a word inline uint32 BitReverse(uint32 x) { x = ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1); x = ((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2); x = ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4); x = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); return (x >> 16) | (x << 16); } // barrel shifts inline uint32 RotateRight (uint32 x, uint32 s) { s = s & 31; return (x << (32-s)) | (x >> s); } inline uint32 RotateLeft (uint32 x, uint32 s) { s = s & 31; return (x >> (32-s)) | (x << s); } #endif SuperCollider-Source/include/common/function_attributes.h000644 000765 000024 00000004347 12756531745 025063 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2011 Tim Blechmann. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FUNCTION_ATTRIBUTES_H #define FUNCTION_ATTRIBUTES_H #ifdef __GNUC__ #ifdef _WIN32 #undef PURE #endif #define CONST_FUNCTION __attribute__((const)) #define PURE __attribute__((pure)) #define MALLOC __attribute__((malloc)) #define ASSUME_ALIGNED(Alignment) __attribute__((assume_aligned(Alignment))) #define HOT __attribute__((hot)) #define COLD __attribute__((cold)) #define FLATTEN __attribute__((flatten)) #endif #ifdef __clang__ #undef HOT #undef FLATTEN #undef ASSUME_ALIGNED #endif #ifdef __PATHCC__ #undef HOT #undef FLATTEN #endif #ifdef _MSC_VER #ifndef PURE #define PURE /*PURE*/ #endif #ifndef CONST_FUNCTION #define CONST_FUNCTION /*CONST_FUNCTION*/ #endif #endif #ifndef MALLOC #define MALLOC /*MALLOC*/ #endif #ifndef HOT #define HOT /*HOT*/ #endif #ifndef COLD #define COLD /*COLD*/ #endif #ifndef FLATTEN #define FLATTEN /*FLATTEN*/ #endif #ifndef ASSUME_ALIGNED #define ASSUME_ALIGNED(Alignment) /* assume aligned Alignment */ #endif // provide c99-style __restrict__ #if defined(__GNUC__) || defined(__CLANG__) // __restrict__ defined #else #define __restrict__ /* __restrict */ #endif // force inlining in release mode #ifndef NDEBUG #define force_inline inline #else #if defined(__GNUC__) #define force_inline inline __attribute__((always_inline)) #elif defined(_MSVER) #define force_inline __forceinline #else #define force_inline inline #endif #endif #endif /* FUNCTION_ATTRIBUTES_H */ SuperCollider-Source/include/common/SC_Alloca.h000644 000765 000024 00000002057 12321461511 022521 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2011 Tim Blechmann. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_ALLOCA_H #define _SC_ALLOCA_H #ifdef __linux__ #include #elif defined(_WIN32) #include #ifndef alloca #define alloca _alloca #endif #endif #endif /* _SC_ALLOCA_H */ SuperCollider-Source/include/common/SC_BoundsMacros.h000644 000765 000024 00000002424 12321461511 023723 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_BoundsMacros_ #define _SC_BoundsMacros_ #include /* std::abs */ #include /* std::abs */ #include #define sc_abs(a) std::abs(a) #define sc_max(a,b) (((a) > (b)) ? (a) : (b)) #define sc_min(a,b) (((a) < (b)) ? (a) : (b)) template inline T sc_clip(T x, U lo, V hi) { return std::max(std::min(x, (T)hi), (T)lo); } #endif SuperCollider-Source/include/common/SC_Endian.h000644 000765 000024 00000005310 12524671173 022533 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* NOTE: This file should declare/define the following functions/macros: sc_htonl sc_htons sc_ntohl sc_ntohs */ #ifndef SC_ENDIAN_H_INCLUDED #define SC_ENDIAN_H_INCLUDED #if defined(__APPLE__) # include #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) # include # include #elif defined(_WIN32) # define LITTLE_ENDIAN 1234 # define BIG_ENDIAN 4321 # define BYTE_ORDER LITTLE_ENDIAN #define SC_NO_ENDIAN_FUNCTIONS #elif defined(__linux__) # include # include #else # error cannot find endianess on this platform #endif #ifndef SC_NO_ENDIAN_FUNCTIONS static inline unsigned int sc_htonl(unsigned int arg) { return htonl(arg); } static inline unsigned short sc_htons(unsigned short arg) { return htons(arg); } static inline unsigned int sc_ntohl(unsigned int arg) { return ntohl(arg); } static inline unsigned short sc_ntohs(unsigned short arg) { return ntohs(arg); } #else static inline unsigned int sc_htonl(unsigned int x) { #if BYTE_ORDER == LITTLE_ENDIAN unsigned char *s = (unsigned char *)&x; return (unsigned int)(s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]); #else return x; #endif } static inline unsigned short sc_htons(unsigned short x) { #if BYTE_ORDER == LITTLE_ENDIAN unsigned char *s = (unsigned char *) &x; return (unsigned short)(s[0] << 8 | s[1]); #else return x; #endif } static inline unsigned int sc_ntohl(unsigned int x) { return sc_htonl(x); } static inline unsigned short sc_ntohs(unsigned short x) { return sc_htons(x); } #endif #ifndef BYTE_ORDER # error BYTE_ORDER undefined, check __FILE__ #endif // BYTE_ORDER #ifndef BIG_ENDIAN # error BIG_ENDIAN undefined, check __FILE__ #endif // BIG_ENDIAN #ifndef LITTLE_ENDIAN # error LITTLE_ENDIAN undefined, check __FILE__ #endif // LITTLE_ENDIAN #endif // SC_ENDIAN_H_INCLUDED SuperCollider-Source/include/common/SC_Export.h000644 000765 000024 00000004107 12524671173 022621 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2010 Tim Blechmann. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_EXPORTS_ #define _SC_EXPORTS_ #if defined _WIN32 || defined __CYGWIN__ # define SC_API_IMPORT __declspec(dllimport) # define SC_API_EXPORT __declspec(dllexport) #else # if __GNUC__ >= 4 # define SC_API_IMPORT __attribute__ ((visibility("default"))) # define SC_API_EXPORT __attribute__ ((visibility("default"))) # else # define SC_API_IMPORT # define SC_API_EXPORT # endif #endif #ifdef __cplusplus # define C_LINKAGE extern "C" #else # define C_LINKAGE #endif #ifdef BUILDING_SCSYNTH // if scsynth is being built, instead of used # define SCSYNTH_DLLEXPORT_C C_LINKAGE SC_API_EXPORT # define SCSYNTH_DLLEXPORT SC_API_EXPORT #elif defined(USING_SCSYNTH) # define SCSYNTH_DLLEXPORT_C C_LINKAGE SC_API_IMPORT # define SCSYNTH_DLLEXPORT SC_API_IMPORT #else # define SCSYNTH_DLLEXPORT_C C_LINKAGE # define SCSYNTH_DLLEXPORT /*SC_API_IMPORT*/ #endif #ifdef BUILDING_SCLANG // if sclang is being built, instead of used # define SCLANG_DLLEXPORT_C C_LINKAGE SC_API_EXPORT # define SCLANG_DLLEXPORT SC_API_EXPORT #elif defined(USING_SCSYNTH) # define SCLANG_DLLEXPORT_C C_LINKAGE SC_API_IMPORT # define SCLANG_DLLEXPORT SC_API_IMPORT #else # define SCLANG_DLLEXPORT_C C_LINKAGE # define SCLANG_DLLEXPORT /*SC_API_IMPORT*/ #endif #endif SuperCollider-Source/include/common/SC_fftlib.h000644 000765 000024 00000004764 12756531745 022626 0ustar00crucialstaff000000 000000 /* SC_fftlib.h An interface to abstract over different FFT libraries, for SuperCollider 3. Copyright (c) 2008 Dan Stowell. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_fftlib_ #define _SC_fftlib_ #include // These specify the min & max FFT sizes expected (used when creating windows, also allocating some other arrays). #define SC_FFT_MINSIZE 8 #define SC_FFT_LOG2_MINSIZE 3 #define SC_FFT_MAXSIZE 32768 #define SC_FFT_LOG2_MAXSIZE 15 // Note that things like *fftWindow actually allow for other sizes, to be created on user request. #define SC_FFT_ABSOLUTE_MAXSIZE 262144 #define SC_FFT_LOG2_ABSOLUTE_MAXSIZE 18 #define SC_FFT_LOG2_ABSOLUTE_MAXSIZE_PLUS1 19 struct scfft; class SCFFT_Allocator { public: virtual void* alloc(size_t size) = 0; virtual void free(void* ptr) = 0; }; enum SCFFT_Direction { kForward = 1, kBackward = 0 }; // These values are referred to from SC lang as well as in the following code - do not rearrange! enum SCFFT_WindowFunction { kRectWindow = -1, kSineWindow = 0, kHannWindow = 1 }; //////////////////////////////////////////////////////////////////////////////////////////////////// // Functions // To initialise a specific FFT, ensure your input and output buffers exist. Internal data structures // will be allocated using the alloc object, // Both "fullsize" and "winsize" should be powers of two (this is not checked internally). scfft * scfft_create(size_t fullsize, size_t winsize, SCFFT_WindowFunction wintype, float *indata, float *outdata, SCFFT_Direction forward, SCFFT_Allocator & alloc); // These two will take data from indata, use trbuf to process it, and put their results in outdata. void scfft_dofft(scfft *f); void scfft_doifft(scfft *f); // destroy any resources held internally. void scfft_destroy(scfft *f, SCFFT_Allocator & alloc); #endif SuperCollider-Source/include/common/SC_Reply.h000644 000765 000024 00000001777 12321461511 022431 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Reply_ #define _SC_Reply_ struct ReplyAddress; typedef void (*ReplyFunc)(struct ReplyAddress *inReplyAddr, char* inBuf, int inSize); #endif SuperCollider-Source/include/common/SC_StringBuffer.h000644 000765 000024 00000003706 12321461511 023730 0ustar00crucialstaff000000 000000 // emacs: -*- c++ -*- // file: SC_StringBuffer.h // copyright: 2003 stefan kersten // cvs: $Id$ // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 // USA #ifndef SC_STRINGBUFFER_H_INCLUDED #define SC_STRINGBUFFER_H_INCLUDED #include #include // ===================================================================== // SC_StringBuffer - Autogrowing string buffer. // ===================================================================== class SC_StringBuffer { public: SC_StringBuffer(size_t initialSize=0); SC_StringBuffer(const SC_StringBuffer& other); ~SC_StringBuffer(); size_t getCapacity() const { return mCapacity; } size_t getSize() const { return mPtr - mData; } size_t getRemaining() const { return mCapacity - getSize(); } char* getData() const { return mData; } bool isEmpty() const { return getSize() == 0; } void finish() { append('\0'); } void reset() { mPtr = mData; } void append(const char* src, size_t len); void append(char c); void append(const char* str); void vappendf(const char* fmt, va_list vargs); void appendf(const char* fmt, ...); protected: enum { kGrowAlign = 256, kGrowMask = kGrowAlign - 1 }; void growBy(size_t request); private: size_t mCapacity; char* mPtr; char* mData; }; #endif // SC_STRINGBUFFER_H_INCLUDED SuperCollider-Source/include/common/SC_Types.h000644 000765 000024 00000003250 12756531745 022451 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Types_ #define _SC_Types_ #include #include #if !defined(__cplusplus) # include #endif // __cplusplus typedef int SCErr; typedef int64_t int64; typedef uint64_t uint64; typedef int32_t int32; typedef uint32_t uint32; typedef int16_t int16; typedef uint16_t uint16; typedef int8_t int8; typedef uint8_t uint8; typedef float float32; typedef double float64; typedef union { uint32 u; int32 i; float32 f; } elem32; typedef union { uint64 u; int64 i; float64 f; } elem64; const unsigned int kSCNameLen = 8; const unsigned int kSCNameByteLen = 8 * sizeof(int32); #ifdef __GXX_EXPERIMENTAL_CXX0X__ #define sc_typeof_cast(x) (decltype(x)) #elif defined(__GNUC__) #define sc_typeof_cast(x) (__typeof__(x)) #else #define sc_typeof_cast(x) /* (typeof(x)) */ #endif #endif SuperCollider-Source/include/common/wintime.h000644 000765 000024 00000001202 12756531745 022427 0ustar00crucialstaff000000 000000 #ifndef WINTIME_H #define WINTIME_H #include // for timeval struct #include /* Implementation as per: The Open Group Base Specifications, Issue 6 IEEE Std 1003.1, 2004 Edition The timezone pointer arg is ignored. Errors are ignored. */ inline int gettimeofday(struct timeval* p, void* tz /* IGNORED */) { union { long long ns100; /*time since 1 Jan 1601 in 100ns units */ FILETIME ft; } now; GetSystemTimeAsFileTime(&(now.ft)); p->tv_usec = (long)((now.ns100 / 10LL) % 1000000LL); p->tv_sec = (long)((now.ns100 - (116444736000000000LL)) / 10000000LL); return 0; } #endif SuperCollider-Source/icons/sc.icns000644 000765 000024 00000125134 12321461511 020255 0ustar00crucialstaff000000 000000 icns\ICN#icl8il32kifcjkã~kðVk ̴Vk ѼV kЀVk¹Vkɼι~k˱вjk —akʠʽekvzʺt`hkվx{qvkkkֽ¥tqtkkؽx~zkkڼkk۽kk߿ŏykk¨v~kkݰۈpkk٬vz|kk׫wxkk㻥kkkk 񌌋kk ynkkoӍkk okk…kkkkkifcjkã~kðVk ̴Vk ѼV kЀVk¹Vkɼι~k˱вjk —akʠʽekvzʺt`hkվx{qvkkkֽ¥tqtkkؽx~zkkڼkk۽kk߿ŏykk¨v~kkݰۈpkk٬vz|kk׫wxkk㻥kkkk 񌋋kkynkkoӍkk okk…kkkkkifcjkã~kðVk ̴Vk ѼV kЀVk¹Vkɼι~k˱вjk —akʠʽekvzʺt`hkվx{qvkkkֽ¥tqtkkؽx~zkkڼkk۽kk߿ŏykk¨v~kkݰۈpkk٬vz|kk׫wxkk㻥kkkk 񌋋kkynkkoӍkk okk…kkkkl8mkIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIics#Hics8VVV+++V**+*VVVVVV*Vis327핅퀕ӁӁ흝z흞z흝zzz핅퀕ӁӁ흝z흞z흝zzz핅퀕ӁӁ흝z흞z흝zzzs8mkFnnnnnnFnFnFnnnnnnnnnnnnnnnnnnnnFnnnnnnnnFit32U߂݀ ր¿!߂ڀ¿ހہÿ>ހہÿBހہ¾$߀ۀր$߀ۀր$߀ۀր¾Ƚ$߀ہʽ$߀ۀĿʽ$ۀʽ$րüʽ$ހ ƿʼ$ހۀʼ$ހۀûʼ$߀ ƿʼ$߀ ʼ$߀ۀºʼ$߀ۀ ûʼ$߀ۀ üʼ$żʼ$Ǿʼ$ʼ$ʼ$܀øʼ$ ùvoo ʼ$3Ļ{smifddehhmptʽ$)żxsnlj mnqsvz$с ˼ſzwts ttvx|~$2ѽ¼~} ~~7ſĴѻ 7ƹDZ4˼Ѽ־MǪѼcMΡǶŻѼ?ӣŢþļŲ џ˭ɀ/Ĭ̺Mўεʹ¿MџмĿҹMӟýȺ¿MНȽǺQ}ʼϞŮɾäMdkǼ͜Ǥnrjk݀9͜п½jzʤqwvqklڀ͝ʴvib^ZuΤux|}xqkn؀Λ}smkihfc\vФӽxx{~xplo}׀̚$~xvutpmigfd]vҤԺ{xzolo{}Հ1ʚ{vpligffhf]uդԶvȯ{nkoxttՀ/㷻vojhfedegijg^sפMճwʱ{mlpv{vkm൴|rliffggimwyii]tڤ,ծxȵ|mmpssm`ٲumhgikox}lj^tۤQժyǹ}mmpocӯvmhghijlpv~~nk]sܤM֦yȾƤ~qpcϬjhfhjklotzql^rݤ3أzyrdʩ{hmnpqty}tn_sޤ0؟|sdƧkoqtvvxz~wo_sߤM؛|ςvempqrv}yq_qDؙ}Ѕyeὡoro}|xz|r`qؕ}:Ј|f۸rrn~{|~r`q ّ}=ь~fִutn~~{|s`p/ڏҐfѰwun{|uapDڌįӓfͬzvn{|wapEڈȳӗfȩ|wn~{{yaoJڅʸ~ԛfåyn}||yboGۂμ~՟fzn}||zboH~բg{n||{{bnI}Ƃ}Ƿզg|o||{}bmBx˄|֪g}o{|{~bm} vЄ|7׮g~oz|{~~clzDsԁ{׳goz|z}|clxEpݚ{~ضhoz}{zzclwFmŘػh~oy|zyycjujƞ+ٿh}ox{zwwtscjs~BiǥĦh{ox|}zxwuttw}cjp|Gffɭɩhz~ow{~ywvvuux|bjoz(icd˵έix|pwzxvx{bhmy&gcdοұiw~zpvwx|bhjwB߾gceִiv{xovwy}xehhtA޾hce۷ityvpuvwy}{pihiggs?޼fcf~iswtjt{ysqoomkhfeq=ݻecf|jr~tr~{{ywsojfeccbi2ݼecfxjp{rq{tmifcbhtܷfdgu{ylowpoyqjecbbchx%ܸedgs}|qpnntol~sjebck|۵edhpvsmmpljukecblڴedhmmlmjivkdc qڶedhjjhhvjcdsٲeehhfcevװeddhvԞ} ҁexdeeoddxneeedeeeeoeeeeӀeoeeoeeeeeeԀeeeʇeeee yeeee݄eyeeeeyeoeooe݇ކތ߂݀ ր¿!߂܀Հ¿ހہÿ>ހہÿBހہ¾$߀ۀր$߀ۀր$߀ۀր¾Ƚ$߀ہʽ$߀ۀĿʽ$ۀʽ$րüʽ$ހ ƿʼ$ހۀʼ$ހۀûʼ$߀ ƿʼ$߀ ʼ$߀ۀºʼ$߀ۀ ûʼ$߀ۀ üʼ$żʼ$Ǿʼ$ʼ$ʼ$܀øʼ$ ùvoo ʼ$3Ļ{smifddehhmptʽ$+żxsnlj mnqsvz$с ˼ſzwts ttvx|~$2ѽ¼~} ~~7ſĴѻ 7ƹDZ4˼Ѽ־MǪѼcMΡǶŻѼ?ӣŢþļŲ џ˭ɀ/Ĭ̺Mўεʹ¿MџмĿҹMӟýȺ¿MНȽǺQ}ʼϞŮɾäMdkǼ͜Ǥnrjk݀9͜п½jzʤqwvqklڀ͝ʴvib^ZuΤux|}xqkn؀Λ}smkihfc\vФӽxx{~xplo}׀̚$~xvutpmigfd]vҤԺ{xzolo{}Հ1ʚ{vpligffhf]uդԶvȯznkoxttՀ/㷻vojhfedegijg^sפMճwʱ{mlpv{vkm൴|rliffggimwyii]tڤ,ծxȵ|mmpssm`ٲumhgikox}lj^tۤQժyǹ}mmpocӯvmhghijlpv~~nk]sܤM֦yȾƤ~qpcϬjhfhjklouzql^rݤ3أzyrdʩ{hmnpqty}tn_sޤ0؟|sdƧkoqtvvxz~wo_sߤM؛|ςvempqrv}yq_qFؙ}Ѕyeὡoro}|xz|r`qؕ}:Ј|f۸rrn~{|~r`q ّ}=ь~fִutn~~{|s`p/ڏҐfѰwun{|uapDڌįӓfͬzvn~{|wapEڈȳӗfȩ|wn~{{yaoJڅʸ~ԛfåyn}||yboGۂμ~՟fzn}||zboH~բg{n||{{bnI}Ƃ}Ƿզg|o||{}bmBx˄|֪g}o{|{~bm} vЄ|7׮g~oz|{~~clzDsԁ{׳goz|z}|clxEpݚ{~ضhoz}{zzclwFmŘػh~oy|zyycjujƞ+ٿh}ox{zwwtscjs~BiǥĦh{ox|}zxwuttw}cjp|Effɭɩhz~ow{~ywvvuux|bjoz(icd˵έix|pwzxvx{bhmy&gcdϿұiw~zpvwx|bhjwB߾gceִiv{xovwy}xehhtA޾hce۷ityvpuvwy}{pihiggs?޼fcf~iswtjt{ysqoomkhfeq=ݻecf|jr~tr~{{ywsojfeccbi2ݼecfxjp{rq{tmifcbhtܷfdfu{ylowpoyqjecbbchx%ܸedgs}|qpnntol~sjebck|۵edhpvsmmpljukecblڴedhmmlmjivkdc qڶedhjjhhvjcdrٲeehhfcevװeddhvԞ} Ҁ exdeeoddxneeedeeeeoeeeeӀeoeeoeeeeeeԀeeeʈeeee yeeee݄eyeeeeyeoeooe݆ކދ߂݀ ր¿!߁ ׀Ԁހہÿ>ހہÿBހہ¾$߀ۀր$߀ۀր$߀ۀր¾Ƚ$߀ہʽ$߀ۀĿʽ$ۀʽ$րüʽ$ހ ƿʼ$ހۀʼ$ހۀûʼ$߀ ƿʼ$߀ ʼ$߀ۀºʼ$߀ۀ ûʼ$߀ۀ üʼ$żʼ$Ǿʼ$ʼ$ʼ$܀øʼ$ ùvoo ʼ$3Ļ{smifddehhmptʽ$+żxsnlj mnqsvz$с ˼ſzwts ttvx|~$2ѽ¼~} ~~7ſĴѻ 7ƹDZ4˼Ѽ־MǪѼcMΡǶŻѼ?ӣŢþļŲ џ˭ɀ/Ĭ̺Mўεʹ¿MџмĿҹMӟýȺ¿MНȽǺO}ʼϞŮɾäMdkǼ͜Ǥnrjk݀9͜п½jzʤqwvqklڀ͝ʴvib^ZuΤux|}xqkn؀Λ}smkihfc\vФӽxx{~xplo}׀̚$~xvutpmigfd]vҤԺ{xzolo{}Հ1ʚ{vpligffhf]uդԶvȯznkoxttՀ/㷻vojhfedegijg^sפMճwʱ{mlpv{vkm൴|rliffggimwyii]tڤ,ծxȵ|mmpssm`ٲumhgikox}lj^tۤQժyǹ}mmpocӯvmhghijlpv~~nk]sܤU֦yȾƤ~qpcϬjhfhjklotzqm^rݤ3أzyrdʩ{hmnpqty}tn_sޤ0؟|sdƧkoqtvvxz~wo_sߤM؛|ςvempqrv}yq_qDؙ}Ѕyeὡoro}|xz|r`qؕ}:Ј|f۸rrn~{|~r`q ّ}=ь~fִutn~~{|s`p/ڏҐfѰwun{|uapDڌįӓfͬzvn{|wapEڈȳӗfȩ|wn~{{yaoJڅʸ~ԛfåyn}||yboGۂμ~՟fzn}||zboH~բg{n||{{bnI}Ƃ}Ƿզg|o||{}bmBx˄|֪g}o{|{~bm} vЄ|7׮g~oz|{~~clzDsԁ{׳goz|z}|clxEpݚ{~ضhoz}{zzclwFmŘػh~oy|zyycjujƞ+ٿh}ox{zwwtscjs~BiǥĦh{ox|}zxwuttw}cjp|Effɭɩhz~ow{~ywvvuux|bjoz(icd˵έix|pwyxvx{bhmy&gcdϿұiw~zpvwx|bhjwB߾gceִiv{xovwy}xehhtA޾hce۷ityvpuvwy}{pihiggs?޼fcf~iswtjt{ysqoomkhfeq=ݻecf|jr~tr~{{ywsojfeccbi2ݼecfxjp{rq{tmifcbhtܷfcfu{ylowpoyqjecbbchx%ܸedgs}|qpnntol~sjebck|۵edhpvsmmpljukecblڴedhmmlmjivkdcqڶedhjjhhvjcdsٲeehhfcevװeddhvԞ} ҁexdeeoddxneeedeeeeoeeeeӀeoeeoeeeeeeԀeeeʇeeee yeeee݄eyeeeeyeoeooe݆ކތt8mk@    B   7  ,i  %6t  *>U .EU 1IU 3KU 3LU 3LU 3MV 3MV 3MV 3MW 3MW 3MW 3MW 3MW 3MW 3MW 3MV 3MV 3MV 3MV 3MU 3MU 3MU 3MU 3MU 3ME 3M'3M$ 3MA 3M' 3M03M7# 3M>( 3MC, 3MG/3MI13MJ23MK33ML33ML33ML33ML33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33LL33LL33KK31II1.EE. *>>*  %6I[itz~~zti[I6%  ,;IU]befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb]UI;,   ,6>EIKLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLKIE>6,  %*.133333333333333333333333333333333333333333333333333333333333333333333333333333331.*%    SuperCollider-Source/icons/sc_cube_128x128.png000644 000765 000024 00000043325 12321461511 022121 0ustar00crucialstaff000000 000000 PNG  IHDR>a IDATxmU> vXb؍-vaw7 *"!وp/w/|O~򓣪lP᠃~ӟ"8W1?!cP"g=7Z?ýۤ~iJ_ ?яx7'C?~ կFj4|;~4~( :H*r-/_%س0r<+?[_ _W}_ {o{44hx]o( 7ix=<Zq6q"TYU吪s\t?Joӟe??{+_9s_w}᳟n ar ?a/~1|vu]zҗtx31<)O' O{ӆg>1y>vx0ù,Dk,jp VKMqMk[ԆW-SoS&{/i>#O|bTϧG#9h1lvk^/x}s?cy7<9?ֳ5l6#15x75T\1޷H:pKPWWږܫ\7nP> ewv}û}?t >餓?~Ѕc}Io+_/X^W /{ˆE#@W$GG<u{H(?Qa!DlDu#Yr_k/I:[~㗾vi?mo{׿~xի^5j?яEt 0 _°;Goy[—#Px{n!A1j E q)4u/;CAҥ|>yiJXx$M$` 0j,Sʹ ڢ7pA[ç?t}h~Go~G^򒗜 8v)^ ̻ct$Y׾?Ep=Tl79TP:(A7s者t{>g>ccҼQ~uU$Lz4\x4!hMs?O D𴽺#h ;H`O*9 VAq%PD`Eun,J $~Wo?k蠃i5tzԣ*CH'PM3|WѮh.S CLm4fC@ Ep|A W"#"߻|>FGe5)skps-=;T&UnW\`7{59rڝ >@HY41H@@ +9iҋ_3,A0> 4Lh*Jp R\ڄ,B0 9?GeѐA@WbDP#"3G΃+WYNT&A 3J<HCinOzp~E`GPpڑv+M˙WExL|w0n9OA~'ɢ\ b,"8G'r"4"=_V@[M#$R5$m!MS1:Am42|!b0.?xIb)7hx8йa]dyd`  '?9܂",#D0"‹[Bc-Fp 16/'@FW"N>.$@L=?Bj[z !i'p^ Lzd DJ6?EY9Aa!%}_] 2KbW'M , !8@.`dy,z{XnKKuK'2A#]bNg,^XA'];^g A9?cw1VoX  /A`b|Β: eh 1\YR>"=u%E8|n3+FqDX4g^GkP FB%  s\3A0L"24`$HwHW.3͇#bp 8{I9JVQ3`x*Q[XD ?OO~G2s'*w8] "( *okP?x |'S\D=1݄$"\R L &[<;"Cҳ9qx/C &"8bw3,G,YFm>T2C{@#ى Q`">Zv ! JkKL(NBL?>>{> ! b = ;B9OLukqt0" $`t u٧\BG䏜G:Z/ #2 A \m%Iuة))aTfƙni!/K[L&$rP$`"|&41$|A"b,=J"8!L~P !wIH |#y$D>'e帶T:f 2 %yzy " *щ@# N%X#|N7%Ft6BaLf&$ybKl2p҅LPЦ=-G:̠R4I> U\D|R1ڛ% hp4oT/Vֽ:X#gimډַDhxNo31%affI/.< Axt/1C&\DItJlGD8ofD V8窗   Vq!YN?|z s  bv00 ٹ!8̄'GEkГ.: wL1DY {% ) 8+kD!0y" -gEP < Ȟ2 #jmUDa MOE*}GLIc "Go` s@!B& R"a8/E@q'+Dץ]Ngr?yI3't]9)Q}ge ~ua-8B)Ϻe@X R/v*\: &W@O5V@Pf"L@D!"A]驨og Ou*XDPzº~fǤG˹^CGۑ/m>ã1b X2E 8.Vg8s# d< ;NÆn8.ˏ>VV4o$d̘LBCD S"B@@%G@2 )pu?7|A E4X/&DLj;IٓuL)ifA r+1G>m$e^v\AbHt x=`;?]Jb1dp |;G}sWҕFӥ"jXAI`p =Xb qJBM*" s"`HXe"ϴ+2GOYZY~I,(HX2V6W2+[2 v,FJ h~bpᲗp ]h87\*WMa@LTXWbEiac&^×Əgvw5><=sSXBdH&?OL+@y ,fQbLOy2hri bB/F !׽5\ \2#.p LOW0*Gƅ!@J@rHڐK&$=s>KT4\Nd㓉<Bxjd^GdR Vl1$7.@.4׽_ F" .w5l&E/zё=ԧtP+2E|JS"Lkw=yhfR|6mx=S9ɫ3Y,;_7OϤx˙|x@=q7dH6tᒗH2xGrpsk$s3jE|~K i o8 n~*"TXk' Ȱ|&JMIBI]fϥ Μ;?2DQ\ 4` n1w=}[Võ}ї1!Z#2 A,Gr,b`DVʲ?@D#TJӁҸdhrE,ÞfhCEthiꃘ4do|x}>"\p}8f7 xb+9#Ƶud(Z7эFެm#3͉-*x[b r*7M6cvш!4EHw@F4hBBw3%'$P*FEȀ {& %tۦɗ8(;;j J\)m*3Wi { )DбM4෾#bF K@Ǭ2x{CX wFi'7Sbx @wKE&,&8fk|Mӫz,4\:07¥B h'+X`3 BNy/'>L/,FlYnJ*LJRzaځ+&1}e9KAa2RR=LZ+>| d.#JT*,W .ḑ\xr\O iS.}1hD@,@$Jdݝ &>9>s=k $ج mQ'8fS&콃V`9S 0홢՗|iv=D r,"rA_p;|$ (Cp3i#2a˽-FuLQzӅD(L!!@>9ְ< c6,c @79%{NxZ-dL&qz!93+pq@Kp3qJ%!vh)[!89W<BګqL_# Ϛ8]ȾuQ P:$HJLd,"g &hz6F2M*iތ%S;WLvvq ^̚4[ Im"L|tNtaB~o3'?$@Dȼ| ж@E S|~!"]04sW/BЀ!@dYB@ӵWՏ6vjx/ GLdeȆʽER)\,8B .1c##@LQp!c;f@,CnJ!!cF 8w?`']05$}4H%1,N@GɡH K?5紷w˺Yܹ .)27B/ B;e͠zq3@' q_Qnn1d)\@lfO:2M;ˮގ} u,B6ȴ,F,pGORk~Ȁ402J'i#Pt;5iSW;5]$.^r|z6P .!峟ae*XY{fz &v0)n 0Yt@BMd`ԑE`(K?O߫%8tE@N23Ȑ/B=BD. x48Ԝ/8iw H/UdaHq$Mf [[À:bp~ *Gw9\PfdVVs|ͣA!9$:vLR,q$TUOnI|qNRѾK H=zLJ'!ii]E G!@\ϐ#SY=-R0X #@p 8fe=H25ɥq#~:2k2R&hvܙ]gD/C=˖ 'l dIbA>|=[צ!H)3=v˪ ^p1dzz ΤLCR ouN'@t -2Ok5m]}ɷߎH6 ^& ~>CNmu2̚,s{dT2G t"D5(+WW z0\ Cd Zʷ *.& n|nI>e\#A4V,@'!g7V\Kr TfAQDYz"3bdx]7$= NNw$G8 2zR&YŵT#ʹ185F@% ó(8f^? t\'_hs IDAT|݋ϲ ACk Bƍe $XvNAeO 2@\!pd'8v]{ ܲiKtp{NsjbP!hS!`k"g4%tLב`$R$ D #Q 6 s2;=gL(?3nb/D S |GAp!:XLcuԩ@{2^!(/Flm !@ҵ*]6K@0PJ)a#`V p0F'a-r17{ 9N @wOڹ˺l+8`w S#pz_C']dZm\n @ڭ܅4`X$@.Q1ӯ ] 9xwO&t|.#$NDef0L Kg! (MT@p+ؘ#=SL1g ' +&T9}.&҄믿_Nub`$Nk;07*lt$ 6 Ad'ˣh߫qJ'~ 8$~ɣ - 3-#>h)a|:2 }cNJF^H\>49#@S10:[hҸ*4#5*ͬ]_Y5Ch5p}N0lRC1Dx@IufjC@!A6%À¸Bu͂O Kw1d XRe4Ұ- u.D2ᙃГS͜Z&dx9ǂŚ1=V @XY<t+H}?=N֓#w`}tV#nh5؇I\ &@p BdLއ_PT/>IN` Fe 6Qy6q br#ϐA;X @F\  dPR|ʱ5C{;g2Ɗ RP 04܂`oh[ ȩ!B' 5 @MS,!K,|F,@> ,2ev8 SpgK.NQxvTX 4T 6=ףI}GLB ͱ(?z%':aJk{ ,Kw4K2h! zq#ڕ@}Iq^`8BUs]^vbC& ٌEZLs<]c4b2Y慴qvC\R1%Pxz2I#@L $eUq:6["BvQFv p~@``dm狹~:`N'@v}O (s@n6S2ô'@[B},D@Y d2jiw\ϜP8}-Y轠5zJo RN, r蹇bp!%GU6~KهO"qB'@鳐$.@##5Yv$[CnDZh@t)MʕQ sߨwbuoK5 9S}1QavR*Ldf]d䩢HLwd <0 PVX.uZ#@RHκdFs²RwY9 D7+|bHzCCv^RYB`R ]ZC>,NBfrc b( HU|A,# ɔbb0^$~+,ݗrB4-Q9KLI.AĚӞ[gL:!@ųjM KBT_?!IJexֹe%KA7-V@~Y<3::#@0Jt8ߵ#Ag-ޔ>WN$O5`=޳ 9is;ST߄$/i(N xQ"b S; wG&C7s3vg%40J Cעqɾ!a^}Y= RdfRO zrn4zJv2TNf:\&@(,E'm\b0$*a@-< ̪ {i-1XGd|?k0(Bn%uC A."L1#Np*f=ӴBL`vs, YdRߺ\}ښitA:,n`WRɉnwg.3mY  YaEW'`a&B=sJKu 9R) N }s4l^@Mfbhd ] fSN3^d1hyLWڌ)ȊD ""d0$ym8CGB !JבKdILS]wJX.{\mpTGaM5<{e5pϸQcLչٓfEiJ:.FԦ轀< ^_ \83,ډ&$h3 Lͧ20?P\P'n1Hdh<; X2 !:ݑ4@&f<pY{YNo#|K=qfk90XT! S/SD@e27* L$GY C+L`A!S {ei2;Y?!^2P$d9qL78NMNkk'띭fbIZt Ocҹ`\* lȦ}o*ۭejP2杤]Nj̨n@[hr\! 税g}BGҺ}rC%d v!7G~q!)Uڋ@i%lM705#OĴB 퉶kgZECH 2ejA@J(]GN:k.Kp|Rf q|\zgbH!@͌K&@>JC ]Ӹ0cVB{OߠJIc@߿?+̃\9jKbCd<9@ @K 壝먾-“CBu -<Do kYY>sm @-O Glt߭99ylӹ>O r \m5B6@y!`2tI ("0""Lwp.HK fr6JP:q\瞦Pe;q#o:ݺt|J%aJ=@7H=^d1XhX@ @>,ژG M2û*FA D̲I+shb0;IX@E(֢)yڡم ғp}uw vݿ2EC,1)pzpT'@V79}#6_b)fOۮ56`+Xy&_'B\d/F.J LC3*MD@`ic@gPZ#XI2oUʖ)tBisȘ4?8KNY =# Wˆ@ȴZ0Bh~@1PB<0UG̘D3|gHB@S= LeZФ Rh?Xgy\ RP 2 yNJw@-Ai]}ۘlNφWI#@ q "EM8V

    U<#N@C33y2h:o6H} @2HLlPs/W:UnWU]Y}٥/Ԝ"&W C1cQ\"x3"$"e;Y 4I&|>V1&Mt?CfP L"̻{d)\Ugl9SWB(Gg>Dx4 *VFTy@kŨa,EiGH@ D4H=# #x3@I4xrInJ&;v^:Epv,rǤ uMbrr-n-[ÒqڜmtY `9.UZUP!U^eURe*C*n &X T8fg^`^Ab 6|E 1%n3:X F3 {Ou٧`au wLT <%ՅWxKg(-}1 l KB.@o\UnZU[U^TپǪ|. [=T,xA'@)ZZ'mByl;~e!ud XUBN ?ۿd@'@0aU]˳*eDGH'dEbJl4r*7e-UXU>TUvB.-x2Y7A$@NoD.؊8!q`47pzH:bx|lb Bgv[uxP=l DLSc!>bjK=E7g%gsKp*׮r**Ϝ-7UyϜhD\Uv*VNX'N2F dB` H4&Gz_r")ZN%Q7 It)&5SI%nM7O3/Q\No AFz܌r[\\w"^6s"{|xJ2]G"* DH%1Xc23tABfg?"5"D~?LXͦO:㻧ȣp>w=<;$'×}rS21iHeO4{ZȔ,:*9S"7p*-+͉pRP|*/;>Uܭ|*uҬqX}P2K GExҸ`,3aQD)a[.xJ.RdH9XLeӆ锰LCV@.OBπ{I%c臕ۻV%k\5%†yV U^1!!BUP_0\HǔiaL$l5VBA O\?m9  ~xw>L䲲t>(270N2`lz)TJs\{h .<}9F2Ыa9.4[-ܠܿ<+uֺ!PfM62m:2 f![ Sǵ<9@gw@3@v-KyY=lQ$᫏zkv&0ϣ@qe,j>%ÝZGTG[̖7rž "D;] gZ} \A=MD(Y`Ptz]9ՖcGT=Ym߷ڽ\ xϒr1oTVಳx ջovj"\ʍIDATgKDP+;fڞ,ҝ@<;U3 Ci.ogP'pDƭkxfPuw!DY?q]gL_:*-/-uǹ\iU\i!DLl)(bU뼢OْBg@|`gFC3f6!.BFJ>w@X2aENN5{`V2i>gĤK::ߪzY\ 85[ ix׽v'?I9Jt/k\4t .Z*u*͖+7g͖,J_b-~RN],2lٜY'#[$̚9O]U@[r-?:}HG"u|Mk.22;I8VU3;%i %7+S+?l)#k?h ZT8h>["Ӫd$!(B;fПS!B&FdL]&M&}w4{tr"ʜU >_ϨSwgL*ْ{jliEd,FPM씀Fsn0u~_ˍ3d 0 <} yc]Kȿ=JPz-$S>I/lGW"= mvʀm%e@\\#h·\ϩ~ 즀yr4 3! 3f;"ruQfN1sZ|[] ( qPj˳%S)xf$UO^%o5[\*>l,5+p#|[ +C/rD(7W׏~{֢˜S`i6;"_Y/Еz^o9dl7-.R7=|x'zWz A x2A# AWtkq\@u'O,RV'ݾEf^ם_3[ 8rՀ˄\z{w)?kMD0R"bRkg~&lrli!`7ާ\~[l5,egd3%)n.J["f0f9|;ڸ J5E2z>=Vv-8w"^{fK˵\ິ73wf4;k!͖2bAc+ɲpA%p=Շϖr~/q%X(r-T~^ "luZis!i8+sْő=a!hѵ+D` u΂@ib ;aFA)ϖ|_Z\>"pquɶΣ ('j$>z4X>[R]LZux{edr<"<'<-x<{{{h4P(Ës' =S;ُGGGX^^666I,N/Md2%ߗiىuuuann" &# <)z/ST8 :XVbhhHr`XPVVTWW'&2)8t:j  F#׌V!1Igggi>RwGGfffPQQɄn477`CC4Mbuu5-(bbbB㒵DMM ZZZV~?-ck₉R l6gfN$i3w'Aܓv455 mmmrkZ8A.D dn[n87M O>'%uaa7  ittv]Hl]׃␛8nnu&//BTBREEErrr{g "!A??}³~%RaIENDB`SuperCollider-Source/icons/sc_cube_32x32.png000644 000765 000024 00000004055 12321461511 021742 0ustar00crucialstaff000000 000000 PNG  IHDR szzIDATXlO{ǫEmbQk{޳{֬kZZ#Ĩ-V$JQ3hBx=|_ODz|=wIl2{~۷oG}!VjTI#Gݱc߱cǺ_z5$&&ӧOT@ѣuVy~OH_N8~&Llٲ]vm?qDkKъ̙3`dŊ,Çܹsry|\xQ<(V2`ݻw?{GCRHgϞI\\DDDHppUi&Qpr%.{ !r;we<)7oވIK Q֭[ƂJa֮]klDFFP*{Ik۷o7>;wѣG[0=TI޽(.R5`FgϞR^=0xm۶v1AR Fd\Pk֬)f8*pޢE [,1e%9mdA)tb:TBH5j=/aC֬!!1+PT[W?lB;tAc2x!k)TTFz}&(+UdVtIR9aOQM>>>a1 $ _>.`j>h8fN/O;3f__dΜw.o4)*}0n 9I ,N[B;}Մ iҤy6mڻo=ɫL#HAD CbZXWs1Y1SF%?7 hҘ/L.]'}Fk?k;q(Z#J߯jTF}~&WjB 䈂xtd4B~t~|"g:/KhtҘGFΔNI&_Nd0 $jIENDB`SuperCollider-Source/icons/sc_cube_48x48.png000644 000765 000024 00000007460 12321461511 021763 0ustar00crucialstaff000000 000000 PNG  IHDR00WIDAThwTU **(*fńssVL&Q1'1+b1̡D̀bDqt!:ٿͻ)V/{z?ګ^U{p.44kRJ &:My //>|w~/ʤIJ8_}SOk\ve%+2uT@މup￿wnѯ_8駟:jԨ鯾; : 0\z饥gϞ/'|r9ʱ[?? #cnasO:<Xs> /|W~]w6dȐ/LxgJK8r駗 .\塇*O뮻y uyW}:/Cs1%pM789nܸ2~|뭷ҡ[n=嬳J{xh)W^ykg-w}w3BrJJ>yd7|9!l@`uwY;ҧO'IߦDuW&{vZ2Ir~%dWnݺ> p?x *'xb9R~Q;&|RwbU)n(rUW%s}Y24bĈy!MsDDGޔo1z%rw%O ?a3l 믿M2%+*}:\tE{^Q4A.{G2iEp_q)!$֛oY>< 裏NMO#v>Ú@q}qu ><0!/Vo9#q,*I~92#A"u9nݺrᇗSO=K4ƱQw f_ 9ңG1Ge`^IUShxE-OnJ)̕d׮]3̗\rI&{oB!8Š{i"K&#&J MCq:He],"]vewOYN$ƅ,tPիW&.vuboDv[:"瞿%+9tIe]v)+Bd  ॗ^*JYuU_|K.7$4hQn9ҥK~'@P8yBā:w\6d$sy->{i޼y۸@tٚu]e 6([lEY3t1dI c{Gw}ˑGRikQ_~s.7_gyʬΚy^ *EMrI\j!Rktx7E:묓6ht~-+0raD$i`wuײV[%Q+rF|/[.s5W L$l'2*v ]V˄; Ć+RnfyVoNR8n psϝN̒K.J@^ ,@B)fOgU%vmRKjժlτD((ob-Vڴicz ӻw=ZhQ<@>֔.RX4"ͅv?WU5Ye"!ƑM74>:Jka,c 1O)3 S Q(F% lIB쓄ڮ_dt9gU"83s2ˤ$^{KdBRTroK/:uꄔzQ-jbƱ)Ӝ*Le 0/-Bn =9ycju c{[zhA 鲘c͊YX0a3XsD[o,i݇ߓ Rh# _~Hj,] N;q}_`=.Ӧ@2Aq,ѣB޾}."GC3!pT5fm22"(Y`'ZrB5ZWU%Hl,dozCr*wT,-_WvUZk"2{v!Der@pʨk>zqsME1"sZSB5I&`_eJffƨwU 5NH LPg};55߅rw:%'݁PUe}'֒rG9iFg~```q ֏b0a:/PXRGN(cbX E~ mqKTM׾WEAkf5F8&[2,O_MfѠj$-GHß ݶm۔p@oѕJ6 * DEtsd) 8b^@Fnf3qgפIdT5HBfz=:Zu.9ȏTg/a T /{xV.M+ jN &rd@00 H*$WNX7U<9GۜXpxl1"*72ذM4^Z)kcсdJ1wjbSQ o\Z˭x]6,=vYaGJ~=[>S5Ԙ` ݒYĜUpS8u>:?>Ұog=lf kRal #&p?qx)>?{5:|I)a~ôh/0-M#ʫI#:u ;3p`}l/o.Ⱎa]Ireӑ{5'l}j[0-onV iV]?lȼak_vak-0arIH hzwuIENDB`SuperCollider-Source/icons/sc_ide.icns000644 000765 000024 00000354455 12321461511 021110 0ustar00crucialstaff000000 000000 icns-is32   "3Y_cR/" /UɺU!/}A[ؑR2AQs2#Qejݭו8]eutUh܆1'_uXOl*/oZN{O'@gFH]bD4:eʓT@849;c •zeUc~́ ߿؃   "3Y_cR/" /UɺU!/}A[ؑR2AQs2#Qejݭו8]eutUh܆1'_uXOl*/oZN{O'@gFH]bD4:eʓT@849;c •zeUc~́ ߿؃   "3Y_cR/" /UɺU!/}A[ؑR2AQs2#Qejݭו8]eutUh܆1'_uXOl*/oZN{O'@gFH]bD4:eʓT@849;c •zeUc~́ ߿؃s8mk0@@000@@@@000@@0il32    #DVXPH@80&$!!'Tune^ch_J6-& !!$-**=x{h@$%**-43GǼ{Z%,34=. __bihvѳit쾚|:/$^hiqqĎlZqsˍ7,)"\qqzz컷qrQZfp΀|3(+(dzz}讪ccMZxsn0%/-l奝eUSZwɳf_,!73t᪐oGQZtΚzYJ)!A9~FCMcPL6&/GKϊqi@?IT^issKC=-"FMp̼u`\JCGOTO>:84)4[RνiOKFB>:514:04d`¯X>5108DB8=gnx龠uj_UJ?P|zɅѮ|qg\WjІŲوŽ   #DVXPH@80&$!!'Tune^ch_J6-& !!$-**=x{h@$%**-43GǼ{Z%,34=. __bihvѳit쾚|:/$^hiqqĎlZqsˍ7,)"\qqzz컷qrQZfp΀|3(+(dzz}讪ccMZxsn0%/-l奝eUSZwɳf_,!73t᪐oGQZtΚzYJ)!A9~FCMcPL6&/GKϊqi@?IT^issKC=-"FMp̼u`\JCGOTO>:84)4[RνiOKFB>:514:04d`¯X>5108DB8=gnx龠uj_UJ?P|zɅѮ|qg\WjІŲوŽ   #DVXPH@80&$!!'Tune^ch_J6-& !!$-**=x{h@$%**-43GǼ{Z%,34=. __bihvѳit쾚|:/$^hiqqĎlZqsˍ7,)"\qqzz컷qrQZfp΀|3(+(dzz}讪ccMZxsn0%/-l奝eUSZwɳf_,!73t᪐oGQZtΚzYJ)!A9~FCMcPL6&/GKϊqi@?IT^issKC=-"FMp̼u`\JCGOTO>:84)4[RνiOKFB>:514:04d`¯X>5108DB8=gnx龠uj_UJ?P|zɅѮ|qg\WjІŲوŽl8mk PP ߀ 00  PPPP  00 ߀ PP it32fT   +1?=FGECA?=;95-)"(8HVTRPNMKHFDB@><;97420.,%!/F\^\ZXVTQONLJHFDB?=<:86420.+*(%&%B]eca`^[YWUSQONLIGECA?=<:7531/-+)(&#!+'Pmkifdba_][YWURPNMKIGEC@><;97531.,*)'%#! /*Trpnljhfdb`^\ZXVTRPNMJHFDB@><;86420.,*)&$"  "!3'Swusrpnljgeca`^\ZXUSQONLJHFDA?=<:8642/-+)(&$"  !"$#5Fw{ywusqomkigeca_][YWUSQOMKIGECA?=;97531/-+)'%#!#$&9+k|zxvtsqomjhfdba_][Y]nl}}zq][F><;97530.,*)'%#!#&)(;E~|zxvtrpnljhfdopW>6420.,*(&$" !()+*=Z}{ywusrpnkva>1/-+)(&$!*+-,A2p}{ywtsx¿vO4-*)'%#!*,-/C5~|zx|{U1*)'%" -/1E7~|uQ.(&$" .13G9¿~{yvj?(&#!0365I<}zxurpX+%#!3567K>|zwtqole6$" 47:K¿ȵ~{yvspnkhf@$" :O`ɣ|zwtqoligda^K&!/>A@QNգ{yvspnkhfc`^[N% =@ABQʑurpmjgeb_]ZWE!BESuثxoligda^\YVT@!0EGUNƁkhfc`^[XUSP5 CGIUΏheb_]ZWUROL, (IKWYʞda_\YVTQNLG$CKNWƠ`^[XVSPMKH:!'NPY]]ZWUROMJGD, GPSRYYVTQNLIFC># )RST[bjVSPMKHEC@0!KTV[̿[ROMJGDB?;$!4VY[¿εѻQNLIFCA>;." Y[]~ȬҷgMKHEC@=:7%!D[]]ȦʲMJGDB?<:7+#!/]_]ˣmIFCA>;961%" _ba_vФ방HEC@=:852'$" Nabd_ѮxzզbDB?<:741+%#!=df_ƐtmtzDA?;9631-'%#!*fh_̚dfmtzߟHA>;8620-)&$" hja]`fmtz񦚙`@=:852/-)(&$" [jmlaǚ`Y`fmtzΗv?<9741/,*)'%#!MlmoaÀpRY`fmtz攓>;8630.+)*)'%# Eoqay{~PRY`fmtz觐J:852/-*',*(&$" 1qsauwz}hLRY`fmtzvgck庌R9741/,)&,+)(&$!3suaqtvy|~MLRY`fmtz}YT]fpy͉]8630.+(&,-*)'%#!$uxaξpnpsux{}xELRY`fmtzYXajs|ۅ~d852/-*'%-.,*)'%" xzaǼhjmoruwzjELRY`fmtl[dmv݂~}|{j741/,)&$*0-+)(&$"z|aĸdgilnqtv\ELRY`fmthhqzً~}|{zyxg630.+(&#*1/-+)(%#|~a`cehkmps[ELRY`fmtmt}Փ{zyxwutd52/-*'%"*31.,*)'%~a俲]_begjloYELRY`fmtwҏxwutsrqb41/,)&$!*420.,*(&a㼮Y\^adfikWELRY`fmtܼ΁tsrqpon_30.+(&# +641/-+)(a⹫VX[]`ceh]ELRY`fmt̹rqponmlk\20-*'%"-7531/-+)aὨWUWZ]_bdbELRY`fmtzonmlkihhS1/,)'$!397520.,*a¥bQTVY[^acILRY`fmtzﯱljihgfedK0.+(&# 4:86420.2aˡsMPSUXZ]`TLRY`fmtz̶Ыhgfedcba@0-*'%";<:8531/EaўJMORTWY\]MRY`fmtz쪨edcba`_]9/,)'$!>=;97531Ma۟KILNQSVY[URY`fmtzȡcba`^]\[X0.+(&# %@><;9642`aڬ_EHJMPRUXZTY`fmtzۛ`^]\[ZYXK0-*'%",B?=<:864naپBDGILOQTWXY`fmtzߠg\[ZYXWVU>/,)'$!8CA?=<:75_ҐPACFIKNPSUX_fmtzٞZYXWVUTSR2.+(&# DEB@><;97_գv=@BEHJMORUXdmtzǓaWVUTRQQPE0-*'%"#HFDB@><:QTջXACFHKMPSUZj|~|WQPPNMLKJF0.+(&# GKIGECA?=]б~}|zyyk<:=?BEGJMORTWYam{wqtvy{~]ONMLKJIHF90-*'%"$NMKIFDB@D]̌}|zyyxvut`79<>ADFIKNQSVY[^`cehkmpruxz}bMLKJIHFEEA1/,)'$!=ONLJHFDBe]˵yxwvutsrqpY68;=@CEHJMPRUXZ]_begjloqtwy|cKJIHFEDDBA60.+(&# PQONLJGEC[ȔutsrqpnmmlY87:=?BDGILOQTVY\^adfiknqsvx{}}\IGFEDCBA@?:20-*'%"9USPNMKIGQ[ǿ|qpnmmljihg]=69<>ACFIKNPSUX[]`cehjmpruwqQFEDCBA@?>=;51/,)'$! TVTRPNMKHw[ñmlljihgfedc_G58;=@BEHJMORUWZ\_adgiloq`HDCBA@?>=<;:730.+(&# 79=;;:978520-*'%"%Y[YWUSQOMpY¿edcba`^]\[ZYXSB;;>ACFHKMPSUXZ]^WGBA@?>=;::97657741/,)'$!L_][YWTRPNWa`^]\[ZYXWVUTSRIEA@BEGJMOQQNIBA@?><;:997654369631.+(&# 4b`^\ZXVTRtW\[ZYXWVUTSRQPOMLKJIGFFEDCBA@?><;:9876543216:8520-*(%"$aca`^\ZWUSU¿XWVUTRQQPNMLKJIHGFEDCBA@?><;:9876543210/9<:741/,)'$!Vgeca_][YWyU^RQQPNMLKJIHGFEDCA@@?=<;:9876543210/.0=>;9631.+(&#Kjhfdba_][^SuNMLKJIHGFEDCA@@?=<;:987654320//.,+5A@=:8520-*(%@nljhfcb`^\Q¿ZIHFFEDBA@?>=<;:987654320//.,+*/@EB?<:741/,)'=rpmkigeca`uQȾ{ODBA@?>=<;:987554310/.-,+*)-?JGDA?<9631.+(5osqomkigdbgOʺzY>=<;:987544310/.-,+*)(5DNKIFCA>;8630-*Bsvtsqnljhfd†M˷mR=6543310/.-,+*)+7ERSPMKHEB@=:852/-I|ywusrpnljhšKҳthWLA@?=<:@GPT]ZWTROLJGDA?<9741/\}{ywusqomkŜKٳ|zwtqolifda^\YVTQNKIFCA>;8636o}zxvtsqo~ǝI⽩~{yvspnkhfc`][XUSPMKHEB@=:85M~|zxvtrĈɞˇGѭ}zxurpmjgeb_]ZWTROLJGDA?<9Br}{ywuƇˠ͇E£|zwtqoligda^\YVTQNKIFCA>@f}{yȇ͢Cݽ~{yvspnkhfc`^[XUSPMKHEBEk~|ˈУшA }zxurpmjgeb_]ZWUROLJGU{͈ѤԈ=в|zwtqoligda^\YVTQN]wԦֈ;к{yvspnkhfc`^[Xl{֨؉9ǵԉتڊ5ڬ܊3؊ܮߊ/׊߰+ً'܍!ӎڐ   +1?=FGECA?=;95-)"(8HVTRPNMKHFDB@><;97420.,%!/F\^\ZXVTQONLJHFDB?=<:86420.+*(%&%B]eca`^[YWUSQONLIGECA?=<:7531/-+)(&#!+'Pmkifdba_][YWURPNMKIGEC@><;97531.,*)'%#! /*Trpnljhfdb`^\ZXVTRPNMJHFDB@><;86420.,*)&$"  "!3'Swusrpnljgeca`^\ZXUSQONLJHFDA?=<:8642/-+)(&$"  !"$#5Fw{ywusqomkigeca_][YWUSQOMKIGECA?=;97531/-+)'%#!#$&9+k|zxvtsqomjhfdba_][Y]nl}}zq][F><;97530.,*)'%#!#&)(;E~|zxvtrpnljhfdopW>6420.,*(&$" !()+*=Z}{ywusrpnkva>1/-+)(&$!*+-,A2p}{ywtsx¿vO4-*)'%#!*,-/C5~|zx|{U1*)'%" -/1E7~|uQ.(&$" .13G9¿~{yvj?(&#!0365I<}zxurpX+%#!3567K>|zwtqole6$" 47:K¿ȵ~{yvspnkhf@$" :O`ɣ|zwtqoligda^K&!/>A@QNգ{yvspnkhfc`^[N% =@ABQʑurpmjgeb_]ZWE!BESuثxoligda^\YVT@!0EGUNƁkhfc`^[XUSP5 CGIUΏheb_]ZWUROL, (IKWYʞda_\YVTQNLG$CKNWƠ`^[XVSPMKH:!'NPY]]ZWUROMJGD, GPSRYYVTQNLIFC># )RST[bjVSPMKHEC@0!KTV[̿[ROMJGDB?;$!4VY[¿εѻQNLIFCA>;." Y[]~ȬҷgMKHEC@=:7%!D[]]ȦʲMJGDB?<:7+#!/]_]ˣmIFCA>;961%" _ba_vФ방HEC@=:852'$" Nabd_ѮxzզbDB?<:741+%#!=df_ƐtmtzDA?;9631-'%#!*fh_̚dfmtzߟHA>;8620-)&$" hja]`fmtz񦚙`@=:852/-)(&$" [jmlaǚ`Y`fmtzΗv?<9741/,*)'%#!MlmoaÀpRY`fmtz攓>;8630.+)*)'%# Eoqay{~PRY`fmtz觐J:852/-*',*(&$" 1qsauwz}hLRY`fmtzvgck庌R9741/,)&,+)(&$!3suaqtvy|~MLRY`fmtz}YT]fpy͉]8630.+(&,-*)'%#!$uxaξpnpsux{}xELRY`fmtzYXajs|ۅ~d852/-*'%-.,*)'%" xzaǼhjmoruwzjELRY`fmtl[dmv݂~}|{j741/,)&$*0-+)(&$"z|aĸdgilnqtv\ELRY`fmthhqzً~}|{zyxg630.+(&#*1/-+)(%#|~a`cehkmps[ELRY`fmtmt}Փ{zyxwutd52/-*'%"*31.,*)'%~a俲]_begjloYELRY`fmtwҏxwutsrqb41/,)&$!*420.,*(&a㼮Y\^adfikWELRY`fmtܼ΁tsrqpon_30.+(&# +641/-+)(a⹫VX[]`ceh]ELRY`fmt̹rqponmlk\20-*'%"-7531/-+)aὨWUWZ]_bdbELRY`fmtzonmlkihhS1/,)'$!397520.,*a¥bQTVY[^acILRY`fmtzﯱljihgfedK0.+(&# 4:86420.2aˡsMPSUXZ]`TLRY`fmtz̶Ыhgfedcba@0-*'%";<:8531/EaўJMORTWY\]MRY`fmtz쪨edcba`_]9/,)'$!>=;97531Ma۟KILNQSVY[URY`fmtzȡcba`^]\[X0.+(&# %@><;9642`aڬ_EHJMPRUXZTY`fmtzۛ`^]\[ZYXK0-*'%",B?=<:864naپBDGILOQTWXY`fmtzߠg\[ZYXWVU>/,)'$!8CA?=<:75_ҐPACFIKNPSUX_fmtzٞZYXWVUTSR2.+(&# DEB@><;97_գv=@BEHJMORUXdmtzǓaWVUTRQQPE0-*'%"#HFDB@><:QTջXACFHKMPSUZj|~|WQPPNMLKJF0.+(&# GKIGECA?=]б~}|zyyk<:=?BEGJMORTWYam{wqtvy{~]ONMLKJIHF90-*'%"$NMKIFDB@D]̌}|zyyxvut`79<>ADFIKNQSVY[^`cehkmpruxz}bMLKJIHFEEA1/,)'$!=ONLJHFDBe]˵yxwvutsrqpY68;=@CEHJMPRUXZ]_begjloqtwy|cKJIHFEDDBA60.+(&# PQONLJGEC[ȔutsrqpnmmlY87:=?BDGILOQTVY\^adfiknqsvx{}}\IGFEDCBA@?:20-*'%"9USPNMKIGQ[ǿ|qpnmmljihg]=69<>ACFIKNPSUX[]`cehjmpruwqQFEDCBA@?>=;51/,)'$! TVTRPNMKHw[ñmlljihgfedc_G58;=@BEHJMORUWZ\_adgiloq`HDCBA@?>=<;:730.+(&# 79=;;:978520-*'%"%Y[YWUSQOMpY¿edcba`^]\[ZYXSB;;>ACFHKMPSUXZ]^WGBA@?>=;::97657741/,)'$!L_][YWTRPNWa`^]\[ZYXWVUTSRIEA@BEGJMOQQNIBA@?><;:997654369631.+(&# 4b`^\ZXVTRtW\[ZYXWVUTSRQPOMLKJIGFFEDCBA@?><;:9876543216:8520-*(%"$aca`^\ZWUSU¿XWVUTRQQPNMLKJIHGFEDCBA@?><;:9876543210/9<:741/,)'$!Vgeca_][YWyU^RQQPNMLKJIHGFEDCA@@?=<;:9876543210/.0=>;9631.+(&#Kjhfdba_][^SuNMLKJIHGFEDCA@@?=<;:987654320//.,+5A@=:8520-*(%@nljhfcb`^\Q¿ZIHFFEDBA@?>=<;:987654320//.,+*/@EB?<:741/,)'=rpmkigeca`uQȾ{ODBA@?>=<;:987554310/.-,+*)-?JGDA?<9631.+(5osqomkigdbgOʺzY>=<;:987544310/.-,+*)(5DNKIFCA>;8630-*Bsvtsqnljhfd†M˷mR=6543310/.-,+*)+7ERSPMKHEB@=:852/-I|ywusrpnljhšKҳthWLA@?=<:@GPT]ZWTROLJGDA?<9741/\}{ywusqomkŜKٳ|zwtqolifda^\YVTQNKIFCA>;8636o}zxvtsqo~ǝI⽩~{yvspnkhfc`][XUSPMKHEB@=:85M~|zxvtrĈɞˇGѭ}zxurpmjgeb_]ZWTROLJGDA?<9Br}{ywuƇˠ͇E£|zwtqoligda^\YVTQNKIFCA>@f}{yȇ͢Cݽ~{yvspnkhfc`^[XUSPMKHEBEk~|ˈУшA }zxurpmjgeb_]ZWUROLJGU{͈ѤԈ=в|zwtqoligda^\YVTQN]wԦֈ;к{yvspnkhfc`^[Xl{֨؉9ǵԉتڊ5ڬ܊3؊ܮߊ/׊߰+ً'܍!ӎڐ   +1?=FGECA?=;95-)"(8HVTRPNMKHFDB@><;97420.,%!/F\^\ZXVTQONLJHFDB?=<:86420.+*(%&%B]eca`^[YWUSQONLIGECA?=<:7531/-+)(&#!+'Pmkifdba_][YWURPNMKIGEC@><;97531.,*)'%#! /*Trpnljhfdb`^\ZXVTRPNMJHFDB@><;86420.,*)&$"  "!3'Swusrpnljgeca`^\ZXUSQONLJHFDA?=<:8642/-+)(&$"  !"$#5Fw{ywusqomkigeca_][YWUSQOMKIGECA?=;97531/-+)'%#!#$&9+k|zxvtsqomjhfdba_][Y]nl}}zq][F><;97530.,*)'%#!#&)(;E~|zxvtrpnljhfdopW>6420.,*(&$" !()+*=Z}{ywusrpnkva>1/-+)(&$!*+-,A2p}{ywtsx¿vO4-*)'%#!*,-/C5~|zx|{U1*)'%" -/1E7~|uQ.(&$" .13G9¿~{yvj?(&#!0365I<}zxurpX+%#!3567K>|zwtqole6$" 47:K¿ȵ~{yvspnkhf@$" :O`ɣ|zwtqoligda^K&!/>A@QNգ{yvspnkhfc`^[N% =@ABQʑurpmjgeb_]ZWE!BESuثxoligda^\YVT@!0EGUNƁkhfc`^[XUSP5 CGIUΏheb_]ZWUROL, (IKWYʞda_\YVTQNLG$CKNWƠ`^[XVSPMKH:!'NPY]]ZWUROMJGD, GPSRYYVTQNLIFC># )RST[bjVSPMKHEC@0!KTV[̿[ROMJGDB?;$!4VY[¿εѻQNLIFCA>;." Y[]~ȬҷgMKHEC@=:7%!D[]]ȦʲMJGDB?<:7+#!/]_]ˣmIFCA>;961%" _ba_vФ방HEC@=:852'$" Nabd_ѮxzզbDB?<:741+%#!=df_ƐtmtzDA?;9631-'%#!*fh_̚dfmtzߟHA>;8620-)&$" hja]`fmtz񦚙`@=:852/-)(&$" [jmlaǚ`Y`fmtzΗv?<9741/,*)'%#!MlmoaÀpRY`fmtz攓>;8630.+)*)'%# Eoqay{~PRY`fmtz觐J:852/-*',*(&$" 1qsauwz}hLRY`fmtzvgck庌R9741/,)&,+)(&$!3suaqtvy|~MLRY`fmtz}YT]fpy͉]8630.+(&,-*)'%#!$uxaξpnpsux{}xELRY`fmtzYXajs|ۅ~d852/-*'%-.,*)'%" xzaǼhjmoruwzjELRY`fmtl[dmv݂~}|{j741/,)&$*0-+)(&$"z|aĸdgilnqtv\ELRY`fmthhqzً~}|{zyxg630.+(&#*1/-+)(%#|~a`cehkmps[ELRY`fmtmt}Փ{zyxwutd52/-*'%"*31.,*)'%~a俲]_begjloYELRY`fmtwҏxwutsrqb41/,)&$!*420.,*(&a㼮Y\^adfikWELRY`fmtܼ΁tsrqpon_30.+(&# +641/-+)(a⹫VX[]`ceh]ELRY`fmt̹rqponmlk\20-*'%"-7531/-+)aὨWUWZ]_bdbELRY`fmtzonmlkihhS1/,)'$!397520.,*a¥bQTVY[^acILRY`fmtzﯱljihgfedK0.+(&# 4:86420.2aˡsMPSUXZ]`TLRY`fmtz̶Ыhgfedcba@0-*'%";<:8531/EaўJMORTWY\]MRY`fmtz쪨edcba`_]9/,)'$!>=;97531Ma۟KILNQSVY[URY`fmtzȡcba`^]\[X0.+(&# %@><;9642`aڬ_EHJMPRUXZTY`fmtzۛ`^]\[ZYXK0-*'%",B?=<:864naپBDGILOQTWXY`fmtzߠg\[ZYXWVU>/,)'$!8CA?=<:75_ҐPACFIKNPSUX_fmtzٞZYXWVUTSR2.+(&# DEB@><;97_գv=@BEHJMORUXdmtzǓaWVUTRQQPE0-*'%"#HFDB@><:QTջXACFHKMPSUZj|~|WQPPNMLKJF0.+(&# GKIGECA?=]б~}|zyyk<:=?BEGJMORTWYam{wqtvy{~]ONMLKJIHF90-*'%"$NMKIFDB@D]̌}|zyyxvut`79<>ADFIKNQSVY[^`cehkmpruxz}bMLKJIHFEEA1/,)'$!=ONLJHFDBe]˵yxwvutsrqpY68;=@CEHJMPRUXZ]_begjloqtwy|cKJIHFEDDBA60.+(&# PQONLJGEC[ȔutsrqpnmmlY87:=?BDGILOQTVY\^adfiknqsvx{}}\IGFEDCBA@?:20-*'%"9USPNMKIGQ[ǿ|qpnmmljihg]=69<>ACFIKNPSUX[]`cehjmpruwqQFEDCBA@?>=;51/,)'$! TVTRPNMKHw[ñmlljihgfedc_G58;=@BEHJMORUWZ\_adgiloq`HDCBA@?>=<;:730.+(&# 79=;;:978520-*'%"%Y[YWUSQOMpY¿edcba`^]\[ZYXSB;;>ACFHKMPSUXZ]^WGBA@?>=;::97657741/,)'$!L_][YWTRPNWa`^]\[ZYXWVUTSRIEA@BEGJMOQQNIBA@?><;:997654369631.+(&# 4b`^\ZXVTRtW\[ZYXWVUTSRQPOMLKJIGFFEDCBA@?><;:9876543216:8520-*(%"$aca`^\ZWUSU¿XWVUTRQQPNMLKJIHGFEDCBA@?><;:9876543210/9<:741/,)'$!Vgeca_][YWyU^RQQPNMLKJIHGFEDCA@@?=<;:9876543210/.0=>;9631.+(&#Kjhfdba_][^SuNMLKJIHGFEDCA@@?=<;:987654320//.,+5A@=:8520-*(%@nljhfcb`^\Q¿ZIHFFEDBA@?>=<;:987654320//.,+*/@EB?<:741/,)'=rpmkigeca`uQȾ{ODBA@?>=<;:987554310/.-,+*)-?JGDA?<9631.+(5osqomkigdbgOʺzY>=<;:987544310/.-,+*)(5DNKIFCA>;8630-*Bsvtsqnljhfd†M˷mR=6543310/.-,+*)+7ERSPMKHEB@=:852/-I|ywusrpnljhšKҳthWLA@?=<:@GPT]ZWTROLJGDA?<9741/\}{ywusqomkŜKٳ|zwtqolifda^\YVTQNKIFCA>;8636o}zxvtsqo~ǝI⽩~{yvspnkhfc`][XUSPMKHEB@=:85M~|zxvtrĈɞˇGѭ}zxurpmjgeb_]ZWTROLJGDA?<9Br}{ywuƇˠ͇E£|zwtqoligda^\YVTQNKIFCA>@f}{yȇ͢Cݽ~{yvspnkhfc`^[XUSPMKHEBEk~|ˈУшA }zxurpmjgeb_]ZWUROLJGU{͈ѤԈ=в|zwtqoligda^\YVTQN]wԦֈ;к{yvspnkhfc`^[Xl{֨؉9ǵԉتڊ5ڬ܊3؊ܮߊ/׊߰+ً'܍!ӎڐt8mk@ @``@ 0``0````0@````@@ pp `P000000000000PP pp @@````@0````00`` @@````@@ ``00````0@````@@ pp PP000000000000PP pp @@````@0````0``0 @``@ ic08U jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XXXPPXdKakadu-v5.2.1 T$|AtmD'=hla?&kjNGs`/A@(GrkAU4lc̆d Wٍ\G U@|Y>mgIq1W,Mm$L>1a4c"+7@e שDw?]Tj 4@[^k_1z"6̆?,[ҍPLHBT4m*Jdt+s%_D,yi07eY]~Vj:B!' ovZ#Ҭ04XI1KkO Ѳs9yw4Y RbU Vs?7$y3mKJZ*3O;Fh C,*s1v\0HNӔ6@՘u v6\d\7mq I(U꩜%8^R/@tL VJ$F,TX20\?e$⟋Y2RL20t!>}G$&dYS=! E_`*VW]SxV9·N+lyvc1ŕ-V]9Mo`2שPAt AU#xdU+cɥliYux/' SWw"%h(TAC(s{On"u m;5idPxh^jk8 1㟎;"OZ`d1每+bᒣ>] _ niE9sO<-xY,MA \|G@[ b BE> a}A_YA%L R^ =ރ,ǹ "T7ä'kbj?` 7 Z`|vd1?;M\3e=-?~j&5N]] % 털P'5ԩSKqAa32f:Mj!SW&,Bڽ2+t!2cޡfr 2hv-`Eo4<wm#Wx%yȜշ#'=~%ڬn<^-o2&vLNjKXjo*0i~p g%E,cIF]pn&ϥ]ۢu/wy"Yq\gwk/'zQYPׄ6+97t=F3'In,8{?dLnʀLfA\E,#w*oH?=blSCd#09$mҘĊ#%]CaˤY)Y½:u(i(fBgM#^y% ʝFPRw^"((F<ܸ>Wv!uj Up Γ/4\PU?CJ+\vZ$!̭4`rÉWla$LWm %Y~ʺbr={q\t!M*1*)wqAֽ6Q5y2ωs`rqVW9C6DfCէUME}cJӓFcǷ=4 驎ޒ1{4u*!;cYU:0G[faP'`gF iBc{kkZ-Blk,q iֿaV?C]L &wgMS}< oDk#SG= ̤x3º̛QwMtR@)vRBn+}Z:(|)O Br/uذPA}5(ĚМ+z]B#j$(p/I g2a7TfÝɤ ū}$c 5w4?.}qh? ZYwg>Nġ'!OY">&B\\Yi{*bИAmfJȴ,$NhWw Ʉ jBRG*9;'^j jcbdY,bXy@x|pGT5#YYˋBG/,~IsR5hr6~;N,} [.fV3XZLng?8mtW*C{y*CbԀrFQ64Ns`$%Bp|]u9 ]*ٝ/eNN} dD9L$m[]b q΂Chyi&־S $PL28!ߴ-`".6S:k2珫c{Um hGKu;" ͐X~M"mWv2Y_(i6e9Fc!~_.sGB5m)KE;J@ ΚJFN=f dWbʾ@7T"WAn:yBƳ=HoP7ֹkMP4S~-!1*sFd GSW!LGzhh"9O~H%l__9ԝV 8Τ=

    R۔-1/sR^G&ޘT"ic'asiY^D Tѓ_S2VD~C>3?(FCo8$ FV`9JAz A p^BC'NO(Աp93E.಑Q2o=j҂Rӊ/$.|ZP3c+155:49T2+%cR"G2%rߗo礄(AY`DI<'C]f7n>c ЫJ-o 223\A}iqLoBU_#G26.]$#u!)slnlV:.)-4%#(a \߫m%:ԕ/iPT S/O,Pg1[͋.憃w *Kc&:_\q~olӣГ룜zW]k{^=uKXs.rgcn[ֳM<~1 :^ݑ89wH"JHwv}}iђs_uf8a}%]lYls FD  V VE'';!u1qtnOan, W :*I^2o $ Ę*rEM ∱KWhUB`g_ 8 qn&2t/~[|ڿp8F }Z%EuRk MXh)VTruʤ)k6SFW,s `Il]|uSۓQE`;H, 짘 zT a?}\yJ%YTU.k|%q"h8=3/f:ꁊ2&9D P$#c 8h)^*yuCA+!EE}WnPfc **+xHo 坿F7ںfQ`fiXO;"E mH \!E"⨜@$~/ 9غ*W2Xlid[* nlv4Zm.f}GW#d>(ۓ5%KHu޴!U_0Ab}3, Ѧyt")55")2|ŜJ)89DvWWZM:eKJkJlg ջ8xyi7ҞcniAgo@IӃ=M;'!CGN"J, tA0mSͬ YRkw}j|Yracp؃輑iڲjD0U{] z, ^>ucsonLWwfO("ss'>#(]&},ȶi%OK:yԃbaJ[ qeҥ@A@O|PW\śpNELfTh{N~7dYɌņRY.w-t>5K$N^JIj+n(󕴥5vk &+cztC7>OHSUq|6Ȗf1=4$m'#k!ܺ x E\j豨%i|d3uᕾ?yAǰ[ iwXT_|n߂1VQnj>[8Y08},exem%MjOjvxXjQ,o>Qr5>ʤIr:KDKp+ !zWEnr+ 99XJS-rǂpj2vSZ{ 6]e 6}8//I%Q tk)5-E&6ިbgIe'z)*i!D2LTضIRU2eդSJت TBFKBzew`C}<0]fyg?[ÒU*ҜB-`2eӰ]䃋-TeRo;"ʸE,Zgd" lCO&.H<9(a$JUpw@<㙳-0tY TvQ9pZJҋ@nJ1. /brVDy.#3|Z7n,' tWNDb 5 sGF~ ?][t%ѹDvU{&*N0 V3ZU!U#=,"UȣV0UJ2,6R $OY,?o}ۨc`UPP oDh<{K!R_y98:n{VTze6M[3 |7E8f#ĝ|?.*R]4b$Pz\t u@EFKl/{" e"y@!-4&u(%@l0%rFJc8c߭7{c6(YSX.?6I<x2yОԟ1o~Ų?KHJۖ\G6͛`8Rh#Q{)mfX¬fF4<<#NCVP%Wփ I`IaUӰ+{b\V;P_W%|v~AGy 7䇻ALz*N/ El{\l&2;w6:mKD܉TT= {lv42 sJ$ԉ,';H`A)OAF8rzDGiD_y3Je萃yW-JHkihck!H.3C6 TH1v/'LkeBanmʪ@ezN6ϳ]X8Yy!&١AÜΗU$O1; :STDw dJ`.HD)^G$fhyS$@bD+ `HXeOmnVZjqva%@noЉc'i݆v [ZBEvT2hoIcQlg}N~*CfMm҈9>O@+3__@F QMz$; RE(x=IAU3'y ] fa3VmE;$4TRmDժ!RD.hCbE a&10A\5l=}\Z#]J+&ԯP!x3R -9 N[jEpLIb6ZhtIp+EBDl8X,L e&l.frٱZ-c|"\B6xCu||Q 떘ƍuTZzQwKL5Z =p p{T'7 V38F >Xu"[b*L@&$ (gp^\&??QeJedjmIQ1>exnl'TՈZi̩ / Pネ"Z=P5&Z_?iGnfQz$_^?C31_FU6Xͅ]98j]A&3W$ 鴠4˨Y[UBԐ]ϭ)OA"Ĥmka HySr?:A ĭPn+S4 J`tm.5QL oRf.qnm-sۨ>eH;ɷT,   bdݤܬV!JØ|W',MHF*,6\~)\eQP& $I FP6z~в}]Oٟwf}]T\ðLBdW ̤Т&%C(v"-KTw[.4}aZ /+XBroF!l️óaB9%鰶M]K۪.z>Erɍdw&+/ߞZ>ψX]Ǿ[:8gVYI,Cݺ5/"_oDѐU[į|,IA@ݓ뛚}ŵA:Y'djr_ K._tf45M :H =i`lޚ 뒠ɜpsmRF6zDwj|0?K"--O '۱a|U Q%_xNz(#!!nF)\^0FC޸ {cTЬh@jWjQC?7h8MSXy|6`^IV7R4 !7*H pGH58X.,4]aymdy -b.*8¥I)<[AC*K xG=q2sŸB/l i ;3ȥ9xk?k:l x D$)KmPŻUl$2 pS`pq!/m-EmY@>fձW(o<3v`4Gs~3\Pz>K=Rc$@qWx H􃶿l GMHI b'`>Xh6` !8KNEEKQ?UnˉTS{ڵ`Pc}ǭ`H[nahH$m6 Z~ XhADc3 NԁQUxߊ4囦T}E]U/k@X?oS+}.xpھ̝@~,4+{[Wf~jiz|)иArW*qv4{DG!Z1s C ז =i߷NUDR|Q`jS+,|ZUs Qf^U5"1xlCX&E 8ȇ ?DAec;"8 ^?",J  28FN+15:W_oi\?KƸFyK]ۡ="~=UcޕUyjAt(T-[X}{A ʚU{â؛;q=eR'bs|p-'ȵ ~LG[Qp/ lqt1"0jH~帕 ǜ% ٩QK?r3y%̑~x*i5/{$^MM#}Q=}F4#1#q/&"Hx1 Qm"Co^Sf ՅNc2– ˠ;ؘVKJC\eJ:IEU҂KSI RTfLtiSeaC%|bdQsQ0Д$iY4r1p%6UAB-9kG(bQzi KBBSۇ%<d>یN)V|z ڀy$GnCӶB#}"Ȓaa =8ۚUSU:f^rLd@LP(J3eG/.n 7sh֓xt0JRNl>#h!~93|DYPXG 6]t3Mh`+ Bӓe93cL1.-ۊ69ODF J2O4 C (rAxoѳ=ArvWv.1GF E~r=ykIL-kuA 54e5D\DztUωmI" `o1zW0s4d+h V6s m3?bAy:WA_' 9=&\y}D663AWdC.AϹf;)Yhwi w1".7Li|vbLA0LED:W[`)"sȆSs `VdJ򽍵HoT~AwE4efI`* Fm 5(pI+wAB<]IZK"a Դ[ \Hw~߂JqOz6 Nf(&I FP\&Q'XJPڽT"dU\}Ml+1LjflpQW #G [%w~.\F&bgRNoJ[h19`mG5S/XwO')M n @ ns5iAEqry{Q fn@E³H 4;%Cf IRʱJ*VYY( F&  ؤJe^No7L Q׎NTKGm=<&7)G]XRGW?Y?_̘`!o_⦩8?wqA9aGr9Ȃn1. S {Dw\^9WD rI-(|Χ4KXO@:G6GpG)7=fNM!BZ;H#nxVs^ObKxݾv#E TEe%OCHL**WcRQ\"ѥv;VsQl]g<R]5Wyt)KM&d~qKt$flytmz]/4Dl[sVun,+NwOUFXc(b'j3K^.ȏg]Ƃ?d+f;>pN>">b5V+-?/Qi̪GZ_75% ?~vlMNoIq(E-C:訂~.5P$ͱ3d262OSn1ʡ_G f7B~ sR ;,{!&/9xQadZ|vfpM+6єWi-Q"$9rRczpg l/wo#ԛ$F&AbJbovqRA%)#=`L HW3G{ ao] 1R DK?Mj/@`[i)30תI-̯ƂL* 0%}+1#dVY!B{n&<(9R wfF;ٵ+3@V)_kӸ bHtߊgȐU3 {}svԶ@nT~x ؓE$ЊZ] jvŇ{m`jpvm;qh89iaspks]Q8&UY9SGa6})Y߽k)6kr֜v>#vb!,W`&u?h0:bDŽdK(!l O5OU`sEe^Ikm6[ۧxɤ.6+hftz; u2N>#/UWSį1~So8 L4 '˶ L m>,As%[ hr&F6wgǮ>PakPJ|c 'C p\|1vazaUP$`F$&~ȝaA \YQ(wx2hHt'1*V;iVr%S$o!RqT0&T1X 2!ުKyQ#dOO)$U';JpL;FFg4vāt T gߛq(OV o1p NQm3) #bU3Equ劔FhaAcx*>E4{=lv5ii1|!elL_cX+;8_R`™}l%WnP -ڟM#L>%XHoaUc\kuPj#By OJXI. }1+|Q6cΖ{ wi *ӣX݇ێ7qg?IIZv*--+̠>)nA}OIl'fGu_8ᥴ%!a#R 6-D5.*!n?R'Z Odߥ.nk`v2(q]`ȴԖ9 $eLl0qhޣ.%k0_Oo Dz۽"M}._$WϺ 405v T0SD6 ~Dz Y[?W7rhCz/mn]w+_3e@V9gdRkY 1XG);!;mɮW*۹?+ cPazql2LG5tֳ/`q魎`D6S=.EuGbԪ@{f`LtS{d׫BZe?Ƴξ1?U2e-Pi)2wrnS!Jm^msM-\蚠 HbIDT,Ha<~g561WH029P~%jnk5o24'fK4+?kI*6ˑk0u! t Yoi>J+ؠs3k; X1a GEz[SIẃ胣ǻ֟[2|?>l&@mRul$vJQA[HOhTpLBz_vNiLC-k$m(Qa*I&RBL4~V_#6πb/f{ @ŴrZDT_8Ѝ[,?JU3BqU;t˾xY\Y:>~2=QRȵ!*0G`'t- iv+WUcHq& mcMR1#c>JAn2"@!5{% 6ߚ-cx(5;~gGA mz#ռ3} 椠P@~=l17_'-{)@1;t\YfSߍ.A aJaZAs2>RV&7#;]^J㌒/ʽ<s )$t/D z,Bf5}8Z=ߣ c`XK; ?|uy99oNtϺU+$ !(8ђ G?!1i xuK-ɴd$g9R61"襬!4lg7cU7kbn]\9쪘#ԛyW*C]#ZRCۤ9f>LK"H ] XÇeV f| 2FS4Y`RTF$ubrkPa­8QчPvދ.!{ ߐ -Rlg9b 9qhBFw8`( (lTPY# N(0`˚~"^>0(#eLO]ɔJsplΟB{ TFꂄ5 hi)?\JV ?9Sgj_ܞ~6k}+ߑ-̢½Qb{#-Ä6}6]Aލu0M #=*3jZO`kze[|b?#bq^e@Y84yIR"Һ62fQ}\VU'M5%ccTw$5}_DɈh ~)Inƕ5Cܸq! Iנ/" ʖ->? eYzb<@ss]=%3Fp,p|%^@r3z0ck e,x{1$<­ORo -~&Etٸjeȥt9BS?S.7RGNDls]k|\;Ȯ3+(u LHoG&!⧔l;NUx"+o\>*l| xǛGQW$x#iHsokLQ+}x] +8LYW;aoJ6QIZtV"W_ӿ髆EGL9k&4׫:b{ŻIFg.:g=)Y`eP%̹4͘0R<}h.#Ů Tz wY МlDG,gq\/踖E,z6 PF&1H9P}WN3G^ |k̤bwcDs9T. "\lw:*Mtu VB1E: P<5cP-*5)8۹&|1CQajWDyqI4~BUu‹3=$VN0ZMz9)C`kyX4S'NOyX䘝k=E:'^=I5rcSڵκIs;ӨQ(&=0Z 6͖5zJgJK(JOo<\@6!Ogm5 zI^(D[ JMxS*dU rGʦ:7 _?5z ;P;Pgq}t'o[վc\~ڋ߶ 3)WW84`QN)N&&vBIq EբYPWOȌwzӪ[^_6;L>gLwj^A@pWЯR9Qandy3ʛ,i&- )Ѻf$węs5ppiGfcnbdXb&DYJK #b3iktR`ɒz3 L)Ae *~՝m6Qo\ h:"XfԜTk/NG%˻1w8\(҇ |"9W|wFz=kV#E9~Gbq,h˙!$<`xV}}`󢚚o&|-n@׋}Msimua4"`aoqP|g_ˁ aF bfJRx{WqtQ#v3Ftn?2NlTv'gՌNmQm=Hk2?Fq7/RC6o-9t?ֽ䌆.?A'Fe`݌IW` 5 dZ˱EY1kq#]rjbLܾkq^S6}C;&lx\9}͹$ SE ccl|Cnn﮲ppvv,\cehJͥ|d`'V+bF΄7`Gҵ-+hM;}`1ɪ4 V&(XEcwubc.9\V}g#W$֡eIbXyVĵNnnH:*I Ricщ9K0%d4 9YD7d/% Z2R=-{u`4e$#3Wfz& 9 xWvb/Rj s-8ƤD2s*~0 7@M \b'%ÓNp!X@ōI̮oPŔI[QDPGҎ:CObYo*p,d"dxZbbaR,q>ƴH\`,,[k ΠBՙWpv8ј*v 7cf^PDiX>Y)NVз%|&SrDS7d' u +"YmwCوK21:it@?꒹oh!4 t yly)?csA#*FX}Qy3c+kR0.†8 Zq8.MMKp-3*w'Jn,Fď(pp:v  O6f_"Mh꒻ -.b1A}"bpBսv-Or=vwބ̱FU o~3w:~ ˟x6ң6ST"@-h#i|kc<Џ zKWv+/|:Oښ?d"ɥ r71'n]sg?3sb勚tk>'cs[b 3e1Hz^gU_{)_zaqyiWMxVp"kL &|0J^vfы}<1'm&$fRI"Qþxd4E*S''{BǯHIxIq94<)`9:xU41"_nȊGĩl[Qwd54-apբ@9e昵d}|пOȽEkgd|4]FtUZ k-ad*o7FbK^kގMStT~[.d"6!$#to$S>MѕnBYX@ɪq6(ڿBE%5?v׏(Xic09p jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XXXPPXdKakadu-v5.2.1 ˃OFz]6)"a]#wބVާC_ezCU)i$!;|޶R.)::D\K6b:{] J ;7{lbj `V ܡ;ʜo3,@ξ0N9e*9]9ކǘ?B6/:G޺a/~Q.^ҞXG0bS uB̡(p~B lWðEO`%Sk'ڬI&QPl< -:e'eR3/TFY>I w~d)tҎ!NM"PO^x,)ڝbVݬhڋɋߞ|Kj[4pMZgw=0Ѧ \;/47述8Op+n"UMz(Yg*D; m;÷Lq-8( u_ܛ/2\5QVM$S_򅠪7S?3 "B Gx=[z;ZBhQxv 2Q/Ɩܮ*TH\%2~w P'hy[^Dd_OK%gADxؒ8-Z*΄N+CڲX3Q@L}=~&>m\;-b̡er9WkX xlEKG~Jo"zs-QBBs˸&yK/7uwim m;ƺ%B ܛbaQ#&R5\>:8T\̻ޠے]^n3[lcLZ}$E$GugDN?(D̴v` "nU9K$m)M BC <r;oCaWrz"90!w؟yѡC9ں7 -$#S$>Rm4_ءɪv*9 +@ )θ,6'r?$m:Q=5PCGvmф~C<֓ں~sP7A\'ӨԈwŘ${-P}H.҇4PmX-Nd(_" Dk&j1X~v % UVXDuCǍ>+N57lx=қEa=5Td,~r'IF9NUb5fC#i);"'y9p6;aYЈz2)y/8hăbKWd+:b׍[$"rDVA͚åg2ͩL\3X >!JrLA?6oIܻ# Cg &SXxV*Rs;[1(9+tEJ\ΜO&. ȖcX3Xoӑ+΃RS*NbWYuF[J,on j2KS qelH{WSK8MaFP}Xg0h$YYT'KRAnԌؠ=G{fLbR!qJo+xR If6 LSPKFCax_leȤйEC l?`f%&4fj eL6@ο Kux{9RɣRvom$7(B~Ǵ Lΐ*O3\x qTt6|ԅP)q8B 'R?GW 3x(CD"J½u4.9YOr<5F&a*2<>_)E5]7R-8|z؝ T jb'[\?XZo)f kȺԮMF /$%_ q.g0|PEtua%5 e޴UFy&W}ivoU|-sȵ>Q=t}4!]W6J~IdQ=}6)^^$Jᚢ=tw?My2Tiք/YRpN@u#lP[m5mu{ЇڬʖcÜ*\KIuhL0B`T$8 sH1% g%^GIT7Y{ ЗeRFwFĵN}HXÅ^F+V4A_MjܪP(8;+"z-bV8~Cl;9RZ7e2k['.4 Sշq4Y泍T@ nQ &#K&d1eX`G$$X,=v}b{,l\W5aDwSCHl {tf a3 _kF ^8$^+m{\ôt>fеxxꔔ攊OXfACW,i$,m..N̰PU$Iڵlr64O,܎yo[UC[. #F/sdkal`ʣ+C)L8N/MoIB2^M //Zgn ;7n/.=5u"D ˒濤*ou:i4|Jٛ: Vvq{ŹʡtYk&HȺx݉Fxp5ŇʣEKHŜ3 \ɐ)x wE%쒿/M"t3bb(ot}@ΓXdʙ"^ X eXe_@}U\H_nȵs;XBhU LM;. ,h0>P}J*wHAQ~1ƂFvډ@8V%?l*G6(H$q;mA3L ٢ \]H])Ey<}<ۄVvWM8@?& iq$Qqgv]LȘ9t/Y Ζ.y HtkS~_WV?T3M\#3T_|՟L<_ō1I !B};97;z.{`xrCmz[s .8-(L`9l$Jc']>A5KV]SVmAmG"Z/ْ߲,9 8cvAf:lgb#}1P /lO]'YJSzhWYn C,|ɦK=u >N8-Y !X("N/sC:1Eoo!Pv+xʥl|vK+I׋,nL/ollvVl4 T? |#F5UcrOPӤ.ΫdJfOdx-LJ ϻ+S ·=@+05Փ-QL{.'5Jn': ,H hk̮IZ6q/ JNcTnn ضd,KүC(N,?{(޵ԥll4E[#[$'NVNMkf@Qκ 7E~x|(UgjVtMD, _E^Wи.F?mo9Leb_yu,5`60a$0 M&w[NPQ_b߇¿mayY+7JWveqfz- ^Ә/~VX[#n Fh?ص.6=%MmU?_5d*$/YlKF́?XsR3efK}P" DZ >}J^X>(t59-Oq8VL/كpTAJ2%6Ȼ Gs{I^|kK n|H#-- qDI=N?-r+R{E3[?@>ˊ9jv')[ j9b#t^rq )y ڞ@$\mKG0,_x\Oڡu2rE4l `EP^Pm7"'MlR'0q0oIpº\bd7;~CJ):6kօI a,]Sȋx3*ny9&v̓\S|+3ټP9isޅEehvl,_=6^M3qbY>~0,D]u\TޤPC˧,Ozaʫ5}ԏހ?D8U蹓vUosn *AiK?>վ]!zVAu_1 Ǣ%}[]OT5 !XN4o|Ma!Y.i>G؋$ècC|K.|od&Q Mܗe"Vc-  gjQ ULu]) [p|V+Ne_3Ek>a2R@iK=L?&Gȴئ7JJūczNylv3%4 `7'ՋYsiG+oi$ژ2Q7G|qA9f i@7*,)-J)W2GV+H6Oi8R+H6c0"7.Ǖ=[>](-++)*Y3BTkCуU&tA f5`Cg7|ʍxX'DN$ S:5": 'W9q @*ɜJ嘤k! H /wRL+c #"M -vk;n3yQϰAd4G"įz2TE3.Sp)ܸcm4!q5IA#y4ظ)69qpo4y:"6N4थzVt&LRbH)lpZwEri|5C,ՒǠbf)fPk-7;ҮwfIS&LJ, Q~X%*p_sj =T9T.4gIГVRVFUAU.Ӊ|#"qkyK/ƊXrNиJ`-j*%w4Z1[F6a&2'X}w/u.c]ެ?%.0@6U7w]x}+g>#Loڙo'L*,2+@/0vjߵ. ~prS󣡁xsrѨDZ7*枨'_03a۲rAK'Bz) ך'3.7TJ_&Yŏlu#`\(CB QҮ`eZ/U_4Fy{ }ΕKSXM5UJG%ة%LTU۫iLڑ~+3,twn^.Q)y<*p](b ushD֪hS-w!W9{ VYbB@S~GR|)X0q\#8V\EקsWϺ!QF%smaq>'Oa<0.lH笥{HJ4o0D^i x.@=T tU{` ]e| z}_Z'h)!3T !UHGrʍH/F!h=N-OFJ<{u«#d?go2rnko$]ex0X.D >#;O rNfɿ|0ʞI[ޜ /tRm',890AL;/Q QK_1Йhz^EX!,ٞn5i:%ra5f7?izu~i2-J V(r"d`>:)CLϿWs|3 Auּ1/}M[ni}pA /x[I(.ۣvfŽ lBѻTXe0^?43vb\@R2=qp"8Z2LڮiEfKM$L69$H'eT 1t4xDip?;Evgto3Bd.eQ)1;sw2;m:eVL@LnbD%+:NI p+\:Yl22rkJ3E} p$ C=TSTwݑzBlt~t?wTũ"Fe;е4Rp4r~sEC,]-0 4O6CfOe`tc7R%4-OjjaZ=h~-#ʡXrZV8 S9#kJ\a a6vk=⊭{A,CNES}pz@H:|〫1?N%zƙք mqŨ0Q|8c߮_khH,9~Hϻ}e&Sw!5R d+7|O'6ťhHq& Zg.( g?}%場f]yliU#k,[I׿Хo2e-՘D$㦀׎CN`+:ϑ)>YeZ]4N^6 0oHʍd`T^ CJ>pQ(+6׹֜ ⓓViZ+M0Sz4 y $gh %  X\羘ޡ>>lNN_S'JH,1d/Ygʂ6$xe"SwqSt4+_leG}Q'Ul3.٣nD`mX?| [C|6~ώG;>^@Aj!/wfSU`PWy/J K1};\sDώ|*V VQ"-\ U[iH3vO9?pFE7*[|X '؈ ([]./|dJ 9gxK?AOr_ԺPEDz j=mR; XL}r84$|}oV lnv3n(}¬tE!$IR%8--yܺ,\y -Vw)AuȉpWmBrLGQT.Ly3tHjL9ڏHs/|2l2:ڕW0ӤO- Ez2u停* (cuy71rߠ]kivXr6O zx(La ]A Ux'zB̑ɂDH zt#jPW%TV"t,r(, !|:C (~WkWVʌ<հ:y` X)̭|[ h#Xkb:ؗCR9,JGitEٚ/uAOݘ2#EtboaaYoyth1:fvq+KSR !D/d<6|᭡[,zBn?jCߊ5ֹ(Z0XS9dk_c# MÕ]}S?M[;KZj8&8+(O>&(x*/LI'p71&f(n A`K˟ҘOtŬaMQ)lwaE=I5*m-S#Zݮ/4L$f+ѸH,>"_OO-}z7M. 1nU8XgWS:+~8LNSJFc!r3bosqҲ,>Oc"5Pj#Lbk(SmJ 7YkZ?7ěRylS^ Tx<~}bٚekIمGL V^2=J=QzcwgXNa唸)ӵxd)S&-L"'O(=9p$ru>mmC_nŇGN C≎HwH_YyjgRE+uj@LT2hs3OK;}$ -@#W2W2=3%؏6;ԟmG| n8|nRڤs;$H`֨QqtKPc훢 ه+-z*EdZv}Im^e ay|'٢C3IlϻcVC5@]t* ]O(ƙB>rN(مz FAe!p)}Aq賹yBq䱛 * TN,c' {d*0`~Sntj!f2k{/2u.9[h #=hY**s}S/0ߢYt!n\rX4d^kwUp]QHpn.xkah +T 2P^+=!H4l<[/J~ >_VWk~ǧ#d1 ]t0&|Tx.|07sqƼ,[cSȃ8X)foy^31J;ACM`vVaC :p{$|:!T`^'(O8+V RT_3l;Yۻ55fb-@l%YNW2ڹpiUEO ''L#d:[n#Dˁ^7[ H!#jRg~`kX?(/1y},55A.u[W8w6wժC8ʰ<\ \G$ ,%+bU>Ӎs"OP+M%8udo/ܰީam({3g]xӫilZ U<+I.eEa?94Ox0yѴ DDZᰉtod*Ldw P\յ赢v ѕB6:iL!򡈵3y@V(Gm#zb]3\(ׅϽsQ*Y7+q.j7r@W1 0ҭmk,7UJ 7O"L[? ?1E:2B ;x^V2[AXknª@bH(X _EPdWh'&eEێr9U>E0F4Eyt߬c [%) ~Y|>v~ׇ"xC:.@AU6yC~ǶN@5gtLbC5b*+B1(߫1? $M!Ѕs9A`}5̢πNgm)Y讚CnO˔OP7os}a"beq[夕bԧ&fo7#%||S,muZF|O&%ޏP@,8Цw=5@9(j9P7ncdOJ9b*1/JZaQ=HNdAb4H7L0%4z ʾT1mц&lJ|P-h\>wĶmpA8v#/>5 YTbN '澛pAüOEi|TBnRF"w# )}\W|5y.R!T7ǁ˅ӦN!45LB"y%9B&l6@ݿh\EDӪ>SI%;J$W7S))rv_2 00^f9-ijw7D} BZ=;7Ցƚ&ue>Z>[YhNGKMEy5bEJ4VYm+QqT_KLJX^Nk HHÓ꼇FZ̰7*q,UzIfjHknu,7þN??͌4xn)|[p@>0 ; T1a9޸XRm"s7PEZP6f ~`Ph:[iʚUG`G6bG`ZP)43憛/5+&f-`wB5kEcQGXF8E8Rc,Ć5j_!sB`fALTmF{tXܿm7RW8`a.yR,XpV.-.l"ef(iM K^@?n جRn{x{\^vߋң ce7ggʢldG=aO"0׵K\}[ Ċp)6GEf<0][[m\ҤOm'Kaa6(lX"fKAg$'kڤe375, "?r^GӢ#r3fO5q[uu!wZbOCyre ܄B V>6eq޳_<D7 .$rW"0\6u ̾D8NGjcbT,;F#Um ^c YV㟊מ;_!HXC2ю]'/+Qߍ_a낣'K<Xt0?f@O(q{r$qR$tnW[n,T2D T<`$3?fEh= /ʧ.w *Nij|zhutɗJZ AnCvZv;a^ Tc )q- 3}h Itkxo& |!ޟUE~ܷ7|789=’'oIuna~}ױM᪳B_|K^[T3z2Jew]۠MIWoW)_v&B} z:۵wNNiA&.uz#F)R|2pwMUmB\{ )CjYӕ Raes"T6wBkl#)d6#R^KI/1WFp{4?/h/2 6"yo ˼D}>틦aֱя J4 yo jjzSIUDp A{cމa]%P4:f(s}L KEMLձ>}[C!l(P[q0vCrSmt}.~ Sj+y􏞛F"ϑ鍿2Xޟ@M^bktQ{uS?E8UMhGT̻e%٢!Ev>36M@:1 hBsf9XBRj71 xcaz)R  jW_Hm61fp-'}B@͋2/UJBLҤEƲX6(BJo]IPUth_OYɘ#pq|51~ ,fhK@YӞFJUܠ%2+$fLGKU#oja8roXy;^oɉ;e $"WmJi Zn4S>Zgup Ș"QE U W}[۵wPR`MJA,6(Wr7$'E8Z(&LMWe3cuT T( 2K{+v):%Be;ɩt?S 710 &N>ge"Nڢ9|^lɂ؋wIbtXˎ(hȔc8'f3mPt2cT<&`vq>PtC48,D{9l^'_E@5mGj} $b*9bFV:TTp"Wv# _3?5|]}~}P2Ҿj" |U ͈ J-oX9jY\5p \P"AMq4t7xR&hjܞX[T\Mh+3$ >2]Z]c&; ^ 0Xi ?YAzFc>8NV]B..&Z.~.[<΢VRD NU@~Г`^Ķiv*s1=/xXzE#f2 n`,v9 ۞e͈SݒN[V"~8t!f˖AjBsmoi^|8=9Q鹽马[^lp`t 9XGctnL'_>H[5jx=L"(9Vȗ S-gy2q}n÷ pkN*k=^աYb5u}* 8_&Y ]ZN|`e),ZUl7?$ܙIsMt [L Hh{ waVW7quBĀ:ټ.6ߞOEuDߍ8|La/HP:|ʴt20 ƩB10%L5HRg^iЀ|W,M>8 F)VTBGƔV&ؘJa""O/XN[&ޚ`/ǽ Yv(%Knoya;iziS;-XZd>]-BqqU x౅6 pRZPc䧫﨧- Q]9aaUF&T`.P ?\)s(p L-oU:8ފ DcJDpf*ʼnSaH))nUn=uzBLkIkȌ8ۣUfjT-FV@ki\P 8KT~nrظE& w5E!c'+}/dt0t6sƯ}"Z*>]fb39Al= &oU{` iȭӇlZRMr>՝/XjClj^HBIή;S7oMI k:|kI~lSԗ4EoxVx4(> O=OΨ?J>OFQjS)'Todp@ (Ȗ5~_0J YH.|z2&#\Z3ÿĂ+3r&WObxtjx]>^['S Rop&WPV6ʼnYF ۦ[3rJR E?rj !cC]Z ]5~\|8K.n0H. ,%3r~f$1, nVƗ`'I `<9o4`L?5 iٿ'*\_L)D8,`s /#ξ?3a[hX!Ot'x6βL8E.YvneݙmY )UcBn_ Z^݉(zO= 轆 /iTn! R=RsYWK w" YPSw0rVk[e6кG p|=4{;cRܱ/ܸx&[HspP/y?"IV? hᠿAq4_a_?/{v ( :xR<ӻa`I`;uwV<GD~:f#!Y^MGyl Yųo| Ot!O $RYc_D֊{?|;w蓗|%f2UQ~EUKg7a_5!m~3uZ`h!{Ju~CrĎu-E+= = >y.HmLBṲ ׸H}t) M[?{LFƾ5/:;xL}@1ȇѓV㭥]&stDXc׹cJ:mooK_F7 CBZO!6wgl[ۄoސ@ 3g^֥'{lVJldy~S" gua܀7",5p|vK3R{n!LDޏ73$4;D\ xQP1b!5i߿]ܸ(vs`O$9O+ӚퟍwP?[-7rإ( ljSTkb_=`svZ,%#A&vX;^Nl <6A^wIJx8&M\.3YD,do8=.2&vhF'T|L"iW3/%9Y'\q'u%Nֹ^S.wVd=&v"Tћf$3kM,U^BZx64|"!.zO!g# h1U&^6.L$Rv.{qnXAZrk۬J{prQ&!u﹙x9HRE G|dIn@CteiJ' !r5R+ EV#(;T[F7xI6yiEdFޅlʪLUa2{#}B&fǹw~? qqQ@xGM{Њ>f7vT 79yzܪG:tcps&,21ѮA Sg"͑Ħ8*~IEBnRK_uK2< ޯs tTh.?jdrt!dTh ί!ܒkrAw7ַ 럚UC%Ys~UNH'U9cWQ?%W}u9P X-$ub:kQUM;Xl[buUR~>]a{mF.G`pOPɲ @ThX-P!3k\^p=]޶.5 f0$ VV0_ߤ*y-3Xzb6𬨐8x> $aXaVqzZm3i&CY yjxt9kXPs' <1cߚ̒}+Jy:=`t ,UE{?F}]tiԳf=4.%ǘ).7ޔVVLN+_dyci]vHԵ598fpbkX): zo$fZ:A[2ZS5;_">E]Fl>0V L eR79*|A`UKZ\"=Dh=4U"J#mbҽ*~|g^b1;4StDnt ˩j+ȱ:fH:a/Ug63P)-|D-J; Msw/;u2l?o'`UM%{\ж44wh r>T}Ro.ͬ0Hː(` ߽խ`Nu|oѝu}]~7쇾?oF߶z'%OV~վ}=]g+z2}]{szz.st,'[kO]U~VaꃟWUB7RuE ;1[۵WDm+F~!s!U2_p8"O,p|A D#KᾶB`OU Mrw2O]@~5ߪy 7%lndiaJHsyy~aڐH<5϶@AG{+­s&.մk Z(,d:wbSҘғoB)T1]Z#(Ppjn'|qI.RgD c7 2E"L#Մ:D;˕+Pʧ2't!/X B}1;5'hP31R 8;Sn?/=wyuzI91E@f( v>3/N{vAAw2|~;*X0D(?ݏ UFIBs7гU|RK\u/86=T|*a:Vw/-8Q0j>D4&yT\YyGB9/&p: E^d'T[ծ(,w8Bz 7J>6O91H#HPdHjn'1Pgh_hO%DZ1[X4o780dc]{Kc0BnoZ1ɥwv2nű[܈V/;]3R>3Isͮ` (A+ϬQ-y*p.P+ W1؛'KUx\}kE*)D(/x2iXs/R5×oF;/Z(yw̒C-A\|JWQSBWds"xT=9FȎĞ4 cn\hh^>;RK<$,,8,:tޛ9N f{Q|eo[4lbL*0tJ p뮤Q[iI)/YC#Z|FTxy_k!^p'oe|pc8%or|t6,K ba"Gt5 m팀7[eD{UCJ/w͐0z0*r⣒4pS`zT< K@82XĻlj,4DMu澦M+EՀ+LMcPq󋄡ۧ |k<n6Cv0*?yM ;R5O6OCIgZ5 'L!Pgt}vVNճe;ƻ 96Ug oB+*Sݕ6rnNxV8Q*}D፵:vkYNBeЃ Qz~E(,$P?ϭv5tdRpmM\ C@FkU1\_ql,:1⣮< >FAyLOʻu,Ft1<F H8[őy%wFwYB zSi@q{屾E&:;|qwc͓8;mR'guY*GZ+H …xۄ?*ة?nn5T4ԪX%tKs;]PvMbU/0LO2-s, e/ }VoQTHl r3~($t}rC">r %EIXZ>Kۆ( 2O>pKk"Q$;]NĐ(>͟ 78&]"}@c694E)=ߌMl !oULiaPKc2`3{lHz=zĀKրq(=z|˼t]N**qsE,!!ީ"EDPD>'ju@P+09^ MA\B дR*XVW n+*XK~Pm\ BLp)}ͻNa?A`&]cbQ:pZ[tʂ8=*DZi#OkD'nϓ'ToqGی׶'f6xqNjB #c#\[˘ˮWׇMWO-~?SE;|o6%:݂ʫfPr -GK^.F#Az4K.%ӭ /.n9(R륯B[MT_򸰘3& 3 ; E &¢( ̬$=%R9Ʋ,v;n\E@ݔ:QAƏ Q?xP$Vu9##- @QyA17&Z~w-µhB7wt@8XzDψ)s-tVɳi= =*,.U`e ס)juj͵8:l'i獺! _'/&#h}wzJzAHVQg6 ,Eޗ:![耿 }J (t fc%2D.fw>'z{!©hI\Go3=ܽZ`"ieK}(b"HkMҎhaѺepa Te{hbOwۮ"y#8d+Br\etΙ8i;mH)uΗi4":onBD,r4\e^ݱa9 :yѫ ō_%%܎ ~_{?(.jn+LeBe*)c~d*̑>=oŘ 6tc xbKUǨd%w>I X_UᒸS-* ۞]ς#im\Q{k/NHYd9_82j(r6FUOusy RYE%k|G5p.TPTi{~ۜ/iFЂCX0lwZE1G?_ŝ9s s%h0w_CS?&NRdv0AP,{{(E(͵h"Dw MEPH嗶c2yv8Ћ .ub~4$> ԅY^3)WKDzT:8rpSym^2H+ xKƀJP6m쾒L /_ΧRՒE=;Bdp ((lz}+Wc,{qmjL8&Zĉ@@o[ `-sm`kAyEXEbTMN"JJ$Qv!ڇF$xrv4?"owmb5GLxDb$/./{`5\Wb/aoH2 R]H.洌ۮ1;RņټEl䨾9n'1TjH"8u,{lӻ}<U-m>%*;lvuʜPQJ)G%NӪyձ\AN1#SiJ4#4ܳ%RHdXT^㡒?JIͦkl.~2G4[[--py9fQVrm:o4^-SlHfF; LqFwڲNwۜg"[H<+7d?X TN! r3;(wRO; llr)}m2$Vu篆hbf4?d8 ~b @6D'dh!i|Sc~ǀsXOLFjۅ?=I6>FxSF*ʯO~N𖷹mck;rf(Le_Q/}xBLZPaN&<1x/[$ytqAꛥv#;$`m@T> \gIbׅ2ZAfj9Ԣ3wE>CM-e'uI1ذ1ghiy @oA$S*L&w[tJTg3ΗhYGu)kmsmPc[W}4 uL>@W]@瞸PHoygs)P"y<ˈap)E:(t㕊ܓ"R`k1 9":t^ojѸt=faEɾ=ͦ,~^*>}^"gd qI¾|hѤʢ8 QY+~|ܦ.pN#sĚ}yHHIYqqĖ'o"A"<ڝXi7Pp(q[JAD]e;xZ?NͧX28Q|6gsX}8-V>Hp8KZSmVCUI x+Y&$rhD=nw1Јyɣ^iLfW%d f*E qs@vT$~:~H( 6*{%7Tb Z!4kx#қ8Qd`'}7ǻE]/'lwHӲmd!#X i ٌaա&Hq+DݼDa8a6uMòC].?$5.(ʤ/Sm?CkJk?<%S&`nhtMg>ED Z~Hۅ\`C !>2yn uDN޶u}oKwګپaPx?ן.m5Sχho oc{F[iQ?/e}@RT957O%β! 0ϖ3QzkIͫqk(%݆/B}֛u]:JM%zk]> &.`PcJwe|`g,EHwC7cxЉCba 39mJh{fS@51V\T9s CcjE{ԇEnBKAeT[2@`Y}"_cFpv˳7|ߩSw0uFTxq+gA[L*eSYK ! (l~QN DKOQ=c f q謢Qo5Rmw}1 fV(U.Rv9(n&1d-kSu H"@1 =V?(yClK7F#0BtsdZ8A >:r"X'(&͛"É Ѩ8XQV$y^1BKǾ(O ۚLT+3|DE)2"0嫭ZxENH Uٔj۾T\B!fcաP ڢ;~6_g?"mW m.0쮚`x_FkֱӋAAբP}I A l !&vlI?t4]-ߵs$j JPMu AM<4 \>:sQ 6PWM4:PX5Q\-ՙ " o)6X&'\<ތ\O?얓06 Qѱ|Zc 0Ir/*s'q:C$_jR+bYv+;׷klTh0LM8e}W;V5) ]Rxm'iLؾmͰ#%4 $V`t0 hR-xps3/UZΜ4hrÈrsS;hj?$c~4ZNQ,}g['\FЊD+̞$~'s}^nO]& įRG)?;1ʿagZuhld{~rh^%}Êg7n6"S0`[I4w}{*H|c(A!2P] =}HʹWaQ-*b'#B96Xut}LO'FkF~of㠰pF#@(g7ֈ#Y t8iWe*15f gyNӝ?.v+u+qIϦSt8؈8]ю4EĜjGw_Rlcyݷy,;`\SQg$H~izcX\C5~vi6E܅JFSlX/qqnͯ͠\ +Pp8mw)ϱSgtf\@xlF.~2 ^Kbot.e- f6a~8T$lP#FqKm,~u􍪩.2C^c]&k<;'ndȊo,]'\ =>gs}P)2t*2[C9d2Vۭ%CTEhw!bp!7T֒MT\&oi`20?t%UYiyvԇQ v:eӭ% xlYߜ+!]\%3\*;p{b(˯z RhFDx! Zτ/bC\c)2m8Gtx}Df m,PQGGdk4ʗW)&zWlXtn%)\ˉmdY -\*&o q`c P=Iņ/ҞLYj];agu|g4eCB+E0[[oD=rZY1u-/:L!/aoZ:L@|7-c$kӂj "vRԭ!Xt9+z2F+:ՀO+tt XI0! 5Sݽbg? G|,<Vol"'+Ӏsn, SaTpk|9b9F7j[Ά'nYHl@/tC@.i+d=ϙ2*rV`T^bG8" AjMg4u(▐Y>$SqTqҵ B6YPh:_zNRÈSfhPC +fBZ@ir,Q=_2D`L {ܕ][~foMPft`|^1GUR952a1su5eʄZo,dh*݆xNEZUDIW*ngDLsaN{m(DD4[d|ԏ+(8ҳq!PKzN6(zʄLxC[kEvTzd:?yGN{]|&rţy8Ɂ_YO^!倫I鑳6<+-uĠ|QE|;T wEzF=~oZt8>NFtNVޡ7j`?wVAs7} WEO5ܦ( .g[i!*iqB1 fwz-w dRR}R(;?sL|K(%<%ْ}]?.]3)|uqݜ ģ(3lF}ˌL1ܵ)í.@R _x"cbώWB !)m21@0j5<[:+Yr:[ěW=M"K7Kdϳp4Q43+͕C#Fؑ_k;b,99̦P/~rYZ~04ֺS7&}}ژRJm"ڃ;o`CN F +kV}p8 ?XSjL>jXvQT[cFgǿT![n: @ͤLeVkk=9w >hf]RbF3X7R#aɐ3ͧ^T >! P LE\&~ 7V%!l_}`X *e%15%d䮹I#9_~V*)b&aY0~o;(ެ@ `{,}{4_1%G`bmOŭdzd`$QaƋ>'1GxkEG P4bwj?cP6,r2ߌVUAPCm_H/N5À+6-uQ( }Ѐ͊qKE*Cq(Y3Vy3^xOTGHLX,SP?LգkޟHӋI3QtIl )n~,Tq027XH$2Lq7 h j,kE=K$Q`~8ߩ_DlKX26Ђ޶;c.#A2WvOh&Jv=p7v[4㊳5qOyZg>)vdQBfg}ȋ*V(sǶ7 \(ڃe$[(o1ga -\+6kd;aXc'%+<pBӁB23*e;H2Jfsa,ĺj;ɘq[',o|$A ]ʔOjr F|B{[ Sw~+t{ Hx[8FWrߠ@UpvGHo@HoSPTg~䇘7%1o;'^?nH MRd;O:V%ct1~ɴL`MKGu6)\ :T[֌K loMڐJQ;Jjh+9׍r>0[a?LGʐ.(K5^/# bh;; SC}&G IdtLGSQ̫U7/ha-HGn&<^nn5vv ƸԴ8u,yjn6)h3ŭa}flLw85 |moJ4|~̀>(?t3*RA:ض 琝U6'XіrK<툩IoYNF;H;ߗVGH15s.j̑1ޫpkV <םt? o8zRmU'`sVk)l..W^8 ,Nz ngRLolAH\8T4#c`Y"!yhrq-MMiJQ.L0:Cg[OБQ:zDf i/n% xk'F-xuѮ2'ӸX9#X{ UƠ׾TĈa\dZѥ1Y[q:АalIj"ZKU7Gɨ5 m" G uڌ!sI5$%:N$o&R`d^nnWJ7$jD j""?jۂ|2#Fk+,$pAcŒ{ǟS5R;rN/m~0\@>Q ;;Y1%5 Iju,,<@ ޚ'S8'3(Pаl[`[0 ~>DYZtPOAדv"iNg E`k+21{߻ WÞ譵0yrgz ?aUj+H3:ל_rK !8{aSjbCY#KInL]jm\J[C8@Ka`lzm<7b]M5 ئr2rKA}Q$|i5 +!;5Oo<ؙʒSL Zn3/N S`@);1lm,N)Mz#Ԓ }^oa~-AR=˳Wov (Sx{z&\r&df,π82 l!`y 8c@r,'~QP²`|+gHSqD'߄)}i 9[dN8i5N;Zkm0N: D"F_' k34cۨ-}UbO߮J4Bx.M aerWQ mxCn2ȉ4ښ`evT帬fV.kIU~?p/*5Es9fnua``[U.Szri(C q?eA7`|#~&<"Y+9_DpS}/3P! *kU?4RlrF{f1uNNm/KG1a#D40oJ3:t| /־ <|_tK]4g4z0 Jm=h l&0g: e>( 2:WpE5飊$;gdcR!޴l(&-8 ;G=h0̡SS!F2=y96# o9f~1yEFQIL2dL[>"ƉjޝkTi绖rb_G]ƴ5A@"L߫гϹgdZwY;/ UÂz)}Jy{$gU#?ØgzLSRiLb# $W Mf0=A|q,qio59tpfHKx7bJ\I>t֤q Ӿ1`$}h2kVRkroΓ75@a3}>eX3WEˍHc3VfktV2JvȆ, {+FT5j[@xn( Q qdaݹnh#H*C|7ف&p.e./t@E:Xq0ryf v/$un{'M9|⸟NG! $f1 6@XAϽ)Џ|h+:33:e11xYY#l\(~вzSi"LUmja9WE\ ѨYRL52o{+)s2"s08YHIrz.-_8A/c]sT$ozlMG?\%F '5* b:GUvfNnO6{\| zB( 6J sʮǶ+c˗nz#LۈS@_#nv-i Ȱf8B;"튽D22/9m0=/:4P<}= %,0h-XU|uBTf=+ w_ea?Spb,$KM~ S?F <⍎xrSl#I@M滉 -(V(HjJ~LuA1/$n%jC>i,Zm 0m~.SXO⡐914d*$.m$(, ;.^49'8ڐ^vը30&:/e#`n3٧_y_98Fle Q4-W**Sيxz'0 ,jY_`lf !pm7HưC2,YB`7Ȝ.Q'nZYM5Cߋϰ̄PmnFF\MQ< KL0}Ӷi+ql>M^idnqe8ň6 ŐgJ`VPۤQ?0FAMF\_jumd%F䳯ïЈZЁ|t;9] X9ww$w[)'17HvkmDƌp~ [q {wRcCeԠEw,A#+FqF^/wI-s$g#PÏREԜJ q !L -8&ڵTܴd.~+=#l'. 2zCMF[v|%3]Hh:ϢOƎdNc*zc6נuygnC SSpBE,Q0p ܹ9H0Vy9ŷ"SkGcdž/Q҃w0rtD:uHʭD# sl_FP,qsBE;nHY&/wف ͕4S#&<[QD}tzE]Bg 7L|g],\g|dibix2UWahU1f@Km+y#OhU'ÿ3a/J1N\ Z9]vUgИ\/~O(O\>d+G`<{t\T*o} &t)ޜ#yv,@5Tc`U)xmcYAw,340 QEyPQtDp_Aod #3(ݳT7Z"[B5 B5\] jkkٳs;<ɱ;<Ճͼ4E^7*lX픲pbOF]_Zr)ݔ.-ah.[3Cj 廧7Z׬ߎF-듲تƦ6ccuzR@-TV`p,>/f}JK,(R7 "7<6݌,6>7.,[vS56:cѼih zgw7󓮳ŷw~xIyQK2_ B0µƬg_iop4)|2(Ԙg2[2#418u*ʥHb'J׌z`1J+U!TmZrfci\J1>N2)%z l'H/ie}+Ǡ@P j~Ƚ 640v`I͗JLLJ*-̑AV8 xo:~Εӷp_KH@>\(P0U^+XS©T&4$*Ҭ5@A.,#@a_AxID6S3q7-)0 DcN Vq ?Z;4 rMdD#6 ?e=&+Df0+Jg d!APok7U ì UJ2vx/ioD'Yo18jGڦPrrdz]h:> =&tw-e/U\e`2]m#(#UZoiPԒW7b]ykrj֙-:; }_5DîOr,c['zl'_a#@YʁݏF L;5FFuNOo!%:t*<5Y@RO~MXD:~:@/a mTڴwnI Uχ]19edCuռ(\NCȐːz@v.zj>Ǽq\{=5HbVǽLd"Bnot0 S`Q#'kōY9h_H’y}/n,B} j|V`%+u;WoI(ƿ-P4y]ڃ\OgrɀFSDe} VX'cu)pҚ:. DiU<966u?GyǯS23i^;W-G{㶕vmz6%5cyrsݾb.. tG  !IJ|ne66IC{^cq}O%_Y.YDb]+q`IӒ.>]W%~u'waT fI헎ay @f᪗8I8$bd˜TweQYx!pMV NPx{o%) 6¬x、``.j˪1Xn4m-1Ӓ"e?$wxĹˋPwXqGLa1KQ5FjF Y(D7b9f`W"gx+kCs'2/8OaL H(uZcjٴwHձy^I}L| <;&!}lMI6¦zL+axP; ,JбajcZT2ұhv_!^. ~~~,i\ybخF\zH]Bv%pGh;c(t&1G^AhV|7*Wn|7TlPr75!$17BIx].?FDèA+m8PddcUj )3%ZLdD`-q'Ήv51L1 |gv+Z.붬][(UϪYPw*Pkksj_[5ְC8 ^r7N MPr47%3_,> X9f;9Q B;\ѓ2n0c5;8HWL77l&LGcH% `$$p'Nй(QG a(s,A+굱\ǡ9đ>0aѤ㨒^, mm@4ꌖ"te'ca4Ưa%YQ?%/ha"ö[NfK}B*R~6!7Y:-0P7cf(/RgU({g KcP5Zw3.iefKGeekcoj>X9&Cn,gPi?hGQ xQX81>"r ' ^5L 6},unSSIFqS<臏E0= h[rQ_'7+-N3V8o:sL]<9 ! I(1[q YonOW7p6%ˈBW'IV`1&\T6BFhFc`zWxejj!bǥN ~KAE}iNnʥa%>Iǭ; ]z&T&ⳗ6O QoSRmV &p> jV?ߌmMInQ 9g  :s% kMԴlPjI<<[Q]nC=`.ŕucI0+' kP6ኵt'JM _Knf:n{ h.MP}1K`fi߁Th{Op `a4A4>m`H:O=0 +B9z4ASa3}]HJ := HRY9/>tfvD?ԮssndK1JEFYl"fFȽs[\H4_@([2;IpT;E# 2 _ڸ 55 ĂT*&z3ğꅭ-m!ĥռk1䃐Bնp/*{yʓGk3~# E6L{Ef}~%aST%Fl+rGg C6{h,^=rEbMւBuDSi-K&a(|؝dr)EB! YXK}2?ʜy+nRsBdd%qlR?މt< v)wC2uԋCJ@ZTsυKa ݉O+P:8pCj:Qǘst53;_GQ.]'[t@b\B#Z(u XtB6 | Jz*/p$^4jw@!d YH7{!|zv*{-^@ Zb Ȥg?Dy7v8;Şlu7♦5r'ȵbM#.pz'k.G|7|UhxSw{8HX_bexb, 5*ń!Z<;RZXzb x,6Tr)3M3 #> o53Z0R>.#F6X/i('^g!K Xʐm~k hh""two=YL^$k/]eetq / S51 7l.֎:c̽p*skELC,(]%pjolx[RHκHIJPa;S`PwwL DOnc5b|RRO62ɾy[wViBR6U@2"U@f"`L%6B&`ceL+w_yrJRے=WR,qֲnMGUb.!N!Soh!cV#Rb,h5C᝼jc@Naԩ\8Rl5OedR[1BT+D C[2~ f)QPIJ=V?zH > e l#cox{BZQzB'2HжK21Hk17X4e%Y?eqжf<"kb ƪR/[]U^3Hd`K1j+:/nܒ}rA~'zlyEhdΊ٤RiKR|Tap;*ք*4~-j^3[):g5c~xh;.zYmB7Zr4bNC7ařЀv\yCZ,IĂ]nUϿ5+4DŶX4,X7⟺jz!ְ?icnV BffSuperCollider-Source/icons/sc_ide.ico000644 000765 000024 00000124445 12321461511 020720 0ustar00crucialstaff000000 000000  cV00 h&uc  (݉  hPNG  IHDR\rfiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx IDATxIfIY}ynPD634C1 }YQ0ڸK#f忢ԅ-QAIDE|Noy|w:qw7Ǔ';kX=zob^=zVXעX =7qE_=kX=p{`n_z`6z&:ĕ}:m`Mu+-o_]p{a{ޜRD:[_:=sZ:B\{nNC\K~W A|p *젣>?S:| J^//•u`ԫ_xR u3:෗NvBՒ:(C;u3'rۿ,de\gN@8̈́VXa-.Q:w|w-]k7W@|Y EڸP\r۾U:=zL{wU,e鮲S|w}!.~q{\w+vxҍ9tnԩI Jۿۻii=S6X9 ?]/ڡb\5)C>b0` .׾vgٸ)?Wxzsx OOz]ϝLX5yhKjٙ-.gp~n,Ǻ/Ov~'[V:o&Un \Rv[wJsϗg vˮ{񴝝?;O|wXas^j9oW֝_8&wC esNV39zKuL s,i+ k =#zZ.Ҷ+m>xHRIOzґm&+ۦM:I\[n 8YY׳;+mpsܩ] lK2 IgFy=֣FË!WlmjtR!Ke@1XntsxS9ΏQ#ȝ{P(l젗mqopBG8$. Xޑ^/)ϷS]OA ֟3{?Qi٘3cCF0#Ylt [t2T)gDM4jpЛj |]m/T83sfj$] /G,S!|zmildDCV+/ÝrQ<6,,>٢3sYI VgLko^+l$eW&"V,Yf}|X䎲L'1r޺0sF)gk\;#T/Ҕ6"__(x@ BԲ@- ='NN>\{Z_s?sjlFv[ԧai7C28FWstZmebZҢ\O{ǭAyf,=lE~nZ2-[  Ps?)D )p_9^rsj0Y8!ӣݿ%/9|v2}ߧG׆p2 ֛bBԍ03Zxme@ GvGN̦(w~f~P4eWr҆mu¹zW(io{M,Ժ~iK/ƅm6܅6wbV/| =yُh@s.;VYtK~ 1qmp{1 cėλiWo[ST=~5=d`g^-Sj;ԧWƓF3d\1?@#s@5]7?[ɹ4u#_t#Tx!Ƒ5{B 54sULV֛j{+ou_ Th^ԋm H6u(m_Ҽt ̜[Y-oa@rF: 1^,9qidݱtA~<`Ï/4a+h+ёcO=>g>3xKNȴg2Kn>ۭ ,G,]tgM> mme/떄o\I7Ƒ5>Gى'=+F<ӌ 8U>{{b7ɻ.A-,EZ -> 6W'̎VnJg_N~ol%Q.c.?(O+tGtpx/Ҏn9Z|^!/ Ǘ8Ǘvđ!l?c}rJAW޼D9` EDQDz(޷d!={kDTޘل| 3? Ob;Ƶi\آY鹘C C788ϒܲ2!c҂>qF:ාH;S;)FyA$`;jS j,7!ōGN)|('-ˆGYpx/m}{s} Tx-~> D(?b&k`%d(ҥKX搭#[J!}=9j |}{bC#д [t4,f{6iM& N"+?HOPyw@BcǸ2X=![ G %_Wx}wu)Cv] %V¡Bmvtx5t&]QOywk0Wix߂X d]-]aӡ%J~Y\!m#[{, 3?CyD:igSqĔoJ;j|id(?#C+ߒG>mjCWo.d%i>6& cre|^WfUA_c){}vd׾vd⾾LKp1O *٪&nt>A xG(?|ug(?#C+ox v~K=MGݘ,e~MG lҔP>PB|ߘٙ"̡fC[S $xNglERRZv`/ ٟYz̮?2k3<:%gc,{!.r.5̟jSh[Z%|e(?ꌵn\ @~є1]KVeA[acK.6 ,6hlQCG,k'=8 Asagbpiҕ/rҁo!˩e(c>lϰ 4Tc5ytMIƇ >lv.t c[_lu?{Sq8uiAgWΩP=>A9 M #1{SdMGh[0Q&G9qe2E46}pA_3.tiN綣MTdq)By/e/ NDulWF %d{@f2r/^fG:}1|l? GIw,Ee3SM Fx:5L* (ni.䄝_̟{,$gvG׸v #DæxQE.Q&ìǟ"uK˸N" }}]Gj1LBeBsC. ֲ hgk+%YRgC8>7g^֑3MYaG>!".Ǐy&g˓f Rf^0! =.BL?c> (^Cq-e}ek>Q7i4y/)qs@*vYV4D6h3#=v"ڪxﳓ!\hϴ[XN,~G#7Fc@`ÍS<+ađ!DZI3AM 3aۦH/˚A:@y7l>'ét䍁t :M6M#eas⓾N}rQA5`4d׿}",<#/♯%Jgʎ$dyēl ڈхW=cZXYl9` 'O+Aqɛ2˜_i}G|qG6ʋkWNhތl.YESlƁU'x7#,}I`"Mz;WK+{M;}{?6Өى~s+F~֎P=KJr`U@Ietk7Qz`&d^w ǔx4L3,_ JS>B8#@6!2 4Cϲ@z\yʵlGƪU&-lC:Qu.CgzV J!hmyAep^G[RQF =!v&6k/->R!L1=u)4X2DZKV>2B)ܤ1j+}![7PvwwIMC9e-5/' Nh@|M`(}SH7(",'9S+ı?Ni\{[9@#%d#M>82إs 4OmpɇMI鏑QVȣ0^eV؎W1 sǣBڕ?sm Oƕ)c܁FSqKm(,f]u'pEލ^XZn/2/nY/o BUM_cDӆ @щ,S3+p%59y}pnG6=y7>zNW <P bz5hx)ùMW}1ښ<ۈP}M }>g:ERElqjCF;PtƑ%(jt6>!!'G^Pؒ߇31:Q&+cȍřYy*9]+j ] u|0v)LÆ`m/rp9ta=,q*?VJF!eJo\~ "O:Q/Џ#ɟe`_: IDATt IL+Ggp' NGbщ|!7o_=>JEF#!S"ܬTv Dnix8/ ;HvZ#1>g!<|?uB2)#<_GFހ~82čv Tys!yeP'SQׄD'}\]?///e F ֲ!ʏyoŴiQB+krBe'&-mŏ{ b-PKP>8Bu6'0On8&g:s+2/ٿβ0V̗D>"~ ӈl|?z7S#OO.l2#G;c9.e.ũ7tN?&[lr1JA|rۃBe\H `4x(YM2?vqbEkRql78hS/ݑqyXbinxv8tz3(' :3?_kէfYۼ$}|;|L 萟%n1l4/R*L_cx#c䳌:s lEGF# ![4 WñWѱ ޗG6^\txq r?x pˀ`@ϼ CJ7 !bZ= :`m/=5hC=yo (y9C{j{*h(qHΤ[ٙRϯ"\ xVԉzGƸ8+ #3 ۑsiXY90@0R ?AߠoeMn0R>C-#M, 8 +c9#6 ^16`^8uiM s>gF9p?ü4ЍGθq gHqLA0c4ȳ{gda7p@_Ƙ3__\Wlaw@&f[ȋ/>0ohEZa@T䦁>XlP =ߴġӲCIUtP5|/,5]:16OpIo}\=13ؼyfY؍c}ux'Ԑ>N ycnJcMV?c6(i**;jAXCs2Q_ZE_L}綂垻'ݹsrYa1_!Gr*&e@m٣>\QA&po~WLq]΅68"]V`m|,StxEH82ā\/MY2]!f3l`y[Ɵ2ѹ`%L'̲ R~a*q Mf037Qh:S@).4xP9ڷnȓB0Ҩ 5[5Zi?l_`Ƒ \|eӟ὾7$-g^_YsZoU[瞛'1kcc7#ISËB\ f"7^9W1:[ڐ6BfLL 2x-ykذӈtXQDZܷ}|C\\!_3Xnq)7giu$x ys`~,["F/fmJ7BS:sO ?3j+GҀG=446z g瞟q |Lc|Ac'͸'ErC}r5_`3'҆aF&\'XX6lఖٴ\H;2(CguN-C V_p;>AASؑO,x3.߭z ?+"'ڎLg|gylH{}:vlxY<s;|&/x;WOOC>nH3MBIgwSM.W5@5h,;@v~Bp/BB*cҢA~LjN n%Z\HA,e#_,oZPG<`ãOƼg| 4Pi93G!yΡk؈\9C燙mqig6 ?D~ڦ63tnf[S`oL⼚, ANi`dy`t GcϭiNMӴp|B}ۂGk3^~K82Ц=mɫxO D9V1%{E~\`R"5aۧLdOW4i,l釈Q&i14JG^vXӒW~%u"喯_8B} ":y=xa]G@/6 %6,th99y 4(j/Ӎ lPۙNc 6ՠc7 cҬٟ5Cs4rb.T&!V #neӐgޥUrlܣg1dz}b|즜v#i"8ce(g"]0퓳|e{E>qkg"qis'ait%8AhgvvSxg lW+>>A]i1H)O ڐfgH:=\ RnL S~ :3`G}&gm#Q[%,9S.6YUk>*lR}(7ƣ/Z8Gދ zN:fNѶx 8&,$`LZYf43`9# ʐޗ1;[:؇WKC;NrfK̻#xakg6(kbtDX_-ms7_mbOkoj%5.6tTh̒4&ơI7"`3;d_"6ߋ[PiK J=Amh>f#}.jUK$H_ 7Q豭6=L1ZZ|^ډﳅEe?ұ_ﳄLl`f9mgGP}E>y#^*ŋCx-!c(0SZЋ9L4*Y_0a<5d҂8#l1Nq;:h/|;56c|'_="g'DV|e;cD8ď-<%iqdr-~ ?yHSFKgq7 4Hf%fAQ+/WdI8||V*6^x}!v/6 sl͵L|y(+x}4G:8:-9d6 ,o'ƙ]Z59 V[ctXЉgta揍Oc۫z׬\UWyS!6u0'eK,+]F6V㥌DpuэW'dg-_ot 1_֋t,2G:UWq`KECx-!cr|NCGZAC߆l\i[ :MڤӷPTXؙחz0}lKkY6ǣ >.R~WFѢ޶DKLKqrczB" ^ͮ(;82-^#i~Ds`KN@q_A8z'Ay3j э9T8o1S3|C[|5P}z}x.x)õ Ё[x0YcvZtG=a.xGFڈuepLlwcrt"2Ґ~M3"he"C#6jБw `0v3S g}/kx˗н7g~0xM|qm"=E:y[n}i/d7޷v[w;;x_Y$# KnjeViDqiFzKFF ﵶyk|0uskJShde3S7>2۠GMFSi·W;gCVADۛ@|,0zݧj_!cf_b'lز:2~]80gTZ "Kh7uE?ڑZbTg %WʵARp<8cN0[ӏ4q_aeCb#ñ>䒁LJ9 X0081--??}[|&O2x%v*d0}ӉiD~H"gdSѷR>ơLdzs'&'HFo͓7\[4{t/| 6:e`8(5{#xAO|*&vkiv?*8wT2I&Y LxQ%.TG*~g4`88O:c3vV}';o ^AQ˓Gt,yEVpi(͉Ufvt405M 9f>hO<ڀFEr?,5#C: nN{ٟPo ǏC^u(ց80iƩlj:ڽ;,#4-in6 X{R)zDZrT&>t-pߣ@uυx) (򯾔)6>U :H;⼯qÿđח9ˆC\O!Ǥa}]^']gزJ JBWsA$}ISR۝`R) /x lLc|R|%ֿ7?;WV2k8{a'~CfXα8e u\FF&Z-zA2_kG TfEJ)nge揝 Ƙř:v.qe6Kp `&e|ӸЉg\l@Q#V(c]2GG9iBN8gu8I\[b(i\RKڛXeb|er<;gh% [P{5>GgixO5oظ#NMN"?8yqꊫS<Բkxg @ΎXi59-ӛo2tSɲ y-u&r^юc!:،'](Nj|C`Wl9`$:?Ljs#)KeN#$Z+'䑤OU1-:.OhU_>ewaj?">R+T򦁓]~`3[p1j'?EΞWih.t4dT,9k>ƖOyBy!v ]<ˆGq#6^lIg01(K|ʘcNNsUg?Îk̻y%އO}!u}+nyK8!ʌwJzL2 ڐa[F@I{_*&k_ZɶC[r6"BS/~񋇕 ]̗ '|K_zHG1}#`/b̦BJ$y,ʆ ?yCtW i89gҊt5c -}7irY ` h(zXȩ8H9T62Gy:<Ew :o-3QvLorKII)0i7㟚RU>[^xqzڔsJ .oPU48cg3MrIc'=IG1lJS&C4g>;G6^S"N'C   X D֑8u侼"O`eqt>ue'P~c5f{Q\# OxBـ2FGof't8W tt_e[ }nrG&^_ + ?]}i YN¥L vN .Eԣ]Lp~)Fvt{Sҙq: 1ҁ4:Bc!V'GҀ5AsBو' ukpþrtn:4Ho5a+vdlC 7S_|;>P[p&LNjʃ ˧mfy %}m΅K JAQ~SE8S &o &`fOyr r 4L#;阎H>ȵdo-Oخkfn^'>P<Ӎϲ%s}=6I;i{OK^.Mn2uBܹsm@4Ιc}: !WVwBrx3D†('IDATqheĕ{ֳ}[ȏx 1Y|NZstH<1 rߟMq1 .?BpOrr>Y{~ԡezԭكqe#䑫u0v凴t_kgIW'ByBB\Lg.x#kn&c7> .YcO;T0b9y?Ȫײ!?C8)ȫS>h4dqb| NĎ C8iIkNK=4iGDL:פ@M'ڊ:A95y@jXʽȕEě_N!\})YQcai^𽠁P,CYXa`;zF69Ctc eL3?j: ~.x1 wm#K.bx)o~,@5ك4«\9_ k /zы =C"6M\10NcӢ~}7}ƕ3ΠN mSS/U "SC3,5M"ddo9yHtpA72<>Йz0#x-}ģ&# M]_pҍ cӢ SGyX*K84*Q'59m }r8<:-V%.Ee[+%cU@vΜrQ[)CZr4 N92Ҕfq ]gic9e*>&_pӟt7 mEq ¡T8v?L#šuZϠ]6[dݥ@n!t9~Qg,6TdyM6iBsBqi-<2 3pdqljQ}:Ɛ\M.NǮx Ow.@!.-W&״vG'=[g;:ͨle3ƽ+>fiQd#WtJ:3E~Zܒx⃥л-k^ÝX/leq:8ƞ]z3.ԆI]{AqmHSF(](=g03#icj2{|[+1BuK˸| |!8256e/{Yo{[Ot򖷐CIٳgoP2I#A q)V1HFaci+hc V @@i 3xϽ*\$kԉҀ\\.vDc' х/Ч0βT;7+WIgɷaҭЪ\1tfZ~ Z2 jOOeĵM\ZƣxmѤ N2xeȏxg0|Ҳ]#ѡ_ 3?QE e?֥BYɽs)[3wx}I!;tؠQ``ro?dBKZ *29/Y?G^(ekgZFKP`!^ariˡ%|e^^W?K9 ķ w,ٚwTJ4ĉclh6`L&#B`ɟu5\jHkBQv_B'dZޙ9]TJFgEsn3tY&"Ρ->T(fǀ}{+H@Eϴwsܖ{`iBuGH1C7ch/C'ōGN)|('-ˆGYpx!Y54}!1qo\^wLF5j//t+˴!pdž6zշ8HeH&qM_bM<*s(Tv.hYAA> '?ˆG?ӔF8<qi VdG(+_S/ܢc*3vG}ZN!c[PkrW}TʍVg}K `sI%+6ky3q6GHb<ڣ3j+ ->tr +-ţ4`o:҅oOzy9B7ۭ_ʛų.#|ObYFٽ }rΧƩѡs?M!8- gxTރcҀGƸŕP~e:LSVY_>z9f,&]yɇm7k6yT(o}'G }/xzZ<; ~ 7!ʳO~po>v1ˏGzehS!g\~'x +M;Q'?jB^ߙqaY+ay7ҟ𵨥B_6>#YPyyo?D=ۆF]*Q<..{ \u Y ˗'іxLO0Q"M^e[[yӖy+.!83?o-ض A]l[Ij۴.A {oN=ʼn{8ru!iXCʋr6HGÛX:ۀNdaq6A.']/%ޗ(#ni[r e,,3Fc?6aJ[ȺGwOh(fE;[ Q>Ibq}_#@Z.3XrCzlؐD~+Q#`pM!3&6j#qvD*o|,Gc1V# |5OL'Q ȵdُaƥs*w^B ^CZw?swqsLg ^ud1?Dz &21]ـ<Ï|g~+2p@o05ȏxVNr2e\آȗ@N]^z}>><3oP^(*2 Yt?["ؤC0 8!aA<3T/Ӈc, bϫVN/9#n>< _Cr->s߀LL#,(-qpPv)m@&*l3%cdxʬ]6o ͧ@cGf5:eHi@ , ٦L'NթٛMLy7M{H7]),%mNu-2hpf #5V$Xhg8k3N'3_^ϱ}NZnʌyF6 i hP_|K_z6:[3Zeϗg{%ح̮9d޴`w51DYf_GYXhzcZlksrst݃3 V,#[  8FWick(E|oojqyr3L7٥hkOOOo9cclAjS/¡&)׽G~ &>jK}׾6&ȝqc|E.KAnxq(KAҢνyG;"$G޸ƅ-:9vs˻<`LFgşlS9Bl1#t ,sO9~l('f SexA .3ph5i"=6H%"(c9jG(8PƓVޜg=pثK1}x.KeX:.ܥεw{)p_-ys[{4o9@&cL?i.7`>24LOS8d{Io==1/Y&'կ~V:Ijϱ[VZ}c | )lh0K]<)඀ jDB5.lpi=ӬPL#r6!ۚ=yNW I634:ltQ!c>[@xdȩ=)/l˰עSaStHW[JGʛg !t~%2X9E  @#kk8ג/~P;@Bcϸ [tsG/瑏rIJ_s#/؍m(;[%uI8㥓F89}e. &'!"G[܂pwwWL#CmfQC=`-ļǎ1eMW;@lF(͕bm^]P 8SVn 8VtFNCCr&4>:ː^nr~_эqeL7-:=ud6 k6B)Ւ;yy XrvmϽdž|4̐-^aUBVٖqbYKM}6O}jˮnC~ll5f(tm?P2[oɀdg6!| [ /ovxrKlq{d iI7ƣyL񍝝U9Rk4ẇ8_Y+>]!ssj:??uf(s S־HDZ6*a_Svm2b{7?4ѹ̚tz.u`i[:fm/)k)۩Td@砇]<8j+cԛ Gfm/i#%YS5oI>t-_^65D#-?n X 4<}䗲5򵔭)vPGOk?v 8<9~XBsWpY 􅱝Ɲm䗲5k)[cp¬_D_,;՝g{A4sķL? P ܸ|m+O!knU&GJ9."mqCEl>QV XlfjssB !rz\;]Vb>ڣ %/w6w*(dyr;pܣ;T߂xZ@ؼ-e+!}ry"9_1OtG7ϗ/eL>h9+<>5ZBg Rir55_-[c_:cLi(Z< o9n_e8S]G5` p֪u-җ5uJ@?7-@* -3{ }/րg  `>(mښ'5O\ST8ư_d:?+.ܐ+XK孺}^,ӇsKc*ݱE-sU䕲SM~Ae8Wf# @?c-e+kʶX) 8C5_サt ǙHp䗿e8>|(;`.C4Gvo? rΗ膻߯,|y]e$[ [+lͱC=o;|qN(7K엛ne8[8[\!0t㭎oj#})[SpXNg pbWShc0p@rqW ɼqW&Q'Nf) t[n֏s8@Y7p.:4tJ.:5g8oA:<ۙٹ Ob^K.'}Qw q>>777000...cccmmmgggbbbﻻ TTTQQQNNNKKKHHHFFFCCC@@@===:::888555222///888999222+++)))dddccc^^^eee___\\\ZZZWWWPPPFFFCCCGGGKKKOOOMMMDDD===;;;888555666555---&&&000```ZZZUUUpkkkhhheee___GGG999@@@GGGNNNUUU\\\cccjjj^^^FFFAAA>>>;;;777000(((!!!HHHVVVQQQRRRpϥvvvtttqqqjjj@@@<<>>YYYYYYYYYSSSpSSSSSSSSSSSSLLLDDD***SSSSSSSSSSSSpOOOMMMMMMMMM\\\UUUNNN>>>...MMMMMMMMMOOOGGGGGGGGGNNNfff___WWWMMM"""CCCGGGGGGGGGBBB AAAAAAAAA\\\ppphhhaaaWWW***444AAAAAAAAABBB <<<;;;;;;;;;wwwyyyrrrkkk```---!!!;;;;;;;;;<<<555555555555vvv|||ttt\\\(((5555555555551110////////////nnntttBBB%%% ////////////1110***@))))))))))))```|||vvvqqqmmmFFF+++&&&!!!))))))))))))***@$$$`############;;;rrrxxxrrrmmmhhhbbb]]]XXXlllgggaaa[[[===888333---(((###############$$$`@###HHHiiiiiiddd___YYYTTTNNNJJJDDD>>>999444...)))$$$@0444IIIVVVUUUPPPKKKEEE@@@;;;666000)))!!!0###,,,)))&&&$$$  pp@@( @ PP  00 |||qqqggg\\\WWWjjj uuujjj___UUUJJJ???PPP|||zzzXXX>>>555111000888DDDBBB888===gggnnnxxx︸iiiOOOKKKFFFBBB>>>:::555111444:::000444ddd```ﯯuuu```\\\JJJCCCGGGOOOTTTOOO>>>:::888444)))444[[[RRRߦqqqiii@@@???IIITTT^^^iiissssssKKKCCC===---"""FFFMMMppp ~~~FFFCCCMMMcccPPPLLL666&&&///GGGKKK PoooGGGQQQZZZtttzzzYYYJJJ)))!!!AAA999PeeeUUUSSSZZZwwwfff___,,,!!!777333tttccccccMMMZZZxxxsssnnn000%%%///---lllzzzzzzqqqrrrQQQZZZfffppp|||333(((+++(((dddzzzzzzpppqqqlllZZZqqqsss777,,,)))"""\\\qqqpppfffPhhhvvviiittt|||:::///$$$^^^hhhfffP``` ______^^^>>>... ______``` WWWWWWLLLBBB&&&000WWWWWWNNNNNN\\\aaaPPP:::FFFNNNNNN@@@DDDEEEooo^^^KKK&&&EEEDDD@@@<<<<<>>===zzz|||ggg555###===>>>222222rrrqqq:::222222))) &&&&&&[[[}}}rrrkkkMMM'''&&&&&&)))  ///KKK___UUUJJJ???555*** ``(  0@@0zzzeeeUUUccc~~~TTT@@@888444999;;;cccgggFFFHHH]]]bbbDDD444:::eee0ZZZNNN{{{OOO'''@@@0@XXXOOOlll***///ooo@ttt@tttUUUhhh111'''___ttt@eee0jjj888]]]eee0PPP襤sss222###PPP@@@[[[RRR222@@@///UUUUUU!!!/// 333YYY___cccRRR///   0@@0SuperCollider-Source/icons/sc_ide.svg000644 000765 000024 00000005077 12321461511 020744 0ustar00crucialstaff000000 000000 SuperCollider Icon SVG - Batuhan Bozkurt 2012 SuperCollider-Source/icons/sc_ide_1024.png000644 000765 000024 00000243540 12321461511 021376 0ustar00crucialstaff000000 000000 PNG  IHDR+tEXtSoftwareAdobe ImageReadyqe<GIDATxYy_$0,`f7}d[NttϝU~+KWI_$9Yq KBuz} jRյsN~8`9C0@*)½bƊ[GWsP*~Yspz'w羀oL`W$؉pw2B¾\CvNrG{.N_ w|Tw4^?ӹrOX>?ݠ>pC8_ot[@/d}AΝ;;1 HOw9_otLJt)|tI  Wxgu;w\,)XrN)1t>)S`۷wbg~Vo.ay ;(28 { &sݍIsȐ!C֭[;1soC!Cp@\`C[n28 p:_b\qC^@ p~V~ `rOyL#;}N^t7o,a`Y9耛7o9p@>3x\~GyI#t8@< 8nܸQ8 {sхE Z=9nܸAA'ҦܫÇG΀ׯ D;&%9_ Ek"`;˜PLZZZ}۰1"~D+r3~J:_#kz;IOFݻcǐ!C>v)8r!;ZD܏ vZ s0MUb P4{DZw8A!*@ڌ9?9^SHB`%xիtYKj+0㝫W0¿@~x#`'PQFms;%֕+Wv` _o8V >޾r u@soνG{.!CW_^//߃5 r)=Ca?N}W_8pѣQpe:?8#@ƌ#.]8#bȉ>}lu-X @/^~}&!fر?pX >޺xL8 ]?ŋwb P_kſk@Α-`p~Ǜ/^,a ߆5rvpS(ց8 mhYm- liiO@H " 5ƍs] |!Cup ¿ùW!G@ Sȣ' 8Ο?O}Wuxc 2~¿kDbΝP B[Ν#-p@so՟<dW4L8 >;Ν+a 3a@&>>{,i=νU`#FpZuݻwok^̢>^?{NL8 N/EK0^ɓ' 8 _߃5 -Ə ~=kv8l8IWy9RdxɓνVIU~ 86U>YK~ %$>1yd ~oj7i$OW#ri ^#@>} ?.FʭX{R $o;vl;f?!Ϛ5 &ԝzԗ:R ;{P }K`S^H>Ow(w8SN>%0=0QDۈX%e/9 *ѣGw`0X+cրJWǎKC;N;"!l<)D@xѣWw8B#/?egذaQA}<^~DQPzPXM*Px3p&nc$>{ VGى)pQ gϞ#G/XˆVuN>O#P796fPO? `o?oA {#*q@]V|p8qpB9 9}$) Gǫ pȑ`ӧO!߿h__+n^t{aG]M.(&3g3sLgĈ 0"VnŪw>?O 'D/rf`߆%+6 8ثhN>O~2i_p3f`b1j(/_+ExqE|>O g@aW>Lq@? -Z eߎCqs)Ç  7bB+*XD?*S28 W'6b~QE,ny^iKA;0pEvX~PDC6Jv_8I/Q#8׷30IST[GF {$T{)-@`G__pd.|T#:!r#ԝk_8 lCLĿHEv7{{{ 8 www;N0rD~;2!"rbGoo/m _8ygҥի1cƄ]Q*M7W2e_a^>Oqh?S1ϓop1ƍq…0@k0&+UOig w,YjK>2ܰ*$8A6^83k,ĿE(Ŋ`Fdʍm셓2)0Z8tN"!O:SNM}Yo*e8^iKrP'kM?oÇ'-'!C64iag̙*Qi7.d3u_A_{m͛^$}6~ϟ &9sH%V`Bm۱ܗ#F_^?pE@CP>R}eʊg$9.Sɼbe5&}hF[Ǐw9"LEE6n,^ ؗ-ۄt!v{ѝ֭[C$p@CL(Θ1c %^DBDWaPmaÆq߿f"@ Xn:gر_C-ۄr;d5|h= @4@n:a"@7o^JڒnyLJAR/{d/#8p+"9b…^?LV)*<ٗ yS7ș`ĉ}gϞ •`Z_f6E=Z۩/ {e/E rہ@K.uyN0M8>kўC-̙3*fQ>O|WH /6m*aRHr3c1?>|ϾSLL2ek&Lm5FW_}\|yߎ?>{ׯ;ΝsUո8B2|>}_.pu?Ƣ:I$%2>'Ni^8Dy:s@gzQN>O|lȑ#ȉ`޽8AgٳG^"_|6]+ PĀ9 ǀpQ_–?]?:Ҭ>MxjK~oooȱϾȷQ7=.Fל8qbI~i|WRw?2p&ܧG+0.'`Rz͍R+EI;5) g \9p̃&$9شw^Z,Y`` 1)$4+W^~GԈ=O<9B~Fꄉ+ Եvf; ڵkk5:Jm$%UQ_ϕpjϟXꕘb/9(?7ߢE%63'#H=}GPm}WR$%'(< .EIZBmYu+z6gQFZ充9N:5F`5z%fkСΘ1cn`sϞ=0H^k kŌ3ʉ &/_nFKE99;8)Ӱ"FD< '@+V"jثھ/+<QN'u*#*8)=<^uS4)8p@#BO?rM~;qK#BÈ9Dyt =g~9%P$sS쥔c%@'={1E>m0yd/߿?FٗJZ7M!39;z3@6_^C.Ʊ?3Ŀtuuy0 ViFp~_j˗tOyDQq .x΀^;)G86C,aZ_nW/ TPQIaBm%gd(/?S s P6]ۺRV/5?m8`ܻX ~ -$}g,ܾǗ1;T;@,=8z! P !C^߽{,8‰O̙3ǫ4?)$zfS3FGǗ1Gܼy3i>\ϳ:5 9{1&\vX#{V\T'LAEQ&y׼yiKT/AO(JӧqR:,x\u'@ݻKpTaɒ%ZR+IP&Q&L̟?ER:&3`WB}*pĉ32G> p<=j˶yABG ZݗC^qEyN [/cR;>/2xI׫,E>n8gȑLl p|gݘL!`W-X"[ΝʖBZM{u_q}a/www;>3}toBvjF4,ISKK3i$!|Q׫(׳,Q!ʾno4k׮y!}V S&u:uL8X"[6l<&_6L ؗ.]<^H"˻(g"6m譫Wz]LƄM?E '@sjkkrԩd?}zKdºygU'+tT磒<ِ1;vKs׫(ק"^ߓC=O?tfPT|Dv(؟i0 4o/9ԾNz+|)D )8p Jp\ϓĿ̜O? )Uvo|3ye׊?/Ϥc̎@z^r8#ep( K._ƨ؟r iK_+3˩ADCL;ӧO{΀ÇO`x$dO>= E!&MsiȆŋ;k׮}V<cRރeP$o^8nW'vg̙^8K۷o'~ f_!֭[ ^Zu0Yt mٰqF "6$'O ˑꩧM6y۩_Gu.^ 5`1Z)\ȔI&uIׇc:gĠV^\q&PZ65iҤ'ORRo9O}P/_AI/zꩦCx8ElpTpҳ_ה;$UH.y뻘b/SuL)٪z'N( );ݭH'|4B!{js*ɭšno?qLgϞu=gy=/0q(c•.j ? AĎ+Z(2ZW!j)ǨU~ݞ>Yuu?tרTVi7nzξg<*cԨQL+ x 0mv,===^5xSDlVMցRɺyo1!K}iS"A”)SOѿſ 1ھ:FyT토-Ϙ4"g򿩚 M6͋OL=E$@hm2'>mʜMr:*n:gM3I, xS>z z' !zҶ5Rcʔ)C?SȄz}zKd+)_L8G!mpTpҳ:._\>@sw\F؃?^ |K!W(Rs/$ D?lj¸tԪQ=kw93fիW8GmxM@r}_ET+d :K= 4_%G\ NmYK!jw wHe]i&MrƏ;wf<+Pp@}%~B!i^? ’fދPrs93_o>3/" 빩0Z3ƋT??8 0D@X|:B %eI! W#GjM(u,?3uTOP9shǏk@lmoocǎc ^`~>uae6 =8T^V 93/R>c p\V'@jhQnc~)ʲepɲiӦoj~;U~y'C" <2xyzKR{{)j 'H;~1aZK$+.{-Y OFpG~wz,Mers!<|sA9/(QB P" WOWĿhH~>pA%{|69+g^ƍsڼ7nP17j@:uꏩ8 ݧ-X"9.]tww7}HKJhmmE 8@c3OXӦM~VZN q; AQsjźǎS@#&zXbsoB%*M }_M0ygʔ)8g ot||zK={x̝/^:vX&D@=eZ%B}y(TdܾfΜA&Oa7J*ɳُ^Nu_|2ɳeԩ{QRPbdĿ ~z۵\=3b ۱ (Ι7l0gܹ^rYtiSNy 1]@TeŊjX"&Nlٲe yqMj|/{ K=m?gy>bZs=lu( E=6SNxQZ &JV\I˿ſĥVmlHYxq$W#.93>}ګ p-+a6+ǦwHj AgIF?~uA?vm9<؄s|r/_[m1?}sy=TB bʕݧװDr_}ao&N&ڗD !is5y۽ &)mƸqg̘1C6M6ѣ;1AZJ?o}[:= q 2*ĸdɒz  vιǯ.z9sCz^Қ/ڗ7n=ӧOȑ#'0P|!w`y駝y՝P }͛Vl/1q|>0$8?3… <_sƏԀ)) 1mڴr`d3 (˾3Td9gL= 5:rH SR ի OٲeQ~q#q/UO0lo^gd͛ݻhZ1_={6NdoK*@A!L>P?UP;w: 5}|^P%Qs&/]95X!իW8ǎ*;M}Or$׮]tww:D!vLرcJۣF U-,}:BPmbJ_)!Q!aBƍ{K&PfI+9rʷ =}+d/gϟ٦sfgOy{1_;~t5$I( 3ds_8np~/ھ¾wq\(/(y\9۵xUBwmrqW]WI g]rUIKڳ]sҥٳØ/~ǎsND3^ӁxY}K˺uB^&Ay]P+V}V{[1zDѣ~/8:q9g-pԩ&+)>|3g|A>M3"1AݟĿUr.}e\iK+W7+Dn=*,_ZUDܟmj&x~ɓ'~&߳Ϙ1Ëطos֭\Ӝ/ qQ^snP(k׮ Pw]ZdxZY}UZ9W03gJu:?k(9 P6N j$}|ٳ+Ikl5tPre[oc`rPѿ8!1Ju|Zף\.㦎)?oERS ---άY:__B @1xjC~zfT_ժ=c6eľ/-_C#C("@=(wh=4rHg݃Je_ǎz_7)Yn]!E r\jOO:V_;vB:c6APdM}"?v՜8pl="T׿Ǹr[݋w`xx׼3n& 3ɑ z}f4_* xA <v">@N k̘1NG) 2WB ݼ~yƄi5͏5}th׌ nld/UK:l_z,_sh ߩ,]&^lWѢER>}{|tۋ%Auӷ1ԯD'qП?=YM Dڽ)-oYwf˗ q" +9BN KZ[):_0],c)3gC,h_e<5=VQVZj^QWVdVմBf ",dÆ ۜ{c^@ENrL׊B>Q -:X؄.1KظqV/DtpdMۗD=NʿɱN_D?5P , Bk9<(B*ayl@,t L*X#~7" j0ܾQ CSj~D?c9TrŞLH0:Uy{9_:.zʽGA|C 7ܧ, _ ̆(jAWD=}joo=6 hD?pT.Νsv=JЖ넍f/"? oBrVDBzCc;/D䜞}uh o| ڍ$Eߗ7nXsQ_V1LOAG@3jgT+/XQmy(@˗/{ۗHE@d:::~\*.` P9Vahlڴɛh5{crC㾚ݷDV QnInٳ#i%ȘyEL4|ﻥ9~*GX׽)"ER)>%1k,ɭlWd&8~wDy\*_>Uџ͘}Gyyw  ǹGIcm H( ࣒ $B y7o쳺-Ncr̛7ٷon#qDE@$i /+VpΝ{_,IY+y9}4ќ[tV{4W޸qû/ f)p@ _wݧ, ߴiSl77(7r{z+4ʕ+Π7a_fϞ<`%d̈cVDj|ݻ[!'7l{9(._@Htbs!pym6,̈́5t-})ժUx)7=:Oh7џ1+*H5A%tԩnEI\:ciK)1&L yZ9bߡCva '"a K=apQU #}5(OǤs_Z(?O~s~>ypT(\i]J#@+̈́ rj֭[V=̧ P/juСw0 Xl٠tIH⼡]W͛7{V?v*} zۚ=}98"rp{z_o{|IgҤIu',~Vy3þF_zaI]{|BjF^q͚sHRh ,0ٳgK4+2<0,E5A z ߮ ռ6Q!͘Q_J P9ޢ[U䗢5l{d/YIh]?tNLpGkYpa"7"\|Snʆ U.EeTN\hƜϦɎ *%@ƣG6 9/! QҥBLk\J5jWϞ=o:ԏ)́^p(_-cLme羞z) <5jP9eHSd)F]g=feۿ9Ǐ/(7)~̙3V=Zs:th0{K!ų/ 'x:Qn-v ~ )uTșsPDQnE7oz1D Epԛ6:Jr\W^:@S`$ͳjժ^,sj gB4[3w2}ƜZǬi]_+7rttt8RɹuV.WRGT] CxYo>\y] 5kx+Lx–T*>Dh7OQDSƬs] wd|o}C˗/b}) `ĉl9s|/M /xyYymeà}-YDg]7rnVBMFDcֵKcU Pl+rL*6h,uBC-C g˖-Zu… gyͰkI˭[no'FcF8ؿ&i-s#ٳ^J ym~{__y0me>ոϟu(4LD!q+ "t-Fy~OfE%!?rH/^D?ce#?cV T0t-[NvҥA:GZ3EL^vb Ew!?4k׮ZԛR}yk/8k_8e] zT;sSxϘ8fu-@8q{KFu_YNʿg5H-@h80²e˖mkX"RgXzE8]W:`莊)Sx5MT?=t+bReY=Ƹ(4-s;p.L |b3ƽ+gÆ M/r8e3T/|nƌg̶yƌ^_ιs縷dЊٕwirNe_!۱^׫Gف qoܧmX"Ъ߰s{%b &NmW,E!D3fD?qT5k'@.{KU@Q6͉^vTii!7$s% @p?TOѳ7ĸ '䷏7{mH!L1#scV] uPʙ0A:2 ;3IjpWnuKcku0N$ƵqFoQO9\38c6U5r е5poIu/bJ yv{gWi|s*p/0EP # 3f5pA*ކ})_YM<>qjv&'1#3cNH^qg׹]Ec0eJ_~3i$ Gz}̐.Dd7i; RzE\uͼVvcv\WD?cӘ؎ ?s/{KzN D(̸u! cܹ߿)pXAKgڴi^Ⱥ7ۣC+ϛ7oM}^o~uϝ;wJ1"ն)g?s9-qlo^^/{ĉDEl 8cƌA ~ӟ A t ?cƌq&+o۾̙SU7;Lz$1qLv9fQ^ Z⾞7gVoQCPZKM"k,9N4]wgϞ5aSQqclt\ǎWEB]݄ AHHo~`h66vXgٲeuCm$e=rfq$}jծoFJ@Hz= DX_lDڦNgggtEym PZU* Y0wS%*, ?Hˆ׮][|^'!&Ieܸq9y&ج1 ;HOJhC9C@|]_@S0D^YMf]OրQa1 ugҤIDd߾} /_C<^% pBg`Ja39Y/MrPHOSghЊJ R`ckGCwM)j{oZԪoeABDS|E)J_3z$/EP @@`Z^Zȝ!ظquH{͚5 H?͉['ϸc[j=Wn ںiI(1OnNʚEIkrU WA-Ptݻ8+>%!yf/QU*6L2nO$%8†*sM)Ɨ!9$FTG@9,:'r(I-LM,68t/&̉+qVw~޽{K"^&ǟGY-ZuͪeL^ZhELmld4qӍZ+AE3z̚W/׫UG׆1SUXP9D  ?jzo &x4 C\{VS-cxW:ܧX"Z^jՠhE.ضKWD}r/ƘA+E-Ɨ1$5&=փ ST Dَc N'Si"DaƱ/Bӵ`K1@f~P߃%rA_ؗٳG'Y_7g Cq>E׽aſHlp4hUX gHM{C-{)"H",rByM^WY8#d7j޽{wbϱB04)SۿZRK7adT36I1Go̚XW H鋚_@PN4C~EZإq(RrFۣĉNGG!]31} ,.a~}_jls|X_bmט%%O\+"꧌?~j7_T_wh[WHңҁFk`9bS0WzѤKL\ۜбŋF4"&zP'Q_tGCǠtQikkVyoǘUbԩ2d݄{g!YsZ})SW30[vO%aiBkUMPW^eLߤ^&q44&hPHjUrD˿BwTUD횓:kCfg3R@ nq۰B0ZoBkUUOEi1kr /j-1UWv sj5Ι3gr~,Ί+_י /ˑ@u5TO#ȔJ?q:VzڎC@,\]K4F ֻGݖ}IkSQv:i8'6YW\q._쭪#OB1QYџ1Ç7~ZPU:y#}Q _|;1 rT7͋-2_]]JYҥKs4؜kH@*ʤN?c@NӧO0ԯ!'@ 4}'Oް0x.\b8@Sh+2ȅ2iKbΝ[ў$Hu47Y@֟;x7y+S4$Z>rDKY1Jý1y G Qa+8~4 D?  o}KX1ZG=/ggJuIBno^qsKW?Ɏ _e?ܤ)deW};楟 3f9o~_xNIޛӼ_=>}l1o͚5tθ` * hVgΜIX}i_@pEU+:VTo5YW)UzCeD@c֪kggS*}4=_7CZ8ߗش(B{O<$ßcΒ.a/6Hw:B$'9xGl Ff1{U[+VާkkfLqC1q AT;]>r̛7ϻ^EQSi\mr(ΏJޙmEw=~8"ݕD?s=)4ލiu)0Q(W1$'/mVϟ??_*7i Z_~@R||ᇹ j>P^_YOn6ڳt.D*,֚T7}IW5*vՠ(?An T&~?4{^^oyJDyc;vwo8zh,Yo<־UGdƌ`ٳ1hv~o~\ }ɁZ3+Hi Yz/Wb ӿ{{64j(O6 3+a;.]h ŋ_!97 <~^2IT)1Vgx c26M/_mU30IgNo]rWcPX]`TE=w-z3ךZ)\׮]=tk3UjH @0ݝ5`&LYߤ]a9Lcjj™U ڀuuu z2Qƪ@cVJ B=ɹD  $w:/՗Gرc7z$0FP傚7/yAQ^IM?s挷{R 4u1)Y]lLK >r(5/^Zzvݣä%3㐭y ڢcvM@@6L\~6i_'O~`$X)sI3|W.*7i y9չVO>魞u+( @aEڙ2ր?t}3 @e. XIKLqbW26kџUήV(92IP{:SD^j5f9{zzi;R沊% ,nHw-k%ĬZeu ^Y_M=Ҿ ݞBeZTgljVYZN8}Mi m2qD/@ʊiW/5Uyr8m׽͛|~mLb);i.!Pŋ{10A/2ޥ*j}@5j;w7q'WF~M5+|7#_orymVZ5iJҮYkE(}޽^ͬ[E.\+p*ǧ <:$hoܸQw~v>eʾ3RjԩSNۅC @8h30֣Uy{a_ӧOV Mxh5&yyٽxS*IFmLSZJcU?&{_zyiejzm{_rUtZHw]n:qvY\˻?B cI/U<N:sk:{l4g}M / Xu;Fџv}.ƺOIr~ кd@ @//={+ɰ =p3sU[M><4& //W?Zi Qϵ%J OqɏY|z( {_sivݿ[ZZ1GWjJ[`AV0i  84@tUN=ך4ZyKk̚P`菺rT V@7_Z4/9JeIz]۷=#_l9G=εM:::?ua̙3'C%k=a_S^$Vxnխ[_y^l̑z;{u C~-RD-WXuCpSiYvٲe7^-[m;EJIQQ@U4@^ e̊M%7 ~_їGGy<\þWzE Z'&~JOgu<ѣG;+WMqH{̫V~{e ѡI? *6tßɟO%j/B.!@\_(?vެux_]-J^5/S >1M!cRRΜ9\~=׭f_}mȑޯ.'>yqLW'A}~t xO?STa>Ӛ%ؾ۹GXƽ^ͼ&̾Ο?ܤ)Ps-qj݋Ԙ㾦Κ5kǘ2#Goʾ8@H-ZdPClU,g(Oc{`j >IGĿW#>C(ƹ^xC?R4'}UbΘzT@E6=X6*7.f&f15`㙤B*1;wEl9f+jcm9AC~cǎw}!%A?'p])W^MlgʾWҥK˗( @Հ5?Sl̙3cRھ ٪V"u,~Mۓ#ĹB9mmm^OSjYW4V퓾_2PJej+1j^c!HjӲt?|_`P>ݹoƾ$QjV62%ٳN__ 4jAB2i Yt)SrMz2>v̫WB9> unVzT@ GAG?(v*yi X-ג`mB_+ '9;pL;J(/ U ~J1+ʢVda+ (?S{蹰Pn;=4k?/_ɳItTQ?YM-& Z't{n&MI1O0͊P?Sh>6h]t{|)/ٴը2~XMzZ/J5^ĕϴW-nҶ1{\I^\&5f?>!!'i:Aۈ:bߗl4n8+Ey/Z|̙9O'm9QzM[@gMkrPy"'ODBA @g~ڏe˖  Jwܹѣɇpjԛ}OIGWy(!֤)\޹Vz+ VZԬ,!#8G{ܽVթ{{o}Rz3J=tu zkjkP@ w̱P9i/|TtQo ce)xVmH5lSZm7%4f} Oϔ8 Iqw!/}ؒ zUT\p#ۥ4vҥMM(sM]{ǼgϞBOI;wl~S(cP nZ;sSVsbKpS@G@?LD )L?%.}ov/.ƺѺOI08upy$ ۮ(e֬YYl:Ey GY$+{Tam.dQqȑ$''b޴iSrW o=^W<:|fM12$)'ѳ*$@?7ET{y?dU01OLLS'NA)v$s5uД[?V{*d:dQ ɓ-͏e{dt-?+$iJl _=7|spl Ih%wڇIs 6 _`= ?Bd:v^N:EҎGx (![`#?5)֪U_Cr:TwY7Z}Hr$@>]q,X hCW )9t{@]8R :~8IK;/̍CP/'N8IZy}յϞ=[JO_3˗G~ ^{_깪艹_ScgSӹl\W1Uʕ?~xHBs찉,9Ȟ(Dž:w="wSOi.Zw븗g bC t{&L3ٗkŋΝ %@Gg?C qW &.`:Dc/TcuϞ=Jc"$ 1K.$Bh `UR_}49ʤ܆#s9Bqhy`}݃^x!kү{-[ ^~墂KkwhC8N7TTt|;-@'YP e?Ic,g bB2țQG]Nd`P* 4C80O-`HJκx`o~ǔU6B$jD9l:uY8a >:oGxLPRjI$p1|m#$(]wvN>]dnzl?P10ޑS*8DxCRuֽ}<C;|9_n;Z})or!XW! }s#,z O9`UErf}"I c71_}05553n{_~1 .57+ 4!Wj3ُs P `R{ UŋG!b-lǘŘʱTu6l@"Ӏx;vu}ZlYEIO/7fG<u݉z} JVA$![:Unݺ7\X>%%]mm#=ۿk{BUK枏܆u7 MYDSfsWևJC-!c"LЦ>&$a:qD]ΤO(e(BݩKN(P W{ s @_7'lyY?Z#T4B%v(ЀJ%@};i]׻Χr>w=]v8P{}O6kLM ;ϪdDŽ~w.5%A(WT vy=r_Cm6's: ދ'ǘץ Ϥmk/v8 ?:*?ft%LqU _HTc[];v3LN1~1VS}.cčرcE56П9sL* Cb.]:{H{ |9)AH?J@˘$+ɪB_]f2 .#=gBb3O?t~7u} G@])Е"98r^NXH 2Nؕ6*:0E|xrwQZaG{9{nLy{f̷1wuWQ)$V{STOQmf…\49~ܭ4C9o1J# -uS8mm&w|; 7k{|a (SO9ea@@ ~&~MeNd{c6u׮\9{ TaRգ@XAHU| _2g P.&=b?үۗ1C|h IJ @AIw`mo,夔:p뭷&,4&-UW_,؊-W Uϳdsr.%Kvk\ǘ3k!I}Ngy?2G`0 w_Q71ǰ6lnXF9oGYo6}_-[D{Sg׍.KCmSqp`780$0~b}aj!̟?pw ^|E#ShC.g}6yn;9L=U|P:Q,` K8HHՔj;u>3^B ȑ#ٖ!kĮΝ;?|QwBP ` [* @Y=`žKĚ{2|kxf )IExI1('d|~ P^@?11E A@'v SB|A?R] N599E|??xD:~@"Z=I?qY9ƺ6!!߹?{eʤriRVpw_#;5uuljub:} <^H@7n b2 u¦\Ϧ0j7}o$$ݿA)P-Qp-%t)*B&Ky!&|N,P( pC}yIHOםpVP9}xvZ|yTv9R=at03NP1M(Cwj߆S2caf2>7 'JTsAIWkPRVg. sC¬_M [+5J]6JR]߆SL^]?q;v(7A4ݯ!WκXUAwuj EnҞ(y[Ho@9?oj_˖-j XÇ.\IN>=x''ODO(;f߼qH(;Ʋ%)w9>Ab' 0g#C5?'ye{gfGzll(!&!=+>OZߞn֭EX5uQEJH:7=P`N ;80I'ծ mKX}X"JRi>׮+cLy|||ko9U}1ɼ;ɝ(1\.kĴ:`zM9f8M{H5NSlJ}Jf!CsΕo21m[%P_n} ?}n^S GNhI).UAk:ۗ1_>JR]ܯ9f ?/} A['YV߇X1BHk۷-gz)f'9fϞ]Yg~{ߛ:`bPMȔ l%)0Flw'،WBd)ncL{(711ǖ\gLGa?ap3su_^x:N:WdU9 O0},6cޯҗ)ہ cm_yB|o\>s_~3 4A6)K"i/bl߾=u@8n/>ӻ/(F:AsS0`glMrÃ<ݻ/'r:@ʙYӌz`ժU3*ws7FG]"כoYW%՘ȥT cXˆ 0o޼B ɓFD1# `߾}IrM`Me8y" QWSX*+VhY>3#/R/| yL>vE?4N w}\:j7pC=e>M%4 *tdQ (2ϫ 'E*IR,_ܹs#>&#bzcmu . 37涢|1G{Hh\t]L焤{:cOflJs?A2Q"0&vu K@L7o"} $Wn36:ӗ,/^>G\M !HVB|PP@OaR'?koٲe+ .\`mNv8uOްpaۆ۪y!/"_ B6B /?5,^8g0ceo$) 8QgsqPR L\65{"S V˗"}(_Z2>Wd݅ b֓ F{_˜˦;P9ɬ9wS6IΞ=I:SޘKm-*sVim˖?Ɯu m:5bz9c^U'Fy||I$J!vf)B]S[>Ƭ)]B`kݳeT0m\kkWĐ3 "u Xg ȿ\wH}]T0W<$ԮmlIW9tu)I OO_r]u{ސdnf˔3k5.dCݶVfkL Ld 8DvL̚bK=P_Tu@<֮TƬSФmn3R摩НUh_1fwS_.5ڐ)&"$/2'c"{Twb}) @1VsYr.a\<$>dL:%uF eKTϥ\:]}VIvp݆TO3SO믿~hѢ׮J S ]Hx!k@N. P q-#f{}Ǒ_m,>1ҹ'N4^ǜvսŋE?ANٳg[mMmxn'${ƷS@fԱOc/\83 Qq_mj /D]WS6(R~*cڽ{PAdo͚UPĘ7A8BYl__.MD C^:̤A!*k fSc R~c:}t.A0@s>GUP1%;f]yhRyDy92êUfn9f\r31Nq @ΥTƴgNр˗;|)?yND5Pց֮+Vɞ ) ~GC͹R Bb, 3IDyط/_^w)UŘnv[]EѣGAC$d0ց׮rث0j!g`_#zGQ^d_! qF9ݧۗ1H}*߿?'`r '@ |;D}]pI⒔WL=!Ӯ-|$ ,r.%-#$6\v6 ҿ%s̙ٽe1Y&u ԵZ M 7}>55 8&z '8wUS-).j3:uj]suv|/9$.]ZB7FVN95 3gx[B^+{u}GTll}a|KSPTdx0&ƶ)zTwm}g践[Y`?P1f*]sy #u Iy(:6J{,6'ߜ֙?zGQ\.D]OT }%rݪ:]ٷE}~j"IF8T!ٲ8|d!4.Əlj(@gϞ)w_]$]6-zŋgμS)?fOT)?sJ'B:;c<ԵmC *jn b$LYa !LME Woޭ{]VOeL uu :KR,gjLjszkj"@Will:td!Ħv,%P+Np1j?UYHi8p4=z5$A:{n9E K߲.(?)EUhr)捵'OrHR@pHdc̨j&9O7@ĘIyHc,"u$W7z tdۛHUpe2RG嘚/vs)ߋĝҠH… m/cD,5Fm";{-rغC)ZטP]]u XIrMh,66rpݮ"z51rWa(Kr'ev4@SSS_ԑ/2鯾Y 1p &}޼yЎ>CN믿LڅDp"5cQڣj66RulW;s&d_" >cf?H'viHd&/7|Psh`ʕk׶sX`Qd{n*;v N<8c .'~;&ɵ BH@35Xj (5RO?z ecdk??^< Jޅ©쫶΋Dpx^75lϗ"@,:׊+FքJ]CXq3L\3 akzM e˖qy!z{*EJa6:@r9/r ;.*,8.M }K,&/s(WwIN=!!f^5ឯv6ls{.Ԝ"msPH9r\ulI˶m:rߍyRTPL̡y]T7E"\N;^kwkʯCLm(O_}ՂWwvBd*p/A E5K@,kPVbϘh'|:E"}~LLu} رy!pcir̢ eߵkWqEeS PmsA:1oR ;_6)r^́\keA#VQjr>}-\ۂ"Z.Տ d(_~n{y6o,_xMv'@ێ-1 (l>sIpRsirDHlN_(sL/_fv j T g{iD4СCE5 V"A%9a];" TP@.uK$v__hQe{rˤ]첄6 38'}j\rLZ^~ئzK $lZW=VSPڠ: D;@07tˮ>.vH]T_PeO: Qg_]c`6.hs#"3Q0;& rJΤ_%ֺCP$QBU}4w\̗tׇ׮Db^^|˖U=qqmO_2 ̝;Wk‰14뽐OƸ` AHbZvK#Ay/v*uVb%7v [L9E\Η"Ib*kr&JHtdbTߥp*M KG~+ղ(?ЉwWA䄪+T GpǐSD@*kWsTD;d  s'@ 1:/$LeA3٧E\\ p\[gL*ϟ$8&&&PP-\P ykuSm9_8qDkW @N&|TdiM>E@lXƯuuemO@Mfնj ,,p)!'h Hi#}pe.'01d|>˲?gob}Cw)|m۴Ec"]~`H~*Ub_lBo۠PļfcLT#n*뿏>x@A$UX`A2YM~Q 0絫 MNLLͰu"m~"(z9h8*B vqkG( ǤJA.H!6#gL$Ɍ;61`3pmDE&X}H5CC)c5z bCaR!ڲ:qC*^4ԯXZo#}cmgү뫩*@W{߼턚@un9ʜ׵vAcp RŸΜ9É5a0 qlܸQS@U%2i`L2 uD5}7̔zTĒҧX5TDιܳ͹9]ΟR LB$"b םt)G)[.݅ϵ-19a[6ET:uG*cZ`ApkiBzK)ct莋 *K{ Cm%+%]O<0S8EQ.} 'v7s_=ǢEH=ߓmrK_Ut;r* XLDM4ƜnXA ѕ?vA&h|Bҕ%7)I)[oT5韮=oX"Sj䲯Hvf1}>('|w 1ThR+v-M1ز]5.P_SK_ɁRmWd.L8 cۥWXgϞ]$\$A(R+;_pĺv"1S*d:Ti?/Z: OfN}&3ImH&k u1:@ c޼y5_7GlT6֪2A/O )wD҅TNZ2>^]QdҏĠgyR%/o͚5NmZ60{ބZ!8nISvJ:'Vmcg%ԜH}~NJTT  t0h&u}Jupȵڗe0l$ 1a_ IMb(^vL]r̓E^EC(k.]"0S 3h #>3Tbp.NsMYvs'c.\8pBTݥ=Bn+aDߔ Q%)W7iC%2#4RcsLSB||VBn꺯S_7׮c90Vw"q@r~1S' pJi7̄o!h]:%+:]J9~پ>Q4 A@4FQMl&1ΉQyP 'rO@7@N˥S,g!穜̗\'Ɵft8b:+f*gw5] ӹ9Zs ޡ$/$9+MzWkoCMkt8B\:R"GIm90ӎ~^)9Tg!G:!׵jT!KtDbj$Ų%*_ȤQx0MTC?/ׂ Nj8hXp!'ԆMe\%&>+(Ξ=+5t j~3JRsuU2 (K&6˃ Q `GA])ϟo|=v-Q'ǨXy,#UL䶉qqNmSou9 "˗L@*мNޛkꘪRIl41-ԣ1|ɵk9f7iCޗlk׮J+u(&sYo`Μ9ɕ j@UD\ÛoEv| LϗCl :*#A.a/]pI}]d6Q`a#^57","d| .XYc$uI)ϋTt :\M@N"^7vHp29f 羟:@ІBNj)?G#^]MmP)B]7ֈ1+3ίT!{uR1ڎ-,Wܹsgd-Lc{Uw&_USݱy86yW:B+^~O][.Du>\ 8wmi{MgnSs_ UDepCKHg&: 291ƴ`:/_~=$iժUN 2;&9;H~-Z~;.vKLvc 39&VhU mwHPU,p?DdKWPkWZ{ r~v2t#qa.DN}AVwۆs^eLH0f|@-#xLy,b܉Q 9ES?}iUwHTcO.Mr~tD`@F$?%Jf)Z39T+Tr)cMna4&(L6ClU *؈a={v.K!Hg"9]}))SK;ġxU5,Ӌŋ3IRrNXdm.[Q5ؙK7T"T1 #ɓ'\ 49mc.al=L6̐LZA P& Oq!QW* EEi 'Ļl$ !C)d%8D>Q0#eNkW~m-{!v@TRUuqrM_2@f?|؝_,4lc \ gs X&.vM'/ȑ#CY܉zP/O8UCg|6}u7zqN>]p|/XAbJU".E&Xڦޯ3T?&8l|)T(ԉOo#V; s=&tBmVkB(}pvU%3d{k. Q+3$u﷽[C)A$rK1 @BQzΤ0 "T}G#:L͗eaa ѯi/ FE.鎥+G8`jj*(⭛P'yaݘ!wSI^{kr ::& 3wcޥLe{9]wO3Ǐz_5]B&(dD7P {*_Mnoo >Af!._"d}2\ck,j]m(Kjǘ3͙c >:A@*B:8s\'dRr8cc\P~n.\IVG-$mRS} * ޽{7 TA$C{5V ڵk9kvVbGd I< '0ض $%.]NuHNcǎVrBbrr2d|>Kp}&1bۺH_2 #RD/0S e@>]I'MMPhs9rO_}p뭷- SE5|P]mpɡ vNɥC2A]"X_I*ᑋݒ>Vh9nAyJMR$?DLGK$5zL[79S@@: Rf1S.3J$&nŵ!ԝ({wYĻMn#{':l̹lΗBϵkuU{'Mc)UBZ"}~М|~#DG!!N6/pn{ge1J MNxΝ;I5PHb뾖qL̙3VׁXK ҈>Iy}1C]E/%G=U_n%PB_\PEɣ_yztKE&e@L1[:olK/\;R~}KϵGc^מ+h9u8GgTsLmwT={;P*m仔`c^_r%e--D ^$;wS/K&7 ӎ>;U5|٥e2=(Mr{ LT+Suo-Qwg⛪g,6Mc4@Où-_J$q+2/vL'sYbߵkg\x_;v,"Ƅ"qk1%j)JhyJVG&ۡx0MN8Tz)<> '_IdO7hɃ;vt0K/OՉpȑ‘AMz.bk wH# u66y  h bMX;݈5m;Ec%TB3ӧ9{)7t`#hw+W_-TV5d皦9TwlpXb[!^Nbn+ݾ!$+$E~|khKK?vqAPW{M!Ϸ#±F<)plذxO~">Fl"Q R6hisdrҿs$$jy%D|1Of&'h+V8rݪ/^Lelܫp`צEe87#Sf~G4bݵsT GMޤA_kW5oDȤe;iD= Z$0U5~tnCTw .І0x&*sٳg ])!'`޽bժUoy<Еc8{r;a#u8Tv)CBͰkP @X'%zVIpe6QB=h:CH_t^a g_lDZB{_|2%;@̪ pIJvƩxgfNa7] I__l{~  T<&Fص n o%HSe.p3d!as_k#ȷ8*ȶȍA_jCSU +4\گILվꞧFUaUN.4<n HAa}{BZtl E$!: lzQ"$>w՗ڰ{ )w^GغM6v篾.װ9~Wcjz?vXJ, x7{;vMMs< ;&[%B^|1]_W1MٲE@>|*7Eէ@ꋨHhp*:/vZksĘ@*AD?`_8m:L5 Hcat5RǮ7|ز}L9 e,@馺?9OɓlrN@D2#l>9&B$,M&ȕ@@W;u sڅ 8b!.ic/1[Js%1϶WystM/6Hv8>mcs[w̨^uMYv+3&gT:@HIdzL"9=ŵJ)gȶ ^Gh#dffyB^F S vKp1f8r:`hQE.u:27|V9M")wecDV_(K䃔B6wYϤ F@$3fH.d| @Akuj s%* kc>jV/T7",Pz3(%&B ZpbD]wQ1*}A2wa5cAxפ׮D"ucD^B]%)P%r) S>HVgg󭎒J )l,H-pj[g̨cb.î]fb}4]/ .ec%͛ePBy56d 9Lf]ﯶ",T$cʑd.HPUbٜ oQ׶ 2*b#6ܷJ%{ɔl/ ;+ƩS%:cA-`N}2UDA4cΝe;_wU֔.c.S?ZشllȋGI[c,( -lV닆b2w_X&Ԇ0CEK5&S(IĻ8z`bbjtk9E]]HMڲ3O+k$)+xaUcD .vxdpR,gre bpر}mb]=U:[O\}mD3־(ϏG2@8w\t_gbE]m>$f8sS2@&:AW_}α_1#]h@(kWI!_0aI"9 %.Ȣ1%>1aD9@z[SeȰۀ]<*fC~T'ae*;l0q9ߖ=mŋSW~SB'1%ӷD6i;_X}V\[8] T`sLMBhGp"_B@(kn,6PrlEq2ΌG&?Y9uc(H(}Y7WxmN*5Rp6C ƄAHᾎPW&16i!:-r/?g@~<2TTp ' }uM]C\E9@Se|NK nڴ)d|!8 *oDN g]Hq@kW9ǓoӠsɖ@/Կ:7w<e?|݇YbSۧe˖ 3V%dǶdɒqّEV5F>ަsaWd*>l}r_S5cz7F!vuͥ>Ciag..b] ?k<8IDyb_m}QZʪ^/ٜm˖-gW}??9aΝ*HM= v]xѹmu|[ ئ(ϓ?8(Ο?dA Bbό'D1 'ǘ@A6!3gN ԁv{2>SsAc$..#I {"ƜD]pڗ5&̓?}R#4 af b mF@9ֹb-f͚LU*[Wa p, 2@TU)?prri!ׅ+h…^ϮЈ)8&PD_(=aS7unIz DxꩧW\I9WD!s3 9 q_s1y`j$3!n2vCP 'NdE2J&$ @gYCkپ ȓ?{H7T*"bLN1cjjC26KҮ>cID @޽{rֹt4 gBȤ?+t6|,Z hp 2&:ǺmQN]/GrHt[975R)cm(CP1cǎ/R~*c_̡Hr`sepWÞeXn;g*TuQSl5KLrw ƛD?F:Iul{CHq5ϛ7(w'kФPϘq41^[" c}gAg,>HLkBM05TR^\ʕ+9agc{M&LqFk0p6mBH B$jN]vy#1]9Uڗ,YbfԵGUj\|b6PK.b".֩c2=f(8sRjiW_#Щ!#?s#׺n%:S  u֘)o?Z>T[6ZdQ9.'GRR$E鹭LDQ0uUa{U1Cs2lĊG.%:m={$3M'v1.&$_d18~x!r5dcrPr;%AHdKpbXJtt4`c?D//fL@B!!LuC'.E5Uɦf=-}2 pվ&_? 5KH[˦srRR=r$|krGZtߴ*.O_}ΘCTް#_7ޮ1}9ٳgs"'*}2}]~SfbS]LvPذ߈l6g%J_]]TݒFCP]1;gIC6o߾>TAw6V:`{ϟjj i/v1䉹9v]b 6De84@>#ݔ$!=ڶF?Jsq_u)o?Mo\@nyD*uyrLW9s ֬Ycf\nvLO l?qA!YbL":O{{]ЈyW_ yb9 $jJ4FUV5&tUd_6)17MA uO!O<7#}}ر1_x1JR}ҥI؟]$ϸH@V ??`--(} 'wC s=#-__fp^|#|.C9xW\NNO v_ X7b*Oޝ|Hd}bljk#\Kw 6nܨm84'C8p`O.\}^յO;6Tn6A!G۝Qc׮]8,:(m߼yѣTTP9&Y^(o$5R~us] Jsr'/ l4o޽Q]gϞl lٮUG5;E9_G?E^yERvx2q72;1UC6vt_"x^{%:-;u \쉾uUo*Uv1+`@?<86UWk !N97a0;]G]Ȍ@ LLLD1!=\|ܹ(Iv!ϩTJ_'?/}Д=4 ".q!N}mj8c.]ɞ$O?t %:iǎJi1H]\@[y1~f99~7? ДƼf͚ˋE|eDr  f͚I?s??[fKt;ԩS\Fżzy?E9ljo4<96N.%e!3u]Ifu!MݻwN.!Ӫ İ\(b\/[LcO^H(;\N!ե"`ŊE\{MVk̸^7|B쒐r4 p17@^* 'sh@rE1pXB=]dϡTuO^_v |>N*gغqy:PJ鿜e@lҎ ϩZ9r$&,kG>e|{}|wgܗgK}o~P.uݱpr䦴_개 p%IίO>H50 Қ(}yC]%cLXcr* r$,R$!qhmfX@ yZ+gq֍Ze]> sSKUt\6ytFOM10{cw4)@dMя~T'''ϣ$&t1w%K?&>7d|9~WK5 믿XْP˩Q*NSCb;DHN&rQBz v`Ν,g @\p"eg?=@ژ!/; mJ_mGb& Q K>5L2˩@Bo޼9q՝g3s/{ 2 q 7e[&}jY&1p:R+ƯA:24@P %4q^. Hү׭Z *!hh{M8_:%}aSkcYl9H샜,U]ף0$cA1֭[7L뮻#$|#7cNJp)gKoۃ={̐%& Y !"&\4@;v;/ vX ,cN:4JbarHj1S&R-S@Rv$nm2.z7pÌ"'^c1n!x ?BBVvڕ9̟z}5f-pp+j.R/{,:x [ _CZ j>96|.±-7n}YUebS.2wSO=58x/K}R=N~&eC %Urs"mӰ"Idy!&ayIHb.C:11Q$>_%r*;vWQ*"h@ /4ij^^}> B\ܗ5aN Gx ]wЄCi@W}U%\ڲeKm-h>s-!~,CZාoɒ%3If`ȑ#EȠs0CRS@"FZB8pr/{cժUgҶ֝+WrQiFy/<@شiS5Tu&YpLN3*sy9&''j{ķw|oH(K.3c)J. 3vr儺qΝY>|Tuϙ_e f??ëPoykU}B_U@S}gPܵkW w >DN(^}ku}ȜCd3茩f* ؅ NxC7='d_<7u]Cm)j{K/w ȿ :ޅvِЇ>-?5^Q@Z~.c@9!cnD&ix~Fa Eo"@8!fC! MsoJk_~Y"X.Ay۞O_$/k0`6`As+E8T蒉DMI`te__` @+ȇh0}ٳgĩ:PNp)C0Us_laV<'y&"ױNء/!8P֮Za"dbh~1,L3Aە+WF/"d@xH˗ 5ȾpbT̺kc|J2=z4yos81{–!vsRA AU?34W~W'h0g*O\6/Nc%ҰZ%ZuB!c7'p5Tx]$lϯkC< '|p<$`N=зgzgϦG-D=>e(#1 Jdh@9u9f4rLIj_[؁garl37:08vIүyLm{իWϐ[,GJuUHy Y3x"fɀl5zo}Hw#1j"bA6b\ckݶmWLױu}Θ^ cq]]|PA9yT[c#%$ ORB!M `!Z-^:&/A3P!Efߛn.c8JC39~;'g3:Vg޽{T&T]u@u/̈ݎpr>*:s$-K@ >3+Qk#!ĨݧaSN @נ 5f$EBuOgJuκ_}p1I1'?I0)3U*WXAҌ|/{0x%0!iiV1\{ͺ}r-4ĉٕ!c&xȇ]95D-_Vt>ɾXy `\H 6o&a nk<ާDN:|15&HwemN 茹J)oo!Ub?y N1&9cێK]cFX,ǘq||Áw /D451C큾('ϣ'>όOhw )\/-R}Ay@\O8H>I>]^ ӊ1ijcFY{BlsGyfv_y77q#Q(9QApMڵ$fƌ( $wށw ҿcǎLUM1~cFXV S%Lߵ{wsBs"u*DF>*v^n'@Luy†v(ȭnMCtɒ%CI#OJκݻw?F/_\dumօQQO~G&>OO 2ra'P'>}Z"dR'.Ǽf͚!u'gߵ_gݞ={ǏwJSO"|nt_fxv;\:2-F)VϷ`M7$wes3DwRvAJeordۡ`m\qaCPPut胉":jW].qv80Mc(N[||K>.~sG?8r^85fHCe)'~~o|rמUcQ-Eu;Bn֍hs||Ác㻆ĉIi_`\ځ&(Ô*#JKxS[U^zLLLl<<9']J_m} NjDlܵ?MNN^Mm&s=\Iw#oZyոS9&1^׺15}V!z.wwނ\ͩk9r۴97۶ /`dS1WU"Ӿm6%(պ6qu-4~/g>~ݟ5Z$cc+Wd:5\j1ڲPKstħ>)x1" @\N1NpP֎<~rh[cNOϜkоko@tpI>/^I>! ^y!RI8M#)wپvڤ>}QOG%.y%JN@J6Κ%./#Mܘϟ?;U||I7`Tcã*7K.-:q믿$ۯ8^:pMNСrY#!<@oyȷp#l]!k8Aϟ?ϤvrG G:<UwnR,PTU˵[nD؋@3v)]σ|2L!nNwo^} `4UgNʢ,jl57:,w~wƧhǑ#GXE362BEb  T aV"$wR1]*6p8چI/WA/A;U$_emǮ @3niaOO~ב)E?>ؿ bv :]n3unK/4DcErN99koܹs>lQmݺdWyA0DV8c˹(WkUr!\/ =D"OOCF_~J. sjWܿyL"=T[-$g(GCoƯ24MޯW(Hfwʕe@ Tw!E5[|(pĉl% SN=$P7]w9,<ԱTRm5-[hm P 61V>TE;.I}l^f`WWW.Csce P}]xqĚQ(k4=OQo}Q앹uӃÇDr[k:Mgv}V~c''O2oqN.u>f =PZoƸIO}=M r%@VܣGR֥p,&KlASR*㲡4 ;(;f.wgw6&8;DsEcUo)j3!lv_lgty y 8  n Hx{4ခq$H+GKN5H] 'ss]&\lY\`RO~F@xƧ0dP mN}1f p7 PH1Hp|%=BۜFXAIǜڤ0_gL]bQt8L_hIE7v\g$cdD;PxJuOmrE_P0Hd!>[Hxĉg`u^3=&_u笎u q]|gΜ9rddיH܏)6I]oKyXVӱ!yCqa_'QaF_TLHjM:MB_)ua8$.k]ؕRWHcSkÆ E.5@3Fu黆x||pS Kҝ|-u֭[BV`翭ZA^Fc<J9lkվCg͚Z0Ĝ!:.]Z8b5P]~c^pahʕ$t40L\P џP/11wSt:?/NtFs=$r~ `@ #ؿ;lɺޯҗ(Đ';25f,_(xҥd9)a rc|rqO?>!Rns 0ݎn&)MǾ՗j̸9RM$2'7'TC$tHlX1UϲWnj2bG&{2Ԕ"ȑ{n%;Y|Y7ij:i76c7aONA 1:<Ԁ%'E.&lE #1.?pQ"?1#! %u 黾p`Ϟ=ƽc.98m# 7ܐ$<@ ǯ1/A7prr$: B_H>C)%$w3fabgkwA766V[-i?UsPt؟e1KK4o|e @be<9T,ޒ&m]iwuNYwRv*f71>}p"y$^+սccuԯʘܛE&V͐־՗w~׊9SǗ2x0/^hg}җ)ۯsëX1)yŊw77&)duaIܕ3wuWr6t8/:OJR(r5%axz[du,Ƙb͚5#2HO{?@=Z(HsU;,[-5sロd `7^Jto]8BbJ_C\ Y}Uȉ/5Tx'g).ƲW}z"HUAT6lɾ]08kfO:U i~u~=wH3?3Cc>J w?L~^(I ;,>ŽhS ]b=1!*$l;]11J.2fTp@M65:0k8:T<@}'3w8ro摹:VO/E.:"rؿo/,!)} 'ʟ<7Y:GE# yWH1;6kÇ#1c]esجer-ܧ/zz$ ]0@/r2/:9ٳ&վC]Hp._CwV ͒%K JFta .kZ}߯3&9t?옪}]^3}]|ח.]͑9:O^;^:6P}ɴqBK* _{ e wK.>j_pLpPr޾IS"1/^,B{q>a(h&I͈a8p;Y^}49>{}ܹE@|(AUE=F>|1 l!&3i*r>I_`2{,:br+&UBRu^v~￿P>w܎ p\#|hhbJ*QQ}\KWǦ[*:Հc_Ι@gN _1c_V\j"$2vYD{B'LMMIGI6sܹBd| Shzߊȵ4r;n*zitpb꫌O|t㛿1 ^3<(ODU@|_ B(G4'+ %@9q!<jj0k?d?rH)4f^^oLSз[_ycJt1>W]B \ag_7~&^s`@K^ioy *nC4Kq #`6w}&(@&O HVy >R(/貔_ݱ+e#Is9ĺ^#_S>"_c  U޽{G&J禎ˇt oNpmv~cBv!Yu\}΃pX׮][=d|Y}$^CfPK;v I{̂7% m=1* {U{6B"vő(7eLB pҋ8߉tJuŒ\ŘQ k֬XpTe2>{ꁾ8A'''}Q'7{1L}K$SIS&z衇hOyZķ-&Tm6mj]\fGbHlZ!-H (rBc1cŋ{ܪ^C9ocn?z e?=e/, ~ye? .7/< w9N_X]@Nr 9m;imqcFkA2XB GL12A=/dٳ.%G|5f͊nmiWB'(:7S r@b&ZMuH HHj<$T(dy9c{CyLV\Y8P9$p_搌>AL7gΜ)ȿ9\5}B_%1V [n\O9Z_g?%L]Q0 E|k_O~rj;:(-kV=WhNC[*'nөp$E\s[JcS_|WB)_lu.]eIj{ɬdF*ǧh۷$%YɱqNC.eVozI@U_I9f\LwqG?{*ϱ'(W77x w^,:$25666ۼy|U9F_=qEF|1B,"d:Rک'^k:OD?@8XekK( N7o$WO_ p[oEɑa rRs98K62uyk[q!e{k\Kx@i3(~?p*<`zb` E@S`kt8g;p5B5m($tp@FLk3YJֵ6GmWԿW6<[{Jի{4ҟ2]oF ˿ D#J31c8Wc=]FЖ/_,xFisYgGfwPӧ7M˄ٶm[GH]գ+0dfA@:uʻu1ǎDZT PQI6i@umvY} iӦ(0ϖ׊2ьF^|Eot/|0A@\v-X)Ե̙3SvqOuu_z' :vFQ!V6'QU65]LDMo>Hk:6=)+4c@-^~e>f|AMR; VWHE9kZ@ezgQxocGV_gc-[Pue,C'y~Y7`c %GA(u|I tL<ôr+vE^Κ: ~so믿.\)F7ڜ}[٬_>~)YQ_o]ʀ. ^3[V" 駟Sl}7s=ɮ`^ ,ċmnE"1Wz0W.=;$CžGHo近3{pr?шĿ*׫8)8ZK=i*@jquliQ9*[C0>ҤI.@3=_#*(W=o};vfӄRҥKT7ϡ^zp 2lYϖu S~{b(L0#yN81TGlGV@)sB΅[9u 7mhsڼKmn]&;vlpg lu7`k}%#/BZ'\3W͛޷~[8IR#g(@ r{:mnm٭6qm42lvN7o7yO?۷o<A{04ǹs9zY,7jWciY-xʕ;Ìdʕ+"O-h1Y6ی7W:i_q~.GMjӚ5koSc5+{Z-`0dXo[D9Թٹsp&^Y91mN~U ?n߾GfKDm3Q 6 zݲeK.F/{sΥCB>OyaQE9VԿV9*Gk@mqtƓrNQ^Wmۼ+V4= oyXPS$7>bARmRaFsıZ9k#hQ6B`կ|͢eh- gΜ9|hf7vE;Khns+QP,ҥKAfџW/dx{*ʳn_gݻ6}V^]]] -ѷo߾c`r C?g|>-Uj'F0xׂ%`c>uvfsۜVLokŖrWh?B,2,Wս7|sNJ-4 bՔ+Le]4EgVZ:P 3e=Cms3mz֍N0QnEȿ+ӟth`u߽oEJOW= 6 ? V@ce&o pܹTki-4:ȓ'Oz_|\~̒aem#!D=WNpı9߄SBiJv0r1eX%ܹȃ#qce @Md_Ԁe˖ymmmkx@fWEm}V˗yQn߳E{#y/$qZ]vnC/] {SZB:VƥllWU2$]^vʦsje+e(@YQlq%Z~LOzPחF٢Q#2t_HXկ545aP9R(0Z@O> G̢5Tpٳg^ʹ_TM PFZ5YDj7?+#GQ|ou*ſ[qKjƄ;a ;v[X%BTphfפv5{,uTz֭..u<]6o֬YSb~R7o^0rn?Uˇ?AK⋿$ vB}S-Be, 9v`oo/+W緼4H%׎ՊSL-Յt,}2޽{~l7ZO#* (ĉ/ZyO=== Go֭[70jW+ǒP\dIyQ-tl˗/{N.\K\LF#+d0a^?=?FY/J~|YrX5 Du4?l…#>ȳj5霔€2liSVU5%@e*wMYm)*ᯚՂ_)/̷h"b1q 0`YغupK&{,t<{K]IT'4atDm={v +akJ 5 K}9-u` [CH|uSZ=vRjX*OM ռ߸ mhD^DΆigq2hB:??V@cDhXX`zV)u:6;y7oެ^c #xZB&zs&YO &ݧHO"sӦMBZVW ~yZb޽{10P@؝X0T`=jqׯ_`gd#ƍiKE"ks֢߄6+ԩ~-yeWB.}߽M$!\>߅z p wHolg I9Jw}YXю/Z)wgl6=stX /p0ns"h +SgSXJUӧOQ;_ PO (m@ZbԵyʪ, ,u~c? p>@D|]vxSL<Ν;g(OS,$y~.)" # +c OJהp_C08'9ߴiS0oҳ5OyJmMh={a @8o8y~ᢀZipmj:u*U`z)6s2dܼysi?6k>;}ݓk@|VhKk_gOL'@  g|D">є )yΌz5V~^9!׺6*ž4׼g9VĿC[ Q+Gs0`W@:0Ԁ>X^sMivM>?If pڀW:-hDĽ6g%ּrliɒ%ގ;|_М˗񌗁ݻwo& )D)>WXaL|Ϫ]I+\!@ݵ&.a(5AB3@M)wmUf۬,*z}}-oufsYjKAudZ-"/2:;;0iK)ڥR) F;<*c@@hTWk/?ypt(+6"?KtٳǛ={u/ٮEy{?Gwލ3/Gm E|( `A*fw, UV&@ef`ϼ>W>3e ~!*ױoq֭g*tY9+_Z#)ѯ9?WGQ!_m5t"&=p,'? ) 2rt{Lh<懛wsדOП6UoˤD~32Ec@~QO0۷'N3a±TaO7Fu 1C/{K.U~,rPH5L`*e*@pFMI !jJɓ'9գł 38֮y9(`Qy/h?/9 `*@\|9X?i+e(`5;:>Q_oalY症sd WZiY籿 O Ra*@BhMz.v&l ޔݺ?* SbB=oe˖Q?9J!VedPQׯB\ajX*|q' !X* 3)y.g{,}D9PCΡ<m"?mZ{ KfsڻpY*sZ^[#/C4ݺuOP}Gvu0f|ﺈD2&ڵk'!hNϝ;wGP, 0l< iϬ7xL )0k?4ߴcɔY~KRa|F?o9Ô%*z ]v x I 0Lĵ eh\25iΏό׉KTmyXk|~ӟjC,*~$0&ɠ5k:K%'Tr[psNoر< /  V`*@BhsFwRt꣐^Ò%Kj.Lף^G}>'2 p4|Y@::]v!սsN<7 W\Μ9c}gc͝;7XAkF#s~. fpNS’|˖-,xo H$̙3KکI+կ^ʆt$qy﫯H_Z2,C59i_E\,φ֭[իWK;v0B4!H\z5XAzZ2edcѢEƍk.XS^gWQ=$玩4OrgǎLH2\L85@Sd ..ô3'鼮Q|8D}EA_$rZ6pS@5l|,10m4#: G̹lhs&<8ȿ u^BQd)A]Ky/+:Oľ۰a?˖d?=/ T]7@zNJސ{_|788C%?>3y?3kĿ??;Om۶XB-gP$ٳg'*+[ZިNJ]ij*F4ݻw#ǓR̸m&$%;;;k7={Ϫ]i<â *LɅ4Ͷm۸l\vq.JX 298#|f\I'(_f{r=˱}!S@@O:/~ڼ!]Z޽{OL +ThR̸ng&XYyz5=?ulݺ0a @&@ɉ3^7n>@!l_S̎i_ڻ}O~_3Z) P" l]0K#Ν;˗K6ҹlyόkH8_KG!?K[2 6?uDzDs^g*:>.\JDF(u%όk%=3իQ<\zj_&6[%hѢaNt|Mb?QgfoZa(5??&ܲeKa 0K$3^jw}jQx>|]I3gΜ@k_zy8 cׯ6Hr 6D\wfϟT^JJ}wݚwy8~(!RrOϱ4H?Jܼe˖ >߽G$e:zE̙3K)xx{j7nAl/v؁φ͛7L;D|ȮtWCt~|ft[z .4slZApȏQ` @Q :uj`3&I&@ 85C}~|fQQ?s7===^G393Ġ $2 ̀[nyO:h&@g[qV{m9VcļyMF>j#i:fu ~oK;IK_DgE ymF @}oFGݻw/һtѣg5ƍ5kx'NLŤX=b !36mD?M]7ݩΝ.\&!9es~K>VZE(;Ϡ0@ d  xp>՛;رcN6]pڵȝ$^o: pNYOH'yê6k?d@? *d@f|]H&+dĔ)SyRz}"Ϟ=vZ֤s~y84/L>}zS [;2=Y/[ϥgӦM _X cTpɒ%-.[ꨦPkz@bG)L\껸4`ǒ??s6oܸ[ceL 2թK3xX|Ɗ!pNhѢ@kO}̚5۽{7/`@Mm" 0o޼`Z@8E-KI.e(+`T'S#_|y 3Ѥ~^m۶ɞ#?L+ CsCD1dVVSMfO# .LЊK؟mذP=VȘiӦItL U/ P*7o)H' $4;<6+R{9otlg ih-T̘7nx/^H&+xq,-%#z!Nh[s~CM=ɓ'(l?؟ܿ028׿GVHPq@RGYJk׮]Ο?LxSC%y̒礑0_{WܟxO#^2h%ì3w7lP"PO>D0 FH@#+#@7|=|(Bѯ4Ld|ŊަM輘Y04_ 3Psif%/ 4xr[L,ϩr_#+K#+KD_K1qL^.0' 0MԒ:j9 4TGdj$yN~MJW [2,⿏0@|owhA+.@V:A7" о^*#M_~LJuM1ZnQ%0goԩttEfT+W_ 55F;I& ~?]_u?'^v`AN"@ kJq,-'$Hϯ1{B LJqK?OYfA`&GH(QST۸%ի!p c2b(Dp6LJqKwf60UU=^4ܹsAgW#\}:p,SQ5w`w m2}#4^ofqN._K#Z%E@~e=Ƅc5zl-qF:! `"`'N0U VJ"ڦqxbPiIZ3RvR}mZU j,^T_xL H8#I4BS4b)qZ:F5 ۷o!їY)m_Qĝxo4K U(0TqUS+F$^>6!)Qn} pZYk,M#0R>4LC̙30E42D~pp0؛^IdL Pk~9 &I |o=k׮E&T"YXkvRm폗 4˩ dDy:3ѯwO2~E|Kut/V)2e 6Kfj(C@)@&kξJkd__?L7D߯Y&y{H: %0i$ՖT۸Se@8@`gI dG~8/q/g٨QM9f͚>'&lT\%S Цׯ{lVqN*ȧ4hkQ} )ŋ{6l  6SN :tD/%S@1 s@\t)x]?j hDy\_^B^(DF0\-[P P(0 G| }jRmaƀ)PYw8aAVJ[}}?eܹQ ?7?`^L+Pj>:J-jXԃgep=a/MS˗සWF&$j(N5"x/D0I:F7od*@YLL>&">KiVb&_|&E.YÈȨ,E/SZ 6Ja6kI%uxady_hX_zl2 LBe6"T[j0IFb ͢le(#ڤ/f9K.塍0'ObXHxD+6cE+% +W"LfAF2uI%uxadnq=s=Ɍ;w.f?&$I[[[ Q:yGf)7'߱je\BA4c^GGStIE&^o'^ԗ;>E~  !?`SNu B"&MBdM/{4HXbP`8:hӦMƍG':BHz"^$7goݺuބ x"004TYi ċy]2(_~%&HkM vE} 'LFWdb1Hȟ &@G"vΛ;q?m'Iw:;;Iw$9C9eh R& %FOߴi7c  LLддBLʷ+V)ӧOz( @&F|He)7RNY_Bʕwe˖$ Z.PF@eQڝlRWL''U_v-Px߽C$ܢ8E|J$~3I(a3gw{?>0 ՖmIxە`tnrpҥ} I` }B0< (lF)W& z -Y qB p#Jm2!Hz"^$cǎ DkpVP`iݯ= t:& ORۉ ׬Yw/ )JxmƌZ9 oVDċ$"|r*CAB291 3!"BXʭvz"^f +|2FD}45`ҤIi"L0I;/ MB29ATmy"z,D9#⿏H`ٳgY! ghjRnR/xˈ. */YJ֘8`R%^f$\OvKٲe!` -M4i:5 vE'y!K?0ܹsכldhivIE&^ Z5U|-^x*>?& P6eM;">\O(F  LFa)7RݹWci%!|| 'M.sFd#^"M0Ip=utt_{=|_"ryz めhkkR"BHug&S>?OZh0rcU6:aV@3G!֎]O+sؗE  &@xJ0dhO6ۘ$ԗzRzܹsh/ @MbP.<}.g#+ Iz/^W͚5[t)i0"_"端.D&:):H&^i ĎxM<[pa IQCu| 2dK$`4d U4mR1InRQp}F74@SDjf-jG^1z%^_`%;BupBG&Pf^( kd)XZ!n/LKs%e4@Ŀ͐m"lpRD!/c^fΜ9spc(a͛KB f@Yq Z"ĕHuzr)^&M ?!"'к L \7рV̀4KmIL$%;;;I~ ǔh_WV@=Ҋh\OKg̘O6#‘&  1%b6XʍTw%Pkӈ?@)' '!`KE/KqPKk/I|$添O$C?J$0 #.^="BiHu'^$?~~gbΛ7oP`@&(h@&Iu7$q=>Zo o|O?f&(?4-j]iS/!c)ԩ^ #Q o*D",ڇ[# [X+&F+E?@ہs2oydbTo͊ZR݉W^(?!_S,4(Fir#=$;::ĉY@|O? 8\(&` Pi b59N2ex# /a"* @DL5BS__.ܱүQJ`%;0gF0A@  ̀p˓e;{7.'O&LGB= P$`! ߓ%Abۮ$M0!2,o}O(0 '\tlp@hhG-S1Kf_/!BQNF0 F@G68b f@Rݩ4ob?,o}O(0lpi=pAL  {}O4)ؓ¨?`F@{ߺ4l_KE7P?3(?㨲!Fjr\a@e}}o npIW { } ~}#g>L5ln2d!61cGå½? o|?@(1T@D>> 9  `@|\rc@~ԛFPF멐`%;8k֬~B H#vbD ǣ%B:W^@@dH3g h1ZYoT=_"UXzj8hDxPlhw Bh4P, +vZZ?zߎΘ1VE񒁽D`D/K0#lt 'q޲P$SJӧO#<2< ȝe{8NB(DxY`(noG::: `6(Qfz h( `B@\ܸq$6m#͛71 ?uT?``#BP$P;>r֭7&SLACF~Ԁn{헾?N(]#l'xY ȏP, K4ohhH%B9c7?yd* _ <L`` -]$2~Y|O>H0d  Q?X',`1 P( X=Atr`YKdD0~D+3f "0` 2TPAѣ ʛF?'<I5TL7FU P#0fhh=9]+{aX@BP  F0F߫T_ 9 5IENDB`SuperCollider-Source/icons/sc_ide_128.png000644 000765 000024 00000016322 12321461511 021316 0ustar00crucialstaff000000 000000 PNG  IHDR>atEXtSoftwareAdobe ImageReadyqe<tIDATxYŶ7"Vq@QZADgv%AЗW>O>'^_@8oCeRQdR:{i\jWO3"v]kʕFtJtJtJtJtJʘƌv6ϩ9R5TwM#;v;uZpO?[8rHqtl8:F>?^.&"p*ǎK _I ~}Dq={6Eg9 93G\Í{;߼ԩucǎ- 2 lٲ9jZ[k.4D+@ܳ (کk&LPZlܸ9p5הܹss1XІF>}zA Y\漟~6ƁJspa X_~k ~je;kZ,L,C{͛77^D-!%yym.:^d]Edg~ tm !\F,8_}>7Q+ 3|8C4Wu#W/V%K4; w]DWߵs3uBK6"P h]`q_e˖/\&܊ ݮoW_N7S*9xk .n}Iχ[-4ޘ2eʐ 0p0xW@ }m"6ƌYU.]i#}Ѣ[z>1iҤ-R=7Gcǎz=is~X5{gQ}ǘ9$+~7G$5fQ߸w0:$qΝ@˪{!m#5~w..9XBϹ+`!fT:v急ھ}{ kU} ДyN%SP t*Ȕ1mڴ"/8։̓ tM'}Ȟų!U\XKb.(@@۶m+mB}WEzY(XX)]--iޞV/[ta!7ⅵ^/b dY R1|IcӦMI#&fƍ6,Qu IWG5(zc>fA O.XXTΚaIh)@k<aG~ N,!>0i:Kc/~.#/  / XѠ,Z5ҫs`:т`H+Piܳl/?0#T߮IrDfΜyY\-c20vM<"oF٢wcSb(df4ŋW[#l9)DvpT@]Q|TjvUW]uj:t/sbZ@ëQھk$+?i!ӤW,USNY盛4ˀ 1q#%Z)f {RAnzYgpk/gi<'=R7.dPjQ@E@4TsSlHL1cƫ7oV `J8s>.67BCsQB<G?08g a`2VFk׫w0D"q-yB4eˈ;f%… #+2aj߾}-sR=,?=Gnz}y7Cr sڀ' 0YtϚ57nH.=KhѢBi3 ͍BhC˗3ԻBLט;rQ#_DBzJ[U,')9wWצ3(EGRd2i#miwƅчhQKz+Q[n=1?cv]#qz?FTsfɥI.!$X6p7YbY,-ѻ-$_}hc?f㭜 =q QX^ߞ%"XZFC2ZEJ&vzf,u}r#2n9/U3-,x'{&reb+`4׊a8Ur Ǧ 9 ;}%n` QO b*OqLIMSF>͟?O?JܪwPUz%kE˩~_fE=sx pfLϲIg @渀IRm*XF26@XG05;R1h|d,w' ah3@MDSڛA' ,RixzGHžpP4aHƎv^R|`Q___Ä843>b<@ q+@wLyKmL4-}p_|0?ý 3Ŵaͽ)l2XYhZ T' S9 ˜Ҏ2],V;bm&hi#k;)F.&9u|.C U&s@ Z݋L.c*Jr/(9!0|#[z,r?T*~ze8n_h -kYWV t L BNiI`\0G.7 cEز/p4TQAI;4[8)VCΓva3>*cZ z ,,V̂r# ˜\X' |PL"։` ֆwP鵡cZj6EOM%o[61O9W'FbCĩenvƦm?wCOdEԼ:IYhA9O@3@5-`Y'`9Ӕ{G[1MLj*5 ck,?cZA>.1A/‡5S/J ș is^L @5/4[`&{wM In.8ߦg*CPݗ)K EZ vKXN@ֹpY#Y-Z\jU_ ˠIT"CÐeLaϠINYp2 eX>y~U}CN܀T@x p5- A&ƧH6V'Xk(뙄ϭ*⃎Dٹ a UjS2g9-2w/p8#lOܗBmYCsCJ dE[A~#xYź?⯵v1,[Nz嗏,_|&䖋'YC,">@jԻiYX%Q(Yкz;8ewqFYPc̫-+XA8hymP1x1  C6eI(sh.P|>k7,MĔʪ*wp__GgACQddʞ\K|^[ƣd*sI|3`DOOOOc;䢃Y_΅Q"dȐ$QI@B,"t!vZs,;Qx v,/DF pXUUmmZwbUrn.!^Ḡ?,DB,5 R>H˪[oaejpH\Cb7."ބL r];T= amaM*}ȯ$zXӆ> uC7Ov;i+Ǐn(f Z6NNNNNN_ ]^U(IENDB`SuperCollider-Source/icons/sc_ide_16.png000644 000765 000024 00000001307 12321461511 021227 0ustar00crucialstaff000000 000000 PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<iIDATxڌSJjQ2S|~_3^;/h&_(+S$!gI=8 ދc1rÔi|mgGFFwѨ399錎:{]_x/'_bB󘝝133쯯fѕ `md2LLLhF縹B٬MMMifvvvLH&znaYZt:CD5czzZkvwww8::Rv2b1e~yytZpAEzHfeaaAYxgxxXc lɶ===mE'k FVCDgKm^wss`1Q(k NT*-T* .cJruu3...pzz~P\.1Ndm jj Z__ ꁈidiha˥fKL#_xhu+-axΒݏckpIENDB`SuperCollider-Source/icons/sc_ide_24.png000644 000765 000024 00000002107 12321461511 021225 0ustar00crucialstaff000000 000000 PNG  IHDRw=tEXtSoftwareAdobe ImageReadyqe<IDATxĕJcQ+q8u5u ͮW+]zAN*8y֮ Bw.p89_U+{Q#:] &b>1c!i@ yyy'Yt{hȇjjj ԖHUU͍\__~_^^(EvJ⨺(ހJKK%33S tuuUfȈ*''ǢIII -//'IRdeeݵ*"J8HD{dr5d;88p""@%MF%Vh*j~~ުfeeE2jmm͈3AeeeVأSIT'$ ^R$AzܜEDlgZ3I :*^ XT^"\hn BfX`vF5`mmEc] wٽɸݍΡ?ަ VeQP5A0D.;`r6 w?8L XA#9VR=(J ~蓩 ('TlaxP=_ȧ?F_i"W)% `||v լIENDB`SuperCollider-Source/icons/sc_ide_256.png000644 000765 000024 00000037737 12321461511 021335 0ustar00crucialstaff000000 000000 PNG  IHDR\rftEXtSoftwareAdobe ImageReadyqe<?IDATxYUNh3@I%U \Kwoī/XEb*6e C "S;!|wr=ֳӽ]tu{=j $H A $H A $H A $H A $H A $H AI&[0!­ oҤc(ιshH@61zر4)I&OQ辎Z8#~mAq'+((0PoFSĐ)S((x믿~ '<]~: aW_}5fGq)'xb[; ;I&m [N:$lAѣo{OfwCE#0x?>͔SN9/Y+x0܊r9G wc\H~rv=?S*l;q'"@kvkȑ#c7|[_}Un{&wyTm'SOm'pB[" ~wE/xw7.) ʞyʛ.d.`ã&L:駟:묳`&m/* rsS;S)8iӦaiJNrV>k,q#h0ruVFqmLUUXZ㸌%EyOe0Ndk[J?֌3W4sZceX 4gI1e .v.WSݤI7~WTJGs,~7y'B  Ѕ=zUc_ܚ5kVg)bU18.c  "eFtDm=:>u饗qSY%5v<&}Eay9S?<0n͟?;ﲒ&Mxf,qK Uczt<=oPJm_zH01!DIw/dFFF4Lf̘*?ҥKsJW+f~>$R1lZϾ}h̜9UmUGJW\Ax1灀2؀58e}?F1NCj"8W$Gsn޽{,fͪT.\ؚ3gN{PۇǕDk,krh~&AEõDx3&={ve?uֵ^o:m(>fIVFWl޽kAnK.dC4Y2a<(_}v] kj,qrʞw9~PDnm~3ĵ y单e/"Pb7_?f:~%~[Gm}'סlƒrd]l`-f] t]-ܹs+Q֢E+SiQr?ܼ,+yWs>СChk+oq(4M)Yw9$7o^JbŊvOVRXʺq"َ,XU ?7pՄXi`OWYÇ=0(Z,i2m۶reG'o ev z}׶ Cd k׮tK/@뵒e֭[8… :_JaT?qlBY 3*%)P)D4[o:˸_6l%(!^e˖eѢE(˭6@n*Puww|V|ߐxFm[oF>+q_}FhlI+KwqGn:o\|{+$54L;ǯ6 Hعsg}z~ ӳ$`37Q p~ZFۧ3 aF[V֪&%bmԒ @GvW*aN6~"@D0*K\Js/^ܺ+L7tL6'HвS+kOFӺ 7 "zG7$p~ky8nW_vZNއÖLFP$U᜔a9IOD v$? e'M7ڊW9("%$Bmٲ]59Ixfl3Sd;ɒ%KWM,%lٲvindZ~a)|LGўzYt) {gvM*̜937QHT^b}Q; kk"x%b;&<\}= yRGWZk#'\+ˁXuĩ ]7I 0:]~F ptB[ʙ~(=wl63hO!3{s^!,!}Y%Vתu~^6ݏif͚㯬^E Ywfs4jXw>k  =K<̦ _=[w^Y*++GTtmڤ||V'"88DV, {oݮhJ  Qfy6(h8f<ӵ i<#醴Ҳ{cɒ%ߙuPx_tʳ"i /;@@H ?s?͛.;&buM\E碖&"0o?%$s1XYt E9X*r&/ `ݻwu2r)0*k.]}a˟zꩡ : ?N?pq54+/}]Z!m_KHW]uU NȈ3p=Xx iPn6CpƸ.[AbqZO0YhUPv`)q'-IAl4zv|10#GT&Q\s 1߇8{z{{'UhO_5ןPh-[ou X wacRG)i*^뽒?wvj4NDWjF'>yI"IH.i1=G#tt\@7YPZ7 %! '/KZ(>f~Oڼ !A<,PR›y Pƀ!MF4 wbŊ j)?4ollZ$?яIΒoH6l S }&@➲V@ O΅9EJ2>Lhܸo߾q3g|Zpu׵W̬BYo=ƷaV)UyvSӲ>(͂i Dq@D/&g>M暶ӭL_R^q_C4 =>S:mb~i :E { ` o՟U!3 řXsU|y hE}B=;}GE>oNF,]+WNj?fb>[!(ωwvQЬUa 4B\gxƬ9hw̞={={F:xЬ;S{n cŗTZ]黉iL Z,ᄏ6Q 4`l?a碠&{X|Lhґt_kLvH0 Zuvzk஻"hSEs^/b1QTax " D{x1i93GX%4H3mfnÖP$U٪-D ^#PJ9ptkƺ˿f3O3~V ;Vos7Wy^flR@_)x|m=ʀ7E5`s6}#J?tRgz:[MKMa&%~&+BV􄰠қJ-L@{-m@&DŽAJ|>^"7R Ω$1i/@I(MUD77gj<i5*fe57'a묿_x¹8(dZaO> Њ1=gNG0C ?@^_A&@Kg.齦`?JV,[F]=恢3YqM6Zk' S@{Û\V +xJيLP;`ތ;wT sp]sN+FvkM2~I(mVw____n̿3`c `O"+Q" 4l{܈03注$ 1$/_ ש5k֐_(]gZi3Bhx^V E0L('_I+Ҫ]g\Sa G m۶dNV Ҫ3)R;N"V#\^16?6mߗ O|/pl&jOL=%?2 Un &!:_qdMߤvjYjSoH?Ȼ>sg}v0-HMT \lk\|Xw#|/?ՠfhI;/oZ?۷oOJkOSmx9xgS#/d KxW"Q+Т"6`sɄdEM ƾyfBؤ p碌 G# 5`63 A6 Z5Ǽh8k f2V`n@IloɎ9/:+2 *kEٖ'IUȜ} Ix$9\T™]@y`H| p~@hЇnذa^mnn2qsl!U6fuǎpE9@@r4\ֱSphh;w0.P|31%e ),`S]Ч R* KIAA9E򱑳g`^Ww-: ,+B̙3ꫯz"0@5kƣT0Dՠi+jMKTi+}H ![pIEo[1Xs=ǮY}o#Ux33V7B5-TSǶǬY|.ñI2w^çsY(, `nW#9hHjdN?y_l&elU׮#Ռ yYzY0"iك4 IW!o&tr@cM?+njcH?~̊b HZԟmH$*ZI ؤ\Mln"1>aӉ!dUд]ollKY$5lLLZ[o(0m۶B&St]?V }M Bח Ύ@v@y36^l[cIʏߤU?Ip JW]`˖-^{ șHFm0N@.G`&lwò+bggUV6? taBSh ,4黫)PCm6!B_8i67Ҽ0  If-gQ*nrq(J0+O(w h]Q8E~ߪl! Ջ*{ؙ}|qqZ7*i/bnYgcЄDفȷ`dtY8V8}t26EVj6$5I9qQr5'mM?.~3od>">3}?ǤJ׸b@^V_LDyƗcJt|8T YE@^*oq-*:9Tx_lA!Yė3 1zsQ_}W!/_PY3t){a%RpUם j@0CB(|f.N?y͆b8dv,B>°ij 5QgplUo @9 *V-ehcBi Zt&Y _ rT06LW7Oln3WN= @# #E/??ԟU^ma*pC匍}LzBw-J|> 6gJ .bȎAi"f& fvu5LוgBhy(>,Y(2C~oSӠ#(5TTvۡL*/GVOs{LUg)y߿cQ 0k#u.6['"-H@@ZO@q_17m}ESFz6 4lV JBYݣMPafE}F`;/Jz*}\jYrPxuN:ZX D1|jK 3mttT$ WZ-lWqF|`CQlg`m=];!ٛ66s%XVטZZNJ#%ey[K8RCpi?.b%Dn|'o"Q@tBJ|aNYa%E|m kr[x_Zロ~"Jo6 }MIײvGKEQ⿗ ߦUs$  Բ3-Ҷ)dtdVU4(yOZlHm >@MA&5dgO<) ^eߦY!"55:n-.Q4`d)R qpV"5+y 8^5?,mkY{~~jy++h(v+PF@\>}i[ rƻbH(hD)d}CE4%vi I햔 \MI\+}><Wo6k-+Ј5,~iCG>N,J[EbɤຠナA$)阜v/5 B0sLD ?ļ5o)y)ZUw8ꈓkDW†Ko7wreMopB1(4 j-HLIqeY-a7?JKF625 99isuIg7n@]S ?aHɶʶȃE'J@ $/|׵ckbŕ"%fD^fn8$5Mk9r3-`kdYiyEq@H|S\p4l]r%FbL6hDew'9$]||ZR^!/BM(}| W-S{ms*˖d >/mfڳoZhm0؏ .UN ųfmƔtqXهqƌVlY?@H+0VkV}*@8]"{&݅}7Y%0` QMSځ>`$tn BRy4 `,<(=0>N)3((,Ԋ(y4!Hu)U QF)*8 G^]QK\NhO&UV(K ꫱6Ylq/cװY5hJpwr вvr:A<0dz]\I1~88lޗh sw{&H mڬ;L]$@'d*@l/J&]be*"/eB嵴&y QUqFOXU`4R@|&+f}c@}Ձή:SE]P>BmCɆAMev*?FU}Rg}LșM5ٛOW`4gCy GRK'`E6}4ʁ#ж ;I F@yJh]>;9Շ1d8S\7ׯ]'i+g|)*ItUhZƗjϞ=]ڛNL&e]zP0ɹfeÏ}sl_z6l?5k_oo ~_nذu$a]e[RF|As\)^̙33sr<$3y/ ,Er]e<S\ñ)0-f{4Wė93P2׆_|6gΜĐIQ;+)e`dШ(7 I^c$vC/zh4f޿/+$\V_$)w sd5w7/ș4Myh@`bk22̔kk(0ù>XTahm_rF5tS4}zC(R5… ۹侕}+46d5B$'iQ*zH/F Aj΍PEJ*"I \џϚy%)NAiEu+/rNݔ $;*2|%IJkqRTiӜM5tɲymX:P՗\W\B@tEv>W^.Jv%AO~y-H!_جSþ5>~XWdU`ŋ}Y1Utﻖ=_fQsi?i=ZZQ?$?>[d{WE7`%U&@4kb!" vqa UOJo*\N۷{U2fÇ lҊՊE~?mP~@E6P̢].݂K.U7d,BC ]} .f W{56e]| Zbcrf==5-U+%8%(!yQ~&On< .+}{Y9Y};'{ꕕScmȴzT4¿~ФI &ODM Bcm +Cx-mK4JBIAm _i;}!ރ0h{m[ǪO3$CK/&?hDOz0&˘y"l4aCWL-ˑX4 Hz(#(?|'r{佇t߾:O*ǣZ6-P{%L*Ê$\sMkͥRHdk p\OҎ;ZTIyP/t"ǂqu}m =ؾKju-yb@IG66B?W[^)ەwJ?גngiE\~4Nځx͚5Z?#Wt`Gga`K{$"3 Z!0lUDNptr^q(I6!fһvk_ڜ* ۿο`P hF''@:+WZnd2A@`Q dOBjwPxhMȴL":kr䌭Na>aOg v s=?3 K ii?yĦ<Ȯ@@6ZJ#9In*yL>@^μ"1B*:ׯl}ݣ]K&Ff#Ʊ/ݡxmW" [ySRRz-CNH4oẇtfVJPYz:iqPl۞[t:+Y+c?U@M- kgfN֭[| jMaˀe'{ޛ4.v(-a[Wm.?yOk< nTak3eub2hxxQ*^i@YF~fT,X@AWNa2YZX=,YEҖLh{qW:tDaSK^vXP%\bEe0Jm]tZɭ1p}XHSoY$ H@yc#wjI+?~f3W_McR'6nxt``d|ZRؐL, *aP9h-J:0Myy Dmd͘ 1߅U쯧Yʏs.L$'˗EUl޼_@&N!>e,$lPeU{&4Q"Eeej!D pFպ889r˖-q!1c h1٘\l0>GUz1(=W޲XSҵPuUWeNs HJkZtUi|RN]4úefW;YWX(YtuMлϿ&T^HvVrMn"CWs=CV~_exɒ%7E4 !;O>ݻ6{Op^x,8V(rL-@vw]_.T[{7|sYhε&/ږIBA@)IUA7*AQDL7^W01J\+r0@KG(2f&#)sǞ BȐnٌ{8\|~(?)%|;k5_~YPdiL ov;`cY4{|w0hTȌYD=Tv6Hz/t~|vI?ҙԳVW^nSP2(5RӺ,$<P8V{:J[0{^:L2Ɯ~,_xpGٲeKKt8I( @*\t,ra%d ϝ;jgRbM;e… _d֭ED5vvMD(1<0P|^esPCP D gl۶e~6:l 4'QtC6-?:)' B0|DY`ݠW]kD$. ߟIfk2g:5(i4- 0? Ο?[tپ}{ &9m'FycI}?)K 8IQt{#/~E@ k,:'Q͛7MuرcäIJhe-DIҕ`+0_g}&3׬(}Vu>`ұW@dM;wVVXUCȪ_o+ܹsQt+pwժTa'I"h9k2*2>BnVdΜ9$TBck7ox[ei^i ZcSX6`UX ^r%ݬC] ٳS  cHVX>+rY3VXfW*֬Yݮ?]"W p ; 61a|UJt-9~<Τ8}6TD = աY]ה+%$ 18^tf\222h5S@k@+UʱTCuL-O2y7: [cݲSk^R.\/o2.ٿObЀAĕ(Ub,q|ƢdMQϨQXW_tEQO-8pbI@*S}6BH1Ƴ_Vξ1y7q>5+UX+}Ys,N=Yv^xᅃ]7& Fn61]۞]w"$!2̖] O0 rСRv RZyjSE] ڣe: z ^;O\;u7>R(=*=ި3RMM&$ ju`7x15Ɖ:Ob W7AN::`ÇWuW0@`".]wI!Y!K찫)i" ȻヒXۭd v\(cerbuwD y;l7܍q)#{PR0:=Є *f+#s΃n>mTq(Hߦg}h ˇ~9J:k$܍2::[5H v~}裏4X<̠ʗO>@ŏN?O?kݨTQN;->BAY?zrҋ @uSNnE?VT;vlo:jѣ0eL߈ҟtI0>/0X ('>ē/%Z )wv*O~ 'lALꫯw̄e@֢юo?>5@ռPHe2epxz$~ίu=%୎͎ O<9(z MhEw& $H A $H A $H A $H A $H A $H A  i}B(IENDB`SuperCollider-Source/icons/sc_ide_32.png000644 000765 000024 00000003030 12321461511 021220 0ustar00crucialstaff000000 000000 PNG  IHDR szztEXtSoftwareAdobe ImageReadyqe<IDATxԗK\YƯq3C"b""htK72sٽr}~w_?F; 4]pyp|{3?11yi777N 99/?k7,D?L۾Domʻ4*Dvww@AAA@ ~R BF {MyD[[[f{{*K(T !fnn. ѤsyyiF̌6⭒@T%␨-%HHH( 4]]]nLvv !HB#,JrqqьC7]AHkxޗ恸O>5޽S馵U #/!'L^xaJJJ7fggLj 3dm(=~7+Ŕ& Y&qCUYZ tcb3_%NyOJJzOT l`閡H/`"Yʈ$,,,( Ңɏ9 culICaWNcE0ʊ!+ M>Z;"`ma *%ZBklsH )1!3ELqA.$$ bNu@A`>|pN&`Brc <` -cc)ŰC pL=IL* --M҇*5ΎIa26!AG& =*bԔK(V!'d8BgݝpA$EvbE(իW̐z9aIVdǦl>V{[x9(Qdfa=x(?;HVOc b6 j? =Qa6!SeӲCfi\ HDŽ:Xx# ARK@mnSuu2ׯ_nt _޽ ߿6uф" r|oU&Oƌ lLJmr7oL\2 Q ѣk7ndշoߴo4_t?>!9sTBX*C'ODA:;;۷+s0%Dٳg۾X栧͆ Œ348qİ|8 g?}4&>0x su,T&z*>}:tuu%'(Kv}ӧ*Pccc% l޼9&r3nܸx-+dg-2 !eH%5<^|ka<hLvژa=x=H4J>BL纒peĈIdaqXDZ_#ЃCJH}8M#RuńJR*€ 2 iʊ4 o D,XE .G%'M8rȨps $^c`چ>!1Y=\G_v-;vj,$Ѫwn:h>b|WYPYWŋ -,qd&Aj8(˂8 Y&KBd@=L󓲸Ή8r6z͓qE h9F!̇սN\,OANJVp8\,H,К#XP@c t, m\e64},VMz[;dj,d;dsp\|j^xٲeQH.E\+ PN3D ϟOB@dU=Ȭk48.5kD j=%1L`k3mZi+HJΝKz;Ӳ)aO@T!)Nի}b w_o9aB$UZM9s&:e\VWZ̙ɚM!/B8ۢEB}%6eh&J֛e t'&4(k|*Z,*ВRF}|uU?YU) 65Y"{1V*ֿgVJ7ϬYPַCoI~jWҶ&-Pieh0R웿IENDB`SuperCollider-Source/icons/sc_ide_512.png000644 000765 000024 00000106253 12321461511 021316 0ustar00crucialstaff000000 000000 PNG  IHDRxtEXtSoftwareAdobe ImageReadyqe<MIDATxi߻j34G#BHLbfƸqIwʰ&+i?>S+kogXNcn;nAbЄ`@[yOJ{[2{_|%oCے,HHƾkI0]DIne?ҟ=2 @׻BEEJk .(3UΗL.?W@EEhEoɶd*z{Pq &(PQ.^xU')[gK@EŶTwg|yc)x (P@EEJy>}zVK_%>9 R@F>1U?N* TT:(;3LZ[tR >q* TTZ*_җƾoҏ6m?M=TQGIv ءBEo֞*ݑ=z)TtN.2L+Ap׿v*TQ ?i_EqO+PQJ˱4>A@4'q* TڢPQ)-(PR U**{ァ@@Exo|ӫbML 1* TdɕW^}**ne*XwU @Eߚ쾯_Ex<R(P "###[&^ 2xF//2cƌ/ſYJp1mڴϜ9U8S#V**d;@4>@E=ꪫLdUT wy)* T*͓V6QQGp<z)TTZ~e;@PQRJoiZX袋z_җǗ^zi /L^N?{l?z|s1W) `^ *2sdFӧJQ{?]Eg~D J0ّlN:5BEJV?*~_raѳ]q eo_|I7}W6_[xBa2CP[v$@@(Pi̝;}?P\r%GϚ5˛b\Sf\l ߫2 vq2@%rOA̙[`|oc\u@dUPZJ@zD&J%KهLk:eb 4]رc.@%念| w~wz .L~-e[!uYBYt5ָ)6lX: Tj*d!IC~F_Z*5 h= TTjCݛn꯳h$qu*>O% 6J@6RRF.]o}Holl7k֬ ger`^xa4{< @忹ׁ4?(u֥Jj*M9>LCWy*lٲWZ5ՠZŚa ţ)qtl;pv]eȅz Tm޼ESԧY-|t(¹lut6^'o~`˖3f:s挺PA/_jݿqJҔ7p1\|mx e'_]wuM6* 뷟nb iנ$u\!+'|2-%YFΜ9褬Xkۜ9sRƌH1k2~\[8[`6P@ K_RoÆ o9]\Yse*_Vf]S\XmN.O{y(B6`쪫}w~ZANʕ+[oz*4M&lKT-F&`߾}(?V_?XOR\ƗAl-L꫕ Pjժ)sVe]ֹsUg<6K7o޼R{رsԩTh`B3p ػw2 %\sM{_EPSߓIa;{sJ zON{{~8JFשK)]tQhY={(POw{P:s[ j?xG_~S{ð _ `` E,BR+XnZƃkD.(@j"dݺuPwyg'RWZ*/ْ=>Ikh}&&&/5.U;xW4`AfϞoC1?{ST豎s $߻|+~V>cc񎌌-[[dIٳgz]@o~e;y P $J"*XgTBv*> ?K͒=ِG{;Q*߹p͚5+OZ-P`kW!>`ז+gǀ5kTc1ْ=> CVrtדzF^y+"ٔ]N% !㪝8믿>]wՊeK| 7pNu>bhP4SB`if]43h @E;w%1~)<yzX`AڶoL3" 5|ERG}TꞴr[GZ+̀'NsR8'b;?[KY̆X4Р5<}t:u=>w9 pl|_|FpQ@9?[EǍm޼y*-5}6zO1#H{]CEuR_=dG" |(1 @3ٸqcA(+W$mPqD\hn $]Cݻ7.>9`fϞҝ / ̯c-;l\6-\B&:P$]C G-^8-Cs +fk2icǎi`e 7ܰ5 q?iʛO Wj ~M6MI)vK>{i1!RߠsLlMdWvfTUPE}m*Y[n% hTK^ Yܟnytc6'_;vje^?J/ZȘĦW}繨\H"ӒזQЮ!i;sh˰LT)PJnF:mi /UisяOb!@z\uU3gΜ-j]31U Gj7妛nڒOqDz}+_9O6:>"],|~z"Xe]ȿ׀zD J@2^-7|3t^D??W ٻJM=oQ_/-Ő.! xҲ’_W\[` K_jja#?IS~բ,&"x[9%|CZJz8yn{!Sme!HFzVsUc[ K/U'tMr}D+7@}&S Tu׿uZ wG$k… }뭷~ZOQR @ [\/6E{ysT@> T90A|Aٳٺ￟v袋bY7% yW&Ga7>_fM/MuQ);9(2F_OcR&/V36mz"}+Bnٲe iK([ga0֮]+V}=lrlTZ*؈t+q .vȑ6~oVXQ%Ac޴Xn4_!}_ϐVsԧr^` _;c=6mvWX/,EMxֺ}0le=O{;,R*= +WLdlW^E>~_ɞn)s%âweKWӸ ߟŵ}osb]Ҧ<Wt@P\ӦM~ wٛ5k>eh1F RO7> %`[JWEߏ2װN OhP:Ǻ0\&3`1ۺ;S(QSljܸq9ξQ3uHu?J14~oXEME B*~2c9r-aMzϽ; T0? `lɒ%&s\Y,1҅sڤmub^{m`/}[~dž|7*ѣi`h ]щ`$Ze~mZU { ,M8?wR <(}1 R׮Hh&(yu\c3`dɒw:#޲e˼Qm%a} %lCf:/B3`F޽V@ua9(h(X# |g[z`ҥ&A$?66f uh^P~Fnɗ>9sn0hɴy/%+옹 0Z& >>L=|pIe XʜX36w|| "͛7UocRW=Wo+o槶9AXk mF_O hhE W@"1@Z% 8 NϒnT*ĪW"&hդFt`ЉGgbTRrܟd𕛀X٨2L6օAkLu*;? &P@dr=lIvߕJ۪` 2YF w} dbK cbie41$w% uIX[rHE(J冦˞x} l39o޼)?F ڇҏ5 @IZUbb  l Mυ+1Æ f6_"h ?`@J΂N`WPSG.]z(;ۦ+[xOO?)76R6m4ئP5*i{}JGLOޱcǢCyIN… NUicE!r-rH$뭷S +hbZ6 Y~b~pxe}'=eqAeе+ХZAEG]jJy |W҂B*3]6)ER8,__h WRξSnXb(!Տ_.HO=6ĂPF=\ؔKK9B\iՖ8p5,@kt)]=aێ CDm,olGc⋭{y1Y2Ls w`Y?W@X Z;ǿu:'8 xv4wـlX9B{/T0- S*tIU+J<XۥoL)u}|p{oJYl$X,"U|.-hIJ_c=&n)3z15$~SE-_ >@ϙ?U񲟡_vU]$XADc;~cl][\bS᧎b 0@ĄSed2 @m(  |f'3@r`b/^^zX`QQz|^,ml}k_ rUwu w,Ҕ~HPF#G 41Ο?_ M XMn$C,.V\=r.' g16ke*l'$bKu h3np0Y ~d8;xGy$Z]# ?ߊTwA#ɔf;bPdDusdrKS&N@@[jo߾(Yhdj]rߵkצo,FUL@ lѵPŤ1 >njcO1.JK]'Jd!~(YH%ߖ8. ??aLn}ѹMYF=(~TWZ޸;#hGwٳS7F\uH9׉'X#LEO(IկnMv[% ?K1}~sSV*F5Aژ?QP4b Ũՙ `{*z/ %PFVZuh߾};cqAd&U utMdV[ĸMQ2f;q+״T-܂\1e@!Bh tveˣ>9}Wضlْٲmtff> Fk_rl)җTޘU\t؞6\[2wժUݻw\ZIU)뻷P&E!-njkh9E]D<>gj@,Y<.kv1A=Pe& $@\l4[2Bu@2uv(H~[G 1{߭<ĸYD?]FQg-A{=T(  /L7Xq$n$b]ɀ2La-oTU\dK(X}5p޽є ^{MIZ*)u&^JPrhƲVw9GE0[QA}-@'B.YVظI0nRKsOR0h$ٳ/8]=aXyt/oXhjS+kwIAȱ7{5UEϗ2YMn bl^:7d16%YQӣfў &Z>(ѤFlٲ-qkc>X^ҌYa>O5ۢ ,?PǮb\ <^9׏ 8w?~׏+ ?}L裏Nם&dVF>ϿmvP,T3.Uzlb$^Ԧokq& \]HYzU̩E+SDa#Įs5*z[.PDL{ECK% X a+S%iC@~#ÇEˬ1|-UY?d4g]ۺoN&/9VAiK?mCif(0hKf HǸkc2-;IcݻEE>hJҘH?ٰar#`2 2jSSgΜI`UΓ|"wIdw 1,>X*MM&# o|c4fW6<&mAk[Lg!'oP}c2("wJ?6G%yW׽迷묟0]1f͚& @le@ x[CƄ%r.u1@B%bk?}tJCf$[䡁Fb G>1Ho1UJY?6nGc` n_(!k׮Ph>*N߸qcP1>,CkEmxBOC|Ӹ]"{0./2;Tp6 cVkO+(7I?Ӕv#DcI1"7_]e+cRyh7q sa(X[6|Ǐם-'3h +TI ' @dM hg$iL t]a4)R~\,_=8q"c ƋM[9@Mtmܹ)DhS 4`yR_r6"-[)dWen+Wo1W~ź23.KVy傫\kQk߾}SQRYA!iga}iRE`˗KSǕ()cIc⦺D5?%_k׷~;.jkyX^?\L٣DHe3=XӭRB 3&$Hꫯ @91ic2yuQn]; 1"XPd=Jߦeb[o&VnW-:cuSnW^9'V#$Tb4k׮ Ǹ\9I0A=#mPd(zMQn"cR&m,uy˼ƹ(8Cvן?)O;{RʜX+ oL@}Wt/Ɵ]ۍkG_׉)]:--UR?u٠*{:RhXmWM|,ԵRn N`N;tyoˀAIQOI׭[W^-m@?Ѯ<_zc1Y]u-#GLaEp=+V|Hu칙ٚXvk+s.ۆi]ȊłWa<fwG^Ƃ/;~6V QW/*$T5\hÊ=q{T]@97/h 7lQ.?Ur̹ m/6+hj >:r@z+:ۗ t2 S$?u]_~YLQ Q 8U EieYV¯:Vl(j꛻T>]k#hP.tuv*v-M@\ɟYҪsNR\$FWPJjBz\cKyt 7;r+i[Wl^s`,Q,l3=IQ:N KJ?ysjiR^,Eߟk ]g?j>a,cmh SNL ؗ 3|2þuŒ_"X  -oR\ :M3)_~A*b"ž0_2`K֥7|){Wx2j!Jgv.-.a #R$RM7uVSsIׂܻw9Q]NDWq7̚T:s`~KX#tk4&b*݊0׮][or9wr=|ee?(})m+*ky@À)v饗N(/08IE-"菠DJrĒh?֡I} ٳg`s +>vQDfPl .w\?NmB")r?K/+?1I؇O/g[X.k7qW<?XqlڴU}6/ RޏY*70@@ `$ C;,_:c(Zv^#GXِ ({2w 8M ?na"Bw|I 3IL+yҮ>2yQBŴgFcMGM*bAUg.hr0 [t@\omӻv:ROOQ"(߿&7I-{mǢG#>PΞx1ԭffZJNs H59@d/]+@c|uPyqٲeXg: z_7s]veSe@%Úf~] Ɓg<{ٌ>>FwyeBj$VZgۿ[0넏zb) wwHcpcCJPK?clK64bOݦ=E,lצPЎ;D)%K,@DpHJ$׮4pR2oe}Acm6잒DCeP+̞,,̢ԿJ߼F_ujXLiqz4h,S>LB`ZiCa<e3E"jIU"s7lΝ;e$Z%5@-_[o?Ay+3fˎŝNpƺZ0V\V(Xؗav7@, %ܧ4Y?m T-H6tv@8zKBc1QJ4 Z5j `AC/ W_Ac[qӧOK.AB3cR~L}(RqXt*S7J?o*c|||~@@#P{užp:/(+WsDK0K({C!@}WJ&Au`h@ (ߍf[|g̥odo}h꿮!T,Y,G؀ x (guF 7A, T[a?G%f4###l^2,.H]mV?]zկ΋np]`JH׹~!*6p -sf#hX ?dr@e2H=1<`6=W_-# R$c Xm_)ɱ(-|9c5$`T`W$A z)W?0G{JgnJXLBb^{711UM1a\k2}GZf9R ( f)WL*_ӛ_? YlG?*~%}hŖzs,m)1;w7gCYૈڰf"ta•VA8scJAf!͞otPW@/kgsUW1O&P6!@$y`bsSANn0iUZR*7U&ѧ Ou/mLZR+lq,_Y2J$VB@eau)~)I?45ʫb)cu>HM-U,J zT&^J;΁*k2XӆC4)\F C1K\u"fmhL D뿮%Ry&/YOj? TSuF:f e" M[#mUE HjEL] үb% ;_Gc%`}U @9P漦}hl+qdstfϞ]+*b-L_h)WB?ts=7TUT3 _(+@eRMCY 8 :;O?X2(W*ԷYA(k?t$c,h(d'>c7XsJ n)vˡVI4quUgQҢmQM:$V  . $  hzH6:璖z$Er嗋[J_VI)3Ȫ= SOT샀li \j#Iqdݒ*ڢ랋5)l2ɪ.LI]%bU@?) |^7*dIWZ%&0H.]EŻn s@,aZj7DZEywSiZAŲ  \0@4 huc,q.4)j2YF3ץˌgO?b4ߏGt LWމ'4*:k Pf.}iw?|TJ%)F6MPZLPIJLƃ?Dat0ĨWPjsYf!p㵸ι aCGeʾ} bZJ*[{u>}4߿df|eƔyI1@*pUGNd)S4&AԦi+߽{V /(AgIuIJW3vtiu#;(T5525.~d̊?Ǐ/!A{?ֈW_0HJb(Vv%  4@11]PEBXF麚yjIu? z}*FIέ:J?ڰ@@ߌc%+'WIjWɰsPYZۆd3ֿ~U' bݗ5}8Y+!% @gخ18|LĠיu&Vio'yT@\7GN9b2c qƚȔ[>_o*x67Y%ԕIg?jMT ր ys,P݌;v,I)P(85俶U.GLs`^6Y7]dG j V`zTkGy22 +J9L`(}l)|U`cndpf[Q,D$u Z4m_ƺa 4\jT}]p0q~&BgPֵ#$?F럌Rr(M)ls/@SC׶A%nY~p(V ܇ 0g~ 'H@"``2bP+_7hנc:^GZ; p,{7gΜ[hyLd0AE;* )T55)p0[ħ @\PNFhhK&HH "+mXU)@W!taCR(BBY?1-?o޼nw1Cugb}&C6$ ϝ8Pu $5U%C~\Z>:"LPmתve|eJ0 ~FJˤ 45hJmۊ'ir_6M3\|e2ʾZ=HPr(| B$~=|7uH4-:Pp+)/SLC) d3eEJ~&>t?wi# ?LY:duI~U"!W`Ooӏ⎰JDد/_;|R4.k H'eZyƓs)t,eG؂ӏc14($bL>s IB%\0EU&ͬ-mS6ֲ˦1-ӚwacЯ/?t+{{>KQZ!~LUB_mm`h-fʌG@Q'5 8J?i]SeIXԈ'dnR< dW(u4TK]EIWL^0&e} 揥HT@)+깻(c\ԹBRJ}6uLH)װo psMm~R.DC17mePVH BI/CJ_YW f:rQdJ Xd\{Q_׮6IqMAeBLM9Tef{60dut4'yO&I\>X)~;Ŵl-_YR^A2V,{7kGFLc65$/M!s~1%l3EuJ?v[mr_|*qPPԿ5t4$.YJ$Gmr.e:ؠi@a^г[$!>:o.YtJ `X6%5 @VE*)84!JFKlP$6`$5S2 4PkRlkNY>;\y"*ˬK.TUЮjWYÂRM4I gHHjeBQFy睠J??ߥD:\tHTӽyպ K/!pP ~b*XcR=*pt*m_J,)5`f-c2^ve?x+`S !4K;0/'ueV_>_ʾz.LL_ Pn"(W?L*:u*NcXj>xS qIq.ȇHVmM!,= F uT\Ӓ[ iuC l l ˪}4 MgmBht 49}eޅ|'!/OPLLL,@Ȗ^u os_fHTlFh߀Pٲr9zhhk0*Tg2pKHDvIgCdb#-%g̘$9O8Z҂~p]]2"0+4͐oeoUW)Ꞑ|}PQ6oQ$ ȑ#RKa\*}i86M\ e/??)iQ*2A-{"1qeбɈ[Wo{V\m\'þsXg1MԽ$a&T䚙㺯U9Z߿_TØ{6^*s_ eР*s.lMMz>h]"t7 lJJ%LRd.'㰠 _X>S :%?~7::`_O\2=\S[)lf1-LP7X~5(^: 3P -]Knc?AҔ?¸]SϜ9\džM# Pk1{ t+6*T`#xd4TϞS q=l="URY|ya@E_~婌 rرZ=\ .R>~V+`P8Z `97XUJV.ɈVW`Y6jggϞʕ+zWEY?[k#$k~q `h?j YB@@ary Z5HĪ"ޫ BVZ?AaAҘ :mtᩀ?!Vc)5H, ض m'*?S?l Z1>a)mW ))7 /ŸlrUv:|6@پe?ӯ@{F*2uc$56WXCuf{uM}BO], T}ӈ?w>w*y~Μ9iX?&{mgnT =$c57MX1Ϫ])]uu9oDE /4Y2A̱)үcRLU@[lR}2Ee:xٯ`9`I32ֿcbms.Im}@@jd#?}{dݖY`T_WVZU&io*TnR3`P-KJ ߠ(]uU2J,ykĔe׍@nc6In+V7~;żaisNuo޽eʜ; 4o$)["@f &! xq!hN0wĊGxݻw7S{!;Ui)v.܌1f 7EqM|MhpJk P*ʤF)S⿮/`l=sfVp&g_:`\& /V''b ,\P%gXɝ*D?sҶ {0>>nIVIU[uUTxՑ^/ŸYCoYm 9e#y oqTD1΅ ?(bOeϯMӔQ&dǨ9ޤ#JБmvrh칚 LPbB*kYϟ'ҤDJ,>RATyCeʟK tW]M1 WLR]բBi8qYU3f:fLg`)bl[ $ +QOPU GLͦjuݴRN @rŤش|ɡs h hdA{?,>5*SDV 2Rle_^R$nGq/7 Hѹ}!67ޱs/k9aph |Tc4kKST Q֦쀰@1D M;An*>|hQqY*xɒ%AT;R.~ՙC qbgqVTvIs iSY=De*GŞ/x7`sKOQ/h5:IE.0A~b2\YU>["Ko6xbM]Z1TAS\g Oe"7k H2fq"2̚5w2+T,c")<]+'*Ք__"/?1@.3c HQDZl.P !)W]Ra$渟 dV, @*\d[ 8Jmjq˙VR ZG1Atb(`GN jnisa՚2!sL=]ޗhʩc(STZ`Ǩ8FJ4ձ}צ={́A&wm]YɎI,Z*\U @7> FI˗/+cAR (^zu/[)F>/ Fgs~qvǴ<BP̟?iY*J.e19;wlC:u* /O_5u`A2>;7VI  3aܛX9M}~ҥSCe5ѻD_xZu>Ms ψEa\Q HXP_8MZ\ZZ,`@‚d*(b=YLw4 !duPҢ{T0nI0])… XU$ x"fm[ ޲ezGjSeA](ө\_>5s`߾}uB,q3I2ֿ",$C?/$) 47Ij4bOY[_%d.nDk7_bD2Ű?R<X>;0P]`6Kaf xs<{T%"{[O7lRa(ږ,}7|pgvHwni"7n5ۚ?V0I}X_X%T*J2 ODYK{O ^g?rH)&n6>>}wȑt3Yb*?i~`$r[>\F'x6}G/dZR#b͹^.ck/{w|dQ'64R,C#ttyUC+<ԍe4;@]fvH3rTub ;d  LYu`N _.鎆Pa`}L`4)}sO m<ȳu:BYF3?[1qeAk@ =^b.,6(lhRظW ]b%oי~lˠr޽ۚw Bm!.LI?: PlXM Mؤ۩̶˺uz=\4cV>j2' ܰ:(z 2*OEM_UuBah?XΘR7*k0GLpDH X\rfwҤ(իW**cE fz<{6[c@({6>?aM*_uv*,,"`TB㰬 Qۺx0y60bvƍLR&vIPKP꾕OSEFgØaϻf4^?lSfچ?6ֿ$XR⩐Qer7֭[񁈩 /ť,z5[+YhX@ 4a犵8H6;v,Y\Wgl;ƀ;'u_]R6l+,_o Cn` }BSRa\u~VI릪)nDb?!aE7 vNpQQu#+HpU̾ѫ!i?5R|Edj<m޷M~6@@~ڎ[uR0YX /sl{qh#5]( 4PX.nNpwkmob<0)O%=]E}_x+,B]7ǥ|7~Y&5`yWkS*TycM,;BVͮ\=)u*]˂21 ¹/JeFY@ gr!}eӀs="o?+ʔB?ymzn~?Կk^]aѢEY*gu09(cAFQju APn2,O?J@={YM-A#+x)q-r=Ɗ*oMHuY7\?O$ P`X$=69|~e r Xt^@ 1ڰr"_*7\Ϸ"vaY'9s4^lOc +#Nlj3%El:t.{0EB~Eǰ&S}7^6vg(KP!a~b}U2(t `<#i0d.XkI Z-[&2gT4dZ팇}1E~MKx .-&3Sf,{.yFڀKd:w$XS>T3kX&  8=XpM_Q[Y0 nO<Ç{Ǐofw| ^ҭ)/c{ IK#Ӻ~sd#C}8)4Y[Dz#!,㎇ Տ>Y$lֿ/KqU\*31P.5C 6,@گ 3u.5p"O<qa)-}mSHcVU]Hĺ&/J3gάLe)^Q&#fe0ۋ 'ONЩU\ ͡pgNwMqĉszvv$u^]AZvD=rA^7 2w}7)E)X >'c*bEkFr~C/VE_V28֢1Eeg[lJH~NK9 ۤw!Q׊tDX GBMIEV۸qc< ".8@k¹p OM"{鹳 F*7(WN3'l{F z &7@lN`&Bӄ*}|y`cra2:7pI@K/e m<ؔ4nxs2*-?EmaKU?~ӟP)Tpm8}y\o>UŘ[ey98ߴi9cu{VXѻ;7*PO67xùιN/"quYw]KGpUk "<)sIlWyYx…S{B%+'E0B0 l6#"rpY/Ic\|ms_Ulqqq ( XgSH(mw>=eCE#U<Xj8Ja7'򨤠 TFo%v:b14'MKoBBn{a{ݱbOs.^DRe?Î/_ޛ1c7V O?;;4d,iLЎ,BPaJ]-rE+IOя=V_$X!,gΜI| X,yƊg3d yI&Iʚg Tw֯?|&#ƴhѢԶ)di`(pU;πaɮhjم *ZZm Ƴ=V0.*]WLWO2]u࿢swܑIdl7fH׭E?VIcY imWEe_AI79 O>I]_Jߵ?7{23]|[4Zesۤ kB2umҔFgXgϞ7uot017{gϱ)4%tMص\~&YWJ7dxHH yR>+/"oǿomIΕ4.,\Әn:A`.N,[o,A\U8 q e/zMj q*XDJUu-Ѕbԫ:T0q _ןT> iڻwoollIjKS 01iFގ;RbI3N060w4By {2 |Hy/I x'?g9 }7UNL~ ! _@CMPY[ 4[MU#m*,RQn߁|UWN^ʞ cMdb˖-c&;Y믿^R(*x f2HV6QmFye]+@=H`>!Ss:eӲr.|0N LR+tR$B`U52ԮTkԸqc*\Sj7oabjX(*E)hEuaM:^jlt.dEڸhB ؚRm,HgJ_ϻBscF`,1hBgفMC$)Lb*  }\FCvmY\$O3ue#d1(kkX(wU}˞tRaL/nlAMi>PR%P*i ۠c:&>XMY;*?Ocpv$ǖ-k2M߹X/NTZ,]\ϻ}07ssUy{阳ٸ}es̙q"۩(TvNꦨ$F@lJ JEusstX'vjٵ01%rqi,~Db21 b>=ٍKk}&tLni*8)e5s>ٔâN5 -Rr/Q̱*kLٵ[` IDLtZqn[o.ET0J(^@̙3{=Z+T9ÀoǼ$.Mf D(ߤ*`RJ ۿJ]5B  [ouZLJs~Nfrm] DK(\rT=41 c^Bo(ڛU'UUY//9>AKO>qWQ~[c܇爫y &d~ןu~r_W?e80e}6& Oy;kɢ ci@F3]\__bL5kWp<#] {zɹ[b_nk*1!.~(~]]2]yI22l6ǽ"tދ_LvɴެYuʗք 1+6g?YZ.W tَq4li_ Xzʥ<.[tsJNcQm 7`09M,.`P/i1@+A)h5ҵ4Skw`h_j:םw)Yl=QKnHiw}Yٳg) t蘅:4QYZXffаdRoYfTEeu֜*kLU9XJf۠;/hÏxEons Ld=cRx4PP54|)5(gZߠ=_p_jOXl{ TS{/:&P/ T1P.]m d:f,~bMShlbtgVȅm!??.,6RY|o|6H45ZN{mߔQʤ>}ʊ+[O>ϴEoNH?I;p@ld =W9@iF`^}4>O>JaSL)Cܠv1_dٲei]Qu֘ o.ŀ[Lg?HeG,)\#1 'h nc2Hx) 4=rllpcRdt7*&:1"z d͑*d=d̂uZ(5~ u% TWVO&*ڳ:t&`X Z~1-ϔ|Ѹ۷/u ogLt?T?n6ⷑ c]hN!]|8$Iƺۮ nT< B1!]O>,e.At4 yLL@`P|6ۉ?Hx^6/{8G~d/PU)uMP{QONT xX>ibwҥK)Ih: : !6`||ܩ2 ӀbDaMlBs;o<^Ѐ@#Ј ]7E0>{צ k4&\87u١"s]r, /OdW{ڪ#[dX%W^xS T>~,Sdb @dBao~"|b*Bsa̤ 3O~B0Vczj1eR\|'`z%t~qe:pSaUb tWd\ s϶6V3`KOhZ rĉ4" PϲҪ m>F#@G@6}MJ?yL >~0ʟyyպ`-A^h\}[n8yqgoڍIf7r8|kﺮC4fjxO9fu]. : Kp͛7h<I#cSCJj`6J>\0!D1+ ү͏Z6c? 7ź?ҫ!; ]Ћ{ݑR_Uܸ<Fxl@@LT S}ᇢ-XrM)ն@(ScY{!]?L ަ a ?uPFBgc l8I #k+;d"hyk[WtbHF8"}T $-R`Xuloǡ䪁4g㱴!)~ ׺I:M1/M__@8z--{ `U.,~ K+(F e6Ce)KX*ks]}D ]҇߈lL&€1,m^ME{@-v_y"QX.|U.\?+Ez])%#wq=]Ӆ{|{l+_?õkӧZ\mo|`P{\v;7) oPKءTyg{]XlY,Aȓ zB@@F֭[wt(25m-mmRu|+v1lL{W8^{6>HQU *&lk{]~zGbQ;忡:.CaWxٳgOC̙3S5*JSFRxP1y o߶(L:I?n cJވGq7-77DIP뮻np%.m+~({߄#E|KX7eo:@@A@1?޽{ 4Y Y.(dϟu*:H#>L7?̯kezOz ߥ\0!K۠|`H<{JRACh`O1򏥼S(埌wbr\׻[ǓX{̙Ti6 Z 6Xk׮?]+ _d%KqP-|B~Qk=kjgoo(d~6 L,)CW= _R z4#4? q`$ο:%̿X27xZD]%dﷱQ>|8aM׀An`@c?tUR6\!!BU@ v m-JA@eG@Qi8J?~o2l ?RƍU{)P4"CRE㚘H)S_.n*>1T#_O)+/{ W"$T)@IcTxZGV?5)K-ks\+'7lj+@,ǎϜE"$!ʸLӤwy'zBI9c~5ҸHDk AUӴiD" D(C<t>IP"a=0iHm[Q 2ZeqM7~HT?WÝs' ʠ@8wޅ^XJ)cp W1ѣ+Y{?o給>o2.2PKavREvڵ9$_|ũ .LE\m7x#*#SY?QS܋q7o<sP7:mڴ ϟ߻袋J/XeSqz뭴M OG SŽT_y啽o}*1FI~ǶDoWm KOv߉u,YRl&\]L(hSca}s9sf TZ~QV^~eX1bTps(,F"pQ˜ėtG.ۯ: S @#`,A*6iM)STAmIwOy^>4R37xc ""Ij"W^iB"C(80R6x7[Y-QmW6@e+`)n:U āI,#8h* 28}t_f jwXX(|(61.\{zkK/}TWLyW[`f͚ջ+ZW*x|'ǧ@E7uqڿ*kתW lE\# +P6 =.bN:;vX׽$ϾNO iqпAP y׶& .`LPuwMK~k`C5>}>[\6ė?] ٷDYfjс eŸV*xlovک0? /  ;VQ<ƷjCIl,~p Q Zٽ{wkꫯnu`_`P@|Pa%2(ogPX(z$JそkZ^{*q믿u`]PIXm-b\|I *4{ٰٛΌY>xl@M6!?+O^Z)h Z`Vp e TYLI 5;9cwl l-o* %{i@@l.JR6 <ʜr^zslwK.qƔkkT+P@\ qujw|i_y#U ){m0V  dz*qullVWZ_|@RWJm\?juOd~U )k%@(D0؅^X8j*m\.s֭[Z*W\_@gAMV\ӦYB+0w|yK.M}mw>(MSmٿ?,``怷=+qu@kNնTXb Ty7Z R@9TUFus_fMwmt  5T.MyӸ\ ˜**@iӦ(y8߉[؀l9aʵ%:ɏOX`A[N#ozw*@e8p`, P+&My]Nˠ/.Dݳlٲ+P)!%m @KǙօq5q0tDPۖ.]_JE02u7@#-%p{Oe+Vϟߥ% O't5WRCڥ #_#Sz{x婯c=U@hm7ii`k@Kw:awT~ů~ؔC 5U"qe΁OQYٶdɒZ+Pq:&Ol)om?MK]8Ç&;@XWS`'TpDEf͚%`/^x\Wg*~@ȴiplu R &U9,ML*z5D GT3&` U6?6Q!\ aKVP+2Ra>ԯ_j<(~-@%f9vf 8'3>eW{KK?oثO젤o5OJl@3@Vm.{*|+ϙ3g\/'zZF) 4W?>]vYGCX'^*'Ojc1`~ xƃ(~Vٳgkz'ޘǶu- KeO:ʞ*^_Ӊٻ( ;b{e`2@30  prLwľH }mlЮRɸtt߾V|sxxXӀjNx_C Щfˇ!}n}/]W T)U.Jop󠐇0b!7~{kyaoߟ|_Q ё Mxq(gqC*or||!O999-}>#б @Y5窱{8==}@I5WVVΫ_Q z?R8(6A\>EgHKMƏ@8;;+V xJY^^N q  Xk |"pF~DҒƏppX~lO#02AC=Yq"CpcBE)9cx J?quuUA L`~XϧʁB$FtM)Nd"tQZx~vvv6U۰E!aN50ߛ1G> !Yp^?gM_9`@݅e2+V_5}0o n{a_>{Y7Gau_A *`y||#y x||,b ŖQ-6ZlX Plk yiZ{ײo%nfgvu%$@+0m6IENDB`SuperCollider-Source/icons/sc_ide_64.png000644 000765 000024 00000006401 12321461511 021232 0ustar00crucialstaff000000 000000 PNG  IHDR@@iqtEXtSoftwareAdobe ImageReadyqe< IDATxIoTǯL3 fa0bPg UvOv g%fqd!$@ 1c3f!;jUWߞl? G:{=UթsE?ʾK  _~3uD{d{/_O*D_7AKmvG{{h5J>:2P(]?D\z7۲V0qăb,>nܸhذag>D?~ E"'O. 6mvȐZV1bD4eʔhј1cO>߽{{MuoV4iRpB\$sug,ݾ}TY@UUUK.=]P]6ZdI4r}܄ 2$rf.{E RRoNY>ӫW*++V ĭ٣}hbqH]vu]`0|&!!y>;vl?x sNtYc4xeСqwҥS@MM >__`Af͚5D+̝;7>|xq]{Y]|9U %H*w?jժ*.=.6o{^lY}hƌ_rgk(qٳ507o9v~w~q vس= iӦ0IXbÆ ! 5=r -ZMz*N&@PQg) 0$|۹sgm1y8d4G&{xyݸq#o߾Μ9Р.(J"T"Z?~dޞg{ <:/o>a=׹ʕ+ѩS)$?J(nr8W6666Xo>~w+ir4k֬BF#~c/^H+k,9 -!:RvZR6nW֭[܁Iabͧ3}Bwm|.(owێV!t>>-| *hX ó<|ATA0K {nLE!` _l֭˸I×B'./_bz4PZfdz(J  (JJ./&X[`!ŽJVj=͛*L< >Q," nKy޺uˣ l]@&%Iku5 /^ LK\+VeBU](6beA wq m;h`HXE!lGGGP^d\#<%̙rD{>@LC 9sfF 5FM;Iar jyMu?F6:pڮBu oؐXWWgv"@4U%=חhB豖cEGGsΥWq1rOWdtaQ`ݒk^jc T$14ؗU|z<t:M <>!@$0Y-\R$8@Nbm<HB+0Ia+,h EG!=9@%3V1\hQV`ڜ p9t=&J!.Rp)GdR^j8 ,]>1GwrKQaRUWmzUK G&2ƱY¢ KD\Ϲ$<`I"ۮmXd[|g8$v K{ i"cئPE]"R]5 (JvRWoD<:nđ V.ޛ6[Ra&.[j/_"WTT,w^=z(cӧʆ_< l2E#6 1B LU[ dZ&!2. !#Z%Ět}4 0hکZm#0lQP`/sK" Y%,}XDr-/-\~@"wb'Or7Yg%۹Ws)ww>dT@}T^bE?n#GH][!*:U ~y­ld9̺t}wHѣYӧOIM.7>0i&>g:5,2hҥ]1_2iYʕ+ .Cy;.yﺫ=.bЯ6OL:5^LAU&kUڅ aai~Oi XA Kp+W]V+}v)׏"*=aCEQkpcǎeYt&U(E>Ҩ0[>V&gϞ^` 03!Ȗ!2mޠ.Cm]%Bh SMx|*05KTP+![QWL -J _גF1tiwMӚ9⌻%Z I*kXB%`͑8溇w0>gKEQ[Yqy%Ei.] aiJSlXXpCg=K*<pi{($*5/Idti`"அ&uQ$r;4S$mpݏd-[qR__O 8q QE!jU N&I;#P 8Cw'u:!"V' XOczKߟS! 6Hؑ.5 d(pvoޞ$rÓK8$ wp q?]mڅ 兇bƇ44nډ(gqOp?F|kQwT}ā;&MX%LI֏Q`物$qP8%uvv*Ay>4|,Raik8%F_N]Z{:TŕMO"Sɇ|\ b!2n/N8+#9OBxba"F?I3< TMr ˃қoDV2<Ⴎ54%)nU*un*% i %Zt Ը˿IK*#%t{&c\&^C(")L['SA{l?#Lt8IENDB`SuperCollider-Source/icons/sc_ide_svg.scd000644 000765 000024 00000003325 12321461511 021567 0ustar00crucialstaff000000 000000 //SC radial icon XML(SVG) generator //Batuhan Bozkurt 2012 ( var cids, fids; var circDefs, fillDefs, uses, wrapped; var incre, incre2, decre, phase; var radFor; var w; ~circle = {|id, cx, cy, r, rotate| "".format(id, cx, cy, r, rotate) }; ~color = {|shade| "rgb(%,%,%)".format(*((shade * 255).round ! 3)); }; ~linGrad = {|id, xy1, xy2, c1, c2| "".format(id, xy1.x, xy1.y, xy2.x, xy2.y, ~color.(c1), ~color.(c2)); }; ~use = {|shape, fill| "".format(shape, fill); }; ~wrapAll = {|w, h, defs, draws| "SuperCollider Icon SVG - Batuhan Bozkurt 2012%%".format(w, h, w, h, defs, draws); }; radFor = {|cnt| (90 - (13.5 * cnt)); }; w = 100; phase = -pi; incre = -0.95; incre2 = 4.02; decre = 59; cids = 7.collect({|cnt| "circ" ++ cnt; }); fids = 7.collect({|cnt| "fcirc" ++ cnt; }); circDefs = 7.collect({|cnt| ~circle.(cids[cnt], 50, 50, radFor.(cnt) / 2, (54 * cnt) % 360); }); fillDefs = 7.collect({|cnt| ~linGrad.(fids[cnt], 50@0, 50@100, cnt.linlin(0, 6, 0, 0.3), 1); }); uses = 7.collect({|cnt| ~use.(cids[cnt], fids[cnt]); }); wrapped = ~wrapAll.(1024, 1024, circDefs.join ++ fillDefs.join, uses.join); wrapped.postln; )SuperCollider-Source/icons/sc_logo.svg000644 000765 000024 00000012152 12766171707 021155 0ustar00crucialstaff000000 000000 SuperCollider Cube SVG - Nathan Ho 2015 SuperCollider-Source/icons/SCcube.icns000644 000765 000024 00000176710 12321461511 021022 0ustar00crucialstaff000000 000000 icnsics#H??is32ʾƱfRUOtwQ2IusE`22IlO@trc;Lj\`Y:ttjIZTFN_3losRPZYIe+ffYqub[GaGi Hr~uf4l)EoVDPS@Fsl%7^Jj`4r.?j]LTZD?or(0QLO[4s{w39dcSXcI9jy-)FX:EVijU3ev}83_hbaYC3f1"<ʐdWLJJ3Wq>-\m^N>2)a518ͥrM3JkC)II704BXx9$ Eо3i Hr~uf4l)EoVDPS@Fsl%7^Jj`4r.?j]LTZD?or(0QLO[4s{w39dcSXcI9jy-)FX:EVijU3ev}83_hbaYC3f1"<ʐdWLJJ3Wq>-\m^N>2)a518ͥrM3JkC)II704BXx9$ Eо3i Hr~uf4l)EoVDPS@Fsl%7^Jj`4r.?j]LTZD?or(0QLO[4s{w39dcSXcI9jy-)FX:EVijU3ev}83_hbaYC3f1"<ʐdWLJJ3Wq>-\m^N>2)a518ͥrM3JkC)II704BXx9$ Eо3 aA/D/D/H/d/a/a/a/a/a/a/a/a/a/a/a/a/a.aqa'c@wMCzӝCG}~_2 Kѽ|bF, NҺ{`D* S}x^B( ich#H????????????????????????????????????????????????????????ih32# ؼȬ{tzuq־ɹu$hpҹο{|&i̔~ȸw(p͢½DZqz*nְop+kپλmhj}ԁ,Ұiy̷ʶrmz̺, \gpǫͶss,)$VdgгzotxS-,233"#Mtxb^omgq|`B) w,;5>G=$"D^^t`W]lmWD6,$ r,D4tfY^F$ :G@]ޑ|m`TI=0# m,M2wvsM$0/#L|sfT@,%;Y1 h,W4U&$?񱙖hN4!#4J_s> c,`5])C멚7" ,:IVbjry|B# _,vi6~bA᠚r!(19CMYfqy|zyF' Z,lr7wqxxn>טv!'1CVht{|xn^kvL, Uy,c{9pddkiZnt#<͏w# 7s{|xrh\N@3]sQ1 Ps,Xۃ:hpoid^_z*9y)!:ytmf]TKC>7YmV5 Kk,Mލ;ayvtb_ɂ/6{0#8qpi[OGBBA6Uh[: Ge,B=Yvh]Lj64y}7%6jpa@BDIJF7Od`? A],8>Rwo[Ɛ<1r>'4cnbFJPYSJ7J_eD 60(@` .*Mȕ{~rQ@Je^?k3(8`aM?3-*,6Ecd &+  zˣVlU8r5&24.*,3=M]lxi +? mϳqL1y6$,-2;ENXcnyo ) axC*~8"*1:GWj{iJ& ' Ssr}9$|8(C]tqX@,  ! DXY0zxziXJ>3(  # 5>=wo'x{qg]O>+  < &$v{jS9    yfD%    5+      ؼȬ{tzuq־ɹu$hpҹο{|&i̔~ȸw(p͢½DZqz*nְop+kپλmhj}ԁ,Ұiy̷ʶrmz̺, \gpǫͶss,)$VdgгzotxS-,233"#Mtxb^omgq|`B) w,;5>G=$"D^^t`W]lmWD6,$ r,D4tfY^F$ :G@]ޑ|m`TI=0# m,M2wvsM$0/#L|sfT@,%;Y1 h,W4U&$?񱙖hN4!#4J_s> c,`5])C멚7" ,:IVbjry|B# _,vi6~bA᠚r!(19CMYfqy|zyF' Z,lr7wqxxn>טv!'1CVht{|xn^kvL, Uy,c{9pddkiZnt#<͏w# 7s{|xrh\N@3]sQ1 Ps,Xۃ:hpoid^_z*9y)!:ytmf]TKC>7YmV5 Kk,Mލ;ayvtb_ɂ/6{0#8qpi[OGBBA6Uh[: Ge,B=Yvh]Lj64y}7%6jpa@BDIJF7Od`? A],8>Rwo[Ɛ<1r>'4cnbFJPYSJ7J_eD 60(@` .*Mȕ{~rQ@Je^?k3(8`aM?3-*,6Ecd &+  zˣVlU8r5&24.*,3=M]lxi +? mϳqL1y6$,-2;ENXcnyo ) axC*~8"*1:GWj{iJ& ' Ssr}9$|8(C]tqX@,  ! DXY0zxziXJ>3(  # 5>=wo'x{qg]O>+  < &$v{jS9    yfD%    5+      ؼȬ{tzuq־ɹu$hpҹο{|&i̔~ȸw(p͢½DZqz*nְop+kپλmhj}ԁ,Ұiy̷ʶrmz̺, \gpǫͶss,)$VdgгzotxS-,233"#Mtxb^omgq|`B) w,;5>G=$"D^^t`W]lmWD6,$ r,D4tfY^F$ :G@]ޑ|m`TI=0# m,M2wvsM$0/#L|sfT@,%;Y1 h,W4U&$?񱙖hN4!#4J_s> c,`5])C멚7" ,:IVbjry|B# _,vi6~bA᠚r!(19CMYfqy|zyF' Z,lr7wqxxn>טv!'1CVht{|xn^kvL, Uy,c{9pddkiZnt#<͏w# 7s{|xrh\N@3]sQ1 Ps,Xۃ:hpoid^_z*9y)!:ytmf]TKC>7YmV5 Kk,Mލ;ayvtb_ɂ/6{0#8qpi[OGBBA6Uh[: Ge,B=Yvh]Lj64y}7%6jpa@BDIJF7Od`? A],8>Rwo[Ɛ<1r>'4cnbFJPYSJ7J_eD 60(@` .*Mȕ{~rQ@Je^?k3(8`aM?3-*,6Ecd &+  zˣVlU8r5&24.*,3=M]lxi +? mϳqL1y6$,-2;ENXcnyo ) axC*~8"*1:GWj{iJ& ' Ssr}9$|8(C]tqX@,  ! DXY0zxziXJ>3(  # 5>=wo'x{qg]O>+  < &$v{jS9    yfD%    5+     h8mk  *Z` 1ba 9ng Dym NsHumyw{vyvTvvvvvvvvvvvvvvvvvvvvvvy`G $X -b $Is&LvˌD(OxͼqB*QzɺlR2,T}Ǹ~jT?,/Wķ|iS=*1Zŵ{gQ<)4]zeO:(6U^M8'  it32 #&þ̯yee.Ϳ˱uqosvshi7Ͻɴ~y{}}|zyxwuoej=ûʶ|yvuuw}~{wodlCʺ{wtux|~}ulcjI̿{wusw̭wkdkǾOƹzwtwü}xttx~Ͳvjdn5zsjio~|wvwxȀζuihm\xoe``hyż{xwwzιukjm}`of``_`hxȵ{wwz|¼мwmlm|`؄fYXYbμwuxz}þxnllxeَe[X[ۯ|usv|¿³wnkjwg֏lYXXɚ|w|źynijv8׆mXXYѥ~-ɻ}mhjuk͊mXXYҫ~lfku~y~9ǐlXX[~ձ"Ģjfls{{py1ljjXX^|Դ/ɦljnqvxsjve̎cXX_yֺ~ܪ{oonoqskdmȑ`XX^vź׽~Ŵtutqonmkf_b~t΍`XX^uʴ|~{wrolhd_Z]jO߁^XX\s²܀!ͼ~ysnkf`]`l⽊t¾̃\YXYoȹxpjd`__h|лۈ؎ǿW{fYXXo̿ȻȻsjd`^`iwͼ؈h6oĺxfZXXo~wkb__aguȺԈdL 'lȻȁfXXZoŢ|mb]]_huĶ ҈M'*iþ@|fXXZmpd][_fpЈ>R*($-g}bXX\lՁŹsg]Z]cm|cn̈%U-*((#-bÅX0\j{{~ñxi_[[blw iM.:̈'V!0/,)('!-_x~X%^iv|tyϸykb\\ahs~jM4! >LjQY%3012,(('!+Zvnt~UXX^gryunoxmb^^_fnwjQ8%>ÈN\)712994,'(&#+X|umdj|OX[_emrohj~leb``djqy~lS=0&! =J^-;437>CA7,'&&#*V{zrmeX_yQYX^djlhdcbabcfkptuuy|&oWD5.-+**(&#!=a0=527=CIMI:+&%*Srxqjd[OXhVYY]bd;efhjlmrr^K@;788420.+('$!<,c4B618;?FLTZP<+%%&$+PjohaZQ@OlUYX]`^]^`jx%vbSGBBDB@>;9642/*'!:.f8E807@?=IQW^cW?,#$&%)Jae_WQC3H mWXXbo3yj]ROLLMKHFEC@=:5/)":0i=J:1/Z^DFRZ`jm\A+"$'%*EV[TLG7%>h{ ~rf^XW!USQOMLIE@70&85k@M;1+aʼcMP[dkuvcC) $'$)>NPJC<*9Ё3xohdbaa_][ZYXUQI@4) 8MnDP=0-[ɷiVZgnu~gD'$(#*:EE?:25¦ytqnlligfd#b[SF9, (*!66rHS?0-[Ƿq_fpypF$$'#'4;;50&1}"}yxvtrpoppmg[M<,!'8Og~V#6DuMXA/-Zĸyjr|vI#%'# %/40+& 3{z rdT@/ '8M`r~\!%6}RwR\B/-Yv|}J%%'$ $(*%  򱝝{mYB.(8I]jt|}Z$)5|ބdoI./Tv(&)ᜑ$/#)/7=BEGHILNPQSUZ]bhnty|}|{zx|_)/4%0vtq_{އgrM./S-'-ݙ'!%)-27:<=>BDEGHJMRYajqw|}}|zyxvz`*16& 0tro[xߊjuO.0S|yݗ0+.ڕ* !%(+.0258:;<=>BHP[dnv{~~}|zxyyvvtya,49( /rplF}tތnyO,/Royqo}ޙ4/0ؒ,!"%'*,/0*26*-nlhwnߑvS,0P_]cn{~zrmf\]oݜ:79ψ/'# !$'*8I\lw}}|zywxwxyyxsj_RF>3-Stqlve4;A,,jhfOtiߔyT,0Oefec`bktuoid\SSoݝ>;<̅2)& !"(az~}{zxxwvw!vqkbXNF@=:851Srnjte7>C-+hgd?pfߘ~V,0Ogiiheb`cgkjd`YQSݞA>?Ƀ3+)!)p{zxwv%urlf_UOKHFDB@>;62Rolhtg:@E.*fdb?mbߙX-0Nlnlkhhfcbadc`ZSWܠFCB~}5 -*!)k{xxv)usoke`ZUSQOMKHEC@>;62Qmierh;63Pjfbri?DK0)a_]|tfZࠉZ+1LyztursvsnihhfeaZSWܡLIGyл}x:%2."!!)fvssrolifeb_][YVSQMIEB@?>;63Ohe`pjAGM2(`][xbWࢎ\+1Kww}wytqw|}wniTdZSWۣPMJ!w˸{v|<(40" !)etppqpmjhfda_[WSMGCA?@@B>:63Mfb]okDIO4(][Yvt_T॑^*2Kttz{|wqw|ujleZSUڥTQN!vɵxsz=*62# !)drnnqpmjjhaZSLEB?>@ABCCD@:63Lc`[nlFKR6'[YWuW]Q~ਕ`+2Ippvyqw|mngZRVڦXVR sűvpx?,:4# !)bplkppnj[NGB?>>@ACDDEFA:74Ka^XlnHMU6%XVUqRXM|૘a*2Immt|rw|qsk[RVڦZZU qtnvB/<7# !)_mjjoppjI:>?@BCDEGGHB:73I_[UloKOV7%USRmPTHzଡ଼d*2Hiip~qw|twmZRUڧ]^X!prltD2?8$!)]jggnppjK>CDDEGIOLIIKC:73G\YTjoMRY:#SQOjtPDwᯟe*2Ffdnqw|x{oZRUةba[!mpjrE4B<%!)[hdenqpjNBEFFGIKNRX]RJLMD:73GYWQipOU\:#QOMhtMAsᲣf*3Fcaipv||q[RUثed_"knhpG6D>%!)YfbbnqojODGIIJNQTW[]SMNOD974EWUNhqRW^< "OMKftJ !IHG`tD6l⻰k)4DYWbx[SSz׮oog#ef`kO?KD&!)U_[]lrnjUKMOKKOQSUY]XSUWG874BPMGdtY]d@ GFD\tA2i⽴l(5BVS^yZRTv}ׯssi#cd]hP@LE'!)S]Y[krnjVNOQKKOQSUY]ZWWZI874@MKEdu\_gA EDBXt>/fn(5BRP[|[STtzzװuxm$`b[fQBOG'")QZUXkrnjWPSSLKOQSVY][XY[I874@JIBbv^aiB CA@Vt:+d»o(5ANKY[RTqvvֲy|q$]}`XeTERJ'")OWSVkrnjYSUVMKOQSVY\[[]^K874>HF>awadlD @?>St6'aq'5?JHQ[RTnrsֳ}t$[y^VcVHUK'"(MUQSjsnjZVXYMKNQSUX\]^_`K875=ED=`xcgoE ><;Ot2$_t'5>GHJSr[RSknpմw$Zv\SaXJWM(")KSOQjsnj]XZ[MGMQUY\_`aabM875DFGDCQpyx[RRgjlյz$XqYQ_ZLYO)")IQKOhtnj_Z\]RQY\__abddN875:A?8]zgktH :87JM,Zw'5=@ACEFDEOl|vplw\RRegiն|%VoXO][O[R)"(GNIMhtnj`]_abbcdfiO685:>=6\{jnvI 665HN(Uw'5>BA@@CFGEGQi~xsldgi[TSbceӷ%R~kUK[^Q^U*"(EKGKgtmjb`abcdfhdJ8848<:4[|nqyK 433EN$Tu"5>BGIF?@CFGFFQfw{tnib]YUQ_abӹ%PzeSIX`S`W*"(DJEJgtmjcbbd"efghfc]SKB<;847:80Z}os|L 210CN"Q܇(,:BGLSQHA@BEGGEOcooje`ZUQ\]_Ӻ%NxcPFWaUbX*"(BGCGgumjddef!d_YQKGB@?>;85676.Y~ru~N 0..?tNҝY76ALQX]XLB>BEGEFO^gfaZURYY[Ӻ&Lt_NDUdYe[+"(@EAEfuljffhfc_[UPMLIGEC@>;85544,XtxO -,,;p K֝bA@LU[bg`OB>ADHFFNY^[UQVUXҼ&Jzp[KBRe\g]*#(>B>Cdtljgfc_]YVTQPMKIFD@>:74332*WwzO *;_IӝfJIV_empfSA:AGHGHOTUQSRUҼ&IvlXI@Og^j_+#'<@Oi`la,#(:>:?dvljgdb__][YSMGA;521/.#R|S '&&4KJϤtY^ls{sW>9AGGHJMKM(CpfQE;Llbpc,#'8<8c[G>2Fqjvi.#)3534=90..-.!,*('(+4AQ_hptwz||~X 'I =ʿЯ[87IJ);_XB<0Etmzl.#'1211--.'--,**)),3>KVafjlnoqtvy{}Y &tO0 ?ϲWǵ)9[U@:.Bvo|n.$(00/..--,+*)*,2;EOW[_abdfilnprux|Z "jU. @÷дȹ*7XR<7+@xr}p.$(,--,+*)*,06?FMRTUWY\_abegjnrw}]  ]F' @ϸʻĬ*5TN96)>ztr/$'++**+-17@BEGIKKMOQX`hr|K T%" ?}}z¹Ͳ*0MH31$:~zw0$'*,/268:<>@@ACGNXdnz~hQ7 O'  ><:85210.*% T#" 0[ke\UNBAh-"54#$/uf[TOKKIGEC@?<;94.& (( .R_ZSLD64b,!20!"-znd]YWVUSPMKIHFC>7,!  #Wb) ,JUPIC:('\.-, +vmfcaa_][YWUTQMH>2% ;(-D$  (AJF@:/d-)()~wrnlkigecbba^YQE8(   &$ / &;A<41#%% &}yxvtromnjbZL;+  5( #272,$ ! #~zyyxzzvpdR@," A*,'!"zjW@,  ;  "" t\D, # * &|aE* ) ) #eE* ' 0  tlG)   #     ) "!)+ %  ! !% #&þ̯yee.Ϳ˱uqosvshi7Ͻɴ~y{}}|zyxwuoej=ûʶ|yvuuw}~{wodlCʺ{wtux|~}ulcjI̿{wusw̭wkdkǾOƹzwtwü}xttx~Ͳvjdn5zsjio~|wvwxȀζuihm\xoe``hyż{xwwzιukjm}`of``_`hxȵ{wwz|¼мwmlm|`؄fYXYbμwuxz}þxnllxeَe[X[ۯ|usv|¿³wnkjwg֏lYXXɚ|w|źynijv8׆mXXYѥ~-ɻ}mhjuk͊mXXYҫ~lfku~y~9ǐlXX[~ձ"Ģjfls{{py1ljjXX^|Դ/ɦljnqvxsjve̎cXX_yֺ~ܪ{oonoqskdmȑ`XX^vź׽~Ŵtutqonmkf_b~t΍`XX^uʴ|~{wrolhd_Z]jO߁^XX\s²܀!ͼ~ysnkf`]`l⽊t¾̃\YXYoȹxpjd`__h|лۈ؎ǿW{fYXXo̿ȻȻsjd`^`iwͼ؈h6oĺxfZXXo~wkb__aguȺԈdL 'lȻȁfXXZoŢ|mb]]_huĶ ҈M'*iþ@|fXXZmpd][_fpЈ>R*($-g}bXX\lՁŹsg]Z]cm|cn̈%U-*((#-bÅX0\j{{~ñxi_[[blw iM.:̈'V!0/,)('!-_x~X%^iv|tyϸykb\\ahs~jM4! >LjQY%3012,(('!+Zvnt~UXX^gryunoxmb^^_fnwjQ8%>ÈN\)712994,'(&#+X|umdj|OX[_emrohj~leb``djqy~lS=0&! =J^-;437>CA7,'&&#*V{zrmeX_yQYX^djlhdcbabcfkptuuy|&oWD5.-+**(&#!=a0=527=CIMI:+&%*Srxqjd[OXhVYY]bd;efhjlmrr^K@;788420.+('$!<,c4B618;?FLTZP<+%%&$+PjohaZQ@OlUYX]`^]^`jx%vbSGBBDB@>;9642/*'!:.f8E807@?=IQW^cW?,#$&%)Jae_WQC3H mWXXbo3yj]ROLLMKHFEC@=:5/)":0i=J:1/Z^DFRZ`jm\A+"$'%*EV[TLG7%>h{ ~rf^XW!USQOMLIE@70&85k@M;1+aʼcMP[dkuvcC) $'$)>NPJC<*9Ё3xohdbaa_][ZYXUQI@4) 8MnDP=0-[ɷiVZgnu~gD'$(#*:EE?:25¦ytqnlligfd#b[SF9, (*!66rHS?0-[Ƿq_fpypF$$'#'4;;50&1}"}yxvtrpoppmg[M<,!'8Og~V#6DuMXA/-Zĸyjr|vI#%'# %/40+& 3{z rdT@/ '8M`r~\!%6}RwR\B/-Yv|}J%%'$ $(*%  򱝝{mYB.(8I]jt|}Z$)5|ބdoI./Tv(&)ᜑ$/#)/7=BEGHILNPQSUZ]bhnty|}|{zx|_)/4%0vtq_{އgrM./S-'-ݙ'!%)-27:<=>BDEGHJMRYajqw|}}|zyxvz`*16& 0tro[xߊjuO.0S|yݗ0+.ڕ* !%(+.0258:;<=>BHP[dnv{~~}|zxyyvvtya,49( /rplF}tތnyO,/Royqo}ޙ4/0ؒ,!"%'*,/0*26*-nlhwnߑvS,0P_]cn{~zrmf\]oݜ:79ψ/'# !$'*8I\lw}}|zywxwxyyxsj_RF>3-Stqlve4;A,,jhfOtiߔyT,0Oefec`bktuoid\SSoݝ>;<̅2)& !"(az~}{zxxwvw!vqkbXNF@=:851Srnjte7>C-+hgd?pfߘ~V,0Ogiiheb`cgkjd`YQSݞA>?Ƀ3+)!)p{zxwv%urlf_UOKHFDB@>;62Rolhtg:@E.*fdb?mbߙX-0Nlnlkhhfcbadc`ZSWܠFCB~}5 -*!)k{xxv)usoke`ZUSQOMKHEC@>;62Qmierh;63Pjfbri?DK0)a_]|tfZࠉZ+1LyztursvsnihhfeaZSWܡLIGyл}x:%2."!!)fvssrolifeb_][YVSQMIEB@?>;63Ohe`pjAGM2(`][xbWࢎ\+1Kww}wytqw|}wniTdZSWۣPMJ!w˸{v|<(40" !)etppqpmjhfda_[WSMGCA?@@B>:63Mfb]okDIO4(][Yvt_T॑^*2Kttz{|wqw|ujleZSUڥTQN!vɵxsz=*62# !)drnnqpmjjhaZSLEB?>@ABCCD@:63Lc`[nlFKR6'[YWuW]Q~ਕ`+2Ippvyqw|mngZRVڦXVR sűvpx?,:4# !)bplkppnj[NGB?>>@ACDDEFA:74Ka^XlnHMU6%XVUqRXM|૘a*2Immt|rw|qsk[RVڦZZU qtnvB/<7# !)_mjjoppjI:>?@BCDEGGHB:73I_[UloKOV7%USRmPTHzଡ଼d*2Hiip~qw|twmZRUڧ]^X!prltD2?8$!)]jggnppjK>CDDEGIOLIIKC:73G\YTjoMRY:#SQOjtPDwᯟe*2Ffdnqw|x{oZRUةba[!mpjrE4B<%!)[hdenqpjNBEFFGIKNRX]RJLMD:73GYWQipOU\:#QOMhtMAsᲣf*3Fcaipv||q[RUثed_"knhpG6D>%!)YfbbnqojODGIIJNQTW[]SMNOD974EWUNhqRW^< "OMKftJ !IHG`tD6l⻰k)4DYWbx[SSz׮oog#ef`kO?KD&!)U_[]lrnjUKMOKKOQSUY]XSUWG874BPMGdtY]d@ GFD\tA2i⽴l(5BVS^yZRTv}ׯssi#cd]hP@LE'!)S]Y[krnjVNOQKKOQSUY]ZWWZI874@MKEdu\_gA EDBXt>/fn(5BRP[|[STtzzװuxm$`b[fQBOG'")QZUXkrnjWPSSLKOQSVY][XY[I874@JIBbv^aiB CA@Vt:+d»o(5ANKY[RTqvvֲy|q$]}`XeTERJ'")OWSVkrnjYSUVMKOQSVY\[[]^K874>HF>awadlD @?>St6'aq'5?JHQ[RTnrsֳ}t$[y^VcVHUK'"(MUQSjsnjZVXYMKNQSUX\]^_`K875=ED=`xcgoE ><;Ot2$_t'5>GHJSr[RSknpմw$Zv\SaXJWM(")KSOQjsnj]XZ[MGMQUY\_`aabM875DFGDCQpyx[RRgjlյz$XqYQ_ZLYO)")IQKOhtnj_Z\]RQY\__abddN875:A?8]zgktH :87JM,Zw'5=@ACEFDEOl|vplw\RRegiն|%VoXO][O[R)"(GNIMhtnj`]_abbcdfiO685:>=6\{jnvI 665HN(Uw'5>BA@@CFGEGQi~xsldgi[TSbceӷ%R~kUK[^Q^U*"(EKGKgtmjb`abcdfhdJ8848<:4[|nqyK 433EN$Tu"5>BGIF?@CFGFFQfw{tnib]YUQ_abӹ%PzeSIX`S`W*"(DJEJgtmjcbbd"efghfc]SKB<;847:80Z}os|L 210CN"Q܇(,:BGLSQHA@BEGGEOcooje`ZUQ\]_Ӻ%NxcPFWaUbX*"(BGCGgumjddef!d_YQKGB@?>;85676.Y~ru~N 0..?tNҝY76ALQX]XLB>BEGEFO^gfaZURYY[Ӻ&Lt_NDUdYe[+"(@EAEfuljffhfc_[UPMLIGEC@>;85544,XtxO -,,;p K֝bA@LU[bg`OB>ADHFFNY^[UQVUXҼ&Jzp[KBRe\g]*#(>B>Cdtljgfc_]YVTQPMKIFD@>:74332*WwzO *;_IӝfJIV_empfSA:AGHGHOTUQSRUҼ&IvlXI@Og^j_+#'<@Oi`la,#(:>:?dvljgdb__][YSMGA;521/.#R|S '&&4KJϤtY^ls{sW>9AGGHJMKM(CpfQE;Llbpc,#'8<8c[G>2Fqjvi.#)3534=90..-.!,*('(+4AQ_hptwz||~X 'I =ʿЯ[87IJ);_XB<0Etmzl.#'1211--.'--,**)),3>KVafjlnoqtvy{}Y &tO0 ?ϲWǵ)9[U@:.Bvo|n.$(00/..--,+*)*,2;EOW[_abdfilnprux|Z "jU. @÷дȹ*7XR<7+@xr}p.$(,--,+*)*,06?FMRTUWY\_abegjnrw}]  ]F' @ϸʻĬ*5TN96)>ztr/$'++**+-17@BEGIKKMOQX`hr|K T%" ?}}z¹Ͳ*0MH31$:~zw0$'*,/268:<>@@ACGNXdnz~hQ7 O'  ><:85210.*% T#" 0[ke\UNBAh-"54#$/uf[TOKKIGEC@?<;94.& (( .R_ZSLD64b,!20!"-znd]YWVUSPMKIHFC>7,!  #Wb) ,JUPIC:('\.-, +vmfcaa_][YWUTQMH>2% ;(-D$  (AJF@:/d-)()~wrnlkigecbba^YQE8(   &$ / &;A<41#%% &}yxvtromnjbZL;+  5( #272,$ ! #~zyyxzzvpdR@," A*,'!"zjW@,  ;  "" t\D, # * &|aE* ) ) #eE* ' 0  tlG)   #     ) "!)+ %  ! !% #&þ̯yee.Ϳ˱uqosvshi7Ͻɴ~y{}}|zyxwuoej=ûʶ|yvuuw}~{wodlCʺ{wtux|~}ulcjI̿{wusw̭wkdkǾOƹzwtwü}xttx~Ͳvjdn5zsjio~|wvwxȀζuihm\xoe``hyż{xwwzιukjm}`of``_`hxȵ{wwz|¼мwmlm|`؄fYXYbμwuxz}þxnllxeَe[X[ۯ|usv|¿³wnkjwg֏lYXXɚ|w|źynijv8׆mXXYѥ~-ɻ}mhjuk͊mXXYҫ~lfku~y~9ǐlXX[~ձ"Ģjfls{{py1ljjXX^|Դ/ɦljnqvxsjve̎cXX_yֺ~ܪ{oonoqskdmȑ`XX^vź׽~Ŵtutqonmkf_b~t΍`XX^uʴ|~{wrolhd_Z]jO߁^XX\s²܀!ͼ~ysnkf`]`l⽊t¾̃\YXYoȹxpjd`__h|лۈ؎ǿW{fYXXo̿ȻȻsjd`^`iwͼ؈h6oĺxfZXXo~wkb__aguȺԈdL 'lȻȁfXXZoŢ|mb]]_huĶ ҈M'*iþ@|fXXZmpd][_fpЈ>R*($-g}bXX\lՁŹsg]Z]cm|cn̈%U-*((#-bÅX0\j{{~ñxi_[[blw iM.:̈'V!0/,)('!-_x~X%^iv|tyϸykb\\ahs~jM4! >LjQY%3012,(('!+Zvnt~UXX^gryunoxmb^^_fnwjQ8%>ÈN\)712994,'(&#+X|umdj|OX[_emrohj~leb``djqy~lS=0&! =J^-;437>CA7,'&&#*V{zrmeX_yQYX^djlhdcbabcfkptuuy|&oWD5.-+**(&#!=a0=527=CIMI:+&%*Srxqjd[OXhVYY]bd;efhjlmrr^K@;788420.+('$!<,c4B618;?FLTZP<+%%&$+PjohaZQ@OlUYX]`^]^`jx%vbSGBBDB@>;9642/*'!:.f8E807@?=IQW^cW?,#$&%)Jae_WQC3H mWXXbo3yj]ROLLMKHFEC@=:5/)":0i=J:1/Z^DFRZ`jm\A+"$'%*EV[TLG7%>h{ ~rf^XW!USQOMLIE@70&85k@M;1+aʼcMP[dkuvcC) $'$)>NPJC<*9Ё3xohdbaa_][ZYXUQI@4) 8MnDP=0-[ɷiVZgnu~gD'$(#*:EE?:25¦ytqnlligfd#b[SF9, (*!66rHS?0-[Ƿq_fpypF$$'#'4;;50&1}"}yxvtrpoppmg[M<,!'8Og~V#6DuMXA/-Zĸyjr|vI#%'# %/40+& 3{z rdT@/ '8M`r~\!%6}RwR\B/-Yv|}J%%'$ $(*%  򱝝{mYB.(8I]jt|}Z$)5|ބdoI./Tv(&)ᜑ$/#)/7=BEGHILNPQSUZ]bhnty|}|{zx|_)/4%0vtq_{އgrM./S-'-ݙ'!%)-27:<=>BDEGHJMRYajqw|}}|zyxvz`*16& 0tro[xߊjuO.0S|yݗ0+.ڕ* !%(+.0258:;<=>BHP[dnv{~~}|zxyyvvtya,49( /rplF}tތnyO,/Royqo}ޙ4/0ؒ,!"%'*,/0*26*-nlhwnߑvS,0P_]cn{~zrmf\]oݜ:79ψ/'# !$'*8I\lw}}|zywxwxyyxsj_RF>3-Stqlve4;A,,jhfOtiߔyT,0Oefec`bktuoid\SSoݝ>;<̅2)& !"(az~}{zxxwvw!vqkbXNF@=:851Srnjte7>C-+hgd?pfߘ~V,0Ogiiheb`cgkjd`YQSݞA>?Ƀ3+)!)p{zxwv%urlf_UOKHFDB@>;62Rolhtg:@E.*fdb?mbߙX-0Nlnlkhhfcbadc`ZSWܠFCB~}5 -*!)k{xxv)usoke`ZUSQOMKHEC@>;62Qmierh;63Pjfbri?DK0)a_]|tfZࠉZ+1LyztursvsnihhfeaZSWܡLIGyл}x:%2."!!)fvssrolifeb_][YVSQMIEB@?>;63Ohe`pjAGM2(`][xbWࢎ\+1Kww}wytqw|}wniTdZSWۣPMJ!w˸{v|<(40" !)etppqpmjhfda_[WSMGCA?@@B>:63Mfb]okDIO4(][Yvt_T॑^*2Kttz{|wqw|ujleZSUڥTQN!vɵxsz=*62# !)drnnqpmjjhaZSLEB?>@ABCCD@:63Lc`[nlFKR6'[YWuW]Q~ਕ`+2Ippvyqw|mngZRVڦXVR sűvpx?,:4# !)bplkppnj[NGB?>>@ACDDEFA:74Ka^XlnHMU6%XVUqRXM|૘a*2Immt|rw|qsk[RVڦZZU qtnvB/<7# !)_mjjoppjI:>?@BCDEGGHB:73I_[UloKOV7%USRmPTHzଡ଼d*2Hiip~qw|twmZRUڧ]^X!prltD2?8$!)]jggnppjK>CDDEGIOLIIKC:73G\YTjoMRY:#SQOjtPDwᯟe*2Ffdnqw|x{oZRUةba[!mpjrE4B<%!)[hdenqpjNBEFFGIKNRX]RJLMD:73GYWQipOU\:#QOMhtMAsᲣf*3Fcaipv||q[RUثed_"knhpG6D>%!)YfbbnqojODGIIJNQTW[]SMNOD974EWUNhqRW^< "OMKftJ !IHG`tD6l⻰k)4DYWbx[SSz׮oog#ef`kO?KD&!)U_[]lrnjUKMOKKOQSUY]XSUWG874BPMGdtY]d@ GFD\tA2i⽴l(5BVS^yZRTv}ׯssi#cd]hP@LE'!)S]Y[krnjVNOQKKOQSUY]ZWWZI874@MKEdu\_gA EDBXt>/fn(5BRP[|[STtzzװuxm$`b[fQBOG'")QZUXkrnjWPSSLKOQSVY][XY[I874@JIBbv^aiB CA@Vt:+d»o(5ANKY[RTqvvֲy|q$]}`XeTERJ'")OWSVkrnjYSUVMKOQSVY\[[]^K874>HF>awadlD @?>St6'aq'5?JHQ[RTnrsֳ}t$[y^VcVHUK'"(MUQSjsnjZVXYMKNQSUX\]^_`K875=ED=`xcgoE ><;Ot2$_t'5>GHJSr[RSknpմw$Zv\SaXJWM(")KSOQjsnj]XZ[MGMQUY\_`aabM875DFGDCQpyx[RRgjlյz$XqYQ_ZLYO)")IQKOhtnj_Z\]RQY\__abddN875:A?8]zgktH :87JM,Zw'5=@ACEFDEOl|vplw\RRegiն|%VoXO][O[R)"(GNIMhtnj`]_abbcdfiO685:>=6\{jnvI 665HN(Uw'5>BA@@CFGEGQi~xsldgi[TSbceӷ%R~kUK[^Q^U*"(EKGKgtmjb`abcdfhdJ8848<:4[|nqyK 433EN$Tu"5>BGIF?@CFGFFQfw{tnib]YUQ_abӹ%PzeSIX`S`W*"(DJEJgtmjcbbd"efghfc]SKB<;847:80Z}os|L 210CN"Q܇(,:BGLSQHA@BEGGEOcooje`ZUQ\]_Ӻ%NxcPFWaUbX*"(BGCGgumjddef!d_YQKGB@?>;85676.Y~ru~N 0..?tNҝY76ALQX]XLB>BEGEFO^gfaZURYY[Ӻ&Lt_NDUdYe[+"(@EAEfuljffhfc_[UPMLIGEC@>;85544,XtxO -,,;p K֝bA@LU[bg`OB>ADHFFNY^[UQVUXҼ&Jzp[KBRe\g]*#(>B>Cdtljgfc_]YVTQPMKIFD@>:74332*WwzO *;_IӝfJIV_empfSA:AGHGHOTUQSRUҼ&IvlXI@Og^j_+#'<@Oi`la,#(:>:?dvljgdb__][YSMGA;521/.#R|S '&&4KJϤtY^ls{sW>9AGGHJMKM(CpfQE;Llbpc,#'8<8c[G>2Fqjvi.#)3534=90..-.!,*('(+4AQ_hptwz||~X 'I =ʿЯ[87IJ);_XB<0Etmzl.#'1211--.'--,**)),3>KVafjlnoqtvy{}Y &tO0 ?ϲWǵ)9[U@:.Bvo|n.$(00/..--,+*)*,2;EOW[_abdfilnprux|Z "jU. @÷дȹ*7XR<7+@xr}p.$(,--,+*)*,06?FMRTUWY\_abegjnrw}]  ]F' @ϸʻĬ*5TN96)>ztr/$'++**+-17@BEGIKKMOQX`hr|K T%" ?}}z¹Ͳ*0MH31$:~zw0$'*,/268:<>@@ACGNXdnz~hQ7 O'  ><:85210.*% T#" 0[ke\UNBAh-"54#$/uf[TOKKIGEC@?<;94.& (( .R_ZSLD64b,!20!"-znd]YWVUSPMKIHFC>7,!  #Wb) ,JUPIC:('\.-, +vmfcaa_][YWUTQMH>2% ;(-D$  (AJF@:/d-)()~wrnlkigecbba^YQE8(   &$ / &;A<41#%% &}yxvtromnjbZL;+  5( #272,$ ! #~zyyxzzvpdR@," A*,'!"zjW@,  ;  "" t\D, # * &|aE* ) ) #eE* ' 0  tlG)   #     ) "!)+ %  ! !%t8mk@%A}{(Qw~*Gt,]y 9Y߄#=dz (Ivw .Wwۊ':^*6nޅ*Msܙ0B}.U#-W'FJHPOR﷗nGQ e".? &6HXgx 2F[n~ !4J_t,?Ti{ ->Qbt '5EVfv )7FVgw*7GXixę`4 +9HXiyԤd>   ,:IZjzƭdSB2#  ,:J[k{ij~n\J7&  !-O_pzrjaXMC7,   $0@O`qȽyriaXOF>7/'   %2AQbrŸyqi`WOF>6/("  &3ARbsӿxph_VNE=5.'"  '3CSdtŵwpg_VME<5.'!  '5CTduӾ~wof^UMD<4-'   (5EUfv˿~wnf]TLC;4,&   )6EVgw~vne]TKC:3,%   )7GWhxƸ}umd\SJB:3,%  *8HXiy|uld[RJA:2+%   ,:IYjy|tkc[QIA91*$   ,:J[k{{skbZQH@80*$  !-;K[kyzrjbYPH?70)#  ".U .EU 1IU 3KU 3LU 3LU 3MV 3MV 3MV 3MW 3MW 3MW 3MW 3MW 3MW 3MW 3MV 3MV 3MV 3MV 3MU 3MU 3MU 3MU 3MU 3ME 3M'3M$ 3MA 3M' 3M03M7# 3M>( 3MC, 3MG/3MI13MJ23MK33ML33ML33ML33ML33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33LL33LL33KK31II1.EE. *>>*  %6I[itz~~zti[I6%  ,;IU]befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb]UI;,   ,6>EIKLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLKIE>6,  %*.133333333333333333333333333333333333333333333333333333333333333333333333333333331.*%    SuperCollider-Source/HelpSource/BrokenLink.html000644 000765 000024 00000001214 12756531744 022666 0ustar00crucialstaff000000 000000 Broken link

    Sorry, that link was broken..

    SuperCollider-Source/HelpSource/Browse.html000644 000765 000024 00000016222 12756531744 022076 0ustar00crucialstaff000000 000000 Document Browser

    <}I/E x;$s / c c .s$4Tswf`n p//&\Dotk    lk>@s s!ssXQ!u4"UK~1_9q"Y$tYO5O/#Hx% //{/vO /|`/= Im[|5#~]s  T w T 6 + 7 T s z T  c K G S c q t n c [ Z _ c Y 2s]jgzwLhIa/hZOZ> .:A;  ^nP>En9^uO/Oj^YTS^|O-//rO/ Fd` OEnG6!PMeB* r^^K/?P^@9nnn4-4/8.BsN;>>FM @KJd7?r W/ F^pWI\Xnn[JsfwvfwNV`-wh.[Y2zyMPoE-I0Q-)03-)9jgjS")`wL=q1l/^4//O^k/{5ad<#XV/q^ ^OP& 8%2.6? hr[Wu!I+7D2_(*rEXMJR~2 o/ OE;@z^AZ*n|OE/mxZ/5 Lq.gj{= myh%8pX}j # kSb Y ? c  D % % o T c J ; B c ' T ] : c}nq1 Of.Bq*W0  9jpp ROO6/ /:OOH/pn/[ONn50 nvnvn"x=wcunI*0OqdPx OO/Hd OnHz: okc!: !''  ,2. d\eL5L --O^ny^-Oag`O1^J ,7)+X 9)Z;B4)t?9`)Rwu=hOk]kr_=;guXlL" n6^lNn1D.RFzsoOn2V^dO|  1k5F0Pa[Qx buZ]smWYPJT! > 8zeq!\n38/c ' IKE.BbG]1W;!  WV2 %[/RaenF";I4F^[(/wF7D1N'mlWQG-]KGb@3sS2,EV8Ks ; c } D = JEt\_0 % } c3>FSLt9'k{ S/"%./$/cwRKhTW! O vG/'&'/Eq Yvut /.^1h|V%fo.QsM7wT4|VDP^R/  =  &85v2 Rb}o JiXeCSXBI~I_Tn^UTnc]r4n?BnF^cEn6%Jw "3|T `r:61a'u@q@)AtXg.wcg9+'I oh~sVn//u&"u2Y(^T/J V|x^Ein"X>@c3oBdis9GFKL3N;c!6F-vMl6P8sUQ//c (" ba V1 /" 8@PI[(vk5CC1=\<F[dps : \ c ` [ [ c x T o %  ,6,  %  D  T js]{< X tOOq/IC4/:uO2nn0+nKOR/uz/ C^hmyV])nXfGg GX7gE@OgX^)R)6g=2w^5 TlU/ T*^G7^a1/u B3/La^=//1d3' OOP/}>Y,} &]RO]|o+qD <4u4vxW+:v;oU\+ !x#C Wb^ U*!$/O.4HO4^40E^g\N^N1/ EcSV N8bz|+e lol -O:" nEIvCONspds " c T t z i T Q v D Y % n ! %  D csRs  P c W D E c cG#1/c/od Y -N :/OHU\O/O}O `'8., ]/<`^^S!^BXO}ko8?QZ5X8pz]uwn0Ot/l e,4)T^2@4] h@Hf6 .S?^ic /w~ODIOOIEGOX]ZO8^ $"/69s)Di'L0Avan %)$9~X% XT) M8o'#C) gwgX!e>1:E(\Pg! Y$/[)WQZ?@K7R@Q1nP8m"XI]YF/ Ak:x}?sk><Yv Uoja`wUaC+/./MNO/G;O(O@9v2wa*0-, e:/Ex c  &/O6CwOX*j3oLY%jJnp^) ^IO)^nVp^/$/c/yYJ=9Q2Q c c %sw\y`5F/q^nB&1n=z^3)FosRBJfDVUR%SU z|ob pQFQW5fmiD],C6 JO^ nsn"&@(3OhpV k 867^^/ PNP>Y(r#ss!& 5uvolssI;Mss'o+\Qb c & T ostYd4Zq' C<xc(C 1n!1nf!aYf%0a DwF,uO"JA:CK&qznm~^4.^O/dv=@q} l0[xv6yMn&q.w:1"tVr6V uOjpsMl(@2A}tT{\^2hO}73 -90 ByG)&K>;S.)162)""()99*))KU+:nB_^]xO_. <yU RvtO5n5w"o<M?L9]s  C c g Bsa-z7Gk2= pxr  // _"}8gWG`(-as> Xsp^Vvn]WK/b{=[3 /&O^nl^h/[T \=OnE FncFRs 9 T  % -91 gG * ) N D !qhEhhd ]kF]9[*j >IO^~ >&Bxn<^O{^W8>nn3^KFe{t{c+BQ (1'jFN ^ }//  8&/^^BqOH/?Ka 4w~C]&ZaDSO ;_L_iS }& I$/Usk/DO nq;9avJ@n( .cj Lp9X71>XryX( X,#}/W$'Xxg?Xu9~dFK9nFOu H Z%5*L<se j S2JK-wIB a'( =8Q5QpY+ *51 *|^,WIaK n=5 r]Wf  u#| /ZOwS^^^ / )/Op/ ;v/ </j N])]A9H7t~Bs/\.;s !  T m l ` T O S X T = c ys T  % "|/I0{}- % n c2AP="]Vl_Obln:^dZS^O/.T O^9%o7Ks U$8O)2{BnDO/ OnP^O&/  *-' 'M".b3v& \XS:sK Si2?i 8?5 /6^}T sYK%o*.^ja{x)<:D_]i;zQr-*WP'9$f+7"F?H U=Px: 8^gof /Ot/D~xR{4QV&D$^i`/&^2/ gp v/NO^9#^d/Q?nu^ IOO&" T  } % BFfWf | b D S h c } c X 0 D Ff+$P y v D tpo5YOcP~u@#n'OgldO'^,1^^^/ imzeI$#P .!~@s m T T n4CZT4@vG0>OOnE=[k P%;%P Upu9!",9Kp)I~9@dm>)&)*)0RS`? )L J~\qJ3x1D&6^t 2h=V?\' KH>^^ J~4]P(ZgcQlB c { c Y [ a c ` [ \ c e L sia"g.h+'hjm / D i % I M = %   % V :D6 w % ? D D = % k n % - D  % D J " T XsMd W$/}qJK_| Q SOanZdcx_ .>)kL9$ 9aW?\@M}nn %oNn/]R7/M JUD p//n/O}/q//n `  6| c/\[A7|_YpFl!/ 8f. +'/iA%j)U.9sg86hV?HVAL9Oll9JX2Xt{nXE>GXirmX2gwgg~wX9f |QPEAK@^SuperCollider-Source/sounds/a11wlk01.wav000644 000765 000024 00001341746 12321461511 021164 0ustar00crucialstaff000000 000000 RIFFWAVEfmt DXdataB/grtgP 9:'dGuG}g9mpDqP,aE(TpD];TC#*/5I;T{xI'|mY$7j>x]WGN9 GN^G{S1K6o{YDr X:`U=_Xf{vN|Fb];3!"w xf=idu{9x;p=8vcA{vm|jjjP ,} 1 e ^  ) 4 J   8 d v  @YOZWEObv0jEQr>n~qb;!gh'LY6"<J`4 &:O5Z'KTLT t<_NEQd# e4){=@HGjt9t1w2 /S _pVK+Jmc; $C!_ sc/=56(F~T8 \LhNF;*>G|Sf&6j Z$pUYfEM MGS&tzV=+=i{ /_YX[fQ q  oi?#,p2BK c6o7fr MXM ax&d#j :@mXqLC-*JDm*;|L3itU%`/-(= ,`!K{'L8VZ`: q p*$;2/'p& @;u-6X9 gVm?^^faJf[ WZ7qtua6Q-%80}^94 raG` =.zo,GE&)p19eQ!U\AWh 7  ; _rE  T h 7 - {d)QuZ&uv BF O"](Fq 2Wju4,DY q?txEggr4NY^YN@ 'l '4l ^1/&6K2hnRnym`F>kKm{N )&,j4 r-TRt)(J` D::`sLJO]!n`1_ (t2\Uo uf{Udj\=f$2?jx/gb-/C\m#e=57}?tCp>Z@'KMfm+E9 do++c(5j@TIn+'@%p3>f5\$-Y,3%j%ueYycgfk#n1D(mDUjl.mB!JJBQaF:c8kup|vs;ro#d 7|C%eky: %U$kvZQ>s_]I2/w` p ::+G%Ha0'HK_hnu")2O's Z z 5 ) ~ ! PFkQj CA+{S q9D.@M% f?B~ F9)wra$Sb NvCE$::v&[/NlYrN^~#,$bP?1[eTjj|(b(@kX9xqe/: ,q6Ap.g7 ?=9%21P%Ext9KY2b^au:=lF ECsu)S_j_Njil(K7.EbT4r5Bd1( /tMPbdj4B=?$,Mpf!{OThH4*/O~\$A~:  H ) IH j g 7Y@$!{9|^QQfKfUjj!]n5+jN_Z3k.x[?& a DDGC_Org6<xiqM[S< ,&D9ONn($cG~fRs >x$ 38$C"_7u*HB  7VuF,SpKR(8uj!0Z5'yeUjL~=}NJruz,Em,!g~\ L7 b@l'BKs5<1\ @b^QZMK}jo?w?/9z,Jw5i$^{rB<}}X =(YIZzY 0A;yT8G0e8C,(%OY]@sb{ y9e|:,G` ug[S3OxS+h \p ="ZKd'#24oH{dPS'Z9cqJg7DKi2at[UVPXibbT' Mm, ^wmEq!Ay \'jT- @{A%2~3!'NAnUKL-*TbQj,pv ! h Q h m m o F ! E ,mUFn7e$YO'p{nucP'7o! ! p H a  Q=8)8 ~ * {  ,(&,7[zrz  8  I%x9#PV.;/N#P[V,/ jW^K^K4B xQFCKWjdK $ ^xr7~l,SudQpKtP?&M+B?^Eb'CGVd/rTI59???4^,Ql^t|%WThLjr]xSg3=Ux+Qxx8Eg /XHj~=!a(VAX!%p\Q;C=Fk!Lq`,MN,GjJqIxLA=n9q P*,02Q T8@T:TL75 bn5oM#qX5 i 9( l!DK@t  ! O,BUE:g4v-:v$hkNF[mQ uUtZDbKRHbTqTV/Vo r Qp;K)KS(4VCj-:g' &/I TKtv$,:&*1#rM9wuMBH=q`A|!V=~{:0]C2  5 ) T 8 8    5 W * F y / d b $ & _ : {K2d A)x6mU#M .Y  a Q1WWFA-fD["G5p\NNMOMy=V0{C~vQ r 's^$7(YR.g25!h=i}K\'$Si_bm2'y 5  W T&s:kuV E , ;\\|}Y=F8c%m}pMMCP&.r7v'4{ rEi2ai{U3Z\6Ku7ja=qT 4 _\(A0  , 1 S ) ygA- / u / { LKq -eA'@LU.1{2[_!#uDC6x:4u2l 8Or)+33k'$c hWA3<z(Sb LV8Wq ~  5 - E  #@u  WpI  K M vV)*\ 5 \ = Q x Y ,2OQ*nj0$2;n]*{%j`jJ9 c,I7@w1} iEo~^m= aY_:";z<XUo/foGMx][x,)t3G (IHlWIth0;3p5DtR/g8]4Hg@ms_ g Er]gYs%`6kO;$'{aJ7+!<KlPzaXj\9 r$GjNY[j^$B,b!5V} ?dAv701'14HN{YmWY*T^s$TdMRxh~n2e>5v] |:7E p8Z6y r N S4  7 y Zx0{   !O6mhv *HR5#xj2]']HS&@jWb*1%_pbCJ)U"ntX/.txFC:M:MU/h/cJ9!AU@3s]+(QeKdHp;, /' 3bb N6TG Du6dWyZv!r=|j6,%+6@ CJ=%BF!3 !N2/ rd!l,dV4YJdQbMN&{& d$>:T.}Maa\8$ho!mV9f1X 4Xd_q\=9M70q mVRk8-(RKmnUmTGH idC \`!J,=dYN(l!4XxH%D$E.)mf XUMN\87ib2&? )Ew,CHW j>z? FIox+H=~ f$^c%BgjN66a1:mfF|I5 _70'b 0YP d~]5yrB q^$/`SN`63pwGE7i.md7\HK!1r&.Ko/\2CKM!}CMg4}9li% z  =XrKP+" IcD6Rph@}A_vkmD!t fA3Z%y|6ee3@]u%5 N!@\8K\N3{y'7'`$/ZFPi4[ma`,4d_:CGI=4ilRXeL x 8< qRwQ3~^gV(JX?u0`b RRVp2u !.=U6# |yN'SHI8&g5'>(\Id-W Om:s,QbCY/ 8 ' F 22`*fk@>m*bUU 3]fc&V dsT(_` K1KvG"9\6;eq%-9H=rjt8RXlfG#P/IZ-G\\ `pqxXCCO,  j"!~*mX^M/ CK7i%!^!7[cjQ? JK a@rQS* LPr<&j#(sT$ TX`YhW,/=\5D@Q'%>"]NjQ~8|Yu {6$AO5/>-NmT&:Ul=dO,x# % QQibg#zu?oo,@ S291#%\{KTyh: )~LTD/zDD FJ^d@<~"|+Gxmc N -!pdb d 8"HmLs~qx> >6F u{~$B6x] nZ q/0'l gM9>YWr YTpGIaQtB#?@eb#f\n =xi}G ~6ulL| 6j1~g  -Y$ Hu:&@, 8j/_8j/+>,"SE0m2eYje7!;g*{XLnPF0T` e3rcz8@j,?TUuuq,:anU~$e/<qN(|\H6>KgQR}AT$>$|nQy9x}JtI'Wx qJL9Q>"!n=oMXJQG9k \mH<2i. |6.&.{:~BNi_{C_Q{y8l[?~ u_HWj.{GH5P'K} 9z m 5m4' 11hvQ{CV^gjgo9}/l49cq4dG~!$ei!fgQ+H,2/<)4&9uq{>Dn{l(qM =!8q`7`QxDw?a bs{z <!.CQ: .mK7Dx~gUMUH! +{dzfa7% Ym ,ulV@@`T8!Do?b(9fr2Nv!\{JM24 Z6o6`2cu(TKK=*^}[rq,iY@o%%!\u2 Tw}&dU) l^l]_ SlU{%8%,g ZQ!nq>>6XQ0Kq/uDneE{,L5@ 05kx/,ki^zU@wX6!'n\p}HBl^&(VR 9?)2fBMP3z_e{<o8KduI.F3x 4&[Nl=&UgjVj M!4 QJ?f[[PwmY)i C_Wq }3{Q<h( 2\Mw9L"N,U=R`[& 0sV4'jSE!S1 o[#MGVtGX1c/@~#=1=u{Zg{6''``lNC@U8,c mPJdNl)([=/N <#\,XRPt.?8Z8f( sD%/`&I_/|hg5* ZFucF550&# y  gg$KAu;;,j:O+Rm3dG%sx:ks O xa|FLPHh6.d/a /aJ,G/~chyXBxSM?P=-{#?i^EDO@0Bu\,O=r#8vHf/wT]T j+"6O0O~|j-*>)KyO% d"Z_5>N3!fku A82Q-{LA0g=00v\7NCA@(Ga|q$(bg Y~c(hf;:;hA` ZxLUn22ZO38NY$oh xWn=8t4;9TZnxHjBioJ`=ED7 "e1fa"vT>mi}t!(;MtKGH?SHplmTR[ 6dit!9alRUig%O5n%t5F\\ j;68b8kGP4cH-9eU{: e= 6\Eq (/SDn rGun\p0\XDJ\ep0m t{y_x,$_^I~P^mt3:1F(x)rlj8}N1#B+_fy ^^Mu*\GdUd.JLb(\lc rZ]rc!z\b)N_R3*'!q`,Tnkkg\~qC,2Y8NNjZ_jLxy@jj( H*d]qCAvx>*5"9if4QoUn'8XP.:1i(uC=g< 'm3kd%6f0G f`5N~Xtdfg6tXq9F{e v\ |)H}~|tHY>g(Y`Ko/jcB5B jpu:aohygHep`vj}}_H8|+FC7q @cT5 H&4 V 4 "+4  (UJg3N!Cnw4m:) } }, l bse)T/{xw=px[SdNp}z38q/\hjkwfVU %WXus.52VT=N|Yug{\ x \Cj`OxuIvd|1|CYYT;1o.X XXr)xOg)sPdV2g Wfri3Uv$:nXs bhr'I'i+4 zl 5bIKW Q ;eS|~Z2*,r 5}j.#!GfYp=jf]ebZ2p8C|qM"Ef CWd~gFy^8E1Q.-5u b)m,vAq=pg" (NJ4 1 F p F Z} N+@P YSj{2dY{m $V:@HF?a6[T&d/z{T|j "!t"4; d   / S z ! 2NW-y Y]-v"X!/qEs&}LHVL~C-]mgV l   z v E & FVoBg+:z=Qo!_YL~4yr{/FV\ 4 v(<6K}^Ydd&{% a0f$CScxmTD_?kug$V{ la`22/u^}5y@mvy]NNQk Q S  Wxb  H )H/%p_|/@WKQQK+2"+@owf)i.o&/n]@  =:|"$m\HY>]$URl}y@eeg/Q#Qq$TCCSai&axo2t7RuwdStu/Tz} 7uQFj\j{gs{lf o P4B%^' )yU')wz)WbkKIkFV~!TvNB  7  H 0+T:ge$,:\9EQ$P I## j@=B<,eyf%pTO-05h9-PK r@$MYS{3+NK\*xB q%Zv5UM}4F) EL4r&h\ * { :5  ]5/ j 6cg/p 8   ,QnW O3He!N_>K$r%Y6a(xDZ#Pv*?mp$7C)g;lEBb7 1Hi:l}m|#5SoXJaK6 \Q %R{%i? \ x9mHG (JE#C _T+mbm&Q^//YJ nZx66)29P?maXpW5~I^MrUV(KK/CLN,-.VNV/km'- \:j!R!!n`J @zz4?odz(/\Gn|Agstc;mkj=yJR$CZbc$]'V87nh~Q{2hNFV :S f1.op &//@x2ger:vpHh0Q|~%kT!giQ :=9Db2Fv^ r : d ^ P   ypR3 - 7 H p / KhT * Ol@_}lu7\ -$ rX{,@&$'b!&" Ii2"pLOq=:u|{VWWA  K  o l GM wwISz?PH COE9~q(R`%!;N2Im$@*fmmqMfYsr 1  H ^ >t#D-OY ~ t4Pt(}F a V  :j,Q'`QjS7qi_>vIjGxk8kNTN;v+DC~V8&v *)<;, o j  H TD;t;z y6t$x  m&,M2xbWLm .G acOk'DW*hB 1yI]~ 2 f.i}ot0AO>U1 +@v{\9Y#'uCQJ!mqph_e${*0X-sb~G:~rFN  9S49<BcARX6  ]`uXdo:u)m:F-T{3%89-bt LCoIN KH!GL$ QdCXy7TH  r O#WEU(!D0RWx1 LY_VmH D^ ;h)5Bl%{D=cbb6>R;eL`U]dacC%IA`Jp!$^^UtG"p l n-("y   r / 4~=&{4+Vrq&@AQ>! @pqm\ h7WS7yx}g^Vr d @Sy%>Ihp*o<*wl4",  =@@umg \;Om"i.4z[-kq>A{]$_FVUy5* K@g)#bv Y.ERtn<dOP 8J m$ALxo#ICp6F`~}rs8&!~>Cp * G]^UC]ZP (wd : `._-$7On g4H +1}cl1f`.?BFO5@'V8h %4=/d8 #U{ !v"V! C5 !!" n]{ KJovm}Fh$sZ35+I]wwQcAenGqZtvwiFqD>jbS^r\a-)82fte6!;Wkx(kF 5Y!/"e"" #{##v%&d'a''&$I"~!!*!!=#$$'$" " &mr&wh3QF1E K4,lߢEJ7I>`LItVn2Skm-a| "C~. e9 2"b#g$T$$$#Y#!#,# $#s""Z" ) c ! v%i< Q P /o_AqDtAzl0RO8nKLK/^j.=O|bGC.3{LC*  XPGG6 !"#%&?(s)*) )$'Z%#"#L###B# "! O*|b'zu!s d  H/F5Rs|hoE]q6tW60FLvhFL3& mrqbU`Dc_N g.>A@L 7!"%&,(()X)P('&&%%&&%''}''v%$!9   ]UK?h%vRWQ~6NU)uCYnT^E5xE6Uurom0=0y0>CY{m7 b r3!Y#$&'x'''m(' '&$"! !6  '(|%fl } :nE PS?ߒ݄b#}ޢ߰!&%Gv`{H-85KVr$l}Z' n+=3/{}l~ys {sm!4#%,'H)*f+j+**)d(&&%%&%&b'%s%$! iLfDGY J ) {oFspqoltm9X0nOn8(k2]`\H*l8ALNu"'Bw oII l m |H !u"#)$$%&%$m$##]"]! :  - LyLr g |$]Mo)c+:)ޢ$ۀڹ;ؒحp!SXz8zkJDKVRmsO-t@gFI #Spyh!#%B'()*V++u+**:)((E'B'''d'o&F%2# lD4P r @5%# I2ݔ}lB06tlJqQ&=gImR. |}:o(7MBUP_u2_b'=b8/ Q * C   ~_rAZO6c ]9 E/&K2(|Hzk)ډeh{|gբrnKBlqW/E?!a ^  =XkiwL [J@6K29(hF~+.  V " ;!|yo ߼sܨB4,4ےۻ޶TEosTN!P[kDY~ 9 zHySn'QtC  UZGty/l K = ,Zcs0dUD@sܭ7yaڑ:aۀ۫ܰ܇ܔݵg@w(HH!@fPMH,  Jy;+v~"Lb@ !""""2"n"!!v / b~;.> k\9H1qF*gݹQݼ$?-w C4\Vv D0ss %    C  x%fyN-^D9  Z1@F]VJߋ݀2ڹWղ~$*wWe҅F9ӊӥԿ$>T!i%eP{ 3AtCx !'! !!2"" #"&"!L!  UxW !!N!! O<^ r. ? I!Ix>cn ?\kٱוՄԬ(ӚZDWֆ~Z/*rdC]X& K;Fr< ybO s #!i;RQX2 T!!'"!!!! U3--M 6sz B Q '8 d:.O(?5A1̞lJ]}Үշի8ߑ4c d4!S]Q=  E "c: !!"V#$&'(**/**u)(' '&&&&:%$~#Y"! R + U2 e  j:dl t~ߟݨ ռ5J6>ҩсRЯC2ӿӲ*ix &Z]&` iEl!"$$l%%&l&*''((()o)))))) )(S'&C&%u%%%%b%]$#:"%vJ j9<}> q 4n؏8Q"_ѿѯb6cϴЏЈIXtԺAٻs &jUq2OyN ^ <[XL6 W!"#H$$h%&'()***<*)){(C((o(T(}(('&%$# "` (Il] C>B <ݴV2ױgֿձծգmA\ڏb޶w!V] TZggxSr  tn1U\!0#$%&'X((K)~))/)x('/''''''('*'N&$O#!.# [ b86jFc% ܼب֦* 9f]fV̸fʻ&ˇJ·ύЮcփFv5.q.L!-ara H9#PW !Q"#$b&'()*))(())~)))())(T('%W$&#Y!\tZ z% p NN,8nl`uݨۚ5I| CՊ~Ө A\ԝՉڄ ۋݏdqqW;d[Y4,uE p)jgl5bg `!!s"""#0#"#$$d$#K#";! 3I6g[X$ d `_ A$^ =@pؗ%;ϩαθΩf?ΎΤ!՗xܣl9taeT{pSYBj& N l ixEQ!!"H##$$#$#k$$d%Y%{%%$P$#"Q!O 5%B\g C  /\R"1r9Y#/޿ތYުfTE_%#wi<h)g= p j2r';=nElM DXVVfO)}]0}ynCusoKX6\)  Ba O]19-t<<;cl ! u  s3#H m!r{,'6z' ~~sAk/6-=&Y^ab3gd )[3M7G/[o.[:, J & ,w$Yg|Pdx6koG*D@OI\&vXYqXKn8\=s $B # m F ? ) l l  ~B ! i ^ Au~@{hF nFy2u7<~QZ> : ' J ( URoJ fBQ  g  Yk,m5vm')mZKbFA''g_CH\_I~m~I a $ 8 Y N |7U9 ! e]m$aB)T"G!2LU}h}nL|`qeK""m{PK1hyWe u <EG }^.v`N%`J@+]3^Ho v !nc PzhIGlIJBcJ4OQx4mTI$WZ  &CcxzEowU Xz+ J C 2BVADLGH # :>Ji&Zh]^uRKB?ڼ;$y؉ךC)o݈ޢ]*vpH8:Q . .rV NF{TG;<47 pL^oaCOnwC_ێj'Aטb׉ױ~ja# ( 8:fvtI RU%  !j"$%&'(:*q+,-/...<.P-,*)b(&$y#"$!J+;&{x 2 ]s@&xQ.pVض׷]։ׁ֥]=YݨJf719}?03r i ^ cL !"#8$$%\&r&&&'''''&=%0$#!!! ! t:$ a  5n1PbPE}^@߆.ݝ|pכ׾؝N܌/ UWssp/ny Y q '!3""##$%&~'(***f+r+***w**=*))1)''b&T$"_!go NkZ{g#e_-6,dމH{jkLO6(~R  JuABIGH !C#T%'#((('(&%2%$#"W"!  `?m ! ' 8 F!uY2A4߃>ط!F%\Ԑ6،Hۢ}2 e9/1=T E^A!O @"u#$%S&\' ('''$'N&Z%I$2#/"3!A!!7! x t`>6/ g  5 7 4C=Yܝߖ߹E 0}0L>32w' S~t | <"vY $ n0|X}$ @ s FGuQ 71lP.ݢڕֶՇӘW!CtR|pm؊uAWQGMD\s~ \>8QPg Vv= g"H##$%&x'g'&%$# #="b!*!d!D!2! t`1z, p}kV^gܥ؃ؾN3׳0sܴx@ݏ'JyM.nO@J&KkN ]l8*R> p!!"B$&'o*,r/122B20/}/... -o+x)$'$" AG8%4 nB / / =zvyX`aF\uS Ԡ5 ֠/_V؝ؾٿ2o3ch"Lpb 7} n5~ n"#$%'1)o*++ ,+ +)z(('[' 'o&&%$"!  fef+9Hu ^ 1[eQ Rlm܁'y/0ו =8hh;ݚ29BGsWJ)cn]'b 7 @lRww !>#m$%& )*(,.w/#0/g/a.-,,,+*)P)2(&%5$" gLp- L. iV oWo(dFUҤҍҤGԒ`!ؔ7=agGLU$~,3d  P8F2 !m#s%')*S+S+*)(r(X(B(''j'%$#!Z ]`yR ZGd{FJC>)Wp*ӇѠiW8jRQ!7ۻ܆N zH} ! l|]!)#%&(*-/z0V1110&0n/x.-. .-,+*(,'%$!$"!O D|c+G  l$"in1En~թ_vπz(̀^wAϛ2ҿԣ):ۨHߗzH0cB : Caqq>!0#$&'Q(7('&&&&&%$#E#!{; x fa72nJSw/އvڿpՏT e`֘%b)ܣrm߉H @Qp/<TL= U]!s$&l)+-///A/`.--=-+,V++*)N)(''z&%$! .ub ! P v ?et0R-(C=Zk8׳֦~ררZڶڗ;^Mr<ߔD(63.lF"8 OI # `h "5$*&e'''{''((.)a)((&&s$##"'"j!s ?rd ! D!EVez\22;/yYՌֺ֔|ػ -ܿp46 *tT@_d!\@ 1}\ "S$%j&&&'','&'''&%7%%%h$#!* y($J|B { w&ppo}Vwmۻܴ#u!t Kr'i! *{j p !<R N" ##""="!q!O!! , 0tI]]K 8;x@&;ۀs٢ْ*N۱ۋN; ޖ4"Hq QLkm!jc Z]$ W Pr! =!2"{"!"!n! n G% * K ~HO>$-9}L+:XYPLV}++_057Lgla00;I :q!!u^>q"c.`a7wMM  d`iE~;nRB115}drY ߸b܄lj.=EDGXZ~~s/)$ M E/=th](6-UE{7  d)xKp%BOiLwt.3n>b{EKi fpO!:D/ i dU4|h*ehRoP}X  F E b 4 d sY#K@mcfeJ?VocrOB&g?=!X 4   s0pFYxqA% s 4 h Z !{An&g^En9y(&s]q:_Fi/j M! _ *n9ky=^g d xUjMN;Tmy+0BO|*QA2 Y1epr, +xmQ NkO `Wj S   ] CK2OkU   )qwG]*yT%A ar= p E^d*3Q~ca7uP fPxeFިۀ(tX[;0yNN\5A\~ZM# aRk~ a ! ]WD Q!!@")"m"" wl+|& x {)8;o+,sL=& gI aiz9 D W@+J z hu V$ldTC&F~Z(Lu%M+iIuS);H$1&%| 2c>6~qR!j!q !A;{  0>~(/5@/*'+ ?w1drG&e -u|=\dL ; [ 6_!##$$%&V'u'&$#" $Y6 & 2O:ENI< #kd3tpp V4w~5$v Ga[**f3x>f}GoKd XL@^NBaOj~O.DR1J(l?9H`B]_!%*n 8 .  <> )"#2%&'e((('&I'%b#!  =X b :\dwx8g$"h*+`< Jtx<8!]Fj) [jb %[; q Zire p ~v{l3-Lu߁ۏ_@IْٱyٚEQxX2}04@_x27_ 9`f Z } ZI !"#%Y&&g''V((}'N&7$Z#F"hk`tR5 o 1 80$97\0{0#BcML3tV.gUa"?C:mSYb3D u `+Q '"H$&(')M)a*++*)(W'Y&$ ;D,m  & jpQ\ j:;,4K+4 ?.q 5 Z5,g/j Ap: K a7o \j "#~%4'S(u''z(&%W%S#" !gJ 5  p{)FXq "f&ߜߓ4aޟުDwGhv)VMS#qL; M ^f!"#%' )V*+:,c-?.-t+M++))d'&# Q!l3H} o $  E}'\^BBVG\uuaޗq(Lh)4zq>N * xiw^zeU d""  hz$$  ]7CD >k!9Uzx&K3 Yz/ BhbIe1E&z2 } X ^"8!#&:'_'&&())d(&%%a$#)"!-6Rx a _~ w#1Z;M)V::b Y4=R;)i [y2 !V"=" mQ| ^CGx b {*j=QtD7a R].O%O $p#, _ K 8s-!'###""x"!hb$G{ / : @ Z a gH$@Y&TvUX| YMD:UnX;d7rZm0ve"sba P [.q "8#$r%%% &@%# bLR & F[bEH@On]r|c s;*g{pwl+xK9} G# ` R+l? @ La H4)@g0,Q ziOr[ Ol]1Lfspu[r EDv$'hK V 6L cF*]!]!/!!{-J H^/ iwBPyz`O-]}n9OCT5% cgmH#e6W ~ EV"0[ic4o KXQp**3coHxNܢllBB"Y)[^ `p : z .  }JC' %!"9  V4*)]K3{$G#7??ct@kK+9 ~bZ } l 7_Dg7&o , S""S#$$B%-%%$8#\! _ :EoWR]= 4& jw&4amPR9W$ly~_  + *9]!"#S$$:%K%1&%N$Y#!Lz1"K : l svRQ"nJ3xު ݭ{ۄۭߓd3 IFO;b!$N3 p : k 8F "#}$&')+---\..-- -+)'%:#_!m'?c =~V{a ~( KݻexCnبנe$}iaޅc>S# K E7#<O "l%i'(+*f+,!-Y-=.-<--%,*(S%$W"ys Ic"0f Wݰ_>e|טYؗ٣{ۭ܁݈EczC# t  \  2A-Is!#y%' *+,S--,-,-R,*@)'F$!< ,>I MW-A?)+Gۄڕ"Օ;'=۴tdID:eI  ^X9 #%I'(*^,.c/>/..S-,+)'W&h"f6`9 N :Z+ߎh1۪ڣFۻK;4,=x^3^QA 21cZNe:p @# +C !*$&@()*+,-.//H/.-+)(W$ .447 vZSoK"AR ܑ~Zטv'ֱؠ؁ S="8nZU,$~ 4 u P.3A! $;%&''(((('&#\" O]>  d0m$'8t ߉2\N֘N~ذن)1ۙD?D A+kF/TG6} ~ QRs%"$m')*?,-j..//.H-,P+(d'V$s naP  P'BX OK&-ܼZٰ٫d#.KB3݁%wɃÿ8I|96һQ BѐNܯ,`yPm PeDK"$')+7./1346377`77776654w320/,*x'$q y-K ;:`"^5jک ɟ9ŌHĽ򺗹'=8QŬɕ$3հ:,  8t2!#1'}*,/*2'4679;b>>??;?h>=<:b97b5J2X/J-)&!#t !;fU1: R֩d!ĉYa5x P̊X ֔[-8q:2Ix{ zN!B%(G+-O02579;;>8?@@ A@@ @>><:C9851/+1';$ [3 |dC5שѽ[˧Ĝo1-nb|=պZ_“z̽@2FX߬zHZ E q#P!#'+*,/R2468:k<=>?!AAA,AQ@ @u?>=<:K:84203- *($ DfC mj5O y2< {ſ;@x뼎s7 ϝңe| bpblx? tA3!%X),/25 9;|>@.BBCDME2FFF1FEEDDCBA@==;G8n41f-)'$! ! F$q"Ȝs bٵw$򹩼P,^:ȩ%ϕҞ)}["aXK Z%!_%(+R.13P57"9G:;8;;<<<<=F??@FBBBBBoBAhAg@S? >nL@@@@V@?>==G;y97k52/)-#*&{$!>M1 ,bAl'Q@`͎T®춏84б豀ʹzŎȓˀν|H.S[?X<K* oo!%)-414689;=5>??@?>2>I=\<;:9n8F6z402D/f-+'$"   Lzp"V@ЖwwŃ\3ظ=غ㽆jĖya0в8;G$ld c$e $:)g-148=:;;=>@VBCDrDDlCsB BAbA@?>;@9e630/.(,)%"Jx  :'wk ߑv`6ƲHallxǺwϿ~׏BGRZ Al]S"^&)Y-0k3s5p7k9N;3=>k@YA1BBBvBAA?><:86Z420-+(y$ klC )bZG2ݑ!~ӖEPRã-2>m.ŞǡM˺̕ЕL&߈949Z4 N 4-!%)+3.0E356v8h9:;8>?@/@@?>=;T:38z641M/,(y%""R Zhrr7޹ֿ|ΕyʈPƤ<[Ʌ"PϦ 0;<߰02\ K 03b"v%s(++i-/1'46789:;Y<$== >=/=<0<;::`976f520.{+(% #A?J KRh_R^lPFNtϺaʡTsW«BGEĭIJŪLj ˖GΛ6{'5tpF #9 #a&@)+.k02|4*679:<<=W>>>>>Q>=97c41/}-+'S$ f[ CW\Mdݰ_͂wɍ^xYabg;7  þ?ƂOJFэxCh%O92 #'*D.14L7=9:y<==?@BaCD}EEfEDCB1BBhA7@>=:7t40-C)%/"|^ a/YݔIŻ£;2GeWaű ƳJζx 7m`эՑ[8g -m":'*^.14'78:~?@ABCCxDaDCC[CB*A@,>:58h51/. +'$  \_eܴ&wI,*tM|ȯɰ걋hδh໢ª͘є܀`T$),.[26:A>yAC:FH1JKMNOQRRSIRRQPBOMLBKHFC?e<84V0+& " yq4knA*c/KI߳򱎰A?lRV(0feL*a JǸz HsVs w#(-+2C6O:&>ADzG#JL NPQ_STUVVUT2TRsQPNyMJKHEB>:872).C*%]  Z R֦o E9wond9w?Ewﳠ辭ːݑ;=d /c#(1-i1v5O95=ADG JKMNOPRRRARQPO}N}M"LI+GC@*<58n3X.U*}%.`p O}Yg؝?N;`&[_ͣ\dFw: ƭc͏kDa& 9"'+-1f5-9<@rC.F{HJLNPR9TUVQWWW{WVcUSQPLIFvBu=83-.("0 Fd0C͵ɤ/Ӿ3Īfǩ(V\˭6(v-xw6?+H׸ۈSvbP~ R#(z-;26p:">ADcGIqLNP%RSU$V5WWXXAXX:WUTRPONrKYHDK@e<82-\(W"b 7)9cr״Z6:v26C]ή#VݫƫSܬa;D'ݼšrȩ#yeFjg `!&w+`04 9F=1ADGJ%M8OPvR>T8U%VQWWX$XWNWjVnUSQNELI GVDA=950+&n!( hRhEeݻAX@Ԫ.&`=޾Mɺқ 0 N!.'G,04 9<@mDGJMPRTWYsZ[g\\\[IZXAW]U@S?Q`NJ[GC?;R7f39ym)QKڀ,;.$4 p,!%)*w.26:>EBEHKM PQSUUVhW*XX0X8WIVTS R PM KHbDW@<"83/+&"' T!j9q_%Ӵg,Ɵ޳бƪ964ylP۶OE\Ƹ qׇ{ Tx"{ AW]"&*.2p6(:=@CFIKMOQ`STGUU_VUTSQONLIFC)@*<7k3P/U+&"Bx ] j^,qՁчGĎưu[:14Ҭo#-xJƈ13eڈ\@j 4; 7%).37;-?KB)EGILMOlQ0SwTpUVmVvVUNUTSQOMKG2E#B`>|:61,Y(\#\Zo{%TEuڱ4=½c8;k+ѦKQFQſ "˕ςٙ47 Ei #V(,048_ADXGISKLMNOiPPJQQRQvQPONM?K@AMC7DD:EEFEXEDCB B@?g><:86k30-)x&"Y  )pR߿`ԍѺ˰#ÄջT|޵ٶǸNQD˒Fۧ߯$"SS 7x#&2*-w14R7v9;d=>E@rA~B7CCDFDDDD DgC_B@?$><9"741-)%!Q 3BݪQt1ͷ9ȑUu{jTp4iƐ 2) Zx/ +O3_ #&),.12*455677<7@76t65v5443v32A2710/#-#+r(x%" ; 5 n4hګKT9ʈ4zr¸¾ʽk켼18[[7[ʟ|~ԞTz#H l i\x!L$&N)+ -.013;4 555i5544e3o21o0.-9, *}('%" $yhDG 78>[66ݳHwѿḙ`tǹ1=tƽ#Bg=ɦ̜6Ԣ֥5_='W ^x #&_),G.L0423456k6l6R6n6A655G5n4L320/w.E-+* (&#!U|<W $h] 8ݜ۹/Z`[фϬϸeOԫՍ-{1MS, B*"a$-&')#+R,N----=.?.q.....|..}-,&,+*)('%#!>s v=\5:""@ޟ۶ڱח֞ԒR"A/Ԓbn׹Bڣ&ݠH Gm1 P !!@=!Q#$E&['r(r)a*+x++,f,u,H,,+x++*4*)('&j%$" z\ Il> .\$4gHjݫ/rߙߤ|yok /%L !"#$o$$V%%%&5&&&% %V$$#"y"! O Q^ **UZ*80{JX#Sݻ@ۣQ7ڄڭ*ۼg?2/&`LLJNe +OR5_-Ry, !q!!!!!!!!0!| p|M P 1TL0oUGvo9Rg`%wKW51_* Y j"Z{2N+D6wz( ; KDxg*-[%SS\ExYP5oS^[Es3FrQ g d^u l|&[B$f[ 1 2xs})\g/u9 :k3A_K42_S /,Vv-URbq.AhD4 Q"Mr=upjA`k+> aii&ve;~<~-a K YzJA eWRh9zUi;\ b`3_?1{CZl Ie ! UEXRt=NQ  5 jp$Xc:1jQ$@Tl<9dl |Z$s), B T 3h yb p =%MwE4 =W>El Q; H% U >_j$xS(j]u@ m P [ Dlw  B<|. 7_=Uba9.߱Vܒ5T܉܏zxNߪ2E}-h3xp! VKVfqfApsb|P ) P _;_0D4[? Vq0k_ s; KY h= !Q""#|#S#"x"!A I})  *  0{@J$D#jC߸ޝޚixNEoBT~$N%(m b ]10TmUsR  @hZ %   sZ/CJEN"%&\B{& j3>|,9gB  VF) ,!~"#I$8%%P&&T''(5( ('&K&d%k$I#! 86AA  JrHb?)uF޶@ܕ܃Yx!VAs?T+5oY N uwvb- !!3"n"";"!!)!; KOi 5WXd .Y>VY_9Qu__ڇؔ0O؍ ~jڄrvMAX  @\v$E d<+n8 p!S"#u$F%%o&&&&v&\&%L%$$#!V iz1  V:NBE+izds!GS\rgEE,4D*V P|MzfGR=5*t7 vp9='ukdp:#:zkp, ׊֌/ט5عبٜ~nYR8V4 m I-s=!{ !!!!\!  sz  _>3/l22^H?ޱ޾m1wGuAc|*xqnCIv & B[,66 !"#$}%$&*&%y%H%@$#"!xx` } ) 8 H%"|/1@5^޻݄<޹=j߫1 D-^t&}6p [=r:O ]!`"#I$$&%$a$#{#""%!sZ}){J pb u[{djhz)[dډڹَ{u{ٶڣۥ=gU2=;`E$6e"  7 8QI "#I%Z& ' (#)))))5)(((d'&Z%r#! vT}7 8;M@&Zs\ZG!a=C߉K.߁gz\ Y_B K 3d%}k[Rs y!!5"'"q! Z J^oC  l o|g$e!'9; o.Vݨۘ85ۉۗ\WVb 3Pz3sY7_"2/ B X E[Y6L-6 !!!!b! ' i<Eo { c.{# eqaA(}w!!)zh$PATLnm N EGR!9F;k/v~Jw   1 |]@C{>x6Wx r#7׌37ךذؿ,}ߔ+ 9.yLDx#;Lb 17SqnX?k6pMM;M" i |K*pbD/>jehy+( ߆<+߅U.hRQr='w eo < ?z,k>x @!x!]!! * c(s|]M { rqQ%:u]VC5to%7߁f^.OcB'qZm9/DQC T 7   QmsD|A e F:&_ojc6.rwuS{ޮߚ|]15H^@@ xSzeWT x!!q!,""r">"""A! 3[n<e  'l)3kZr9BXn}rz*<_8b>#{7)) i lp* !!!!!!!! R 2 -@ %! E u>-gY]w߭Hܶ۔۝ۃܣuޥ~B\BVQ7ac;  1jB4?tAy{8F2<Zr+7/P K  dj?pVM,x? aY=f Pe&rTj J a"M sXW`T% ! q V -  Owy7[5  ~ @#$g\uLIw%HR9/g\ܟju٢TܠKݚmtdH3&9(h(/*Y \ p "`[-v+~Zl]%7N}b  $~jS{8[Yߖ1ޝ݆ݵݚ7pyWi[~*47B* Sz1yq !-!!T"V"""W"! UFUh]add  V5U߼ދ;,;VQM}ݭ,j$j")l;ZuC??.7 s b 6B3A86 !n"#:$=%&&% &%e%$#">!9t` Y F  h,aQ/9 )ޥxBQخg;H{~r{VY}+B ?>c)b .'\!"8##$%&/'F())(('&&%$##!kP@7 w7v=Z /Mߗ$/ޔ.߲G &c6[L93T{L C  <=9@G !"W$%&'(?)?))*S**w*)Y)2(&K%#"!h 8J9: S?xkyFA+NjۘڻE׷ڨ/ܒ:G?C{CX *$8!-#g$%Z&&''''('V'&&%##! `"a&H  \ffNhJzwFrܭpSuڠ}ܕ\ݢު߅Jr^!z~l ?Y |"#$%&'()Y****,+*r**K)('_&'%T#2!|4 ^ WUg[E,fq2ݢہڌZ>Qքyp:Ւ3]٥8NJm{:*TkV,$ x iU 6w=W \! """0#)# #"s"!Z! WZsn  l #S" (c7a*Q۴O֍լ]ӯӝ5ԩ~ ޖ6? N \ qT>C !"$*%C&'()(*b*}*o*f*w**)F)Y('%$|"!{q" ![BRP13iNBb߶ۀdفؘ GչhCԐ$բd"4ڦEGMCt|]av98 ^ E: ]"$%W'()*@+U+H+P+[++*)?)'v&Q%Z$F#:" \i7}T : %~,\(; ";,2m,ӽCnиЫv%UqՉׄIQ~($/4} |2 7F K"#u$T%\&N'g()*++f,,R,/,+***('_&$!#5!8GH9 B {>r5 g$Iܼڎk׍ו:@a@?B$f(H [UgJ Y uAX(mH!"#%8&r'()*u+4,--.^///|/./V.N--,=+,*)'$"  B P ~qz2`<5Wڔ|G҇pCW,Ck؊W p@)E4Z, g  v'C !"y#$8&'()}*4++&,,,6--u-- ,*)'j&,%#I" -_}u A$$My0`,@KW_ h>s8AՇ֚b/#܌ރ$4 Fl `F aI! !g#$&()S+,-/ 0#1122D2E2100/-,+)(%#" o^( 5<b`^C<ݗP0 gף@;Ԅ@Ѡ6cҝӅGh՗A~*ߚAqE BB9" u"##%%&a'''1'&5&%%&&%%T%7$/#" :Lz4u R :/Xoߌ7>nԯ{Z0p ԛe!~u95g0 !uZ @"#$r%r&\'(())))_***V+=+/++**$) (&$" _= E@]"%U,[Vޣ#sׇQQh2>ҮӠkbՐ{ܠf?9^p\-'Jx$H { &)F g!",$L%-&&'(b(}(e(+(#('M'&%$]#S"L!- n`}i. nu ] tcH۪W֨XQӷX'-vش;@ߤu}Xb{#@ C f'`Ly Q!-""W##4$$$$?%%%!%?%e%d%%$a#!H /: v 8VsI9kUS,:j ),#bߟ߯D wL]Z[}/ <XJz; V!""|#$s$e$y$K$#g##"0"d!$ =?#JWV[jC = $i\0] + @K V_ێuNKؕZ/:܉##`%]4Q)tx4 P S [+Uvt{$eNt*%`Uh.|:  `>H{ #:T>"q[ iJ4z`P?uQ8{|2 mN J0 " _I M1P &3 S2{,.O&\ziH _13H|gL 9e@{{ P p 1   a M= .:{BBJ N  \N\2 n,2(ivEd+9-3p4{To6 o  X u[ `;%`WGEq E u * p=D,-2wiU^?"[ oY%"t.(R (',y m dB1EO 76  N F / / 'C }0m*keft ;s$"~!r:` - 4 & _ o /d~H+]RBy:A{#Pm& 2F v[@aekyk$t6L|TY{,Oc=   ?7S7^qYfJ4g6%/2 g  y c`O9@$:_Z(Ls~<.$k`. 62GnyR 2-=V{?NtR\xZj = d  } EMu\ } vBn[G1JPr  8 8 W y eyfX1\^l[N V*JlvTj#v&/7r  AuO%#V :  ' r ]x&~Z&__1ߪ߀#H+dPLLl_T-6g/ ; 1.B vf*(63`] o[:+x   d~ yGs'bXL r6#<}(l zJfftk;o WL@ , .] s!)"#####j#"3"!K!@ 2p'D$ @ d%+?#/9%)>;5 /6H^xJdh lep~Z>rCQ,xM;~~&L7 5 5 5 y  H $ I 8  - vd ek>KRG 1% 6[S2)EB?&)cmT 6v~u~2/Q rE  H  !  Q 4/%{`"@Ko11}u s#2byEl,Xx#) `~/@!n~R){eZXbU 3 )^<,}X=#?Qm iS= ~}bKNd} [{=zgX\Lv6,H  N8\xx/O Zh:#w+l\J {NS{&`C@jbHP~-mP=v#s^GQoa%^?^&M,3:q0qq2xqkjcUDC0;m~3f Wt4S6<lob2j8HS2&H !i~2S_[Edwv 2>&/ 2 S j I T S g ^ e y g 8 / ~)F!y:n-`k+9fDfVaaH@ct^4X.{zalu 6u7}ruQb/~>'L2@  y)V/=pF>@e3/e |NwY(#a1 WmTNyt9y!ts"g4  4YY& 7 : 4  0uW\3;@j^l Eps5N8)HoT7rl}?8Wdo?~P# )ER`/`eXI2d "t26<?M EDN@/ipaB a9K 9Nr{S299VP<9E,5Jp@)DVL6O:hW|uh0'etYI8xX0L6g lw=iM=r8da&KVjlKZY75o)W~eS#V@Sa:Pbp[^_o2~{axK2/4Q ![??xm^o}7G=^S1roVK[9u_jw:Bf X'W2\vH($LTh3n6@n2Y) omwOtyc\ st"/t5Im)VppxHYQ$5T~(K$QqO:/61)6OwdM j=#x[7{@\=c9j!Lj 3/pnb* \eT/>YqyVuvQ-b/OX%sI6=1`>m35ng"d'C-8yk0,Ab4Zvm= `&v3sh-NOdE? [,YjQ ?Sxl}iB :MP:yC>F2W0eO~],2+]||XG>(-%;'%!I2Uw9} rg!YjjV)Hg0v52/RxT@Cn $$$0!5I8j`*%t=wt =`ufbsk6/8>C,,j"=V <l-~x"2'-~N9' 0 >=/qL=l)!l?l(:=!{)%HtdYGHiv@KsxT/{:\*x$!1\&:M!\ bL3g-8Vb-%*$qDsnof6uXaXNuD = 7#[lWD$!/!aj@irJ~a~Cxnu g   _ Z7FK{|2K0\CsbOhU&u'y$y*,sYf= %E#db#xd{d]W7SSx }KJxF:]Hs$T2bb _GQxX9 $IbX?#[W> cQYd\&=JS&spzy-CG9zp,   ^ \ B 8~Z 4 S  U]i%d,@J}u47e~N\HjEYxH2i<\//6<[i+x/[/p3m] PzttqlT$$0|]rw6ci= = jO2qlp>W=V|k,Q:V@D&.DuO(0`*/%"Qyu = 2 o j f + m  l  E T ?  o C ? 2IQ`%5Os'@LA$=q0.jKo x\u$d   ! E 6vk;^JM m F OC ~!q3R>vczXZyt}<7 * l  '/W PVGv"(;B.|l;(9 U+)@4;Z=@B  Q ) = bi?#+ wX+x . K  sVQmC 5kA?y"|B44:g[[ZZ I>-_jem$?YXMAce;  f z/!Y  gRcoAfC  N >R, _v:2KUT> DU|'J[$YM7{aiH   @ ! ,fgG19wgg1D< ' x  Q Q+&SH;ecW %?h OqYC''p)($C) Q j  [ u  r,?OrVn>+,MdK:@  T  3b"dlgFzPKTj;!0";B d-e"|Hv N * 8 5 lJ =mbH bud/7_ 2 } Eh`[.f7xk2(v'' =}wJ Q$F V @ l )19zK^ YCQ4 # / b X m  N E  !IE3Ttd~x)uEbe !W8"|'}_@@x=l9!9nZR;Ed/  - l 5  r !-";]~5L-_\0!m%dYN& N C/dL.MR6zJTG|`F#i +Zm25jH \ )  P  v  J l { l ~ o h NR;e 1~-n'AhH: 'b!qg/9q,T$`72d  B ) \&@ =u1? 1a#M^xfDHX%  # b;CZUNP/MP>Z >b%%3`2P 7[f8;0!{;j7 @ K 8 u ~ $tPt7UgV m S d $ =$Fb^ sa8Wp%84JXC ? ! # < J &{  x%)}Dp  o GHC !  & F  0VL"P/B Q<#`sg_NM89kb;_+CVpE7^aq *8>5 } E  HX\ B ,   8 8 P I e F g ygTqQxjy& v'Gy~+2KAj{N7,c7)!* \  Q w SQNoMKb, _ T ( x e@=x)P88F]@>UOdd6:lBV^|WC8,-1U' , d  7  * 8 7 m  rAY@@4_4lM2Y-e;QqJ+|,KBQ7 &1| l H & + %_/,A^):?lYqu2 V !M _ -Nbhe] 4u&wPEL"RyMc.%%/ bu_w D y] x l  1 C=ig=Xq\wuf1d 1 & , a ]_AC!7}Ha=s\ g-OK|>,=m^H#YS & 5 + <2.@<MuORq<+X?O*lktr; /(  gzd=y{|%I5Xs*|CL"K|7<) Ke} e  [ 2 ? ^ i p  E  ? 7 1 a d p P  g &  \ h-Z =v-/i+~,1E=e|W:!\"'v8`c;"b3Eb:MK}z=Re'~55 s  g d 93)3 UqM7w  z e \=/pEa yP&q#+fAXcLznB_gj/T0L=v>ym/hb{Lu> /W\{&gRpcQF"=o/F~AG0!ct[e$Tw3O$&WiY5_j>x m r  4^(lH&& uRg C  h$Q{`s}_t$hgQ-5-']=pD>y/"5Y!  M=9@-,a S  5 7 5 u  { ' [   H P '  W  C / ]3Q,.,/hj0|!\>t'GinLIU]~ vMW+zy  u )  Y :? xnNV K g   Q /' a pLW]tkfXT*32 h6!"Hj`Syox9Mzwkhv:3Exp # e S m P 5 j h e 4     InP{N;$m*I <+@WIj):aE~X:G `sy _    a b 5 @  7 P  uE V P  ^ 2n\;Q&mT>;PU4 :yAAq+ 6;"e={ g17lmwUJ =!Nmq$hx x'-=:>R 6]ARl!T1jhC ~mbZ %R'l'GCX *UI!Q}-!wfPBj~{IcT y o MXr2 t2&\ [=9i={dg x # o N{5YAof~y\`_q8"@$\OAB u)7GfhOg$T2yZ F 1 9i?fGGXGH|+l.R 5 E =]8NH .ctwUQ aBrmU(Qj$yb,;>& ' @ YOB9^qU/"J<q / K  h7x7&)FWOeN2:6T =|*GOs_(:;a %]Asmj }   C b?n[qq |ql<M6[>!~ r 6l9$#"Zy9TUW;WR4;Dc VRV9O]L-E'2s\)[gG1A8/]& a a  ,: gg <2 ]\` G^*ZfsF^ez*SLoRl]]$s-U'UENeldX F~!Iy ! j 1<)SfSo.L6Bnwh 0 ,7%&s C \ E#FHxF|mG8>zq+~jmV[#\O]B v ! @  u6.[)caWSB%rVnwj NUl: W r nA'EQSdIsF3R3k*y+'6<QRbhc#X<u5@ o p C 2 . (3M}"#lW[WcG<nPK9 b g sgXf5Gn*/%)>r_fES  !I 2  ' Ya}[`r^Pc,dE1/Q # o T  _c!5!Fs O -+luHi U[Jqb 0Q ~5T B _ z 5 Dc)A%0v*sn,  v"1?<zp_$PXaV VK# aMDDM'>'T !vZ9$fEjD_~) , , \ p a?\./}r   :5OjG[ G=L%G<&AxXS9o0F;Nnn-PY1 cI:#s K   }" ^ gK4Y } 4  0(HO`KIR0(`I)U -|"D6Ig{#f,D`YeOm _ ~ =Y;ee9<bn%SJYq1! *  ; 8Z{nt~M'%[yto9^Z+XJLk;Q o[  w PJoaU[  `oL.-OTdu3. !E{XQ)zlp,2bWszfG3>5CO-W'QN j~y  J9K} >1]%.H a7fJj  y(h#}hKK2sO ?>SYi+[8NKj{m~f7P,jgb  x p 6,|t*i[`c*l|F# r  { ' 1 * pEmW/HBHO0B4[]-oy{\m {&Ot,s! Z / m  p!):1)r"  7 u ^f^3 yR%^i] z([|>ll n:2[G@%  b  : S 7hUyA.4 o eAFI5iY/mLCe3Ea X`Q6U~2-,=' . iG3]x d } T w7uX? V( >3q[c>XOXj  : /Mu&*tWh 6vMa%o3y((F5\V:\_* ! w  Ho<>-^cn63ncX4%Xp~2Q ' M Z _-%/gm* 3fyhXvpKpH_7Sf`\5p  a   w%wtJRZ]>RO z:i  aW-n jK`]y50JBz7u@ ja";AhtkKCbrxJBc:me8 8 F [rilk^Z#z3]8[ebA9SM C  +.:sgyUA`3|zG"Bc ZUC+p~ Nsl  $o tj M : }  >](mPCmp]7iME OJ]`n88*=}5632=/ & H Majz?&h3LlE<<KpS  )1*`pK2Ny(A?SlOR`i=:G Yx. 5 Adc4lQUgyz}o u(a^f6y.O(Y= :zOp(m8_ E N)<q4^|{(-FC5OS&ati N h * yFoP*n2Ln.5s}J0Sq ,#AqD\db}?C: Y$  =Qg t9c.qfz*zP p , s  d~PN,;y0 Y&BM^+ {M.16%)u/3p*C7 N ) Miqi q#>n`3W^>n}VX<  E a  ;]&lZ@knUa-0{Ob)aG eT & s =+< y+lu f[`(] %pd #y$WK+I[`%rt u%^(qqGJ-"%Z*:/v  jfiD^M1`.Z~RTw1tM&{ g A,ea*DJ6Z#E??< Xh*M[-TYHIZ 4 V(+}XliPZ)6P w?Ul o Y@m?H=Y"26[(wo&Vj^& 638|Ug @J8c]s@? s  J? le<<"pO.%x(H 2   SvJE8`jF|*JW[i?yy9M;`bbh7boK1S ZNFW ; ~ m S . \g cr<V$(u{~ ) &y jQ,uD;(RE 7%Dn]1yL]0F5W@hy5.2.}Z5hQ V : E  O?I8h%l;ZU}U[l & 52wl!+*Gt?3UAc Ji ${uIs5Z  _ g--Wt.;[Dn+r9j i 72m>tJ?hE?nwBJ`) & ,u8tcuo]|;n58eie $0>yz6JuV.pq;C7N \ H Y@?#V  wJ =Y\ T 7 %~u mm_x( (Jt/UDdwwk9"Ik{^ zX/K~'d u . H )gP&Us. ]q 7UX7io T B V ? r F@j4}@p6y[ v[#U WRgb0#>awpwtu`t`kySZ & ,  / )JXuYqz3Gu ^z QF s I K,9ZNh/h7x,?F=Eq|gd;@ x  g  ^<] 0.[9[ n&5"B*s~G0Xv<[ovT>2{L~]KQ$ NR'um ^ ^ j p r GE-nlFO9Lfti pi^FVY[ o ghq K~ L9 ZLRI|@~?) -DYvB  . S {x\% 9?. E ,!/?i m >dUH:A3Z2|F*6GcX*MnT Ke@bF%> , l Q } &&Ji&0 "J%0O^.c"   H '%i=(\HNg`vdYdS(; x;! 7 1  < I E $ j t.[ p Ecq&P:Vk `m 9 d & n$x4iNWe\GsYTFyp8kH?PEjjAC"|=N=  ! =( m _ :@jq}Oo>dVSP m 7 gnNzC[YNb`8y LWI*u){_M =<t%7Oxd  ' d 5 j &# a }  . l+2@#Y r .  I_yu@!/Fbhel1n?"SxP)H=N qE5 ; )  o V } s l e m )/m}qi(EurO:~T1+R  z6D%"SVS!@V6NyOb2 = N0)b ) l C r d  \ x ^  emchWx;2gV=mfcX| OU"0-cR;nEum5 $zftpn F i K  d $  ! } F x u  9 h  F uD@D2Kgem\p,m/c;F2bO0\'qW)>g 7 b   c@646|z?]oEAPNmJ_=& '  v DwBaVb}LDeOZ!pk(iJ+|" y?&Bzw:NT,  -   7 Q l 7JQJ  <Kx/9s S ) J ' ? @ I  7 m {t.u={=3IU(Z3OL/|H\egu]=|* e { #)m)k  1 ?z1S~ f # 8 V @ vG{x([$C3Q2G?.a8z0%Cc\Mrj"KKhb dCk H S ^ 4 V E < X#tC *  lx r T W3X|6 "L=L1|g )6Bi=Qe2\=122e     ^ & iYo9uH  o d  %dgrmby`nj Djj@.a#)xD^ r*fHVUIo09 ~CKs<&5_ $  Y7cU3#;c*09 | f r`:$ m V I$%uaC( 8GlO6[6UT^un`~: { QPi@SKydw"dj.,c+} @k r Q vb A$jp39i](d^}$Hߨ1zf)X {U*2? P } GE7DD` EitR"vU9SDG M $yj8tHp+X7ܫeHޗH#,Y&oeF6>:> gZN I  VMG> r+JE$licz  -jWw1M/-@ZB 3B#Vަs۫*I,ٍ؏SgݹP_oq- b,z0~Vs m l  V* HPop KUuPYHyIZ :c Y  o y-m=aPEۘU:/=lSD]]p`lMR?h5 m j ~ E7$} z`B>Tm<h.-Str]P4u2 ] Q(| ^mpݏ7a@^$W 6et_hLCq0Nt=F j  8  Y 9ti%  wp`vXZ sMJ  C euNe YT 4zo(~.6L / l j kb { S j B:YHHlrv0eeL["nog, r45f7 i߮ܜك:8j>Rץbܭ7 ~I'K4^!jGv$R2 - )  Y )tl%>>>5y*<r[SR M %NVs:$B/!7߿o-ܱvpܸܰ6n.D$U)X~~C(r * { d  faiM4AyXhnD33Mfm  GiDf T ֒;ն~֬]^ݝd( q'C'3t@!cYi|TfnjB 4  < C|%zu| o6qLP ,/gD X+zߥر٭RCj׫;։E1l݈ߟ!`Dhx d0RDan%L2,EG(9 E%SsiS^J 7 6\n)cN$ 8Xqu7 ~fS!(.&[dNߠ+.OD9"tS.A`Y Y NX2ipF2 a3U6Y!"y!/ :!~ N iX '@~- ,fmV{ cfS<Cp(GLfwd/K:_/K  Y  93v^ QMسCF7{DwijH]v~`,J~@j'K_Sj jU8"#V%%#W @zf>{ G VF>M5ޮ݋2ڏۿ/%%~n C ? Q x a 4{l"\r "!W####$%% %#>#! t+,f  7%ab2rٱpսd{8?\6+R y P P [ ' yN % ^SF } H!7#%J())x(%#" : A< nbm/I`tKs֘$ցO֨גx۫,.]RKh Pp _   Kq)c!t_e:  vO #&f)))*+,r/110/-+^*'%$m!^, l 7dES+ V5@֣ҩWK0LؠVJ> 7DN~4 l u & I ) N  &GUXR go AxI/ ~ {JSAGC ] j!#%')i'Q""T"  FM1Zd׺k@0Rҫ'p\۰,+JpmtjTy%HBx/tK& ^&nhDe!T$$d$#&#C#|#$:%# #" W   ]z[We_ܰܕ#0!3i\ܾViQCj2vC_025]\9d ?To T E<5fU0 F!!%!! g F>X60(  K l~WCߔC ׶T!=g%hډ۵ިa`6$2# |1dxOvxprv a JO0 $&E)H*~)('%$}$T#" ZCCq`9LeFKzVx@/x63!:%=iA8;nqC1' ?>!a%(}+./1231/,)(Y*)'p&"") D%"#ۇb=ܼܼݔ[rwZU^`2$7 xHQ_2&*K 2#> "p%')V,.A12210o/u--.K+<'\$ c8a *:ov ,\ ڼہT(>h1w(Uj~@_8 Z|{ \"&')@,/3357 76i6M6;54^3G1,'% ' R) _9DE4A>&J_G+pH4od*a:-hx'A e/A l  k#&\)+,-.00343&30-4,o(#!|'(> wM6 V0O)2iގdKBE5 ax d@: 9 xڝ۫$ R"ZSm= >h8 h($T{QAe}( rf,*C #&((*** )M&E" %d @Z5<Cٛq0DГϋЈϒҲ>5ܵjߵz\! %vbi:xhQy $ o8"$I%(-S15773520- ,:+m*x'E#*#m s -2D.߮ ։v;ט-3H:Ւ֫{cH9@6\ cH VNOL""gglm E4 # P M%W"%),1.|1456T7642w10/-Y)%!t^Mj o?wIvsvٗyӱhҫ3ִلܟ H ZkVuHkW'$Q{C Szo$ )-03Q67I8_8-8766F52B2/+&&"L#t :.)&ߪS;*DӏӮpֱZa[i$m Y2 \0 ,  %g2"!  A[S#H'5)*-1R6m:=K<8T630H00&0-)I&!{ *yV؊vּqqhqgՇhFݖ!3zVG@XBQwm&+v 1 @ * 7] #'-i36v753]1w.S- ,J(%#|;K &Ddc3(iڮ:Lԝԣh ՁԂҲ3"Yޚ f;bmT 6 *PJ&Cx9% M ~i4D]!%*.X378899857+7p5210+\'Y% O? $~$~sݿ ցҍqy׊j`Ԙvp۟߶S*pm:wh=rnsHe&S K<#'+.M/3/a.+*M+)&%"onQ r U/zynK̷͞*үв2-ؑEg[I~ 2 XfS8 Pl.b A9cd!&+%/i23620P0.7.-,g*o%k!]H e=drkbԼ3ӹ0ֺZW~/, 7E45ys }S :\R" S j6 f T`!$&4)+H--q--,,,,)&$! } -xڹ֕ӏ ѺK՛Ԃ9ѵ'X*ss$5l6*0uKVA\ j _ ib e   R3qtvi"s&!*a+*)w)))*^++5*'#VK p 8PR[R(WjՊԲF&ȸȢp-Ҽ`п',A,I8E mM 02yFT{ ;!"$&(*,,,R-/1345B42U1 0/]01/ -)%Z!glh +_qH5Պ֊RS˖ BϕϪ\[vY=[~F* fzq(C{v "m%1' (N('''(*+U++,-/k1 20/E0//.,)'e'&$"|#= \F@5ў&Q?5¥Y/ȸ}87{uG1hT3F [ 9a. O"&*,&,U,,t/358R9>8O8;9j:><===:(85441i/&.*'$ PYg 2 IPNoۗ ֺ(bXˋ j7UƽGůłq"+RRKٟ^e7G)   1#'*,,<.03G7C:;U; ;<<:=>V@?>,><:8520H.^,4*% a+X Ic w5ڹ(5ϡc,¾_dLQuٻbőȋdn͇vnذۡ@gg8 W!"B%7)-257W8 8W89:;<<;~9Z75o30-d,@)&Z# 8z 5 $/e6+B&TֲӛЇnPĵ@bx C†gV=[l@4"5=7ݐAnT+P%I <uO/!@$S')+.26/:O<=>@CEVGGG{F@EB?=W:76q64c0-)s%$T%#C z L*?/+9;VJKr0ւӅӞ*ӂϬ hDͤ6`9GȆɍq+LҺԌ CC>Zd? >y>"!%(M-;2A7;W=>?A}CEGG^G&FEEzDB?3<86s4d2J.)'#g  *&YVB=ٍ؁~6֗ӈzϣФ ?^Ƹ_i]ʩM͛ԗaXAr !;$).257 ;8.7652H/)# yf zdCPE+0^X[ 4M%޼}mڏ5ڛ\@ ؉ھ܌7XJ`-5;1 P""b'++05;@FC7EDFDEGEI JG1DA@=<<7l391,))7% 8 |4<@K'DF1i/,1cNo`SߎdۭEi_,jd=޶Pt'P<$Oe !=#&)[-0^34y6789y88"989873]/D-+)(')$7} d2 B4 b݉!ܝJޗߵgaޢxEN{. ܨp߯qrJ`2pT 90!%(++E+**6+),,/,(-#-M+)'$ "N!T!c' v :aJ_Yp~U/ 1_ brQݏޔ=l+>N~ O]5 [w!#$$$m##x%%$$" = }U9 kEOU>0#)# U_+Gz<emmب\ڼoݏޗ߀$F@v +<!\%'~('Y'&%&(:(&% %" xj M9` 3o<6=BVI}Iq16z^4oU7X('_lVF  % (r*(,,D,),,-A/.12104.*'p%"W(l,[ |ahL0=ߎܚe:B6E[}FAs!:g"nY$gc]`B !#a##"h$&(+-t-V-+('$#B#"-"T6j 3=Wyiމxշkذط0׊ۮn L:~79Q`sY l %@! "p!! kW1zEGiI$s}>K u6w)S۱ڠ@uֶԡO׍uo0 NnH EdK]O!=#$^%}$" ! D H"##$$# !$ xb%0#DU Qgj;f$!=>׌֗:,3cnVJ% C=XNb_"!#%)$+*a(&T%$%%%$&#S"s!L&0+ )]MB*<0ځ٢ؔ5ԤI=kՕՊ֔\٨ڿܖ߻QYSIe, o;F!o${') *)Q(\'''X(1(('$#"! cCB\PJ 8O{<y`%^$}Bc/M~ݎܒڝؘ5\ٝZ۫uS5z i K lDV<pyES{@@ e 82osOlg@ ߵ޼ [X'pBPuP-:mb. \,)S`Le UAf!7\ mp{yMAt_gucR2Sf[3jn+W ,G s /?[##j] y L T * %CWP0 =s!m@tIObRXPE>D+ UIoNS <a6mJbQ j 62vnoSu  a3,j>UiP0PnAG&"X|M3{_`m &O? 3< '* i Q  K+=!jBL3|s>MX}9yP*IY-pvr#{6%b* m K BH-G>tq]U& h 'lS5bpO`"3]E}P+b~`^!^Rsp o,u}:PrXZR ,j[m  qY/HZFzv.< ;%(A{FQu T 11 B : ^<6`l9/ D15X S M   gw)=~%R:%DsIes\QDO\8mw++`jDVy Y   a V \:R 4 N|0+)x2I)H6Reqcqc22!2CnZ2&Y>hyq;DFnq}8~B S;OM&?\ .}5ppN$18Y':i<2{sL@q3{@`8I, n=%;u '}VB=Wb VX?PV/,Nx[w6,cwK$7#EqekV# Q l&CV *    Y O=k$UoD%=#Hj FvHs?ar^Vh|2;(Qdxh]S$=H8Zea[5dTsgR5W`UeI1Q ,7npxAvEp5p j '.w h&@0AyQj31n  _ EYtK[~ T 1 h 1 = & = 8 p@  E_9FWZjbcG- 'tDMz>T A!vK"'+0=u# g Z ,K ]8\m2^Y=L~(Xv8R>yF@e\>yCyE o    P=} F K 0 h-|:tV&ul[xaTC,j L ':dN!\4b ~ T . zX?olwD(rw 2  =,KmsWdM@)Hp\\mQ;L3%k;F/B=$! _]pL:  [ K B}aE\7_S   ? jBrgF2&V'8F4jp5#biVQ? a %^9zn  E]qDR)    WYvZUr^5)xm]IL!u&HC$_   p dqEG==i #   H * : #mK1(#Pyq2k]yvQmvzeo tk//k  S  %%Q Q Q  s ) x,q4@Rf_$YL7HKsXx5N5  B a z w < i p , B @ C PBC' OA*m`2cvQA7TC$pUX"DZR |uL5LWO\_-?[!m z NNYvWZAUF3g:j&6Mbc=$A=6&exI# \ 8b2h*"|aBX,9.=Y@P.SwX;$>_  T x u \ u X 1 QXXwu  < ^ B b  d ' p0xF_#QjDmhf{!s- m un\H7S m } 2  dW`Z38T % wc}V!,W% F&)lu{ r.gi! [H*Tj@+wvCRxG?[cn~%AHHQ/{@|E 7Q gc,V$g4p v >ebVb6n;mr `6c@5 N M/_\% O.\}~'b!>Rgg>k    '3xyL @6rjQU/C*54z2op#z s'.5)5n =EcB=w }oo$Sz/!umVlpD ^(zsgXj!!Vbm"]|cq(hbRod uJi 39J4b=NPpY)[>j*LYe;55P=\ < ^^`##X Pmdygoyl vJm~EP%(BbmUVs/khkkh5W,();v!uZ6ht4+Hj)r?6&MC9OC]xhy!,p=8Ep$duTxti[#\tU_!J@/]j|~ID8c>L_>Gf,6Vi/#:?E=}z~m/)Yc|o/CkH",' " {  2 Z5!8IjQbHTOx:@ !dV7PPmG q!BJKc:>nN:NW3 ~ij3evim:Q\C~THL'oF_ EHK7T& /:l+.\@p =(14b izvj@=K,/mM wA"3p`~%7\T*"WMV?uBe>W>@O;d T"Fp q' {ck`Y4qoXGq+N% :m[D 8_LZjq%(5O-{@-]Wew|XU_"J&tx}l|4lxi?,\`"K;8yd:C `"$A82|-@ym&s7: >-O^jg^z/#wU7 )%jVBz2` _%x|FVI9xPV n+n>k*-"L-2n ,H=!vW6We\vY  _\pq/Dt|Y j1  GDmm*2+%mqw3"P4Mt<m u Bw4fo{ mYGPP6@z[PR) i^#D :g6pb-$n{+"3dRU+%RxqioO++dYpc|eL02 $\|jL 2""j6`%j "7TnA8RQgyj(;q`]yf`J"943MY5AcQ(- O>T> u9wX`jz)a3{9\GKjGjp4fNdxzt/[d?N@rX\lG%4D<*U $6h$/98v`@/jt_JbU" |U~j$V7o@+7`q(!@Qo)K?\19G  ta+,^J'p!Ex_EPr}Q-dC__&maF/MH? gz (QfR],(W{~-T{2sKFN%qt `V/,'b$hkR/|DzY|OgzE=x4\jgPKV9wx}E)m@a +3f6_3heuLL"/N;Is|mCA7 ;0/Ax5!/R8Z;9"RLKAGTKOGRm Z{~ssG!08It$-!/q3|K< i6 V+ #,1CbpO_39cjf?PV.GCjQT[9Whj8-{ C+S7T\$?5btGgN&7y0r/)MH$JmYT4#=w\9}(#1i}r[9YP96H^~j}@>A q:;0eyxXLljU)l,u H{t "MwXfU5+ 89NOk;b p'{p)0)O`hC6A;  wV BDJ/"(d "G_pN]>>G9s`!|~Dy3RHA'U/OOq<4KuYB73X!2QZ*v-ZW-@8g{vjYud/v)HQ{e=3((uP)=+i}&Et?),q l+i|aaO^)&93% xqV.+JRR(D3G D4a }J/jd)) o7 FH u+bV ?}&7)8oPH'2&Md_N8$BbN,$/j +Ubg~!$m.[<}j+ "?%4[K.<Ard\zaYx,A22]\ D? R.X+q 5Xh3DfHS`oNpDX2Z{0gA"`|c X(6\ B"7zR/j=J= 9@= rz^ ?M+raGW*x78KeCXJt $OQhj0KkGF=yZ]=N]CAxZx=]DAp5 r? 7&w).l, @m6jf.i+ a^Y1 ^iMlB m:t?^=zb&roV)T r4+$, S:V HV SH[o#q;C=x ,F-!,Icw,D\dRwkG=U+{@[+#NVNxwaPYg+S/{(xE'MBC@@8srHpaM/&a p~X 2il M=J:=ba.^Q}_(4Iq.gMUagdl .[wA<zhyQn :%h=O|2*WY{*kk!KR>N_\WDx\K"63~ TDNq!]~:{C G%WLqkQ`epttK,`A h!$LG-IqskYxO2ro?V  TUA_c3T!x0 V:YnT]$3u/`ruhTx\0jCeujxN0%d{ TNc3p(L>Xd8p\(2pWOZ3//axG9sOGTcw\#%p'#PCmr=@E2,N _}S&H4{cRLf-M9 ),H(5p|2L(D{NZR$ $`mv;yK'\ *,Ou$\%3-=9 =t ciM(UXGiHtidQG VV7 dF))o_ u^1= g1rx=F2{2 x.[o } zj'ObkkOmvRFDlL\(!!e-*mhI;`\%he>066K|CQ`Dt K{h@ I%_GfQy:]nHVW U!O+j";@]bc(k>vKD@0xZUF{(6bAAx (;IvA33 @Y L:\Xfk@QOb|N)'N:,@u*ICx| 5>p"WZ;X9+St3dg)g<=(1+iP:/M{c#: =l@5C2z'gowdu/ V#={B =\&E4)PclKiG@f%u},*_ @P$%R6y`0HrH?\[OhI8w()YH9x lgCw<[ gtm6*=?*x/I"$vIvX&ARtR>F@e*< AG Mm!= ,oYxa[ttK H/{o  -c -8]tCk"~j\cD6,wA`|%ny>DL2f`{7CQ>,2nh !>xb)Z*O>-~nD Yc]"*%{c`@QI_kS1X[o GB@%Q/\]5(gQ5{,4 9\cz4[YPmI eBuor.<[6M[l*L]QZT$"M3Q(. i}v_Qq%w+zf=#9 n I8" gGY}m ![x2K&) b p$+:NE}Bo5xrC1Tb)BK\J6p\)#I78Bp.}a[,rd&o& 7?)Q) mYGh ~bA6An;,k@"v(=%m_$(`3!=u|5Q/%ZvAZ@b//FbOiqO>0@n"ff G2-pfG5JNSj{{0\"~=tcmGG_msp(D/ :t v`_6nk{CXqtF(${c'KUtX$(D@=L-p~@ b' - = Z jE;  W } H F:T{aW$HNn32G5*Z@3S@~C%%\3(.oH9IV6HuwCI<&J6N( # f%f<:X:&^fYBYKGJ9 1Xz Y PBH%Sa9q1BHl`jnqeZ(]\UjtZ(3]FD!NGjK!<9,o/g.x~x !mI eb:5H8,oj]j]&CZb).*7Vp2SGftS)x)z4 vl^SmYEaQ/@J^{{2gr!GEEX=o F\vn/U3D:D( &M;kfvhWZJL5X4#.\C` 'I`;-~0FZL-D>'Tu02k QC0F 2=KOT@GOp]U"0/$0\x32;vkT qD 8Uy2 ;`_\e6\jyHkgg-h;sF=d *0/vkvu`I$F\xW*xkK! ICyxh\q-v],\K_y/cm`tycc`_nT(R8$@ybD2RMd1&?42Rxi #  Qc) 1a)cPNHM Kc@?lXEPg= FAKR-:~v;DDYO>`IOmVs-FO5x UjekcxG1U~u2lC\J{ Y*Ma:1KEa i$l~$14y\V_QsM+@mGKp(c9Uc #/~Q{0"A'`q%1 R^O(9s'ky{qdDR#1O?t*_As2;:yU5O~$Teat-  f QZKOet>_mk]"q8@@ZYDeqbgD@"bF>/f' Tg~G 2IAu",sb /yOK@2@N9=\]0jq $\exh!TVONxO{x ~h=H`AbE~k;! V IuN >)-khr_DeCm!_983"f"`wA:r&?,(}d^(*ja\7BNNYl3 Q [g%7^P%pN Jw1f6 <.44%g ^)u" dcv f'gfZ-c5K"8/&#qc"%7nZ\9PU?6PB~3Ud4r4?b::@$^#-g=52M@H1LrhYaC_}g2bH!T&C!S@ssB~r)#~ *w2~BNlcSw}cDr@QK{V#(l=)R z#%l wgx+!C==@1z%/5G!f/r.4afg+u?9g/?*}a(%c\#D8u HgY /9,jy\cx lEU_dgGT?BeQ8D6.bl #X Mt{LBc@okY sXIF~qBg<q77!)hPvC;Fk-vAZ ~1 M Y(*!`~Ce|pV`#43 U[; 5Wi< j5Tlz%TxhCeCN%Y h' ;k$WneY* ^ ep:o I k |aBH;pu4=%9V_& H3,jeiGXoi79tx.m_[lsCBEg!f&EtjHl,f9r tPr^r+(+N==SYX"j^i!U/  F?2rqF"`QV)+wCq slq:@jnB+/_g@[E4=;SNB@$C2VdMx-aTuC2Hs)\V-a@N(z[\F^71'\{2-dT@@5$vUHz 7EE7xf_U^(  !NT(ZA_ k-'"5>{ZW  9 (-{f>6`.++ fF!C{YY`H+c'{Ixl :,@@c\-241m~!85{=j9O "k<K /\ %f* N+N_j{ / !xy vT5;3, : !LW z   = ^   } x 0_ j 5 J  y   Q r  ~\'a V[ uNczjyJ9TV/7I= jhf;ru[\PlrS9 KV^HB!f r9Z<^ 8:@?)MD` #lk8*=LTiL6m@^.)}|KnF(ejUy }Z0BV: NOj!q/ ,I*0%|SQqdv1=Ya:3 o,z7Ymj@d BeSd?i MqgW;3g\-V8 g!>Ieo ;P=5uj$sY4z/Nl0 jUBK| s>qmF#>& ,4(gyy_lPZ7X!NR$umVy @:! T@D $5=^9! Y &{k9/UIuIb, e!qe F 8mL[} $xm1NB`y aG &q\Oi,=#{xc>RT=pc R U6[E0YA'm:P c%" \ Rx'e&Z Q i8 = ,Lsja p  yV oyA-$w8na/ +V^xO;UeT  @ c/ ORfq|rXNA'P3 3c6E 5rX%vI? N/ 't#jIC L8 *;  f,,/_ *;6jgW m|[_$[ *EbV&ncK_K/o ,2MwKKgCK+[\(~S58Q@KEN'}w $eu^\G6Mq"d~<7jaz2^(j~YsjkY{@p3Hgm$'>#+\!0NV_ y1o6\.2YXlbtS4S=l;Ir[E~jwwQ]HS70TDVqv#ec/ /_vNt! a {b70*e Xj  % s u{C  Cbz: { j" \u [ <<  ZlpMZ4 H`eHb"4&=_87&5,#NjK&m<@Gm&j qD^ rVE jR)Z[.e 8!v!zmD P$Hv g{3<DDo=: {W,og&tkkXDt#?@5 NLCiE =  xi8rJ1h e{ F  : Z9?J Jh#G;CKwmke ShNdP Q: IvtFH]9 4 &:.lMoX?MN[SU$rbl] S$ ["R~O/7uR9\j@>/F{pU+kn7Nsl2tp`M={HXm CQbwTxH*G|yM: ;eQc#'!!)  j9]$ E:{c l7cW:^i+3Z E Ajo-C3#vJ,EGW4dH -B7eNrr)\`4%=7 u^=a=xm\p)s?9N\H*o_?C/4jPl)3;*^fXefV~=Fz,1FFCRN\3)6qozNF]dH S =6jdw": ~ ]?  2m7;&!v6OuN-{dC1 {\~U2xO=u! VIY~(Jb:|lm7cNw a,G^ sG-qJ:T{KlQRyu#|Pu2Ud1BRN XUa?!+ ,x!X-EI k m5~ml)o-T 6e5L$\k *_^-P:Pb;m+f$-p[~Bs3WU-jN! l{mDO"qG,/ 2n  :Uuix=Vz~5TV /~^&<x|$qpFFp>33ZKy:5RZbD%K#oS \n2>/p>V$ZkRT=T,mENs>hs|(%9}rF>i1<XLW$X e++``7wJ%X0:6cvU(1[b5\i(0@d:2xx_|\/*8'x g: !d'/[$+wO0r!a =\6_UkAF\Ay;]LT~ C P 6%8Uj Yz44RP~l 1, V$G=]e"Vh N ~ z l  %= 2 s ^JH  p 4 7mAC)DEXFFE)FuFDCvB@=];8631.*&"6b 'oַш͟g54뻇kF5޹Ⱥh7пac8ުR5:G H>"j&)`.?26/:@>ATDGIKKL|LL LLGLLL6JNH$FlC\@>Y;7W4+0,,($>6&;[\uа»"g˱4RY1bi<\̧ИmVD S!&+05:$>AKEILMO1PLRTT;]72=-'"<q 78 kռЇ̯.ļAP[uîPGش9e>ی DL d%*05$9<@@*B1DGJRMDPS TTTT3TTTLSPN4KFB?;834g/*1&-   Qqb'N{Oת _8rT!|z9ת届K[E6 P}%l*"/[36:>BEILZN?P1RSTU2VUUTRQOMIE}An=95n2.)#f{8=۩Gɖ.)?ܬ먆Cʟȡ&¥çѩO\Ė(ҝحYW w!&+#1"6@9"= BFILPmSUWY/[C\\]4]]]^r\*ZXhUQiMIrE}B,?:;6M1/+$ $ "M3"ѯwU u#u*#m̭Oh.L-Ϛ6`*c q>#)/4N9T=/A,EHuK^NWRUWXYY_X"WUTSRAPNLHC\>933/+=& +^ r&vOBbʾѭXը2Ҥɣva2ԮǶ7+ԟIi& cD#!*f059vYYZYYbWTsQO LGC@=9}49/j)#  `NMߎ۔D1Ω Ûzְԭ˫,Z$Q#ɥ5몟h۷ EǸD@X<p#)1/4:m>BFJXM QSUhVWY*ZZm[[[YYRVOTQNJ#HCE*A$=84 /)#. l/߼(6Ϻ27" !/ʨrܭܰb۽21kԴٟ3b%po D &+06:B?,CqHLORTVVV'WAYZ][Z"ZYVROMGJ7FeA6I|͙֘ۛ'l6*ѷ`v_# Bg%&,28=zB_G#LQUY]^C__^^_aVb6ccb^[KXSkN}JE@Q;60)$ x<~=ِӇ͈KLyGˬħ}="[󮇲жpf`+[?DN H%*05:0?DJNRVY5[b\\]h^K_N_ ^K][Y\WWU?QKE@914/+*~#$8Y s?HҰ̜1޻񬑨8 ,ĝܜ*NgTaʅ2ڔ H T 4Zr$l*1/|49>CFIKDNZPQS*TZU=VWLWWVT1QMJaG,C?;61,u''!.4 R[N}?Vp Jਉo2)~[&3еQL!˜~$5j Yv!&,1$7n<)AD+GIiKLnMXNNOQQ6RRyRPQOKHHDH@<73/q+'#r ^ ކ] J_ÚĽX5bGӲ<ųyO/2ĸqLnҫۯ$%ͼŲ0*dڿ߆C ui~"%* /26F:==d?AB[DEE}EEE}EDTDCA?=;%9f6}2O.)% ^ T٣ӲΦNʻ_tv(JX=nF̿.]tlHdG X#(-2"7;>ADF IJVL|NO]ONaN1MKKKHFEgA$=96&2J,(#vs ~xhډcFʖb L5F 5δôֵηǹ{'“[U{ܑ^(pk86ZR#', 159<@gCEcHSKMOPP>PONqMKJHEB?s<7A40{+.'m"Q %?Wy:^ǻ۵޲3Ѯf׭]ѴҸZ^Ɠ0քS, c $)/s4|8;B?A EHzKMOQRQQPOzLJHFDBr>9D61+P&!^ .8׽ͥQ﹨h°ȯ<O˒!ֶ w|aa 6#C(-J26:8?CgH;MPcT~W;Z[\]^ _][QZXbVTDSQ NJFYB-=b70*#e s 0M bеU`9JVg&&dѮ8ҿ#~ԗٝ$gl K 'E-38=lB~FBJMQTWuZ\^_$``z`^\ZAWTbQNLHwDe?924,& 0:,ݗ֖V˃տw){訪rwwzt\ [ԯ0g'Т֫7Il GL$*06;AQGLQxVY\^d` bbcfc,c(b?a{`^\YVRBOLF/A: 4S,%G EJ¿5`̫aŠv\5AZmӞl\ͳ$1ʂ2m/:Ls"'-4:@FKP~TX\`cegiBk3ktjqhf}c)a_][IXTOJXD<5R/(  Z_a@Kۨ#ƒ@[밙/ҞRm՚mNƬ0^4= 9n")/5:?aEzJNRSW[8_bePg&iiSihgVgedav^sY8T(PJD ?:34-#' * rbQߴٷ˥x%ٲ52`ZD6k럷=J%ܯBL*SޯF6&&>\#)+0`6;AiFJhNLRQVY]`cdcc$cb\bCGKNQ~T0VWXZCZYYhXVS}QNKwIFA~<6/(0#y~ !A 4ډtX8j'R[Ĝ֚AU T©fփ]0 P#!',P1T6;?EuJNR VXOZ[\]]\[ZXVLVTiROKE>7a1@+%" A)/ K EZ޻զ~ue!^}c~7#[ f1 Q %)x.f37<^B9GJNQ TRVXZZ[[\@\[_ZXUtRqPLIFC=J71*$~l ;D$ڦǠL?ګg{*|_3UFǟaޤXPЦ%Z,* [$++^16h;?8DHuLZPSVhY[\\1]K]ZWU`SnP+MJ HD @:4.'F 3H @W!#ބ`t)ĥߜߛfߛ*0{ԥ7`$wq ܙrq@:$ t '.4:!@D I?LJOQ|TWnY\[\V^~^]\\[0YhWUsRNJ G4BL=7f1+% ۴ԬOa޿ֻ\!bjNġEfH0ܹ~Ӛ߾ymr~e]"'H-28K>dCH#MQUY\g_\ab~cYcNca_]\|[2YVSOJE@:5 1f+$U fӻ(taޠh~H]Sõ@CčjbH58$+c1s7=BG&LPT;X[Y^aVbc7dddqd(caH_\YVTO"KF~@9a3-'>!'g-lp򶓱x<5*2țܛ$:O칌n.Wmމ8 Q (p '^.4;VA~GgLQqVIZI^agdfhljkekjGigxgwfdcT`\WRL(Fp@-:3B-g' K  ?Ўɼؿ:8F@~o?HԱIPӊڂnX flg!K(c/J5{;?A/GlLQV![l_}b e,g}ilkk;kzkjigfdEa8^Z]UPKBEs>82) "k} `j?кF.EdFD[GdEl zjk{] +w ',1$7R8+2E, 'v!Mckid*g]RXӣL5ki1j"CήiXsPOgw+ m%#+06A;?CdH[LPXSVZ[]\}\[Z`YXWmUJRUN%J'E#@93,.(!, ELw *&+0C5q:x?DI NQGTVX!Z'[\]]W]\[YRW$T?PKGB=894S/m) $>6 W[HAØCӵԱw!ɣFSӢ!4fk%Z Fm `"(,16;@DPIUL8OQ TU,WX*YX;WU-TeRP*OLIEGeC>95`0*>$C= q-ڇı`9Fέf#24Sů>NMI3[ UWv$).38=2A\DG/JKMOQR0SSS|SR^QP;N`KGB8? ;5[1-)5#=U b !h}ݫׄ&!? D1[в2ʺ.{R%ϣc_ ym tk!' ,n037;_?BEHKNPRS/TSSSSRRnPMJGD:AZ=84/+'"L ][\L+z4ſ Oʷwz𰵰+ T7ȻF՜,4f{7# [OI $(7,u/2693=@CE6GHBIrI1IHGDGG1GFwDA=93q/*'L$ eK YVAk\օDq~7C>>ڭ]ƴnCͿi͈ت#d)#(x+ /7257t:=@BEGHIIHGFTECB2A>;z73/9,K'>#@ Wd2,ٝԓ;ʍvȻŹ︊Ƿ%ٺQ ^Q֌9^ |#'+,/R259@7BCBA?>s=y<97q4/*\'# a}  TLVܛخXПŢ/!0˺I三Ĩǩʟ͇wLYPS !~&*.1h58;>,@zBDEFG\H(HGE DuBAP@F> <%95k1-m)%!GG d]?pجԸZ=d¸ڽٻ#ħNJ?͘ѯԢQzS/+! PqL"%s(o+.14h79x;=?g@4AAAA@>?->7=W<;W:86d2 .)E%b!=%s s ֞ΎXʀȑ,Á7@8 K1¹=Ǚʍ͓*kb M"$H'm)+t.J147:??Z?>:>=I===<;851..*'$e"Gfud _l(߻m ;W)%]dzƥmˆĻͲwvҊdb&-i4: 0") h#&):,U.0h2479;<=8?$BWVH ^ 0*"$'*-023"4333445654M3&1.,?*(%"m^ `o03Λ3K\QϿY!ÆtQƅ|ˍΐC?|[]v #i$!$(,41^5"89:T:9:;<?P@@?=Y:7543w2r1.+&I"|}@ ^  b{'ڇs6>fǾǻ6dʵncDъdٌw޶Rp-1 YY"%'*-/0i112235|78L9874h20/...Y,Q)%/! - *VHݣjcΑ̂RV/^àBß`$=֭hݶ(IL97'h[ O k!j$a&i(t*@,G.<02c468t9998X7643w322o0u.+'#F *  ~;~ܳQw9Buʋɡ?`hUbة# ݆ߤ~&. eA #g&(+P-/>2579-;<=>??O?=>Z=@<;:89865270,')x%>"Y   {qLdL&LZցќ9ɭơŻĖĜłʞΐӂ֘Nۀ7w {!$(t+d.003D5e796?@@@>y= <$;3:987O63%1-*^&_# ^ M7|.2Nʯ\ȂX˙9<8ӚeHZٚ ?X: @"%o(*K-+/1]3589;<<;n:Z8^643J32S21V/w,($8!yhs @M1.ܴ"օZѐ +нϺP}ͭ0a>-TLNb[tHw0Y i $Z&<(,*V+,-/245U7898-87i77654321+/,)&#R# S D;wk' KC[9і<Ѻѩ(ԴV{߸3~m6K jbGD s"&$%&C''5()a*J*C*)'&$#{"! R-!  ? k?vJht&7*\׆8ִգJ<`6ӡ֥׃-ڥ-.d2(z ,&<Jv5<0 "\#$$$$$W$H$y$:$#"! % O3#J-,VU} s rB^ &=?lM eF*V N@=x* 5 MH l XIwk<g. 7 I ;"2Ykj&!,> ZD#F| MGe6Ofv}Cil:.r [W]5+R6 { hqLAbH!6)OusFݧEZ`[smcVT JA>UR/eZg  ]mR^tV.i)H H vDjt0yO?߫ޤ޼߫ߋ5.ݥܧݳO X(}9r4 _j2 N"p$$$y%'()G+%- .,Q+*x*)*=*)((&L#)(11 ZBkQ@qz< D܇b/׹׃ۣ܉W_y;ݰ5m4m#x ch |>#' *)'%;$E#">"b!] ,! T]`O>]f,޼LE)'ү}n8س"=N)^?[+@ { 5 ] m "$$4%%%%%'$(&#" 9hGA1}4 , P=DYދlzގ:@#/clk5Hu  HW !!n6 3 !!RUlxg2 xGp@l߹ޟY:ܸܥ8Rݿ#PH,1K_b oc :O H[A 7#N $vt# _v} JO.3L]R2|=1 ad.G6n3]*(Yf(^o b Y a Z~sjJV%%:8Q yTi  # xyXmWu~ FY an r & W  x 8FCmh?{m[Y"TyOnsFjaMpxtI , &j= po 8=~p ? :qROW{a^{4d0Ke2jsi uYiox&>k jk sj`V ?B &G2 9 x ; 7\b<cgQE 1p5n<E})#Q.D{v    l < AA`$?B[jP;N/]y,~T6i>)qq)j>"EZ}YE#'5#]3I'u3;QvPy:B,tRK ? ,5EsA   Pc [  p e\@DT/DJ!^ ;FmlUhG(WF5 )ZeF K Q 2 N ~ } , d    Z r~nIs V vDW^]3=>R~Ueeo/E%+  P o ]m ro t$C u (&qwhx5BBVmg'E2jgF[pjK&. ' $Wn,SMcx  ?6Sx>( @=2   xT#N7-fnu`"tyOJ!8u.j KZ < -  +ix }4// T W ) >/ W +G2qzx~P2smkx82T%Ymvm_)P$`  o ! F V T AYg lwa u 5  B ' * H - wcu^p8DD ;N;bjpmPxT0\SLqC  [ : . j3i4 H ->cUM b /4gumW,mY5r3bgY8=IM1!'6@A %; F Ge1 w y@k= Q K5~=b!Qs:vjd-bd]x~:W M4/drj(mN2!-Fa)v5emTGdXL4^St\q-`hLUy_6Y]TmjomKPD%V&gm 4?f=I.!E?}/k_ @SeMp~}:&9)5EFxK u}hx\Pd5_CQ4/#Ed~jd.4 UcxL-~vv'Asu6 ,ICzFX_ @.(N@8B@y jS\    z F y Y -Sc3x!9.u'<4$S2(.bP,)8zJEj,c\;n= K ny8 K k2hh ,p r 8 pEU'D~Y[p SeW,758^Y1):#qSY/&7= L^>  y   x  P T  -$0 5 4 kIk%,xX7|q!@YxRfxfTAuX  B  F  w H ' @ r K >! ]AdX:&Uw7/WCm'#T]@7*59)o#@)\)a(7?zk\(F g;8 km -iJAsDm1'x* Lf'g)bo rRcf"h } (_$ [ ? Z ' K E5*>jd%p B]Po|v@a RMlc q,K9 &%q"QZ0 l T jZW*CI$6t.mH@ \ebvvn|AA@Te5ZbxK .^vSrCLHg 3L' @  W 8necB>m/a7a1Fu0VI s2 d~32RK+b; mnhm} Y    l Cp }  ;$p>'/<Ng)P&SzlFdg{YA]Hu! - )YN0-GWA,%C%wgH/n_gcrBdC,~\H!,g%emCa H #   _b wA@y ==[a]B+L6AX.<,x4,"k btE  =Ym &  }  [ W y W *=+qxx;t/`WhsDEMlSwods: 5G 5uj;_>r   39"S`mWQHX'$' MY,28M}m3q`q52n!!SUI)M Q>d:{'a[Kw5&QBkF;V_x4yW<?5i~$QkIpjKY_ Nif3/_/DR@Z~ N Xq =] #kE*6 [ b696^r3e;Xr/jx&K8(OggK, =? ? 52bH  eu88 Q ZEC,v e,_0s?$I. A_fYB> x?=E:CqKU,*=,|,VVc:dB2;aPs7rgi+O ) K  E & Fj=Tcj*S\7) _W~92\1<n69`g = ! !  S $swKN  RPnQ{3  !:rwT@H_g!hd}+C\ h4#no? - 57"[?KWBSdaH&Np:#z44[g:/D= l $7 h A} 8]xL &   K T UDQ;J8 v4C47AZ= WGl*1JEL"w  H`Z { Ze i mmn I5 {@2IQcV:Q WdY;uqNL*U N-  @S9  C75 EQa S?9"Y:S: zEF{U5iQ=14{,n-&`I" i e v g < & N < w D# \4 *   O4  FaPSJapu oH;/\91!- I !_ !}> kbif :\Uz/$Ns35OKV.KbaU+!HaW@2\S%j_b ^ Z ju R$x-K]i6.+?) 7ss5FzrMr>Xen ">vL7S s2 WKH7#W yyq2Ohl*}{] Tw}P )kh '&rBJ'7aj sd0K\ y7)8 N/X1mL i_znAW ,uRL]Dm \ HI ,C6.! , Q# O _lbkx^-:*K`[YlX|x }! o=*+)ZKN\0F;29pa$k =A`=CK~6L6~Zh/ ^qE e^Ef(` ,@d@X#&)cuRR  d` yM)I   { ; zV>S82]K  m3^ x<|= j \ @ o ks F N m  ? 0 m \{ bs  IU eNm \d<_krB9b{!5/Z \1D8; +SV C o (W Xlj FQ* F6bud2%uk$"b6%! mlV  n`?I -&iO"5!TSE/ 5Dn*^ "6%SY")$c^Q`luo:7ycZZOCx4v o&H< hC7N2=x>KV, Pg?_Fne&m/)7X*, MKt t  -$|1,J#(Cm_K N15rY'=3U>V;gi/)1Q:=O-  S,,-P3 $Dc/IZmv1K  %re_tR} 8^J(Ll  -=W 5V@t Bz xRl: A a9\Hx0BuUThn;&nUN6P\Od !tKC ZqY$n?cZQr`=5+>Tg@hd=\l,5Jt v8/O'PzNMmr_FJcF8&%$z apFTw"@zn {r)6!L@+~ J)^_:yf]h=j+H IsYl(a6ENJ:j6zD=5T53|]\wk8'C {"WEU6$ *tp6N]WNXi8 s:%WnM {P3+ c'ngg -c! %oz j  e aK T a ]c@ PV=vhnm:T_KF=\1JR(r$RV|("9/F,\ *RS 5+ #x+%o G`YVRC\@pO  Qb|pmdIox,S~sVY+q{k\mrW!rF|DYEVOdlzc@=N}i/3VK#EP6N| V,*Ta +FR!Nz^SA zr /x l@4ejK>3{9[L)nK8QUXHj@G!#'X VfuM/2IH3\| ' I.0EO0TZ*\5ibsk!O!ek3!5*VP)+63e O`KaI8 (m@uk5o[!$QA|Fy`d8M~A+5P3 LzKt~ 6U<0 ps#tqjx=w%!R` U.=E RnQAE<&B ZA C N @DK* _ s Tmr$ \E AHS70S} x JE{+.*f 5{uIu5wu/@Ye-d/&OpDr|8Vuh=laWq|{f:>w6\ x w&W5 @KK#o1xfcb/{P\3uXpV>`cfru7ny3` fjd KzY aH`#1F{8"=h3ZOK'7&7Vz^mo/wNG,-[xuex f9~ 8P&gh~ZMB~uX[< B,x4PK7:C YC \Ij> }P`oLI)0K[ OgL3Kk8uvnt49Dq"' $ "rM*F`aobVNAu9 M0?D2b=1xYXQbt[ H#NzovHu4oo=[JT~wM\j Y%i#ux~S9~m7/9 (~(x|KU), _*  +YHqS ! E EQ  { klL7 j\ g updZ|x 9W !jHKp! ) >6$Lt\ 2!7 ?16\AP[fgfeTkO\mRF!eX}_rixY8omM2 /e\D4{bt:qh m`>'u 8gyI7XN~/wgLB,>S(IHQ/Y9j/< GPJh PEGE@\/kB})/m&iP!ld6P-E Dp$ K@|BS:QEK4b S 2brq=x\&KR{eT?PDHtC]i_ 5m8$2= 8 [ r(*@ .@0-21,1z~gap6\EG /m(gqY6LmSHD=TB!i->HHxd.wNi1n|cW7fM2,2&(^Cw`$`0 |"#$ # +4=@KeU{ 7 RhOjH5C pnkDr, E s  : 4  v "$xj rqfd@0m;  kevr-AT"'*-RlpjEc(:jeBp~wt%4$!twxdSz" K5.E_ EH#oW_dTTN}E_lJr.Y/J)G5FgQ*N0ixp$MBR3K&M ' tKNDs{.F\Tf m`m$j # ,Dg/^K.IaE~lEM %7w:+V[.QEgO^ 5K4>J \qC3wVPcY{b !P/2_X ) praLnx:Ax]ZX  b  4E ^ F   .t5 6%8h E %2QBGHV:/Czwcq~f}# I.[edb_W?Yj xc uv9Vy qTFRvHuR*Lks]+)]= 4FxTA<(_!g ~Z>rUz=&5~-'(QEj*P4K~M^p#?d la.g)}9iz='77jay(Owjw\=G " 9K#\n:JS UpE{?,o(DQO!|h-Ro{+ '34BN^'mghxxC>Vb0do\bC|l)Y?57^6x pCNHZT2]S6eIRnYe(C`fnA7}<8?~u`=;G! O}lUVT\n :7dM y6S |m|c5z4u X7&f rT 3 1j2)%=Y Gp el}C - 2OVcP\W J >dJh  ~ b je<$^2UN@1UG.AW{vT+H5 #)udH:Ms>_cPywUS_UF%vN-9[@:+h,a&5 xaYcA'9uhS4 LC:Md;\, "& Yi;_pxc& e&[_m%&*j_r@eKF3T\]h  /0w;@{f^:Fvg90uAc+%s7YDpfBN4 "m g$`4t;[ _N5V^Z;\Nq_KWT=pTQ+uR\[$!S%Z*3lXu:PRGD5+tn&M fAg+Nw~9ld+, BH! Ii) 'T! aH' N~zzYNUX(s 4pz 8 k( / TF-8 /$CB Q*0/:Z&rGFbF@vUpC.NSxkwyOM''o'` \ Jp^ejsr 5a b\?Y&YTf2peV\#^krQ1[MT$Nj T* /v_e-7}; f&/; Z >'=W@6RYs`7 /3R`'S2%q!;m+=,o/&&%$Ny2K6 8*,hGeXS?[WIe@N<:OG_!lS ?Do\E 2+0; 4A%Qz<a42>]{t(-"=":D /o\Sfv:KU!?>(J&AS$m[@/ uk- u"Y }\ S /w/,Qq;FH- j 0\c3(3pcW:I# xs(Tk-uK , ,ab(t.34~cfEQs!`!{&J+X`=l(Xw.Q1r<7&ZlztNxx`/b nM/.X|mFQ@,|]A]59PQN&dd[4nH715HSgx:K 4~_~:@tE'!<a.zhNxNzBSa!,we?/J8;E@$525J!eK 14,S#PRzo.ZFi+@5m* "LHF{Wj g$'0 j+6ex*"hfBS;)x2f}</@?YC3Qytwje2!fh#} w@Kd\?7f:,wB2@x.g2=U,!*9SQu,r[@7/Kc4!R[V[,r`iKzX9d4 @2?c.z1P8B^Vn6Gbi '}:i  O 9HoPH=MXfycN HFZ=R{VBe@bR/~yT)K* *=N & $s7|R (_ N,Q g '(=KAsh}w 08HcT{$k]x3 @^:H1d/r Vg2^[2{jd?g`gg={'r4Q\x H~JtM G02\HS6.%]s?33]:=;ykkK86Hb5kj\t_`' XZ,"_6f$0sKef|:@Uk'ph>TjpsscY{Q(L3Q'$A{e>T=kZ0G  U /p[{_J$}M C:Yl2:5?<&KwK'#d[wCu: ]LL@ 884S/!445g*8d 's{ ,b ^\g{ao\ a=7?(i\[SA:OyQh  `$;D):aE2h5RkZ^ Gr7?g?9JP[%oXX76UL"Nn_='!`E 6qw%<S:#J,<:mI+NyvfC;IwLe"+BMOxDzfD+ <R%rNUrtDH%iH|C5b$ ",tC;yLyCZv_kW; r\yyT =  F$vr7p"'eQw +:}KaAgCJF  qXX (AHo3NJw}VmX^a)cM (,9%62xwNu! zjYlx?)<4R 8 %;I,FDn5QUNn CtpT= kn\$XTy33RjY %w[3 +ESE bEPTYF,\uxJoQ/9S+\id^#MlH2J JE7S!lHdB72=\V,l/c{UJ3" (\.QxVj`E#783F{FRmZn]cv@ %v}3:R[!Hc}j(f,G4D&:< /UTMB{P )8Af5k>UL?=!SEN@ = /x~U kmnX J(7S/0"NkZk QTZeFJ$c|8>Rv)"$&Oe]\5erN' -7"KbS7ggA- Vt8X1'DO3JpGL`]f|Rs\+J 9 i!{Ud~wr<e\ UBEtr\mxcH1N ru?/om:9-h*% |bc\mv2=5@j,*h;fyp$:=YRO~/3,Xx/+iJmaJ/U,l:u&zCromM ',4 },mv I^-P&=r4o1 pVK"4J6/ gzE`YXwt|8$xn/D\5A]O/XQZ{03ZO}yvfcA>Q/XWTR9D~c_8sXpX>@9u( U1 N"3j Rfwp@r<(mc2W/}`qiENR:B` q(RBfcp}(P#cquqxR (1ut%\s{bZQD3$"(*\p*@%3Tk`'@n`=bCYkW=0]LI;|J,[42BxUG@oU DsGArG 3g =$6j xR<X"u3p9/w2usp=_{b-j*]C5G%@,bFhck/A2 4T WCWL_G2=6GvUUvQ{gGgR'q;> + [%q nc77gxX8GscfuaU+C=1Q <}.u ~l<qDGu/k{*(7&_r[$~Szw,X]-Zy|\:0k>8;6'3_sb*'I`~F] qX(^H @\B)+: iBMNcwmgX?pf+owrJ [+QSgp#=.)KYX4awj /X<^q-Qc;R{gG\c%.3#}w[1wR.(26z!~KT!BsEjM$i_dZ}}j&#8,Sz5E7)4Npl:jV!EM2N!,)J<&^o p!i7jq&4Ki{g4 6BP&t({bU/ Np3\~3 +*+@\{%'%5O>-=eG5h9**5=5A+80(2F`vZGK3808F;k\/$6*6029pIRgY2!>'|nh_fLD,/ \ +BD/ m A|/;{eyXRZy8v'bj/RVT! /8;*%7TbQ-$=H`]k-2Qv~]7Oy\",>C$hhtxK5Z$Xorz\+(T kjb=!* O%#<iaJ[HM%|=U!{WD9`~mG5 E/ \WsF0IOk9\v88ng{$*!!_Gy(="6($ ! F(K|pO0|C5xYH:IQ|bZ"Kp%C~FGA\h2zrJ?%/="M:Du8>QL0P^RX.Kp.%1w+r4fJiVVilY).6)R'!"-cW%3>OCKOc`C*3"WuyKs:x%`|$_Dy\v"(Y@JYX 0`~> a+)K\jqw *ORTL3w7 `S2,([MS2X&)mb_i=xe1mPtftYUiz&u BoG  X =c[u}^3?7 7r zg 0feL-$=eRlD)g!!ujuJ<#Q[UK .4.Ug&K: \z2! i w}5j/NdgK5lHNT$zbda?uV?uex5~+z t<1 N,l%VND8+q'5 @bxZR_b$YxsgQNN=GA]A~\ x\C_yp`x7y7h  cm5t|/%0Lu{y{eQDxstbe- \ GS6/BrkG|UfnYSX^UGPiLtJI;R3>62n3uj@\p2*DOb25>dbrse; *mC>qFhCWKsU3"R0k_X/rGu mbBD}a6 G$ ZO3@L8%3v{ k_N\TiMYxFQsGWN"=RK(]ecskI2X%ZI]hnvjFLH!Ze{gs|~\b72{hj{s{svsm{dbm8$2A!9`JBB  zD4U)<:KmEE,@E+&EN./=\B&Jl!f ggMb MSg~}uzuE91#)}2.,f KN#r!{?0pU"_I ]D0!-FLy>fO%X6X^+Ugm/[fi/$9PF)5y*"Ne{y-{N5y$5,A p9*2{hhT\bK8 h 3'Cb%v H jZxM2vQNNmxeV>ILm%{D:HZejHHmq)>0'Av|KZ>"'KsZvn@|xtp_;%;-]NntO`/LUGZ*P./`*8wxYA/3SAr;`j t/=ifSVjwilm[tg?XrP/N:_E(VVxl"`'/FAmY@JVYztMi$@c%hR +o" 6:9B&{t4obAv]T=+(q/uUS@U{wE^)CCZZf ~6e=6/DTN3>ICHjnUhy|nW*vsksq+ep@GpDZDFIQAtT5L_'m@(QsD6@QZ\N;t3R:cbImqI@ !; b_Thcsj*DFh%km'AYQ~!mp>v \gOZ{ T { l ? b-Ov5~bx-$|2b' "OvF-CQX_qhNF%JDA;XS94o6` "TjD=w/HuJ#xz}2 Q7Su1r{f?dD%K@9htNe'*m~W=FqnZ;$06T"!/iwJiHoBGi:oBg)+}<+sob!a*aFz?\ #j.bv/$#j@ Q hFFPN&+,,)ta  %7!:,B=Gi"g$;_"6Dh]vC @mq65qhv6 A~wnJ""6ObfX>wfO. ,g%T*sDvJXD/^'JDAC(28GUtnv8$C=D8"I+ U~mIbbN5G-bv"eR+$3XARIhFj]pp_Ces_W`=g7_>&UVa{c"7,AV91o#:t9Eqo|\YM,X,3\@69/ 4DSJVq^J`Gl!Ba72iB 6S:77V< $dp_aJ1G1#BE3 1c;5j]D(fUbv{UI3>AQk{628O|y-6cA):a:Y9cgSw J #d?_p=& pV^F5dj Fx i 2xj._is j$'7M??s ,Slje _7afm:R!/)4PcR3dJ!/?1Uj|5 GcN"5$JWAW6+F@jOmyLtU>>"'0Zff8=?YPD =9Nnj>"N%O& XwAYaf/!}l_XPV=61<%(,|!>|`Q$ >j&AL*{70:/`n%h\-=t#, S=pkNNN;0_Q]Z SD2|3;'[zoV/{9wKHGdau7j'|;ymmX$cX38( '>+Z`-@+ %Q'_L'AU@6=:kv0ye~p`}E6@<(PQN&S vgK@,Nm Vg =7.Yu@~rS -m)i,f4u\S2 K'm'p:uW5&7m=T4Y2dSE4f//`"SYj qA#` +GQq5%( Dm _QCy{IqIO9=N0X!%Rb\[&)3BR#++M7B,1[JD73r*5*w?  N # HN[rN4# ,,Et /\xaA/.6+B`}or`dn;=O|5''>8,Zx:"  !H8%8;= k`F/Fux{hRYquh:`*"y'5`L; {X2Wn;qO' |No <Y\d+2S,,:~ X/KommV^R1ffUC B#Xd  ,djacUPxA\-!F_Wqb~cZUn gem(]-j0 i"mt.&YRiMG==bFYRV>n2$-StqS@& ,o%G^ugz`M.c?^qo(Vwt}Gu 3a*%i+<6^Y?Vf?"OX~L%c  \ #i)xD(>~yNLn{U\U>-p{)*O\2@pZSE#@'7eu=:AvDL;'+GMG,% .Y:B?m}[#2)7uB}ErgdUau}r/[wH:HMHNYr&Htx1r%wMxwc|x1o^6J_ QtQ;@`>DVpK gC!8UI@LD=6ZN `kW! hNwnuir7 4dG^PH'~=}o9gi92H~8 &&<==J.moN g_$ EW1_oM!2/,5HQd#N5f,\2:l%Aq^&( 4UXjMO<1P##jq{XA$CL9z1fGxz4ilXc{x:Y,99Uby*.BU m$9UD_c0Gq?o)7 om=XH# M1:S\B=Uod[UYdX6(wo `9\htkRQ*"%-]vg'A-2 TemA\y|j-5Bosgm - = F _  pv\Kj%A23/:@*%!t'N.HKr3HH]I>TuH(px/c&Y_u <^[(xVC2Fot\iK'@NLY[VJl3'm0-IDc>`CH W@\\YF \7\I%`_|nsyX|`9u Eg2GV/{ lg:!=xSX=z~[w_M,QLu$=v 7BQ^P&88^\KY2 [)uw:7o":jDOCk-TQ]tjM BL*kb 8gUO;;;eN0fD*r,"1& 7V6@JB3dl!mX?K)/[hvx?9,:w{QZKag}vb*Ze7 $[x/YuIY>Ff ux55B  m  5 k  ]3=\Z+X6q@3z{2~\wSߵ?l>"1\  ucOoG? '[0q %k& = p%"tC4/NY3`xE2=|A tRGk8E I r N B V , E )  ' S S [ y mb[TjQx{?p@TaP1j mbEJU7M B[}x rMi41?x]WH\L00F{h*0!`!!7{Q.=d>\N/J:m&=7G@\W M 5 o // -'e a 2 F W ? ^ ;OG<^sKEk@C0"TI U8XsvGDs]Q$b% k;d5QCt(gTL  KP<3ohDTcmG4w4o  X2}pb@j@3Oh_y8TamlavV|vVQ@~=;  Viq5/ L W`]3vyilLA  ,='s2h=(L`qrZAb|u~ $e?N{uV2N]e'~OqCe2sY2:J91DW x;T "#N&i(8('&'g&)$!S x  -  34aSp>&yY*~Qu$.Uoj?m'zu#smvA-2p_B| Q #wkGyD !"N#Y%&&%%V$ #"!!g1_ S\v.yq % G :>8gAm9xDWC>82354som"!`x N BGtF5!"&"!!$!kia v * \_!)DD!{o#l$S _YmN{KP*Ph]$();VfkN & 9)km88 !Y"!TW!:"X`& S _$_ KQu_IHbbvfR$2w~ Ah7@x,{PDr 7 !M;k !"2"-! m!V"0#{$$#"N"!\nDiQ # } F YebG3 2; c6FI*qssct yZnV44qX nET  ! K!|,uO6kJJ Q 8Gp*6 1:H={fdu/=Wh X*0|19UqskZZ `%jE ?:H H m M m E4c.3pR  fcD?6ZB^ 9 w gGH<&a,  l={Hb~>5@>Im]>'|hhaQ4g}@ /; = ~ < ?g&J}J(6+Oq B Qh`b7{~GfN_jMyy85LKOf (3Dy8vkQ{~8")Y,4?FopLF$b j g4zl1L 6 s V om+6C:wJ 2xv '  zqL<j5Ho v`_Y/=E!QJZL**DysnL>Okn3nNaFE~EjMuo:%dj 4 } . S7 $(g{t ""K(!NWDh"bra&Th^vBZYv,@jri)F&%68k ) l 1&"2fLIB ~ CXO6y5(mv:uqTgNp{ebLQE r^ <~C^^aZb1,5xVe{ r!q6T M w 8 6jqXX-eZl g8TnZ!!G"N"nOE{f!F@5-!=Z}(jKO x?QbY!vYh ?^4{l MR! kl y" 5"~c$`"^QCH,\H3  0)~XRy|\FKI?@:D\+p-?XZ~IyTn^?aIQ b  6^3F%$ #"R8iGJ b  M_ <@*&8*TEy9'2:@HC:_?_F jx:Cu e0$0pYlR<[D& S zzqT9<Y_  _Kn(=xVj*HHK,b!]+|38LseFTe&FU8[y|3eep-H#.fV[k: & `9Zfz9w. ;I( ZqEB & $ * x ? Y s dC1!5_"m0SZ&)Qu _dX._hadpgy0h;W ~{ 4  to(%S9>vbRm j7I ne :  o  ~IpK6XWj 7lH2Z@ju']~L{gt, BWGbnb!~!p xIh    T WIFdB o ^  b  = j 4/i}WChR6tA:~bBee qbG7H]m 5 7.?uLZ ? EzpHd "+@:cr$ 5pLMM YSN8c3TjWQsF-7 L n*"&h {*8C-8CD]`  }  /CP \ C e ~ W E  F/wYAtJf?LDIh~0p/_h`sJ+#w7r3 Om8=p (> S40ttWO  L!|K3Y$h`) :0\>:Y,:|cvE %J^Di}) 7|b8`mXXj-Z8t$HuRS ! f[;mT'( T"#$" N/  = ? BY s! & QvT0hi"nQj'1;-!RZ_"]$:mm!C 6=#i L8 !o#V"3! | I *{ jeHZH # y)bh{f,.&jarm.x }qj!6[_@@Vr\4${qH@/kW3~3z!5 m  1<F3`8U !"u!e6+n: Y\m O7n5!Jzwu}K`v6wkW/&vgNe R*](BkLWti!]3diOq>7  YO|wW_v|Si o r  0u=*32!G-I$I+QgFnTIB`!  nWG 2 K :! C ^C h L,b[c`bg*-6}{=Qx85W <1(d &P7Q l4xIN-%~yXU=. ^&_| m"_""!0 !"!3- @Q K E  K6mK>(L7` rV\A~/)L>pmEV9P=EVlt&w,xo:SE~Iy7;C1Y G! =^'k ! "V"-""m#"";r  8C0$~\0 D'/m1\T ]$0/ QVuVd! Bj]$mQ=o v]%;i-^aBh  KX"XL``? ]U-n\9 Y<}\Y'Lb-5LuNP@6>hqyC2\gfood)Y:ACh"s_";8S5sv ^ j")}v?]0[ddVU8 5)a f[ Hj5"'bngTg5$/7#yO\o?N=Q55'i(Zl <Q8gFAb B'+9 #  vM.['C6UD]q@4 29)H!KJesA@rLnb N-`I%[ 1:s'mU x#`0Q`5 Ph/% m!!/"!8L1M / C  NY*jN@$xTtV+@7S ~Ss 1 E7{5m-D(9p SN6Q"R*>Qv_C /8 j  0$T(oXE @ v4 s W z S E "(_7gE,'\1w4%)6 = *  ^  HW8`tY2"!@ M6}]eh~`/_F$,D bg U&8]BTP6 EaY-{CM@@%=s-+  s_F>]I3hba~Q=@dgL]zvb4Kn_5`j_';@2m{@ , :?oC<53-c =/G'$*g='jx\s%q@ KyyB5RmN>s]g_V20_hkEh1(^XDqR'A}1@ a_M!= b8D|0Rx{LD@ QIN~Pe2+/~"F;H  e g _ d aTFDX9KHYAV\tb2fD8QQfAG@ Q nX.'3SG9F 2 dhL)~@OZJ#@#8u*gg=G?| b:  _ M ? 2 e  pqo4!QdZ\;9!t3!Fec0BrQS ]66lTM"g 5 Y 7g3~rF&: 'Y{ :'@p 6 z <  _/  5 : eWm _[[j$NK 3a[=H>(\ ~rz6-f<U Th2 @Xgby *_OA6X.Yj51=v!Z /$2dL,),YDj*-,h  \)j`E(U} / Wcp^Br{:}QCP\_Q[&K iEG[)Z@Y{ gZN @ @~uw".|'~lG&/;~ 7Y:P^mV"H .ByJ p7+)} A_gEKTl'\xV/:tj[BSO!2,W dH4vuHT -,i_7 7cUI6=s0vA/%5v ^ @=j 5mgC gC,TKTF3XVk*H HjP,,KbKKLTrMi$G\}  )@}q/*TUbR5 v Y o U[ { u `<EV@zYV B 4 r h 2 7 2>TCF-J(!._#@_[d. =m1jp\+ i 1 1d  2 a11 &I+!z$::v EBl=,xmaM!=KbHZWx,eo4@ 27NMJ+_.`mQ'Ad-Q$d-nh5'k(LK\kk 'y*g!@G=SJ{ulj&md~*Suv )F)2"Y`e$ 4 A7t=G*?jL lNV'N)rw$ k *>hh|-: e e _#a;)L`gLII_>2\DTW/  ^  Nx5ysys`ceS3x-`nChK"7&9Dn{'3V3,Q:8x+H)q@ iw /=xRV!QAJ=m({q6PVRJ(o,fQ Fx$$pI jrB7s$PlT w&BPj'Tb$$D>kK H5Hm;SFR>UXY^^(t~W>vhBBc/z ^a#&jBqJNz$rX..M7,~xKze#!M?)&F4TX2/SorA7N~FB ZFNS\@~Y{~}Y_K{V5r,17R:64>8Dr lgs B=4(R=\="~*=:{RTt$LL5YLsLLAy\bSY --s9 f3#[R^HM{r3f;>}o6i6V9#^Xm%rG^@NWj/!eqm~fc/!jQu0H",3I$jN!:a5OI_N2g#^_S&q>D~O!SIm8DYW`t]v$k>s Tgpu{]W) S T pIL~*TE#3tzfEimwcxlq EUJ=W \:EH<  PS:sd @Mixu/  @=Bnq|N4m@^M$7,.S[B B@{aPBo*6_9LZPw@k/ vWXIttfa?93X(|Oq'5"L+Ry'd>D~~pFn_e%w}Sjgf:!*WO+}lr6Id=\  - 8 '  m o  S!FqnuTs/;_ ' 2k;:>%k{I6x43z>Xy537 R, #<(a M,BoUf\S~9$H?' FwKQ1C}z~_ }^^&7UxdjR:X9R`\"KAa \# +j,i"Cp`;rtx8KW5gs%LA ?zB%tU)pBmj5'H~b!P* =oMwY,mj,\CK[)=/#?xiPK u}m1aPb)[{d2id\#zt4@9@.gaG|> !bjU!n  *`,$ "A  6F 0/Q`yezK%AEOJ2k*CQ>Kv/ujH?JlU3{|nL\38+/sRg>!]NC;*pNT62=I~fJtR.`%U }ddP{YX !+`*>3U_(2WAZ/3j$0FvvH\*{L3p2\Nu L\cWT-i <?#:+o)S)?m!J72plSgpg7Y }Ymoa7 om\THjs.:b1}.{1{6<^@=XaaX J?PH.Jj'@$3:UG;=z=f1!+Yjtg4BNN&czHGjtN 8YmZsnvn/"= ,n| L!:Qb`/,c'yD\s%bpZ=qy+q=: <lX/ 40_jpysLC3 !Rx$Pcgl}uPH1?}r}S Jd}c!zi& Q W^[rqVM?&/Uf|A!'22/T{W0''CKhG=~ D3F'D:lu@ $ Ud{xS [[x~ClM[@@SdpiVH@EUd}ul1bKE) MwQs,{He 7Pd?=x.JC72:gxja^d )@$O5h/LN/86-@`|j(0+9FK( /s";0>`qQ%5$y_"TbT`6jAf2~~f9 6 ngol}0 5n(AxxUL0 {|_j]s;n=f"qJ(YNG\&tH;|ZXC$|]26QD0= oU9oa$fR ]n  *+IbUc`8`*@]|xg>m|DK0% XUoqud76qp+ &)E?RwcRq)q{^^6UjI sI"-5UN*fh>2oYH\V:"+w@b>;G/@63-2(N"=(@/-g{g0'`IGz76 {tOS|n LU-U("7DoPO6ao} 5k Rcx\Tj6LZxC0'2FTFY0_h7K05`@v:@YTnx,7=2e4j':8q}aOEYcnCNn{`8qP {oE|a"rREYw PPco(\s$T,< X1qYz4tVPq7DY{&?w!!2+9FZ| CQ~~C3%+F;y3=~!D\,Q*AI0v>UGqf:&lR\^\X\Ba9/U.Y1H ~,dxI}F*5Y)b}}NY_Tszzz,w=ZBILN/dHls*#iQPpfM$Q{#1J~_/` nmT*X 4R!`-_f{ 6Uy!b G"{,> 0Obfk{LnxD0Iq%LeqY"tG' t[S/EU7K6a1(nTnqw_}gwY4iQhU/[+RYfR(^"+?1+m Uy\Gi4xKz)GfW@NyhL'\/L_{QdCD!"O;2'pxKK*/meZl3` zcE69DnWhZN2lzPDtoP:jo?EwrlRc(7%(_aMwT}BPM2 +  [pi(Urq\dzB``6*5F!$=pX3*90Ab/*"I$+\]N~!e|xsOH6z RNC:QqMz@[Eu822.PM42EleY5$xT 6gN=^/ljEm#C8,} a#& ._i!?~B*S Su5/a;1K:NT{r d.zHHa4(oY|<^rd"  J(,:x|T8jbkKt]cfIW_X9Th,5t{h\% L%j_/ v>s$Fr}ua}`r\E.@.!V&4IRtWubuv_~ Qw- Age/d&YPsf2cQN0d779)=jV3Z`x053DA~Gg!>*Wj7|3;A  N 5 M ) N ?(/T W - \ ^ _XxmA@hu>"*7MU~7{];V5/G"9NtxOKtm u-N_2"mS)A{hEm7 = H Qc>/}B@N>pj`fOUF5v W M K =Ut s m d b zj[gH_:QO5 *`D?Hxb$N^RlaB?!/rpyhx .EKUhybLY_ 7x1r=x#mmoD =Dr\[f2m/1d:&5 N}uPtHvn5+x/vUtj;VC `5,;5 $ 7^ YeR'b H C o+CH8Vd&dYK@@3~obKs {r5)@n'/8=of<=Z@r&S,Uv,   .4J  @%'e%T w *z  _(S$,T_1 bM?f p S   mF*'H:K^`&zJ|&{V\_r{C^jS-Q_= &U "p#j#"4 @da3}|* ?? ENx~VHA5n={L$ 9&l "i'BZ8CQ+Dh ) x 5 x-]3_Fs~ _0#&x)+X-o-+5(#oG @'$:K]l: B#  1bLGh(`^@Z K j EX Nx &  D5&K}~  T!I*BwRa"c4 t$w(+i.01U0-)k#J=cM}ޝzWUK ; !&ph \McmQZQ5pv } dA$ j}$0]I2L\pK)x~Of ||;7l>p"Q%')+7,)%p ;E# E<l'i ;ټ޸p 6XFc`" >YHw\a3f6?KH V Hf{ /-OEY>-YX?s:\ J[.E++*NK ~$5),16U887 3,%BN opm.<^JEKIm!#u$s%%$r# 3/ sbhil wb-Ws , 3Af+ gZD%D#'H9:' 8H$]3D}9L,VE"'+x/B36R774&/:(x!9< *v=dۏbۚ߈:H;j# %$ $!I o*9Kf#BCHZc ^D_ @ N6G{ XDc,x v ^ < ]TPcXG}9`  H"b'+r1c7<5@BB?Q92*7#O=F _|~iޑߋwq N $)-..,("> J# ej\`a{ݶ8-ݧYLW2NlvA[;t&nwn[X U)Y&1,0U4663X0+&E"0{  Y :neR 6O {֫ L/ݥbs}F9ާEDv2 "'-1357e740,r% m9}`#4coz{=j#z& 'T$*!WX_ 0{$%Ct^o$$ cj: }5U1PERx(KjJ= c14 L!&*..25(6P40,'-  -ink rvt $"V"  =WsA=HM2Pm ? 7S+ Z{iwuXHH* ,+q/-$+#1]6>;v>?x?=950)"3dp  sRDfR^}s "n"8%%g% $! gbUZ A@<36-$3S{ sd3{n7 m %^{ AIS -4Qt~&$YbKw3bP)H \ @ [ ~lbMQ2/V(([sBb:=տKֱ۸7T :q!%(*1.0256<51),4#mb$`<ހsg[F  a+hCd F.4o(?a5:1c v  *|6kw gGlA6k^m?U9wnkPS&(Ob Z 'U |wj_v ~ `Z:( Y dD<-I 5pc7Ka݇ܨݔgd6")/G4<79::9 84/b)!! "OkSbx ?! #%E&%$" !(m%fwCjA8VRT Mo( [  W@v^tmuUUX3dXJck| 7$_+916:<!  8USBq 0 YDC h`R^2Jg_Ox  bR:N a  9X$>"-8ch6vWLSB@hyneF8DINY7K^ dLm#N+f27";=>=;851,%i > %@!lnnT!#7$I",y6) ce$j1Uy]R2N (7f7 Ji4 /5*c'|[g4uqlu uU0 .!i(/48:;:8640,( )eM@A C q01rj t(AG+-L+| EAH s,8INH)u4&SVX4U}h>E}4-5 m#)]06;>@A'A=?=:6"1) *.(3p{3A~ q= Y!w?lR=L! : DB {VIE  rKj5io*,!L 4]>"'{*x.v2k566c6400+&o^ ~Zd/ UB%x!m$' )r(u$ L /BesID$/9 E S^r Aa9g D&n%F'R28-n~eYxaSBw'l&=_ #p &+9/d2z4678"740J(  Np~֒MY+T)$&''$_  Pݏۗ@ݠ߰38tp$ E X/Ki d =.72<o[Z0K4;KiXX߀ޖߋYf(* UF%+.D13469:;\:7w1)!9$ EGS F{ & #^/00ps /1=1- 3W3"S r \ VN0r@kN3RLv`=+)?" -$'*-2w69;";8X4R.'2"M Z7]Id %t gu N Zr6O8y2N' $ldJ V E TRXD'eJz>*2@:n J!',`2689:8@88>73/() Me:o DTW $&'*'j$`7y3rV0gn{  \3 ^iiv)A{h|S<z] !f y3]!$w(B,./h12`332(0*"_. ,Bic.0X/e \$ & hz1 D523]d&PWN{eN B F <_ 0-1&x>5CEP*6}.82# 3H G"m'+/I366(7h776w572,g& "\ uniw >  GVHߌދ߾uaXy(p* k{  2 !\R%bP }q;,1 j[-v E$'+,.01"3O430,5'cq:@ qkU NS&8MV zc[H! bqzPDD\k,YoApmo B\ ^KHss~j^/8I5C0 *nx>AS `!&*/3L67 :N;*;:R84.'"p  =3q9\u B"Wy "#!x ,-e|YI+{/. M  ^ 1  Qv }QL=]'Ay#g\\l8-z7d ? 9N!$(+.91 2l1q07/-9+C'"24 70(@ 4߅R&uf Jt?R^ x&sfy&^rc6 WH^e K9c XrDz?Ts.nI\;s$ , C p%m*.-o/1233f554&2.)"Rv  .Nh ;TH kiM6  R,+-2$W` \_U`hxv =    UT_GJqLMw{d== OX!T',<035567'8|8<73.( kv t caj  Uz6v>zN =[L>6ZkvL8UKc 2 Z = >^Wv:_hDvQ>L -# T c(  %* .145*77%8;887L50,%Re se;#3H +n]_ GvP, v0Hm1}B*I*+$%N   h5U' hUn 4XO]n oP$r2BZF$ Us#E(+0Z3579997l63-'  O^oGOIj 3X>O# \SY'U- }k Q iDV&l g x Np0ZTCOA1Cw{A5 - #~&.)+-. 123B3D2 0^*d#% kva'a߈NQ r  }&< N'(k&Yn;Zba5  V  CixCv1>=;h6/T(U& (lCD^zw~& : vXs4 CI ~'$|*3Pf`(r _ { d , ?Beb@8_|P< to=Vi: A*7 H&+/379 5s,Kj:r a DoVv"DKdf$VFZVݪ߳`&$))_ e#(.i37j:94?/( V ^ ~GBw(e`x5 &%f, @ y #2RiEc9 mE { ^ bK,}E3JN_݉ۉ۳ܸ޼P_4V:} w"7(9-Z27I:35<8I50x+H%O \XhTpqL)s+]WLXD:!!P_s>G?.XolqzZ8AzPUCL $ )@v* {Ujr>ZU ߌݧd'5z=8H H"&7,X159=ABDDVDA?A<7/("% R ?wG 0M'9 _ >E)Cd%%zoVkB{5[8I  # [ _Ft!a,@#ez ޿2D^`L#',28:350)+$ql1^FJi@;m72+$ Sp[ci3t]g   ] @k@` T@0"lfGULK^b9kj  $\0/5eCE`K٨8\`/V UW$=*/4R9<@B\CBmAL>93".m(_"h NM9mD= |*G ! ! @w1r, ^ A?{)<6-ZU/85Q r V @I~t$Z%W OHQݪܝZpoݼߵ(T8V q!'-L37:<`>>=;@9k51-(`!# ^A97$1Lh3h *f]YWI <)5R.S\gStO1b-8h o *pqX*'Qܕ@O>%p j,%t,1539y<>K@BAZ@=b:604,*'%!F% RxMhxC@@o; 2 i2=C u 4n\J9%>X"{s.zsp V91QLU=\a/$nQ$O" U1$*i06:>ACCB5@>6;7G3\-2&a \ ICkN^r{PQOj" _=gFj$A8 z `43"]E/l ; : g sFMC o3vu #)?@@??=9%5)0a*$9 nK03(bj (l Fd^ a { ? w QB ' >P8p*939P+~2E# Gkn-AhV(9G-Oޝ ݑO| #@!8',25F7I87654 2-H)$w[P'xLKJ]p(3f-j!Z7 mg Q E, xp~T|UZqtk-ZW f7Tr`|OO;s(fEk@_& 5 &,035b6556I530R-' !>^T : YNkcyFf8p!7\Q2k !]x= L3mqj7cJqsV=#dw%@8]z^'~ Tar ZZ$}(+-/0000/-*='s" #  %bG6CPQL@/@!g,W"  = ?  a O7p"]hAj6!gOT{OXP8ncn9-4W' ) T$4(*,P. /c/0d140a.+&E";; F49},xs!]%U A|6#jF:kK  = $ $ !xZ~ORW9Qxmhg(xh~u.8 n`LC<KF >>"&X*,.1221/,d)u&p#; G W u 36mGY.7S2!sh@ E(b e vair)v Zx.hNk}2W D@F_Im$cl !$%l&'w(J))(:'L%k"25 +17HTw6[p7^ffgD=0eO:{xkub%-]@y$vKIaV\2#)d~2su3>a=o D#N'))_))))j*<*(& #5 l s LK^j9Ox%VI]F6spg={xx/tcT #W8^5@FAYIVAY;~f"=_ 8 !v"! Y^ 8 0qfl=wHPBY24m4LTk:oH$*TAG=h% ,v~ \mD;$z'"{yZ d@TQ MM| NY"#$%$5$#|##S#!v7i5 5YnNFjql7]/qcbT!p Ee!9wN{!OpQKRl$myK*0YA@n>\~ro:E  2)"$ %Y%$)$d#W#8#!G  - :  = %n8 I ,Khp8~)n,yu=js R7hdAY0~2+9j+YSc`~Q r `+r%@ %!3!!!,!n!!!!- (0)E Yn,W1h/UD=,Vx uE@JytUrw KP&m]:x_+_TX!4Sq3 v \Yw*"y##$###" "s k`4 K 2 r 7nNNZh"eY!1a'T/dI79` GAU!Q`H!;2I-pEr \ =R^I# # o0uXg2,GBl:L qmIkXj >M9;I/,72^4H{j5C/>CDbcQK/tD]5~j{^w= & 6D) !x#$%d&&&E&%#!lm jQ*@08v0,CF=^4]Y2]q&KgCNZ":%08cU^W } ~*py! -AB?/v , 6 k"m##u$)$##]#:" $ux g NSACne\|@pN`0vWQLDr 4|>(cfJ!m 4Ip2- c KA%T /YT  q!#%d'8($(''&&B&%$"= KA3tA[+5: S1H&-IO>;\A@D4R5{cp\n_+WGw^` #2BVC;@p5:jdFNf T #" ZR   "qkmV52mu\A;_h 5?`R%qf]=WgneYB!v2@QldH<)- + (JMBnhw' /%y;  C 6 D=CzK  !<= r r 4 ;*3,+{hK>Su\{V&%e@pW7>b'o&uW3m>CrH@q 72 < $).iN 7 g{MGt[d,U  h 3`:: r Wb>,Enb|gei[t-QWL(YzxLTIClrf|  r ~ T * 8  &+z#;D S_} =MEe':a /{I*[l+d3v]v`vC %5\nvbE/B+[M*5\2 p!\cO%spn)Ym P .M d M d Z;G6#N%:T0NNs*Vnj4K$^,}u:H7 P/) N4,g}yp _h}B8FgWMX?:7&7C_r;Nx/&Jr  J  s 2+gghBe`AE9 b X    1 AwMu~y"8e(lU// k09 gEdJpU~\g2lNY)FY5g4&&:L_ P b m #gg|)f @ W ; & 8  EAGBPbpzdE@! / tj[l e:*aTdf *7us1!_ _!2QCKj Q   F C } m & B ,o(l,: ) Q E xvx$L-v\+!&#lKm Sw ~aj,4K [HN\h5H;|n;?K^"\Lv^ 4 C   r o B ]>0kCj6x.  7Q2#xH[xS{ Y/r ^x^o+da w1}kngq/O2x a {E*-]%a6 <8}-}Yoha&;L' }!!/V]5|8s=h i\m?'C5u-p= s  #  v Z 1 & Q  b*$o_   g  b) NdL;_tv"$A/3<<1Xl[{5)4Ux Hwm|mt5|xu|Wg/';mbK! my2(6>2-nXSKrxP,66p7_g +} }!4\H1{m_J&,wlW TPpiX6ZG5FjD8uK8F;HhuNT>8 ~ QC99}r7{?$T^#=d&h qusDO~2^\s$.o=@ ((|!9UCA50pL2V(vYU'[q!?}6,+,7ER#==~' x<s j'M ; rs0K!,I7pD,~Q`{O@||IQ>2S HyuKjg:]AR /k +@@en|`-WI-:v`:v L s ~ ~  K a I ) . C F C H M  s#psk0KI8: xejtv'$.[))CFPM$2e5J5j6$V1@f1d[Y'BN^Md[gdsBVEd/4Y 1d%7+{*K $'Y  @ Y ^ o v I  Y!ev]5LS`v;A%X#tcuz lENj5'<'_N*e&Y{m\W/~C}9V 3{$kW',Z>WISm{ 8=NZ>|L8Ke,ekh_;n+|mMD2P}$!~?_rm!=S_$#(,x@V,2H2;  j;~O"ry;h%,I/ jY{.Y$Zkj{WZ~)}~l)* @Ns #=rGt\0$kc=CympQ_ Z  -     Y&VkRj;5sIZeu[/Vz~+ ?/2uTy*b1!eITsNOgZyggI Ies:'5$gS}^GB#)(bA yC'YB&#dcf~+__K2Q4=:MdKF2<'fra@7?OhpQ%|26y x- x   h  ? hy/s5T)"v8mp=%'"nx=)wQC/KX4@Wx; YuyTT`}yv* YM&)Jux19E:KD2GHDNh(GG+`C~]C"7?|@!)CaV$lW&*p=.zSY\ @wc X/Qb*t V $  g  ) S a N w   8 ' i W  e   x _NFpdh)n(ZUNN'q )Y:#&Wd}WxHC$ai ^^2fu M#@e7rs;S  j ! g < { l C s #  w d e 5 4  L$gs<SH|?M/jwS arEo 9`!o7X91,w_V!"C=L u 8 1 H   ? {   x S ZW2AIVjDn2%"CWfMg#xyOSH'`\, r#I:g;Sd5V=jFb2_7~$ Z \ ) T lt6Nt9= BCH  \ C 5 )  ' r_l^d[uPlNP2&&\*doWa\eVKM8B*l^g!xm ;6Rmh>8B/P  s/Cn%~z\p}'M jp=:TEbvE)<CEzgr?)KfpT"Z ? 4   B  Q:17$7  { 5 Z)vn5yu =^{g@i{:N1gK~dw^gC'2K^2x.UPu@wz?+}hu)O2b6w'(IrKF Y , V , m  S 8A{!Zj|zM)HKQLIsduu`hI/eE p 9 XSKc?/M  :  o  7-'A0*6rEH%:=^lJ{ xhk Ur)Me^/4}2FhWS-I]H>{*-F<l/Y6\p>WNLo  F M -";[zS&t_ F Y E V{6oP:&):;3gg>\aTj=uh\B;77Y{2y@ SpvSM%_{ } [+J^]zzL FFT '!!"! N h 6\s2SxlEg Ctg!5>G`3-3;I Cg1^r)4m\'Y~KL|[+`jKK0KH~T r ~MR6P6frZ&g sH -W9fIs :3,8//S?%iE%Y+<zB\Z]Amn$\Z$u'|Q >XZ[U= 0!u 5 ]Tu _]JG:I t%%\1Vq v*. psb7^2:7d_rp "8X1l}2(3'5`gK _ ?IA "#j%&&'1(.('&%$"3! Q%e  >5 (cq.[9}sf*jK "Q3*=!+&Jwf2O(DAx@o}>L3&y2 \ & AhO!\$''.*+-./Z000/.-t-+,*1)&$"!/+*od MZps3b>@_pL5/(fbeV 8  ~aI>wik(rmr*ibB\7{;b Y dN $V' *B,-.P0133333&2#1/-)=''^%##m!N3: Q4ge> 5I4t:E$S ? 9+Stx  W @xa@TmW7zSpd)[ _b 4G2 q"$m&[(E*+1---^-l,*)'&$"OAz # dy9xP!~YCi% e+$gY &) U$]Q_Cyh][VN1ߙߵݰݵހ~g|Hja<V & K}OR :#%'/*+,U.E023321 /?,+^(&%#?uY7 H mqtFadhLLs8FkY4TSNJw {\)2$Tw59r49[߀ߑތTVݠݿtXn({\$ P +OL"$')*d+D,+^*)&F&&#;! p  \}x5KH};&TXmHDPA5Nb@\&L h~O\Jm#}bq_&ia%7(uwRJ` w J%@N!$%&2(*,.0123R204/-+(%# 9? \$e;-\$BBTNS, CYLQ~DcPi8j KYw"0O\Nߌޠ߸ߝߑ3< [ V "%!h$&'()[*#,J.0f344|2t0+ (P$_"!e =B})$_{[1_\!  2  s>[&x- K@cJ~" %#4r#i}H&h#) 8 Yt a#%!(*-/111o12B21P0,)%2" s[ @+wCWkeue1!t Xz7aF;LL%kk.Ll >fLA3i<@d$?m@=Y? thH-3H J.G =$&)/+,3.d/A01^3|5766I4%0+)1'k$I#  !&Pe}:K\=(nQ u L'Lk>oPKm7g]$;; j/FD< #o}p{٣ԯXsԬҨҚ-%%׭چXQL OZ I "#$&&&'((*+*(&>#~ h9H }+b CN \2 P W s =mNCJ&W!dC:wVN:EE$bE![։|@yZ״3=vr| Bi_!Z#%(+a-t.a.d. /+0022 31/-q+'~#X}7  W;oV [ M:  i 2 |;yxB 5mU4+|Sc<&X~kڭٿ׮ T !A$ UBFR!##&$$%&%_%g%%b&u&%$###v$$$'"Rtq  x8_ Q $ / )  sy8v%Y S_ATNm!YujhTInJUy, tn ` $fxFdc ^cWX?4B<'%!e"##]#F##"s! kf4 QVbS' N/@7S,t:x!,[} Z<$0b~_۠1qB[['_C; o   i BZw!k#$F'(z*}++)\(&#!f&7 ZPR?0P-CLRyO ;pyJD{: ?[^$c JܿKҺ<ўy9|Zޗ1;1w[ga r{1a _pMz@?y93i'elqqpF t4i^[MLUv;O|WM@ Y Q'/$qor K EQ W = B 3uX\h=[rS[V Nx IZ;I6 hb-B_kF\7s?N7pA W  }@xoZ^RF*A  $A!gIW { \  pW2jH\`s`aCt4g\ \qt`)jn.IK:u~rb7{k eCm)K& ib&Q)Y 2 g  ./k P oW{='z!t @" *loj f7%6E?, ~    dk#W)=L5yD]at&RAE5{V1\S<+EP5"gZOKK,7H:5\^o.S[ :Ys^FC;  C \}uYrw  pm{CCip[UR\{G:&EV|C*n? Os\yO[(Zb-(k_!}jV@/)MJ|-~RC{H,hFV (0u.&4}  ^ '{sI~vp K : Q  ! F & S~~Li4Sg,<JH,5\C(76Pr&Q zmx41mmh%F/T/Y@jMa 9 z4B 1  E \wdXGug C 7 h u x0KrZ' s&/^l@v>neU+) g}QSU^+mwFC"NS,TW<`1Qf9IZB 2 r $ b  , Few/rPlpVz xsnes@\d?~u^x&*(Y~!!iB\z_l^!,'O]Qb&^:pVQNS)HPFE\jrI = u f 7B=  7 B CfeM2s1 ! l Ly 1 @n01:V2)t  !5 m  T v-\7CI$%Zem@R E-\P^=?dF^$*3 r   p :\ m r ] K\l[2C~YDT B # u Pr #oj  Eg{5b v m C  @ E W   T ^ Y^9<VY3)PXpEIo>yN6=cN_45r7'*8: W d  +lAi:^ = Y@$OS) :S: ZP W+u3}_tm \ >de",Iyu'**7bZsCFD))hY"h1N  _ m *  , CB I&^RO }  VP.:{ _ Ld S$d w HrYHti1+g o *1d~_2G(j| QpD:2&gZJ_ b7j)J&~'kxg7TQ9 `f}{Hw2Q3=T  S< V c 3PC 7 Ujj7~ M B *}1~Lg{2"ZIxT`x9 |r$rt(- P/jl5 85#Qfa=J<,v^F_G1lKa5  oaz @\ ;:n!k0AN}8<GN2"3N>-5Iq( 4_s]>Q#@x;oE %!e`K0}Ya=sd g\_ [{~$HawO&d H T W __Xuf\ d|jAy~sOODu74Xd / U d  4AzNglEZ{[KP{R5jF\C F.9K!/r<6 @sjM,D)%\&F F l |CCvr%N"y= e E & T6@aCxg/!aB3p7R q1F21o'\3AHy\[F(RXm)j`5=}4&Ho-dCTl2~YS_84r5'u,"j|@7,;~*4Ko)J?< l7;F*pB!EV=M,=(K Q = ={\e 5 ^^! @ V &vqR4 1 W Hvp@Ce%}5kT 5 '45:9BY\p8 iz@B#_E_cHsoyvj)H}}}51lw:)12+$d aE *;,v7 YAH    n]ROO;qKj{,]\\ sE:/=_-;4!d?&5U"&\T ;B:}!Lvfa9U?" Xc)4{}i'  /c!6\8@jY1(#<bvQ,Qgq{VVjLy'17 jiXA sqh`g}),Nzz2C@mxMilc!\*1!'?~?:>.. jBo&u{\*u/F cA;(R:AL!FxBl#%hj@-jNEWY rk;F}V"CW0/ `D|-F f3`Ac[,Q~~bSjuoJHu!;ITZC`try" m*SDW0"OXdoK*kD ^)qnSg9&18 fZxE=~ ~D(|f9 <?L_jAR"88o7AHQ gc/A p u  Q>\ H @ b N 5 Rjs~b=!,20W0{6/D85E V$L\G,XKj3LZu2 pa}VX1ox=KGQB\*/ _,@#d"IGdm,a`T$i=c=.P mo z%m%97@G 8HqSvm`mHu>MKIxmAU8< :a _+2s4EznAc%bimQS$! \a5xm2M1UVS1MO<@<\xp~?+Xc^)O}&u\j|%U(djB8%NfM~3%@{jzwY9=;gxgpU r+Nb0(co TSk=;Iz3f8A-hR:.cNherV=i#jt~Uo?K_G&/"DSGNzDTW79'~[YYo {}qk*.v.^rVY@\U'q pxu3CB},245snF2DRy Yb6(hOQ `HVe,&Z/@W/!\E9Gy@,8 iVT8;jJ7NnG&`Y( t_w=7(3th\,\29{E )5e$jSFr*z7z=ajB,t}D!1C(Ku@U~8pgd@`j{Z@[U95nL+Ek0=2 Gd|!n;9,hNq6d)11+X}#5uP*,#f hgu+G^O sdjH DN jx*5Ba_/R&f_{v8wq)/q,#- Q1g[SZ[ga;R}K./Cw r $ `+\xtaI{u9M`wQO|C{F" o~Ae/[eT!DNxafx%5|g/l}^}r+ ?zt[u=S.P(RS,u/$nO2X~-Ty@"IV5)AD%Z*DR>en&2V{b8XGQDd9ICx% DfFEEv_OFat1=Jo_EwvDjlp_7HE$)W&B[~d/"8-zNo!I-#qMNmAy)|xg4 %@g%Y@M"_XB2a"Ojx]q ,m( IIWo<$}t9ViOVXQjw [U+%I) 6}[0-G)?@oR$;g>x\,06mATg KI-;:>_]Cx{]:55F30/0 7 SX,Km/:GLw Wx$,$:&\*~c%KJ[SG0mwXa_Nqvqn/g$:KlU5oXNMz2)oKElCt]^m5w O2Wf ZjnamE6iL!@<!Uqf fTVh;TK=Nn*_kI%+}pQ[~ ?=&Ra+w:71u)$Ewt[O9iSs)lgoE:H}"T!h7!ok7*&Cdq=IT]=y^YKf=62_qRj! M S+G}zGrfEKPjvw Qz#}\| F +H~ 63 znnv ?1S@t/`ImQk5f{IW08=`5 \W@^}pVt{Hw'Tg5=%z*. &9dC{^8 &  ma$T\P@[g}GI#p_5d?^lTs ?:b{ P}}\'//XN$S2)6yv_P{RN,. A+{mJ/#6X(PqZ_cl{!TW +Gca >j0%,4grk52VrBrWj_cBG|?4(`B*>vx)Td'7 ij%%M\d{rPX\Va/}C*X [Y+/{!_:"NF+/' {2~0/;Fg$upc0KFx  7~ZD-S/'h/*-2O=t8UVx>NOxc bkR}2!3 0AttrzX.MR''}@1& @3`\) ^<1H2O9/ m(X<4Ou g=S$@dR~PLT/\h 9rxZ| ;Ale3VEaf)Y1 X{ zB4z X)UMSVEPsd:6\C0@GJ lg]I=JpZRQ0/,f[t3mmTrmrZG &Hr_lm]1i2*m5s*hOBi) 2Am# Kw!";d4B4B)n5|\=d,nUu K PAnIbEF9SfqU`z9J(kR5U;SD6,6Qd@yO:!(8@$@,/5 "&kFed!x0W`Ltn{4]fM_(8ehx;H$P?&PRxiSUl!/J[^/@ja@KHgVY+/LembI!wq\9AP`[oq:z`%JPzj:f D?KiuV3 .=BU"fJ.(GSXNN:7[du_( l,).(.NlrfgMM6$G=?m4B{4gt $ZI+q\mje{~@ VpY W!j~q|qvCCK*~fF  3UNUAq1 j3, \/c,# 1MjaX# pVrXz1=,6 0_Q>;`GJC'R}GzutYDd_\?7^?_ 2T&Mop::#?BNgS& IW{{NbT4Y2jU5?P 7K<:jXH 3%= -FGTv>(@];K2Tsq=!85exgdfu@A/[%)U3W|csX8%=C0LITkLnkXO(+@$tq2`t{q0Q_`%t7 HujY?7DO7#Etu7N(i%F_9IU%D0t"(-*_gxK'An~L,e*%AkyH:/KNb*>3;! QQ22bc$2R5OA5  H]pvVgOj%;R0/2I5UUWL`(j :qjG#=pP2Sfrw},u3.r*GUqA+OA+TAp%W2Dy6 `DTqkQ>P<i`1/M}jHjc24!J tH:)dT2 8IS}SKT5N*=Vmjjzsd['#Ha lCd:BI[MWgi1)!=u *a1 Ngur_,Cf,1\ ,9{7xH^5XsN-t~-OpfW!2j|qvC`f;- J]~vh( ++>!-3j=d>vI $T{+3y"Lv'+hWJ;>ejk+Rf9=J3 "G`Pqj= 4=ogK\r|"pjDx8n5yey=5'3~L~V>jmp)eH\gu|N=Ns  | @=bZVv"$=LWh=!p6|=:S?6_<9oiox{~mP$~U42JPaupb(9u{)M!()Yig}M8_vpt6$\mKx2~ k-8]t0=Bm7{r}oM Y!YMrF' xMjg{m\u}ve7gmgC'@4Q:'NQspJVm1=$.Nu56##JdUS_x/q7Xo`&(BV5Xc26 +1=:9B/t/6%) (%47Vw'@=N* tPA(Sa| >bpqTD+5-XeLa=<Xu *2GCbL''8FD a[}fJMrG^aU3G B 9cqY%(/9Zsv]bhbZh-Vvxg:]bs_V0'>C/>\N'msW'~q3|myxjWf$PfUf/DdfP3n (fM GK6 16GdJxQUmjE,@iQJdH:+jN,&Ujmw:UP!V^(,4N}&?%Df # 9n|Y  &\ $K GBSJf\*@T|JPd( 4?r^@&}wM4#ClP<r:^eB 2:?iC):B_d$S\joS& #\aEfr#(qD]Xe;05$QQ @tU3h|b=ZK,k0ec>9  2INbGy_]`'(=G`  !5XqkvK~`Oi:G 5CZmkD%0+' }zj/."xgS=#&7a^(&`Yqez[oMJQ"2OxpvtgC qUkyjL80;m %'I(5sWQ> ]k|; ("GU,`(!*/9'+O-0=N=>ec23L9{c <!:w[#zPM'7w+{ M&%jD8~t\GReseemm$<[=KuAn\B3{sjhk{nD6N>Xtw]kcnOmDn*T>'jU8(3 RMVG=<<^mod:i&2wrwwz\eT$i&v8 !#55BzP! E2_xxdJK:' 7^[[$~6`/ 9uqr4PlD)%mDf 3E3"?SG=(* ;O96!$ !;U~`ITU+DO`("I3C/-_D3\Uv'YAHc=AXT!"=p'Lk( !LW_Ze]\ycNW|bb]Ukpv~LkqU8>9\N a}^HX`dq9d2VXg[1(^~P=E 6p6lzU(5|lD4%?PY Rt|F5FS"HanWeZ|6T/bxQ-8jfTX`Xm_9-IA Aq~yjD2GGkm\D%` @f/GD@B^cu,, V)=N +R?xoaE g:7lK#~4\5Mp\@9BC?1#ox9H&\&AK:Y\z"K0et!Zx5 !(' wm_F@9pm{wv`NG@ZnhqC!"+NWUNtjjbmeFo3j9{Ixfmw^Vg}q164&J )`f\,w:j:22Nz1@}j9m[9G1)!u Rf^E:BJHd++Md +Unf c 6\p ;]kq8-sW{gZ2=/@>'um*ZU ycj_@vTppZFNFr? 0A%J&HV!Oj0qGq gM^a9Y4\M,! ! MxfgpUE7fjgdYwdMNb~:@2!4{uH8\H.Vr GN$MTZ :FY dCg'+:{_J#@G(D7:ou^xmpXJ@+E\:c:+-|%p;Rc)!38{8nU@DRME^tlu" /\%'D{_g9 /),.<cJ-GOq,/0' =7VT+]3 ujStugX`-9@>Tk`QZ\NJfhDDbb\Tw<)u% #8!"Fbw{w69 M+ C}9[qg" ^X;t6fhtK5s/:3gvv"{K (GATNnRC cXH`7cO6/d =.c&tSJPgB=S7EDlS(c#M)z}gS PxQ(+/ffti_M1@V1+:KiRP=/m#i:~>K :s~]*yC'~j]|0!2Opsb5q_9K K[K=rxKc .dU_@2 GpB VC^j=inbmsUAyAxjcz-6ZDdKj'@n89>@= P(,z$EgRtq^X!#3o:\?7rGsT (/Fn{q2`~-Ik]=\=hC%8ej'IY2I|D  I(\c$2h FVziw{}X= 3EuBm }[Ya,o7lx< zN?P( m<(@tr+ocECb{sD6QO!a4A|"XymvktKZ(yA26`Cg=Zh8n5q HcR6y@ Q Y7t=ZW%*Z~282mk$!%/'!5 !q]:'-N`"N+ q33D|bCQ0w\1GEJXwJv-h Q~/N"`P:iD|ALD\"9ju~.tHGzM6@md-;AUqZ~6tMa3&=BAJGY|G_|{{9s8v,"Z{{jA>OK"N{K\@HpF_TA!8}loc}--;|b*!yD' -A(=py]9p;9 af9/camQj$?~1lN%xJVJ@tfw"svhO\Z`3Om:\Ob@s+'6* F5FX@R~I ~;2`Na!uNUxfP({=_!s= FPp TCE p{[[eV{8a'Blz~Q*F!_orgLYZ@)@C} S_~s%`_%j+y K{WAC @rl|\D2C/I@3OWZ=I= gL! W$R+v2?Y9M}xVga/: #11c #P} K_f2E=K5d \mE$@T PY \4\BRx=%=!jO/8Wh{A*RD7[wDTCLFNt5XZ%s$6LyW5=he "o!AghytUQ~\'}w*8NwskcNCzuRYml`U:4r3d"DZv{h-|}`"gl.UUG< ^oj1xsoS)El&?G+?lrHo2=@ZL0 t4VX)(H{7R%KjDh9,/39qAqqbPi,4\dJq o~\#BSv7H,jH1{Yp9YPP_zSXQm_^<$b{, a:ji 4zE/amKwD3j'\p|~W=yR=5x!{3/"kn|"b;=*> 8eh$ {Z-w\c?EKGdia]mqX=%XWecThbA>$T6sUaNM:Y=z3LA9>*! *R*5*~kc V|UR".<U|zcE9+ OjtFn!UyVD VsT{\YEW,Y>F>kF2R\TVQq|]ppx(AAR=7$xB{@vW~fQj9RkhKKI#H8_Q5F} }E6VmgD[j<QNMY4Eu?bQ \+r4IK 5[8PV)@@\+, rtU9$f25[g}Pp}64cM=JcdcC]_+m"kkIG0* %ALOx`"NKZ0!+h%`\q{~DNd\%m+G@fW]me6 "$wh-"!>A635DG-+w+iMG\z6gdMBRE7[6 -F9`fajNx{p-@=YxnIO|gc6Z'$CY`c``j|e"=pXX`{%8;*tq|qT6/Qss]G0Mm\7.9Nm \d#l4wo}<_t}ti\UQbt#12111)$$()/224.#t[PKXj.l S u[PRiKS=e +8FKF;!_3">hDO* k!W*wcAKJ rR<6=StjJ\r& i&Sp+X~o=b9m: Cp2?C@9,1Ej$N\=B7:l.54<-%HM#}i[[_\P2iS^9&`GxqY/:K[o-T%y2G\_p3bp:qgn"T~xHxG"2m(3]k\: @t|I% 5O_`ZF0"'>]*3;CGNGC/{6DaVc 6@@6! Y ^g}7 K: (+ &;389@@@0|{+f3GRWYbmvy`6/J'YjPSxmm{7g_u7^w#!&BMJ/ b 5NPH~^@*)5KlJ+?p1u Sj=9*jc!= p9 *=Tm*2-jW>* 'Q2b\T g{6vT;!(D]s~~wqmmsvtb; lOEBEE9%3lD/;5!h2%'" !Gwy5D)VY&4RpDjVH=) N r^S_{H<IK'3"=L>Gmwjn5 `K,k0r)7:28R8DN`( 9h|\>" M Ytfm)^)=6Dp6(6_Sx#mix~gP.\!)VJl^4?HEJKRM<DMDo%D %Rygh|kN-|G hC(!3IjC9NuE"c(GHUFMV:MS{2E1tBN[BWl^j{mYVd)iJVt,V*5 -KdE 1\9m,u7jK{%iG}  =Zsmcbjwj@ oUA33AUo"q>gs;kAf'!8Qkt]C(tcUKD=:EYI *KyG{hn!083-/9U G]CJ$U"}DM(DfSX?6Hl(D[o|R& )Ol*D]sm__hy3`2vZm0   2]F@T]bZ\]ZZVN5 WCI/=,K:quv(t-QvN"X_\l:o1VY9i)u/ggz{[!S~#UzrM)V\ u:E{.jl)%S &?JOSOJHEBBMgCh-2%=s@Ymxe;N3GKA@IqL~`@T*Y9).:J\^YE+fiMrJ4,.2=CF@9/'&1BT\T1W N5g Qf![~ =paf+exj#H!-_KF$/`"t]O/`)_smsOVH~T,N~nwi< :n8b'8>>656CFD9v0Ec%SxY(g11Y}YM<5/5KH^iPuzRz{[)iQ?2$ JaE:VgnY< f@4Dj /X|J#q Iwf8\kc_RZg~Q/w3uB JqXPOG#g4r7u,{W?=Tm5K +=Xoj9BCmxVNQTQ=mbgu}vsx}vY:2;25}#Id g<'Kgx(Ec|  l6A|I2ZmqcK(`C0-/82{vy|ykU>%(Dh *8AGIIC6*OGU2  nG/'*-/" t8|X1 4AHOSPPPJE9% r P%V SuperCollider-Source/sounds/SinedPink.aiff000644 000765 000024 00000017734 12321461511 021713 0ustar00crucialstaff000000 000000 FORMAIFCCOMM, @Dfl3232-bit Floating PointINST<MARKAPPLauFMSSND`z=o@=Զ='0|x>-#>PN=Oʗ=̊l<`=S@!<"='.=o:,=j@D=`N=쀿W=:_B|~'2h{ixQ9s|=n=hM=C@aYJP<{ӽ _Z"H9=@=%a=)=\H=@=Z=>6`=1@>ul=`>k>J>U=m€>{G=>7="@?=ղ?\=*?!#>;p?-I7>:?83>VWP?C}_>@?Mu= @?V= ?^>-?fc>$_?l="?r>D`?w1> @?z>Ġ?};?G=? =[@?:>?~]ff@?|.1^?xv?tz`?o==?i]?a ?Y}=f?Q'-=@?G~>/?= 5J?1=%+@?%p=V?r->, ? N>%>;>E>۫>>Ùm>Os0>v>:A>=ؖ>O_=Q>$>bP=><-<}?-P)2=fO<.r-@/$!<+q=j`7{=uBN= L^=ɬU=^ >Q@e=xWl;=(qve@z`k]}R/0y.>5ur>@o[=i=fb~=;Z=\R3=kH>b>F=,3,c> ']> j =@ ,=2=!==ྩ=Lh=V=ʀ@\=b<;=S`;::="==X;H+>(H>>g;=;>=>Į>a<>@?>=?_ؽ d?J<@?*n=|?65n?Apr@?KC<?TQ>B?]!4=?dƲ=}?k>,?qX>`?v8j=z ?z =r1@?} ->:S?~D=] ?=`?/=UZ?~'>Y?|=Q`?y=+?u)<ڀ?p=`?j>5ɰ?cz> 4?[c>j ?S<'>?Ix=??}>*ݰ?4x>cG?(>a?Y>:r?W>V?>V>c>Vm>R>5|>u?>an>>P>]>>=.=W>LP<>f r=(2>!=,`>7@#t>u~>0@|=Z@腜=xR@R>@ޝ`I=1@)84=I4d?=J&u@Sjk\4c j͜}p] @u==y|߽K~ ݼCf_~= |Zy=v sq"-ܖkF'<Ϻ_W=;zͪ7 K>k$.bdztQ%ƙ I 'r<А ڍ=LAK>>e>XC@>D>7? 0>"b>D5$@?K?[,?hKY?'ǽ?3u?>xB0?I[d`?R{?[EU?c`?j ?pp?u2i?yS:֣?|yK ?~pX?|?Hh ?ƴ?}:'P?z`~?v>B?qd?kB֐?eN0?]ڽ?UF&!@?K<]?A=`?7 7= @?+w=?8ۼʾ?YYV>N魠>O.>z @>kE>,[7==5T=7;_Q @Q̾Vƽ5?CվAV_C0 ֏' ICMp&w- r 2RU=zþC[GQkQվI1ZR%kbD׾# iS~>owzKt x籼|*oݽ~oـɽ@ؼ;v}}``zY〿w!?rUwlf8p^ƾ#%PVF8MPC+ 8On=^@,Qꀿ fW@q `u )#SXu@=e<`r逾4'޾MtR K<7;.=7(> o;>J=>¼0P>RZ=@>f=!@>޸=>*V=S? O=?~GH?%h;k?1=}?@?.(W~?"ܽ?Tw?% >Nо5P>ף^>>>Nh>zP>;U J=8=oMX þD<Ӿ8i4ӽʚ@CžJ Q@VvP0?nM  0k=@I3m#~2`/e;@EʾِOf߾!Xe_t`9g@!Tn'%;eso3x{*`~<m ~@}L?}9=;j{u=Fw=Ws|)=n =.g=v@`h>I X@TZ'@O>>=EkO:ҥ/}#x6@UL@ ɽ'dνeO5= TXooB<"N罻FPC=t4@=?>{5 p>d=9`>E>!>bY@>Ȇנ?<μ6+?U:?"EuB?.[_@?9?Dm?NSڽ|?Wj[?_@?ge`?mzV;?s7=n?w=&?{*5=?}=c@?b½ ?=?=A?~24>?{>!?xh7>?t =[?n= ?ht= ?aH!EC@?Y8ʽL?PN ?FF?<B?0s̀?$q ?Fl@? =)@>g>;>d`> E> >IZ> ]L= )<&jg!=Wt нsS58;Ĺt=D=B@9⻁`Uӽݠp? O%@-e^8yC@<]M>$!Vl޽@^ñf: lo,rk¾PwE zE/eP}ɾ@ǽ!սmo72~gп|s-Mxw?W t4ȿo^n!0i6b$jZ.l7Q]G(@=L(h4@2 ߀&Br> }VFҠC?<4E P͔!apʣ}=9{=U>. k->l<ʀ>n=D >~=)>Y=X?"=7?;?o?+,<"?7:0c?B=z@?L%==?Uln;?3o`?'t>?1:Qq?!=f=?>OBX>ǣ26>L>n@>Wu5T>L<=$FQm=8_= <>=x%>0<9S<=>>c;w>^.<>p>ې>= >[=q>=6?=A`?J%!`?( =8?4ȼN??н?I/@?ScA=ǀ?\Խ7@?c=@?jS==+?p=`?u;>?yd?|= ?~P`?קa ? ༀ?~ϟ?}Y?zʻ8?v%lK?qA}e5@?kjXd?dHE>U=<><>Gf-=;>'7\=1=S=Hz={'dP`n= TWy@3€v3`n¾@ ҽy'/3]ּl>u H=x/RZ<1[;b i,\@o=3n@u~8y=y|iŽk@~<ŜC9}H'5 zt,`vӰq+@l νb;@ex xS@]XKUyƽL4Y"B!7K~m@+NG @n\7e]Rþ Ѫ׽ ;`mG.h`ݴ=\&;o=7u>Pn>j=؀>l=O>X=,@>!j? a??&0&?2`C?=;⽖?G t@?QO1?Z!ǽY ?b ?i,<?oVcj?tDr@?xȾĐ?|A@?~e.M??F?(Q?BC/p?}\Ea?z?w?rsP?lӞ?fE?^׾f?VzW?MLyp?CP?89m?-4? c?$&jG@?5;>p&P>T>g>>(>t^3>5&=3_P=XMuP _ɽ,N<֠ /<>B <>^'>*Ľ>WN->h;R>W}s{? xg;Y?=?#e?/l?:O?E\U?O0 @?X3d@?`]K?gl@?nν`?st=?wﺼ?{qeɀ?}/%S9>ۙD@>1:@> @Aʽ>CB><=j<; $n`Kh LD:=y<źD<=)w<؀$U`Q@vT!&2@.9 D1FN}@=W7`_{ fJPmWayrýwyܼ{?}mi@\:@k@0~=6U{ܠfnx~ӏt&nّh+gatsVYj,P;C`FΓ 3ȴFp>r >7>Xz?>']`>C@?a*@?.? 5?,|^?8>7~?C9?M>=?V9Ž?^ֽ8?f <%?l<?rM9?wȼ?zzb ?}y/ƀ?9@?{??~r8;"?|.@?xW&0?tn?o ?i]n?bP$=?Z_>Q'>+2 >y>L^>M^d>R;h%0>W =@<=J@4SuperCollider-Source/server/CMakeLists.txt000644 000765 000024 00000002144 12766171424 021736 0ustar00crucialstaff000000 000000 if (NOT APPLE AND NOT WIN32) # on apple we leave this undefined so it defaults to .scx (in the code) add_definitions("-DSC_PLUGIN_EXT=\".so\"") endif() include_directories(${CMAKE_SOURCE_DIR}/external_libraries ${CMAKE_SOURCE_DIR}/external_libraries/nova-simd ${CMAKE_SOURCE_DIR}/external_libraries/nova-tt ) if (Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) else() include_directories(${CMAKE_SOURCE_DIR}/external_libraries/boost) endif() # here we choose who provides us with the FFT lib if (APPLE) add_definitions("-DSC_FFT_VDSP") else() find_package(FFTW3f 3.3) if (NOT FFTW3F_FOUND OR FFT_GREEN) message(STATUS "Using green fft") set(FFT_GREEN 1) add_definitions("-DSC_FFT_GREEN") else() if(WIN32) message(STATUS "Found fftw3f: ${FFTW3F_LIBRARY}") else(WIN32) message(STATUS "Using fftw3f") endif(WIN32) add_definitions("-DSC_FFT_FFTW") endif() endif() add_subdirectory(plugins) add_subdirectory(scsynth) if (SUPERNOVA) add_subdirectory(supernova) endif() set(plugins "${plugins}" PARENT_SCOPE) set(supernova_plugins "${supernova_plugins}" PARENT_SCOPE) SuperCollider-Source/server/plugins/000755 000765 000024 00000000000 13007315613 020643 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/scsynth/000755 000765 000024 00000000000 13007315613 020655 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/000755 000765 000024 00000000000 13007315613 021204 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/audio_backend/000755 000765 000024 00000000000 13007315613 023754 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/CMakeLists.txt000644 000765 000024 00000017313 12766171707 023770 0ustar00crucialstaff000000 000000 cmake_minimum_required( VERSION 3.1 ) if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth-4096") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fomit-frame-pointer") if(APPLE) if(CMAKE_SIZEOF_VOID_P MATCHES "4") # cmpxchg8b is available on all intel apples set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686 -msse -msse2 -mfpmath=sse") endif() endif() endif(CMAKE_COMPILER_IS_GNUCXX) if(APPLE) include_directories(${CMAKE_SOURCE_DIR}/external_libraries/libsndfile) endif() set(libsupernova_src sc/sc_synth_definition.cpp sc/sc_osc_handler.cpp sc/sc_plugin_interface.cpp sc/sc_synth.cpp sc/sc_synthdef.cpp sc/sc_ugen_factory.cpp ${CMAKE_SOURCE_DIR}/common/Samp.cpp ${CMAKE_SOURCE_DIR}/common/SC_fftlib.cpp ${CMAKE_SOURCE_DIR}/common/SC_DirUtils.cpp ${CMAKE_SOURCE_DIR}/common/SC_StringParser.cpp ${CMAKE_SOURCE_DIR}/common/SC_StandAloneInfo_Darwin.cpp server/buffer_manager.cpp server/memory_pool.cpp server/node_graph.cpp server/server.cpp server/server_args.cpp ) if(APPLE) list( APPEND libsupernova_src ${CMAKE_SOURCE_DIR}/common/SC_Apple.mm ) set_property(SOURCE ${CMAKE_SOURCE_DIR}/common/SC_DirUtils.cpp PROPERTY COMPILE_FLAGS -xobjective-c++) endif() if (FFT_GREEN) list(APPEND libsupernova_src ../../common/fftlib.c) endif() if(WIN32) list(APPEND libsupernova_src ${CMAKE_SOURCE_DIR}/common/SC_Win32Utils.cpp) endif() file(GLOB_RECURSE supernova_headers *hpp) if(COMPACT_BUILD) CREATE_FINAL_FILE(libsupernova_final.cpp ${libsupernova_src}) add_library (libsupernova STATIC libsupernova_final.cpp) else() add_library (libsupernova STATIC ${libsupernova_src}) endif() set_property(TARGET libsupernova PROPERTY CXX_STANDARD 14) if(NOT WIN32) set_property(TARGET libsupernova PROPERTY OUTPUT_NAME supernova) endif() target_link_libraries(libsupernova oscpack tlsf ${PTHREADS_LIBRARIES} boost_thread) target_compile_definitions(libsupernova PUBLIC SUPERNOVA) target_include_directories(libsupernova PUBLIC ${CMAKE_SOURCE_DIR}/include/plugin_interface ${CMAKE_SOURCE_DIR}/include/common ${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/include/server ${CMAKE_SOURCE_DIR}/server/scsynth ${CMAKE_SOURCE_DIR}/external_libraries/boost_endian ${CMAKE_SOURCE_DIR}/external_libraries/boost_sync/include ${CMAKE_SOURCE_DIR}/external_libraries/nova-tt . ) if(SN_MEMORY_DEBUGGING) target_compile_definitions(libsupernova PUBLIC NOVA_MEMORY_DEBUGGING) endif() if(NOVA_SIMD) target_compile_definitions(libsupernova PUBLIC NOVA_SIMD) target_include_directories(libsupernova PUBLIC ${CMAKE_SOURCE_DIR}/external_libraries) endif() find_library(DL NAMES dl) if(DL) target_compile_definitions(libsupernova PUBLIC DLOPEN) target_link_libraries(libsupernova ${DL}) endif() if(APPLE) find_package(Portaudio) if(NOT PORTAUDIO_FOUND) message(FATAL_ERROR "Portaudio missing") endif() target_compile_definitions(libsupernova PUBLIC PORTAUDIO_BACKEND ${PORTAUDIO_DEFINITIONS}) target_include_directories(libsupernova PUBLIC ${PORTAUDIO_INCLUDE_DIRS}) target_link_libraries(libsupernova ${PORTAUDIO_LIBRARIES}) elseif (WIN32) target_compile_definitions(libsupernova PUBLIC PORTAUDIO_BACKEND -DPORTAUDIO_BACKEND) target_include_directories(libsupernova PUBLIC ${PORTAUDIO_INCLUDE_DIRS}) if(MSYS) target_link_libraries(libsupernova ${PORTAUDIO_LIBRARIES}) else() target_link_libraries(libsupernova portaudio) endif() else() find_library(JACK NAMES jack) if (JACK) target_compile_definitions(libsupernova PUBLIC JACK_BACKEND) target_link_libraries(libsupernova ${JACK}) target_include_directories(libsupernova PUBLIC ${JACK_INCLUDE_DIRS}) endif() endif() find_package(Sndfile) if (NOT SNDFILE_FOUND) message(SEND_ERROR "Cannot find libsndfile") else() target_link_libraries(libsupernova ${SNDFILE_LIBRARIES}) target_include_directories(libsupernova PUBLIC ${SNDFILE_INCLUDE_DIR}) endif() if (FFTW3F_FOUND) target_include_directories(libsupernova PUBLIC ${FFTW3F_INCLUDE_DIR}) target_link_libraries(libsupernova ${FFTW3F_LIBRARY}) endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") target_link_libraries(libsupernova rt) endif() if(Boost_FOUND) target_link_libraries(libsupernova ${Boost_SYSTEM_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY}) target_include_directories(libsupernova PUBLIC ${Boost_INCLUDE_DIRS}) else() target_include_directories(libsupernova PUBLIC ${CMAKE_SOURCE_DIR}/external_libraries/boost) target_link_libraries(libsupernova boost_system boost_filesystem boost_program_options) endif() if(CMAKE_COMPILER_IS_GNUCXX) if( ${_gcc_version} VERSION_GREATER 5 ) target_link_libraries( libsupernova atomic ) endif() endif() if(WIN32) target_link_libraries(libsupernova wsock32 ws2_32 winmm) endif() add_executable(supernova server/main.cpp ${supernova_headers}) target_link_libraries(supernova libsupernova) if(WIN32) if(NOT MSVC) set_target_properties(supernova libsupernova PROPERTIES RUNTIME_OUTPUT_DIRECTORY "$") endif(NOT MSVC) if(FFTW3F_FOUND) file(GLOB FFTW3F_DLL "${FFTW3F_LIBRARY_DIR}/*fftw3f*.dll") add_custom_command(TARGET supernova POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${FFTW3F_DLL}" $ ) endif(FFTW3F_FOUND) if(SNDFILE_FOUND) file(GLOB SNDFILE_DLL "${SNDFILE_LIBRARY_DIR}/*sndfile*.dll") add_custom_command(TARGET supernova POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SNDFILE_DLL}" $ ) endif(SNDFILE_FOUND) add_custom_command(TARGET supernova POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ COMMENT "Copying supernova to targets scsynth and sclang" ) if(SC_IDE) add_custom_command(TARGET supernova POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ COMMENT "Copying supernova to target SuperCollider" ) endif(SC_IDE) install(TARGETS supernova PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION ${SC_WIN_BUNDLE_NAME} ) elseif(APPLE) add_custom_command(TARGET supernova POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/../Resources/ COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/../Resources) else() install(TARGETS supernova DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() if(LTO) set_property(TARGET supernova libsupernova APPEND PROPERTY COMPILE_FLAGS "-flto -flto-report") set_property(TARGET supernova libsupernova APPEND PROPERTY LINK_FLAGS "-flto -flto-report -fwhole-program") endif() if (APPLE) target_link_libraries(libsupernova "-framework Accelerate") target_link_libraries(libsupernova "-framework CoreAudio -framework CoreServices -framework Foundation -framework ApplicationServices") endif() if(${JACK_USE_METADATA_API}) target_compile_definitions(libsupernova PUBLIC "-DSC_JACK_USE_METADATA_API") endif() SuperCollider-Source/server/supernova/dsp_thread_queue/000755 000765 000024 00000000000 13007315613 024525 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/sc/000755 000765 000024 00000000000 13007315613 021611 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/server/000755 000765 000024 00000000000 13007315613 022512 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/utilities/000755 000765 000024 00000000000 13007315613 023217 5ustar00crucialstaff000000 000000 SuperCollider-Source/server/supernova/utilities/aligned_class.hpp000644 000765 000024 00000002272 12321461511 026520 0ustar00crucialstaff000000 000000 // base class for aligned classes // Copyright (C) 2011 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_ALIGNED_CLASS #define UTILITIES_ALIGNED_CLASS #include "malloc_aligned.hpp" namespace nova { struct aligned_class { inline void * operator new(std::size_t size) { return malloc_aligned(size); } inline void operator delete(void * p) { free_aligned(p); } }; } /* namespace nova */ #endif /* UTILITIES_ALIGNED_CLASS */ SuperCollider-Source/server/supernova/utilities/asynchronous_log.hpp000644 000765 000024 00000010545 12524671173 027342 0ustar00crucialstaff000000 000000 // class for asynchronous logging // Copyright (C) 2011 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_ASYNCHRONOUS_LOG_HPP #define UTILITIES_ASYNCHRONOUS_LOG_HPP #include #include #include #include #include #include #include #include namespace nova { namespace asynchronous_log_impl { struct asynchronous_log: boost::noncopyable { bool log_printf(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); bool result = log_printf(fmt, vargs); va_end(vargs); return result; } bool log_printf(const char *fmt, va_list vargs) { std::array scratchpad; size_t print_result = vsnprintf(scratchpad.data(), scratchpad.size(), fmt, vargs); if (print_result >= scratchpad.size()) fprintf(stderr, "warning: log message truncated"); return log(scratchpad.data(), print_result); } bool log(const char * string) { size_t length = strlen(string); return log(string, length); } bool log(const char * string, size_t length) { size_t total_enqueued = buffer.push(string, length); if (total_enqueued == 0) return false; sem.post(); if (total_enqueued == length) return true; string += total_enqueued; length -= total_enqueued; for (;;) { size_t enqueued = buffer.push(string, length); if (enqueued == 0) continue; sem.post(); if (enqueued == length) break; string += enqueued; length -= enqueued; } return true; } size_t read_log(char * out_buffer, size_t size) { if (sem.try_wait()) return read(out_buffer, size); else return 0; } size_t read_log_waiting(char * out_buffer, size_t size) { sem.wait(); return read(out_buffer, size); } size_t read(char * out_buffer, size_t size) { return buffer.pop(out_buffer, size); } void interrrupt(void) { sem.post(); } private: boost::lockfree::spsc_queue > buffer; boost::sync::semaphore sem; }; struct asynchronous_log_thread: asynchronous_log { public: asynchronous_log_thread(void): running_flag(true), thread_(std::bind(&asynchronous_log_thread::run, this)) {} ~asynchronous_log_thread(void) { running_flag = false; interrrupt(); thread_.join(); } void run(void) { while (running_flag.load()) { size_t read_chars = read_log_waiting(out_buffer.data(), out_buffer.size()); post_outbuffer(read_chars); while (read_chars == out_buffer.size()) { read_chars = read(out_buffer.data(), out_buffer.size()); post_outbuffer(read_chars); } } size_t read_chars = read_log(out_buffer.data(), out_buffer.size()); post_outbuffer(read_chars); } void post_outbuffer(size_t read_chars) { for (size_t i = 0; i != read_chars; ++i) putchar(out_buffer[i]); fflush(stdout); } private: std::atomic_bool running_flag; std::thread thread_; std::array out_buffer; }; } /* namespace asynchronous_log_impl */ using asynchronous_log_impl::asynchronous_log; using asynchronous_log_impl::asynchronous_log_thread; } /* namespace nova */ #endif /* UTILITIES_ASYNCHRONOUS_LOG_HPP */ SuperCollider-Source/server/supernova/utilities/branch_hints.hpp000644 000765 000024 00000001750 12756531745 026415 0ustar00crucialstaff000000 000000 // branch hints // Copyright (C) 2007-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef BRANCH_HINTS_HPP #define BRANCH_HINTS_HPP #include #define likely(x) BOOST_LIKELY(x) #define unlikely(x) BOOST_UNLIKELY(x) #endif /* BRANCH_HINTS_HPP */ SuperCollider-Source/server/supernova/utilities/callback_interpreter.hpp000644 000765 000024 00000012272 12756531745 030133 0ustar00crucialstaff000000 000000 // templated callback system // Copyright (C) 2008, 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_CALLBACK_INTERPRETER_HPP #define UTILITIES_CALLBACK_INTERPRETER_HPP #include #include #include "branch_hints.hpp" #include "callback_system.hpp" #include "nova-tt/thread_priority.hpp" #include #include namespace nova { namespace detail { struct nop_functor { void operator()() const {} }; } /* namespace detail */ template > class callback_interpreter: callback_system { typedef callback_system super_t; typedef boost::sync::semaphore semaphore; public: callback_interpreter(void): sem(0), running(false) {} void add_callback(callback_type * cb) { super_t::add_callback(cb); sem.post(); } void run(void) { running.store(true, std::memory_order_relaxed); perform(); } void terminate(void) { running.store(false, std::memory_order_relaxed); sem.post(); } protected: void run(semaphore & sync_sem) { running.store(true, std::memory_order_relaxed); sync_sem.post(); perform(); } private: void perform(void) { do { sem.wait(); super_t::run_callbacks(); } while(likely(running.load(std::memory_order_relaxed))); } protected: boost::sync::semaphore sem; std::atomic running; }; template > class threaded_callback_interpreter: public callback_interpreter, init_functor { typedef callback_interpreter super; typedef boost::sync::semaphore semaphore; std::thread callback_thread; public: threaded_callback_interpreter(void) {} ~threaded_callback_interpreter(void) { if (super::running.load()) join_thread(); } void start_thread(void) { semaphore sync_sem; std::thread thr( [&]() { this->run_thread(sync_sem); }); callback_thread = move(thr); sync_sem.wait(); } void run_thread(semaphore & sync_sem) { init_functor::operator()(); super::run(sync_sem); } void join_thread(void) { if (super::running.load()) { super::terminate(); callback_thread.join(); } } }; template > class callback_interpreter_threadpool: public callback_interpreter, init_functor { typedef callback_interpreter super; typedef boost::sync::semaphore semaphore; public: callback_interpreter_threadpool(uint16_t worker_thread_count, bool rt, uint16_t priority): worker_thread_count_(worker_thread_count), priority(priority), rt(rt) { semaphore sync_sem; using namespace std; for (uint16_t i = 0; i != worker_thread_count; ++i) threads.emplace_back( [&] () { this->run(sync_sem); }); for (uint16_t i = 0; i != worker_thread_count; ++i) sync_sem.wait(); } ~callback_interpreter_threadpool(void) { if (super::running.load()) join_threads(); } void join_threads(void) { super::running.store(false); for (uint16_t i = 0; i != worker_thread_count_; ++i) super::sem.post(); for (std::thread & thread : threads) thread.join(); } private: void run(semaphore & sync_sem) { #ifdef NOVA_TT_PRIORITY_RT if (rt) thread_set_priority_rt(priority); else #endif thread_set_priority(priority); init_functor::operator()(); super::run(sync_sem); } std::vector threads; const uint16_t worker_thread_count_; const uint16_t priority; const bool rt; }; } /* namespace nova */ #endif /* UTILITIES_CALLBACK_INTERPRETER_HPP */ SuperCollider-Source/server/supernova/utilities/callback_system.hpp000644 000765 000024 00000005477 12756531745 027125 0ustar00crucialstaff000000 000000 // templated callback system // Copyright (C) 2008, 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_CALLBACK_SYSTEM_HPP #define UTILITIES_CALLBACK_SYSTEM_HPP #include #include #include #include #include #include namespace nova { /** \brief simple templated callback system, using a lockfree fifo */ template > class callback_system: private callback_deleter { typedef typename boost::mpl::if_c, boost::lockfree::spsc_queue >::type queue_type; public: callback_system(size_t element_count = 2048): callbacks(element_count) {} /** \brief adds a new Callback to the Scheduler, threadsafe */ inline void add_callback(callback_type * cb) { callbacks.push(cb); } /** \brief run all callbacks */ inline void run_callbacks(void) { callbacks.consume_all( [this]( callback_type * cb) { run_callback( cb ); }); } /** \brief run one callback * * assumes, that the queue contains at least one callback * * */ void run_callback(void) { callbacks.consume_one( [this]( callback_type * cb) { run_callback( cb ); }); } private: /** run a callback, handle exceptions */ bool run_callback(callback_type * runme) { bool ret; try { runme->run(); ret = true; } catch(std::exception const & e) { std::cout << "unhandled exception while running callback: " << e.what() << std::endl; ret = false; } callback_deleter::operator()(runme); return ret; } protected: queue_type callbacks; /**< \brief fifo for callbacks */ }; } /* namespace nova */ #endif /* UTILITIES_CALLBACK_SYSTEM_HPP */ SuperCollider-Source/server/supernova/utilities/exists.hpp000644 000765 000024 00000002053 12321461511 025244 0ustar00crucialstaff000000 000000 // templated exists // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef EXISTS_HPP #define EXISTS_HPP namespace nova { template bool inline exists (container const & c, typename container::key_type const & k) { return c.find(k) != c.end(); } } /* namespace nova */ #endif /* EXISTS_HPP */ SuperCollider-Source/server/supernova/utilities/force_inline.hpp000644 000765 000024 00000002207 12321461511 026362 0ustar00crucialstaff000000 000000 // small header for forced inlining // Copyright (C) 2007, 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_FORCE_INLINE_HPP #define UTILITIES_FORCE_INLINE_HPP #ifndef always_inline #if defined(__GNUC__) && defined(NDEBUG) #define always_inline inline __attribute__((always_inline)) #else #define always_inline inline #endif /* __GNUC__ */ #endif /* always_inline */ #endif /* UTILITIES_FORCE_INLINE_HPP */ SuperCollider-Source/server/supernova/utilities/freelist.hpp000644 000765 000024 00000004771 12756531745 025576 0ustar00crucialstaff000000 000000 // nova freelist class // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_FREELIST_HPP #define UTILITIES_FREELIST_HPP #include #include namespace nova { /** * simple freelist implementation without any memory allocation features * */ class freelist { struct freelist_node { boost::lockfree::detail::tagged_ptr next; }; typedef boost::lockfree::detail::tagged_ptr tagged_ptr; public: freelist(void): pool_(tagged_ptr(nullptr)) {} freelist( freelist const & rhs ) = delete; freelist & operator=( freelist const & rhs ) = delete; void * pop (void) { for(;;) { tagged_ptr old_pool = pool_.load(std::memory_order_consume); if (!old_pool.get_ptr()) return nullptr; freelist_node * new_pool_ptr = old_pool->next.get_ptr(); tagged_ptr new_pool (new_pool_ptr, old_pool.get_tag() + 1); if (pool_.compare_exchange_weak(old_pool, new_pool)) { void * ptr = old_pool.get_ptr(); return reinterpret_cast(ptr); } } } void push (void * n) { void * node = n; for(;;) { tagged_ptr old_pool = pool_.load(std::memory_order_consume); freelist_node * new_pool_ptr = reinterpret_cast(node); tagged_ptr new_pool (new_pool_ptr, old_pool.get_tag() + 1); new_pool->next.set_ptr(old_pool.get_ptr()); if (pool_.compare_exchange_weak(old_pool, new_pool)) return; } } private: std::atomic pool_; }; } /* namespace nova */ #endif /* UTILITIES_FREELIST_HPP */ SuperCollider-Source/server/supernova/utilities/high_resolution_timer.hpp000644 000765 000024 00000011504 12321461511 030330 0ustar00crucialstaff000000 000000 /*============================================================================= Copyright (c) 2005-2007 Hartmut Kaiser 2007, 2009 Tim Blechmann Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #if !defined(BOOST_HIGH_RESOLUTION_TIMER_HPP) #define BOOST_HIGH_RESOLUTION_TIMER_HPP #include #include #if _POSIX_C_SOURCE >= 199309L #include "time.h" #include #include namespace boost { class high_resolution_timer { public: high_resolution_timer() { restart(); } void restart() { int status = clock_gettime(CLOCK_REALTIME, &start_time); if (status == -1) boost::throw_exception(std::runtime_error("Couldn't initialize start_time")); } double elapsed() const // return elapsed time in seconds { struct timespec now; int status = clock_gettime(CLOCK_REALTIME, &now); if (status == -1) boost::throw_exception(std::runtime_error("Couldn't get current time")); struct timespec diff; double ret_sec = double(now.tv_sec - start_time.tv_sec); double ret_nsec = double(now.tv_nsec - start_time.tv_nsec); while (ret_nsec < 0) { ret_sec -= 1.0; ret_nsec += 1e9; } double ret = ret_sec + ret_nsec / 1e9; return ret; } double elapsed_max() const // return estimated maximum value for elapsed() { return double((std::numeric_limits::max)()); } double elapsed_min() const // return minimum value for elapsed() { return 0.0; } private: struct timespec start_time; }; } // namespace boost #elif defined(__APPLE__) #import namespace boost { class high_resolution_timer { public: high_resolution_timer(void) { mach_timebase_info_data_t info; kern_return_t err = mach_timebase_info(&info); if (err) throw std::runtime_error("cannot create mach timebase info"); conversion_factor = (double)info.numer/(double)info.denom; restart(); } void restart() { start = mach_absolute_time(); } double elapsed() const // return elapsed time in seconds { uint64_t now = mach_absolute_time(); double duration = double(now - start) * conversion_factor; return duration } double elapsed_max() const // return estimated maximum value for elapsed() { return double((std::numeric_limits::max)()); } double elapsed_min() const // return minimum value for elapsed() { return 0.0; } private: uint64_t start; double conversion_factor; }; } // namespace boost #elif defined(BOOST_WINDOWS) #include #include #include namespace boost { /////////////////////////////////////////////////////////////////////////////// // // high_resolution_timer // A timer object measures elapsed time. // CAUTION: Windows only! // /////////////////////////////////////////////////////////////////////////////// class high_resolution_timer { public: high_resolution_timer() { start_time.QuadPart = 0; frequency.QuadPart = 0; if (!QueryPerformanceFrequency(&frequency)) boost::throw_exception(std::runtime_error("Couldn't acquire frequency")); restart(); } void restart() { if (!QueryPerformanceCounter(&start_time)) boost::throw_exception(std::runtime_error("Couldn't initialize start_time")); } double elapsed() const // return elapsed time in seconds { LARGE_INTEGER now; if (!QueryPerformanceCounter(&now)) boost::throw_exception(std::runtime_error("Couldn't get current time")); return double(now.QuadPart - start_time.QuadPart) / frequency.QuadPart; } double elapsed_max() const // return estimated maximum value for elapsed() { return (double((std::numeric_limits::max)()) - double(start_time.QuadPart)) / double(frequency.QuadPart); } double elapsed_min() const // return minimum value for elapsed() { return 1.0 / frequency.QuadPart; } private: LARGE_INTEGER start_time; LARGE_INTEGER frequency; }; } // namespace boost #else // For other platforms, simply fall back to boost::timer #include #include namespace boost { typedef boost::timer high_resolution_timer; } #endif #endif // !defined(BOOST_HIGH_RESOLUTION_TIMER_HPP) SuperCollider-Source/server/supernova/utilities/malloc_aligned.hpp000644 000765 000024 00000005606 12756531745 026711 0ustar00crucialstaff000000 000000 // functions for aligned memory allocation // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_MALLOC_ALIGNED_HPP #define UTILITIES_MALLOC_ALIGNED_HPP #include #include #include // for std::bad_alloc #include // for std::forward #include #include "function_attributes.h" namespace nova { const int malloc_memory_alignment = 64; inline void* MALLOC ASSUME_ALIGNED(64) malloc_aligned(std::size_t bytes) { return boost::alignment::aligned_alloc( malloc_memory_alignment, bytes ); } inline void free_aligned(void *ptr) { return boost::alignment::aligned_free( ptr ); } inline void * MALLOC ASSUME_ALIGNED(64) calloc_aligned(std::size_t bytes) { void * ret = malloc_aligned(bytes); if (ret) std::memset(ret, 0, bytes); return ret; } template T* MALLOC ASSUME_ALIGNED(64) malloc_aligned(std::size_t n) { return static_cast(malloc_aligned(n * sizeof(T))); } template T* MALLOC ASSUME_ALIGNED(64) calloc_aligned(std::size_t n) { return static_cast(calloc_aligned(n * sizeof(T))); } /** smart-pointer, freeing the managed pointer via free_aligned */ template class aligned_storage_ptr { public: explicit aligned_storage_ptr(T * p = 0): ptr(p) {} explicit aligned_storage_ptr(size_t count): ptr(malloc_aligned(count)) {} ~aligned_storage_ptr(void) { if (managed && ptr) free_aligned(ptr); } void reset(T * p = 0) { if (managed && ptr) free_aligned(ptr); ptr = p; } T & operator*() const { return *ptr; } T * operator->() const { return ptr; } T * get() const { return ptr; } aligned_storage_ptr & operator=(T * p) { reset(p); return *this; } operator bool() const { return bool(ptr); } void swap(aligned_storage_ptr & b) { T * p = ptr; ptr = b.ptr; b.ptr = p; } private: T * ptr; }; } /* namespace nova */ #endif /* UTILITIES_MALLOC_ALIGNED_HPP */ SuperCollider-Source/server/supernova/utilities/named_hash_entry.hpp000644 000765 000024 00000017316 12756531745 027270 0ustar00crucialstaff000000 000000 // Copyright (C) 2011-2012 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_NAMED_HASH_ENTRY_HPP #define UTILITIES_NAMED_HASH_ENTRY_HPP #include #include #include #include "utils.hpp" #include "nova-tt/nova-tt/rw_mutex.hpp" #include namespace nova { namespace bi = boost::intrusive; PURE inline bool strequal(const char * lhs, const char * rhs) { for(;;++lhs, ++rhs) { if (*lhs == 0) { if (*rhs == 0) return true; else return false; } if (*rhs == 0) return false; if (*lhs != *rhs) return false; } } // thread-safe symbol // warning: don't use from different DSOs struct symbol { private: static const char * duplicate_string(const char * str, std::size_t length) { assert(strlen(str) == length); length += 1; // for terminating \0 char * string = malloc_aligned(length); strncpy(string, str, length); return string; } struct symbol_data { explicit symbol_data(const char * str): str(str), hash(string_hash(str)) {} explicit symbol_data(const char * str, size_t hash): str(str), hash(hash) {} symbol_data(symbol_data const & rhs) = default; symbol_data & operator=(symbol_data const & rhs) = default; friend size_t hash_value(symbol_data const & value) { return value.hash; } bool operator==(symbol_data const & rhs) const { return str == rhs.str; } const char * str; size_t hash; }; struct hash_by_string { size_t operator()(const char * str) const { return string_hash(str); } size_t operator()(symbol_data const & data) const { return data.hash; } }; struct equal_by_string { static const char * get_string(const char * arg) { return arg; } static const char * get_string(symbol_data const & arg) { return arg.str; } template bool operator()(T1 const & lhs, T2 const & rhs) const { return strequal(get_string(lhs), get_string(rhs)); } }; class symbol_table { typedef boost::unordered_set table_type; typedef std::pair lookup_result_type; public: symbol_table(void) {} symbol_data const & find(const char * str, size_t strlen) { mutex.lock_shared(); lookup_result_type lookup_result = symbol_lookup(str); mutex.unlock_shared(); if (lookup_result.second) return *lookup_result.first; boost::unique_lock lock(mutex); lookup_result = symbol_lookup(str); if (lookup_result.second) return *lookup_result.first; std::pair inserted = table.insert(symbol_data(duplicate_string(str, strlen))); assert(inserted.second); return *inserted.first; } private: lookup_result_type symbol_lookup(const char * str) const { table_type::iterator it = table.find(str, hash_by_string(), equal_by_string()); return std::make_pair(it, it != table.end()); } table_type table = table_type(16384); nova::nonrecursive_rw_mutex mutex; }; symbol_data lookup_string(const char * str, std::size_t length) { static symbol_table table; return table.find(str, length); } symbol_data lookup_string(const char * str) { return lookup_string(str, strlen(str)); } public: symbol () {} explicit symbol (const char * str): data(lookup_string(str)) {} explicit symbol (std::string const & str): data(lookup_string(str.c_str(), str.size())) {} symbol (const char * str, std::size_t length): data(lookup_string(str, length)) {} symbol (symbol const & rhs) = default; symbol & operator=(symbol const & rhs) = default; const char * c_str(void) const { return data.str; } friend std::size_t hash_value(symbol const & value) { return value.data.hash; } friend bool operator== (symbol const & lhs, symbol const & rhs) { return lhs.data == rhs.data; } friend bool operator< (symbol const & lhs, symbol const & rhs) { return lhs.data.str < rhs.data.str; } symbol_data data = symbol_data( nullptr, 0 ); }; class named_hash_entry: public bi::unordered_set_base_hook<> { const symbol name_; public: named_hash_entry(const char * name): name_(name) {} named_hash_entry(symbol const & name): name_(name) {} named_hash_entry(std::string const & name): name_(name.c_str(), name.size()) {} const char * name(void) const { return name_.c_str(); } friend std::size_t hash_value(named_hash_entry const & that) { return that.hash(); } std::size_t hash(void) const { return name_.data.hash; } friend bool operator== (named_hash_entry const & a, named_hash_entry const & b) { return a.name_ == b.name_; } }; struct named_hash_equal { template bool operator()(def const & lhs, std::string const & rhs) const { return operator()(lhs.name(), rhs.c_str()); } template bool operator()(std::string const & lhs, def const & rhs) const { return operator()(lhs.c_str(), rhs.name()); } template bool operator()(def const & lhs, symbol const & rhs) const { return operator()(lhs.name(), rhs.c_str()); } template bool operator()(symbol const & lhs, def const & rhs) const { return operator()(lhs.c_str(), rhs.name()); } template bool operator()(const char * lhs, def const & rhs) const { return operator()(lhs, rhs.name()); } template bool operator()(def const & lhs, const char * rhs) const { return operator()(lhs.name(), rhs); } bool operator()(const char * lhs, const char * rhs) const { return strequal(rhs, lhs); } }; struct named_hash_hash { template std::size_t operator()(def const & arg) { return hash_value(arg); } std::size_t operator()(const char * str) { return string_hash(str); } std::size_t operator()(std::string const & str) { return string_hash(str.c_str()); } }; } #endif /* UTILITIES_NAMED_HASH_ENTRY_HPP */ SuperCollider-Source/server/supernova/utilities/osc_server.hpp000644 000765 000024 00000004320 12756531745 026121 0ustar00crucialstaff000000 000000 // osc responder class // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef OSC_SERVER_HPP #define OSC_SERVER_HPP #include #include #include #include "branch_hints.hpp" #include "nova-tt/semaphore.hpp" #include "nova-tt/thread_priority.hpp" #include "nova-tt/name_thread.hpp" namespace nova { namespace detail { using namespace boost::asio; using namespace boost::asio::ip; class network_thread { public: void start_receive(void) { thread_ = std::thread( [this] { #ifdef NOVA_TT_PRIORITY_RT thread_set_priority_rt(thread_priority_interval_rt().first); #endif name_thread("Network Receive"); sem.post(); io_service::work work(io_service_); io_service_.run(); } ); sem.wait(); } ~network_thread(void) { if (!thread_.joinable()) return; io_service_.stop(); thread_.join(); } io_service & get_io_service(void) { return io_service_; } void send_udp(const char * data, unsigned int size, udp::endpoint const & receiver) { udp::socket socket(io_service_); socket.open(udp::v4()); socket.send_to(boost::asio::buffer(data, size), receiver); } protected: io_service io_service_; private: semaphore sem; std::thread thread_; }; } /* namespace */ using detail::network_thread; } /* namespace nova */ #endif /* OSC_SERVER_HPP */ SuperCollider-Source/server/supernova/utilities/simple_pool.hpp000644 000765 000024 00000006745 12756531745 026306 0ustar00crucialstaff000000 000000 // simple pool class // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_SIMPLE_POOL_HPP #define UTILITIES_SIMPLE_POOL_HPP extern "C" { #include "tlsf.h" } #include #include /* for std::memset */ #include "nova-tt/spin_lock.hpp" #include "nova-tt/dummy_mutex.hpp" #include "nova-tt/mlock.hpp" #include "function_attributes.h" namespace nova { /** * simple memory pool class, based on tlsf. * * its size has to be set at runtime before it can be used. * * */ template class simple_pool { typedef typename boost::mpl::if_c::type mutex_type; typedef typename mutex_type::scoped_lock scoped_lock; struct data: mutex_type { data(void): pool(nullptr) {} void init(std::size_t size, bool lock) { pool = (char*) operator new(size); mlock(pool, size); std::memset(pool, 0, size); init_memory_pool(size, pool); } ~data(void) { scoped_lock lock(*this); if(pool) { destroy_memory_pool(pool); operator delete(pool); } } char* pool; }; public: simple_pool(void) {} simple_pool(simple_pool const & rhs) = delete; simple_pool & operator=(simple_pool const & rhs) = delete; simple_pool(std::size_t size, bool lock = false) { init(size, lock); } void init(std::size_t size, bool lock = false) { #ifndef NOVA_MEMORY_DEBUGGING assert(size % sizeof(long) == 0); data_.init(size, lock); #endif } ~simple_pool() throw() {} #ifdef NOVA_MEMORY_DEBUGGING void * MALLOC malloc(std::size_t size) { return ::malloc(size); } void * MALLOC realloc(void * p, std::size_t size) { return ::realloc(p, size); } void free(void * p) { return ::free(p); } std::size_t get_max_size(void) { return std::numeric_limits::max(); } #else void * MALLOC ASSUME_ALIGNED(32) malloc(std::size_t size) { scoped_lock lock(data_); return malloc_ex(size, data_.pool); } void * MALLOC ASSUME_ALIGNED(32) realloc(void * p, std::size_t size) { scoped_lock lock(data_); return realloc_ex(p, size, data_.pool); } void free(void * p) { scoped_lock lock(data_); free_ex(p, data_.pool); } std::size_t get_max_size(void) { return ::get_max_size(data_.pool); } #endif private: data data_; }; } /* namespace nova */ #endif /* UTILITIES_SIMPLE_POOL_HPP */ SuperCollider-Source/server/supernova/utilities/sized_array.hpp000644 000765 000024 00000016036 12756531745 026272 0ustar00crucialstaff000000 000000 // templated sized array class // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_SIZED_ARRAY_HPP #define UTILITIES_SIZED_ARRAY_HPP #include #include #include /* std::allocator */ #include #include namespace nova { /** dynamically sized array * * array class, inspired by boost.array, where the size is specified * during the time of the construction. * in contrary to std::vector, it is guaranteed to use continuous * memory. the memory is allocated in the constructor an freed in the * destructor, these are the only places, where the allocator * functions are called. * * */ template > class sized_array: private Alloc::template rebind::other { typedef typename Alloc::template rebind::other Allocator; public: // types typedef T value_type; typedef T* iterator; typedef const T* const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; typedef T& reference; typedef const T& const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; // construct/copy/destruct explicit sized_array(size_type size = 0, T const & def = T()): data_( size ? Allocator::allocate(size) : nullptr), size_(size) { for (size_type i = 0; i != size; ++i) Allocator::construct(data_ + i, def); } sized_array(sized_array & arg) = delete; sized_array & operator=(sized_array & arg) = delete; private: template void init_from_int(int_type size) { data_ = Allocator::allocate(size); size_ = size; for (size_type i = 0; i != size_; ++i) Alloc::construct(data_ + i, T()); } template void init_from_container(Container const & container) { data_ = Allocator::allocate(container.size()); size_ = container.size(); size_type index = 0; typedef typename Container::const_iterator iterator; for (iterator it = container.begin(); it != container.end(); ++it) Allocator::construct(data_ + index++, *it); assert(index == size()); } struct call_int_ctor { template static void init(sized_array & array, int_type const & i) { array.init_from_int(i); } }; struct call_container_ctor { template static void init(sized_array & array, Container const & c) { array.init_from_container(c); } }; public: template explicit sized_array(Constructor_arg const & arg) { typedef typename boost::mpl::if_, call_int_ctor, call_container_ctor>::type ctor; ctor::init(*this, arg); } explicit sized_array(sized_array && arg) { data_ = arg.data_; size_ = arg.size(); arg.data_ = 0; arg.size_ = 0; } /** move assignment */ sized_array & operator=(sized_array && arg) { data_ = arg.data_; size_ = arg.size(); arg.data_ = 0; arg.size_ = 0; return *this; } ~sized_array(void) { for (size_type i = 0; i != size(); ++i) Allocator::destroy(data_ + i); if (size()) Allocator::deallocate(data_, size()); } // iterator support iterator begin() { return data_; } const_iterator begin() const { return data_; } iterator end() { return data_ + size(); } const_iterator end() const { return data_ + size(); } // reverse iterator support reverse_iterator rbegin() { return reverse_iterator(data_ + size()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(data_ + size()); } reverse_iterator rend() { return reverse_iterator(data_); } const_reverse_iterator rend() const { return const_reverse_iterator(data_); } // capacity size_type size() const { return size_; } bool empty() const { return size_ == 0; } size_type max_size() const { return size_; } // element access reference operator[](size_type i) { assert(i < size()); return data_[i]; } const_reference operator[](size_type i) const { assert(i < size()); return data_[i]; } reference at(size_type i) { assert(i < size()); return data_[i]; } const_reference at(size_type i) const { assert(i < size()); return data_[i]; } reference front() { return data_[0]; } const_reference front() const { return data_[0]; } reference back() { return data_[size_ - 1]; } const_reference back() const { return data_[size_ - 1]; } const T* data() const { return data_; } T* c_array() { return data_; } // modifiers void assign(const T& t) { for (size_type i = 0; i != size_; ++i) data_[i] = t; } void resize(size_type new_size, T const & t = T()) { T * new_data = Allocator::allocate(new_size); for (size_type i = 0; i != new_size; ++i) Allocator::construct(new_data+i, t); std::copy(data_, data_+(std::min)(new_size, size_), new_data); T * old_data = data_; data_ = new_data; for (size_type i = 0; i != size_; ++i) Allocator::destroy(old_data+i); if (size_) Allocator::deallocate(old_data, size_); size_ = new_size; } private: T * data_; size_type size_; }; } /* namespace nova */ #endif /* UTILITIES_SIZED_ARRAY_HPP */ SuperCollider-Source/server/supernova/utilities/static_allocator.hpp000644 000765 000024 00000010346 12321461511 027260 0ustar00crucialstaff000000 000000 // static allocator class // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_STATIC_ALLOCATOR_HPP #define UTILITIES_STATIC_ALLOCATOR_HPP extern "C" { #include "tlsf.h" } #include #include #include "nova-tt/spin_lock.hpp" #include "nova-tt/dummy_mutex.hpp" namespace nova { /** constant-sized, pooled memory allocator based on TLSF allocator * * \todo this violates the allocator requirement in 20.1.5, paragraph 4 * objects have to be freed using the same instance that was used * to allocate them. * * */ template class static_allocator { static const std::size_t bytes = 2 * count * sizeof(T) + 4096 * 2; static_assert(bytes % sizeof(long) == 0, "static_allocator: bytes not an integer mutiple of sizeof(long)"); static const std::size_t poolsize = bytes/sizeof(long); typedef typename boost::mpl::if_c::type mutex_type; typedef typename mutex_type::scoped_lock scoped_lock; struct data: mutex_type { #if 0 data(void){} data(data const & rhs) { pool = rhs.pool; } #endif std::array pool; }; public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef static_allocator other; }; static_allocator(void) throw() { data_.pool.assign(0); init_memory_pool(bytes, data_.pool.begin()); } static_allocator(static_allocator const & ) = delete; #if 0 template static_allocator(static_allocator const & rhs) throw() { data_.pool.assign(0); init_memory_pool(bytes, data_.pool.begin()); } #endif ~static_allocator() throw() { destroy_memory_pool(data_.pool.begin()); } pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type n, const_pointer hint = 0) { scoped_lock lock(data_); pointer ret = static_cast(malloc_ex(n * sizeof(T), data_.pool.begin())); if (ret == 0) throw std::bad_alloc(); return ret; } void deallocate(pointer p, size_type n) { scoped_lock lock(data_); free_ex(p, data_.pool.begin()); } size_type max_size() const throw() { return count; } void construct(pointer p, const T& val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } private: data data_; }; template bool operator==( static_allocator const& left, static_allocator const& right ) { return !(left != right); } template bool operator!=( static_allocator const& left, static_allocator const& right ) { return true; } } /* namespace nova */ #endif /* UTILITIES_STATIC_ALLOCATOR_HPP */ SuperCollider-Source/server/supernova/utilities/static_pool.hpp000644 000765 000024 00000005126 12756531745 026274 0ustar00crucialstaff000000 000000 // static pool class // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_STATIC_POOL_HPP #define UTILITIES_STATIC_POOL_HPP extern "C" { #include "tlsf.h" } #include #include #include "nova-tt/spin_lock.hpp" #include "nova-tt/dummy_mutex.hpp" #include "nova-tt/mlock.hpp" namespace nova { template class static_pool { static_assert( bytes % sizeof(long) == 0, "static_pool: bytes not an integer mutiple of sizeof(long)"); static const std::size_t poolsize = bytes/sizeof(long); typedef typename boost::mpl::if_c::type mutex_type; typedef typename std::lock_guard scoped_lock; struct data: mutex_type { std::array pool; }; void lock_memory(void) { mlock(data_.pool.data(), poolsize * sizeof(long)); } public: static_pool(bool lock = false) throw() { /* first lock, then assign */ if (lock) lock_memory(); data_.pool.fill(0); std::size_t status = init_memory_pool(bytes, data_.pool.begin()); assert(status > 0); } static_pool(static_pool const &) = delete; ~static_pool() throw() { scoped_lock lock(data_); destroy_memory_pool(data_.pool.begin()); } void * malloc(std::size_t size) { scoped_lock lock(data_); return malloc_ex(size, data_.pool.begin()); } void free(void * p) { scoped_lock lock(data_); free_ex(p, data_.pool.begin()); } std::size_t get_max_size(void) { return ::get_max_size(data_.pool.begin()); } private: data data_; }; } /* namespace nova */ #endif /* UTILITIES_STATIC_POOL_HPP */ SuperCollider-Source/server/supernova/utilities/static_pooled_class.hpp000644 000765 000024 00000012066 12756531745 027773 0ustar00crucialstaff000000 000000 // static pooled class // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_STATIC_POOLED_CLASS_HPP #define UTILITIES_STATIC_POOLED_CLASS_HPP #include #include #include "freelist.hpp" #include "static_pool.hpp" namespace nova { /** * base class for a class, which uses a static memory pool for * memory allocation. * * memory is allocated from a static pool and freed to a lock-free * freelist, which is freed during the memory allocation routine. * this way, the derived class can be allocated and freed from * different threads, while all the access to the pool is done from * the allocating thread. * * \tparam pool_locking specifies the locking policy for the object * pool (default: nonblocking) * * \tparam recover_count limits the number of objects to be disposed * from the freelist to avoid (default: dispose all objects * of freelist) * * \todo we could allocate one word more and store the size of the * chunk just before the object. if a disposed object is large * enough for a request, it wouldn't need to be added to the * memory pool. * * */ template class static_pooled_class { protected: static_pooled_class(void) = default; static_pooled_class(static_pooled_class const & rhs) = default; ~static_pooled_class(void) = default; private: /** free one object from freelist * * \return true if freelist is empty * * */ static inline bool free_one_disposed_object(void) { void * chunk = disposed_objects.pop(); if (chunk == nullptr) return true; object_pool.free(chunk); return false; } struct disposing_allocator { static void * allocate(std::size_t size) { free_disposed_objects(); return object_pool.malloc(size); } }; struct dispose_n_object_allocator { static void * allocate(std::size_t size) { for (unsigned int i = 0; i != recover_count; ++i) { bool freelist_empty = free_one_disposed_object(); if (freelist_empty) break; } for (;;) { void * ret = object_pool.malloc(size); if (ret) return ret; if (free_one_disposed_object()) return nullptr; /* no object in freelist, we */ } } }; typedef typename boost::mpl::if_c<(recover_count > 0), dispose_n_object_allocator, disposing_allocator >::type allocator; public: static inline void * allocate(std::size_t size) { #ifndef NOVA_MEMORY_DEBUGGING size = std::max(2*sizeof(void*), size); /* size requirement for lockfree freelist */ return allocator::allocate(size); #else return malloc(size); #endif } inline void* operator new(std::size_t size) { return allocate(size); } static inline void free_disposed_objects(void) { for(;;) { if (free_one_disposed_object()) return; } } static inline void deallocate(void * p) { #ifndef NOVA_MEMORY_DEBUGGING disposed_objects.push(p); #else free(p); #endif } inline void operator delete(void * p) { deallocate(p); } typedef static_pool object_pool_type; static object_pool_type object_pool; static freelist disposed_objects; }; template typename static_pooled_class::object_pool_type static_pooled_class::object_pool(true); template freelist static_pooled_class::disposed_objects; } /* namespace nova */ #endif /* UTILITIES_STATIC_POOLED_CLASS_HPP */ SuperCollider-Source/server/supernova/utilities/template_functions.hpp000644 000765 000024 00000012411 12321461511 027627 0ustar00crucialstaff000000 000000 // basic arithmetic objects // Copyright (C) 2005, 2006, 2007, 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef TEMPLATE_FUNCTIONS_HPP #define TEMPLATE_FUNCTIONS_HPP #include #include // for std::min & std::max #include #include "force_inline.hpp" namespace nova { template always_inline T identity(T arg) { return arg; } template always_inline T plus(T lhs, T rhs) { return lhs + rhs; } template always_inline T minus(T lhs, T rhs) { return lhs - rhs; } template always_inline F inv_minus(F lhs, F rhs) { return rhs - lhs; } template always_inline T times(T lhs, T rhs) { return lhs * rhs; } template always_inline T over(T lhs, T rhs) { return lhs / rhs; } template always_inline F inv_over(F lhs, F rhs) { return rhs / lhs; } template always_inline F fmod(F lhs, F rhs) { return std::fmod(lhs, rhs); } template always_inline F less(F lhs, F rhs) { return F(lhs < rhs); } template always_inline F less_equal(F lhs, F rhs) { return F(lhs <= rhs); } template always_inline F equal(F lhs, F rhs) { return F(lhs == rhs); } template always_inline F notequal(F lhs, F rhs) { return F(lhs != rhs); } template always_inline F greater(F lhs, F rhs) { return F(lhs > rhs); } template always_inline F greater_equal(F lhs, F rhs) { return F(lhs >= rhs); } using std::max; using std::min; template always_inline F nova_max(F lhs, F rhs) { return max(lhs, rhs); } template always_inline F nova_min(F lhs, F rhs) { return min(lhs, rhs); } template always_inline F sign(F arg) { if (arg > 0) return F(1); if (arg < 0) return F(-1); return F(0); } template always_inline F and_bool(F lhs, F rhs) { return F(bool(lhs) and bool(rhs)); } template always_inline F and_bitwise(F lhs, F rhs) { return F(long(lhs) & long(rhs)); } template always_inline F or_bool(F lhs, F rhs) { return F(bool(lhs) or bool(rhs)); } template always_inline F or_bitwise(F lhs, F rhs) { return F(long(lhs) | long(rhs)); } template always_inline F shift_left(F lhs, F rhs) { return F(long(lhs) << long(rhs)); } template always_inline F shift_right(F lhs, F rhs) { return F(long(lhs) >> long(rhs)); } template always_inline F inv_pow(F lhs, F rhs) { return std::pow(rhs, lhs); } template always_inline F square(F arg) { return arg * arg; } template always_inline T pow2(T const & arg) { return square(arg); } template always_inline T cube(T arg) { return arg * arg * arg; } template always_inline T pow3(T const & arg) { return cube(arg); } using std::sqrt; template always_inline F rsqrt(F arg) { return F(1) / std::sqrt(arg); } template always_inline F rcp(F arg) { return F(1) / arg; } using std::abs; template always_inline F isnormal(F arg) { #ifdef __INTEL_COMPILER /* intel compiler workaround */ return boost::math::isnormal(arg); #else return std::isnormal(arg); #endif } template always_inline F1 clip(F1 t, F2 low, F3 hi) { if (t < low) return low; else if (t > hi) return hi; else return t; } template always_inline F modulo(F lhs, F rhs) { F ret = fmod(lhs, rhs); if (ret < 0) ret += rhs; return ret; } template always_inline I wrap_optimistic(I val, const I mod) { if (unlikely(val >= mod)) do val -= mod; while (unlikely(val >= mod)); else while (unlikely(val < I(0))) val += mod; return val; } template always_inline I scale_linear(I in, I const & low_in, I const & high_in, I const & low_out, I const & high_out) { return (in-low_in) / (high_in-low_in) * (high_out-low_out) + low_out; } template always_inline I scale_linear_clipped(I in, I const & low_in, I const & high_in, I const & low_out, I const & high_out) { return (in-low_in) / (high_in-low_in) * (high_out-low_out) + low_out; } } /* namespace nova */ #endif /* TEMPLATE_FUNCTIONS_HPP */ SuperCollider-Source/server/supernova/utilities/time_tag.hpp000644 000765 000024 00000014212 12756531745 025541 0ustar00crucialstaff000000 000000 // server scheduler // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_TIME_TAG_HPP #define UTILITIES_TIME_TAG_HPP #include #include #include "boost/date_time/posix_time/posix_time_types.hpp" #include "boost/date_time/gregorian/gregorian_types.hpp" namespace nova { /** time_tag class, compatible to osc time tags */ class time_tag { typedef std::uint32_t uint32; typedef std::uint64_t uint64; typedef union { uint64 packed; uint32 unpacked[2]; } cast_union; static const uint32 ntp_offset = 2208988800UL; /* seconds between 01-01-1900 and 01-01-1970 */ public: static const uint64 fraction_steps = uint64(1)<<32; time_tag(void): data_(0) {} time_tag(time_tag const & rhs): data_(rhs.data_) {} time_tag(uint64 timetag): data_(timetag) {} time_tag(uint32 secs, uint32 fraction) { cast_union cu; cu.unpacked[1] = secs; cu.unpacked[0] = fraction; data_ = cu.packed; } uint32 get_secs(void) const { return reinterpret_cast(&data_)->unpacked[1]; } uint32 get_fraction(void) const { return reinterpret_cast(&data_)->unpacked[0]; } double get_nanoseconds(void) const { return get_fractional_seconds() * 1e9; } double get_fractional_seconds(void) const { return get_fraction() / double(fraction_steps); } bool operator<(time_tag const & rhs) const { return data_ < rhs.data_; } bool operator<=(time_tag const & rhs) const { return data_ <= rhs.data_; } bool operator==(time_tag const & rhs) const { return data_ == rhs.data_; } bool operator!=(time_tag const & rhs) const { return !operator==(rhs); } time_tag & operator+=(time_tag const & rhs) { data_ += rhs.data_; return *this; } time_tag operator+(time_tag const & rhs) const { time_tag ret (*this); ret += rhs; return ret; } time_tag & operator-=(time_tag const & rhs) { data_ -= rhs.data_; return *this; } time_tag operator-(time_tag const & rhs) const { time_tag ret (*this); ret -= rhs; return ret; } template static time_tag from_ns(float_t ns) { const float_t units_per_ns = float_t(fraction_steps) / 1e9; if (ns < 1e9) return time_tag(0, ns * units_per_ns); else { float_t secs = std::floor(ns / 1e9); ns = std::fmod(ns, 1e9); return time_tag(secs, ns * units_per_ns); } } static time_tag from_samples_small(unsigned int sample_count, float samplerate) { assert(sample_count < samplerate); const float units_per_sample = float(fraction_steps) / samplerate; return time_tag(0, sample_count * units_per_sample); } static time_tag from_samples(unsigned int sample_count, float samplerate) { const float_t units_per_sample = float_t(fraction_steps) / samplerate; if (sample_count < samplerate) return from_samples_small(sample_count, samplerate); else { float_t secs = std::floor(sample_count / samplerate); float_t samples = std::fmod(sample_count, samplerate); return time_tag(secs, samples * units_per_sample); } } float to_samples(float samplerate) { float seconds = get_fractional_seconds(); uint32_t secs = get_secs(); if (secs == 0) seconds += (float)secs; return seconds * samplerate; } double to_seconds() { double seconds = get_fractional_seconds(); uint32_t secs = get_secs(); if (secs == 0) seconds += (double)secs; return seconds; } bool is_immediate() { return data_ == 1; } static time_tag from_ptime(boost::posix_time::ptime const & pt) { using namespace boost::gregorian; using namespace boost::posix_time; const date base(1970, Jan, 1); time_duration diff = pt - ptime(base); uint32 secs = diff.total_seconds() + ntp_offset; double fraction = double(diff.fractional_seconds()); if (diff.resolution() == boost::date_time::nano) fraction /= 1000000000; else if (diff.resolution() == boost::date_time::micro) fraction /= 1000000; else if (diff.resolution() == boost::date_time::milli) fraction /= 1000; else assert(false); assert (fraction < 1.0 && fraction >= 0); uint32 fraction_units = std::floor(fraction * double(std::numeric_limits::max())); return time_tag(secs, fraction_units); } boost::posix_time::ptime to_ptime(void) const { using namespace boost::gregorian; using namespace boost::posix_time; const date base(1970, Jan, 1); #ifdef BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG time_duration offset = seconds(get_secs() - ntp_offset) + nanoseconds(get_nanoseconds()); #else time_duration offset = seconds(get_secs() - ntp_offset) + microseconds(get_nanoseconds()/1000); #endif return ptime(base, offset); } private: uint64 data_; }; } /* namespace nova */ #endif /* UTILITIES_TIME_TAG_HPP */ SuperCollider-Source/server/supernova/utilities/tl_allocator.hpp000644 000765 000024 00000012031 12321461511 026401 0ustar00crucialstaff000000 000000 // thread-local real-time safe allocator class // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_TL_ALLOCATOR_HPP #define UTILITIES_TL_ALLOCATOR_HPP extern "C" { #include "tlsf.h" } #include #include #include #include #include "branch_hints.hpp" namespace nova { namespace detail { #ifdef __GNUC__ template class tl_allocator { static_assert(bytes % sizeof(long) == 0, "tl_allocator: bytes not an integer mutiple of sizeof(long)"); public: static const std::size_t poolsize = bytes/sizeof(long); typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; tl_allocator(void) throw() { if (likely(initialized)) return; memset(pool, bytes, 0); init_memory_pool(bytes, pool); } void * allocate(size_type n) { void * ret = malloc_ex(n, pool); if (ret == 0) throw std::bad_alloc(); return ret; } void deallocate(void * p) { free_ex(p, pool); } size_type max_size() const throw() { return bytes; } static __thread long pool[poolsize]; static __thread bool initialized; }; template long __thread tl_allocator::pool[]; template bool __thread tl_allocator::initialized = false; #else template class tl_allocator { static_assert(bytes % sizeof(long) == 0, "tl_allocator: bytes not an integer mutiple of sizeof(long)"); static const std::size_t poolsize = bytes/sizeof(long); struct pool_t { pool_t(void) { pool.assign(0); init_memory_pool(bytes, pool.begin()); } ~pool_t(void) { destroy_memory_pool(pool.begin()); } std::array pool; }; public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; tl_allocator(void) throw() { if (likely(pool.get())) return; pool.reset(new pool_t()); } tl_allocator(tl_allocator const & rhs) throw() {} void * allocate(size_type n) { void * ret = malloc_ex(n, pool->pool.begin()); if (ret == 0) throw std::bad_alloc(); return ret; } void deallocate(void * p) { free_ex(p, pool->pool.begin()); } size_type max_size() const throw() { return bytes; } typedef boost::thread_specific_ptr pool_ptr; static pool_ptr pool; }; template typename tl_allocator::pool_ptr tl_allocator::pool; #endif } /** * * realtime allocator: * allocates from a thread-local memory pool via the malloc implementation of tlsf * * it is not completely stl compliant * memory allocated from one instance can be deallocated from each other instance * of this class as long as it is done from the same thread * * */ template class tl_allocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef tl_allocator other; }; tl_allocator(void) throw() {} template tl_allocator(tl_allocator const & rhs) throw() {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type n, const_pointer hint = 0) { return static_cast (allocator.allocate(n * sizeof(T))); } void deallocate(pointer p, size_type n) { allocator.deallocate(p); } size_type max_size() const throw() { return bytes; } void construct(pointer p, const T& val) { ::new(p) T(val); } void destroy(pointer p) { p->~T(); } private: detail::tl_allocator allocator; }; } /* namespace nova */ #endif /* UTILITIES_TL_ALLOCATOR_HPP */ SuperCollider-Source/server/supernova/utilities/utils.hpp000644 000765 000024 00000010110 12756531745 025101 0ustar00crucialstaff000000 000000 // utility functions // Copyright (C) 2005-2012 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef UTILITIES_UTILS_HPP #define UTILITIES_UTILS_HPP #include #include #include #include #include #include #include "branch_hints.hpp" typedef unsigned int uint; #include "function_attributes.h" namespace nova { /* we're using some member of the boost namespace */ using boost::intrusive_ptr; /* some basic math functions */ inline bool ispoweroftwo(int i) { return (i & (i - 1)) == 0; } template struct is_power_of_two { static const bool val = (n%2==0) && (is_power_of_two<(n>>1)>::val); }; template <> struct is_power_of_two<2> { static const bool val = true; }; inline int log2(int n) { if (unlikely(n <= 0)) return(0); #ifdef __GNUC__ return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz( n ); #else int r = -1; while (n) { r++; n >>= 1; } return r; #endif } inline int nextpoweroftwo(int n) { n = n - 1; const uint bitspace = sizeof(int) * 8 / 2; for (uint i = 1; i != bitspace; i *= 2) n = n | (n >> i); return n + 1; } using std::size_t; /** \brief base class for a callback function */ template class runnable { public: virtual ~runnable(void) = default; virtual t run(void) = 0; }; template struct default_deleter { void operator()(T * t) { delete t; } }; struct delayed_deleter { template inline void operator()(T *); }; struct checked_deleter { template void operator()(T * x) const { boost::checked_delete(x); } }; template struct intrusive_refcountable: public deleter { intrusive_refcountable(void): use_count_(0) {} intrusive_refcountable(intrusive_refcountable const & rhs) = delete; intrusive_refcountable & operator=(intrusive_refcountable const & rhs) = delete; virtual ~intrusive_refcountable(void) = default; void add_ref(void) { ++use_count_; } void release(void) { if(--use_count_ == 0) deleter::operator()(this); } inline friend void intrusive_ptr_add_ref(intrusive_refcountable * p) { p->add_ref(); } inline friend void intrusive_ptr_release(intrusive_refcountable * p) { p->release(); } boost::detail::atomic_count use_count_; }; template > struct compare_by_instance { bool operator()(const t * lhs, const t * rhs) { assert(lhs and rhs); compare cmp; return cmp(*lhs, *rhs); } }; PURE inline std::size_t string_hash(const char * str) { std::size_t ret = 0; // sdbm hash ... later try another function! int c; while ((c = *str++)) ret = c + (ret << 6) + (ret << 16) - ret; return ret; } struct linear_allocator { linear_allocator(char * chunk): chunk(chunk) {} template T * alloc(int count = 1) { T * ret = reinterpret_cast(chunk); chunk += count * sizeof(T); return ret; } private: char * chunk; }; } /* namespace nova */ #endif /* UTILITIES_UTILS_HPP */ SuperCollider-Source/server/supernova/server/audio_bus_manager.hpp000644 000765 000024 00000004255 12756531745 026715 0ustar00crucialstaff000000 000000 // nova server, audio bus // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_AUDIO_BUS_MANAGER_HPP #define SERVER_AUDIO_BUS_MANAGER_HPP #include #include "sample_types.hpp" #include "../utilities/malloc_aligned.hpp" #include "nova-tt/rw_spinlock.hpp" namespace nova { class audio_bus_manager { typedef std::uint16_t uint16_t; public: audio_bus_manager(void) = default; audio_bus_manager(audio_bus_manager const &) = delete; audio_bus_manager& operator=(audio_bus_manager const &) = delete; void initialize(uint16_t c, uint16_t b) { count = c; blocksize = b; buffers = calloc_aligned(count * blocksize); locks = new padded_rw_spinlock[count]; } ~audio_bus_manager(void) { free_aligned(buffers); delete[] locks; } sample * acquire_bus(uint16_t index) { locks[index].lock(); return get_bus(index); } sample * get_bus(uint16_t index) { assert(index < count); return buffers + index * blocksize; } void release_bus(uint16_t index) { locks[index].unlock(); } private: friend class sc_plugin_interface; uint16_t count = 0; uint16_t blocksize = 0; sample * buffers = nullptr; padded_rw_spinlock * locks = nullptr; }; } /* namespace nova */ #endif /* SERVER_AUDIO_BUS_MANAGER_HPP */ SuperCollider-Source/server/supernova/server/buffer_manager.cpp000644 000765 000024 00000010556 12756531745 026210 0ustar00crucialstaff000000 000000 // nova server, buffer manager class, implementation // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include "sndfile.hh" #include "buffer_manager.hpp" #include "utilities/malloc_aligned.hpp" #include "utilities/sized_array.hpp" #include "../../common/SC_SndFileHelpers.hpp" namespace nova { void buffer_wrapper::allocate(size_t frames, uint channels) { if (data) free_aligned(data); data = calloc_aligned(frames * channels); frames_ = frames; channels_ = channels; } namespace { SndfileHandle open_file(const char * file, std::size_t start_frame) { SndfileHandle sndfile(file); if (!sndfile) throw std::runtime_error(std::string("could not open file: ") + std::string(file)); long seek = sndfile.seek(start_frame, SEEK_SET); if (seek == -1) throw std::runtime_error(std::string("could not seek file: ") + std::string(file)); return sndfile; } } /* namespace */ void buffer_wrapper::read_file(const char * file, size_t start_frame, size_t frames) { free(); SndfileHandle sndfile = open_file(file, start_frame); sample_rate_ = sndfile.samplerate(); channels_ = sndfile.channels(); size_t end_frame = std::min(start_frame + frames, size_t(sndfile.frames())); size_t frame_count = end_frame - start_frame; data = malloc_aligned(frame_count * channels_); size_t read = sndfile.readf(data, frame_count); if (read != frame_count) throw std::runtime_error(std::string("could not read from file: ") + std::string(file)); } void buffer_wrapper::read_file_channels(const char * file, size_t start_frame, size_t frames, uint channel_count, uint * channels) { free(); SndfileHandle sndfile = open_file(file, start_frame); channels_ = channel_count; sample_rate_ = sndfile.samplerate(); for (uint c = 0; c != channel_count; ++c) { if (channels[c] >= uint(sndfile.channels())) throw std::runtime_error(std::string("requesting channel, that is not in file: ") + std::string(file)); } size_t end_frame = std::min(start_frame + frames, size_t(sndfile.frames())); size_t frame_count = end_frame - start_frame; data = malloc_aligned(frame_count * channels_); sized_array tmp_array(channels_); for (size_t i = 0; i != frame_count; ++i) { size_t read = sndfile.readf(tmp_array.c_array(), 1); if (read != 1) throw std::runtime_error(std::string("could not from read file: ") + std::string(file)); sample_t * data_frame = data + channel_count * i; for (uint c = 0; c != channel_count; ++c) data_frame[c] = tmp_array[channels[c]]; } } void buffer_wrapper::write_file(const char * file, const char * header_format, const char * sample_format, size_t start_frame, size_t frames) { int format = headerFormatFromString(header_format); if (format == 0) throw std::runtime_error("unknown header format requested"); int sample_format_tag = sampleFormatFromString(sample_format); if (sample_format_tag == 0) throw std::runtime_error("unknown sample format requested"); format |= sample_format_tag; SndfileHandle sndfile(file, SFM_WRITE, format, channels_, sample_rate_); if (!sndfile) throw std::runtime_error(std::string("could not open file: ") + std::string(file)); sndfile.command(SFC_SET_CLIPPING, nullptr, SF_TRUE); size_t written = sndfile.writef(data, frames_); if (written != frames_) throw std::runtime_error(std::string("could not write file: ") + std::string(file)); } } /* namespace nova */ SuperCollider-Source/server/supernova/server/buffer_manager.hpp000644 000765 000024 00000014540 12756531745 026212 0ustar00crucialstaff000000 000000 // nova server, buffer manager class // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_BUFFER_MANAGER_HPP #define SERVER_BUFFER_MANAGER_HPP #include #include #include #include #include #include #include "nova-simd/simd_memory.hpp" #include "utilities/malloc_aligned.hpp" namespace nova { struct buffer_wrapper { typedef std::size_t size_t; typedef float sample_t; typedef uint32_t uint; buffer_wrapper(void) = default; ~buffer_wrapper(void) { if (data) free_aligned(data); } void allocate(size_t frames, unsigned int channels); void free(void) { if (data) { free_aligned(data); data = nullptr; frames_ = 0; channels_ = 0; } } void zero(void) { assert (data); zerovec(data, frames_); } /** set sample for specific indices */ template void set_samples(unsigned int count, const size_t * indices, const float_type * values) { for (unsigned int i = 0; i != count; ++i) { size_t index = indices[i]; if (index < frames_) { sample_t value = values[i]; data[index] = value; } } } /** set continuous samples starting at position */ template void set_samples(size_t position, unsigned int count, const float_type * values) { sample_t * base = data + position; size_t avail = frames_ - position; count = std::min(size_t(count), avail); std::copy_n( base, count, values ); } /** set continuous samples starting at position to a single value */ template void fill_samples(size_t position, unsigned int count, const float_type value) { sample_t * base = data + position; size_t avail = frames_ - position; count = std::min(size_t(count), avail); std::fill_n( base, count, sample_t(value) ); } /* @{ */ void read_file(std::string const & file, size_t start_frame, size_t frames) { read_file(file.c_str(), start_frame, frames); } void read_file(const char * file, size_t start_frame, size_t frames); void read_file_channels(std::string const & file, size_t start_frame, size_t frames, unsigned int channel_count, unsigned int * channels) { read_file_channels(file.c_str(), start_frame, frames, channel_count, channels); } void read_file_channels(const char * file, size_t start_frame, size_t frames, unsigned int channel_count, unsigned int * channels); /* @} */ void write_file(const char * file, const char * header_format, const char * sample_format, size_t start_frame, size_t frames); sample_t * data = nullptr; size_t frames_ = 0; unsigned int channels_ = 0; int sample_rate_ = 0; }; class buffer_manager { public: buffer_manager(unsigned int max_buffers): buffers(max_buffers, buffer_wrapper()) {} void check_buffer_unused(int index) { if (buffers[index].data != nullptr) throw std::runtime_error("buffer already in use"); } void check_buffer_in_use(int index) { if (buffers[index].data == nullptr) throw std::runtime_error("buffer is not in use"); } void allocate_buffer(int index, unsigned int frames, unsigned int channels) { check_buffer_unused(index); buffers[index].allocate(frames, channels); } void read_buffer_allocate(int index, const char * file, size_t start_frame, size_t frames) { check_buffer_unused(index); buffers[index].read_file(file, start_frame, frames); } void read_buffer_channels_allocate(int index, const char * file, size_t start_frame, size_t frames, unsigned int channel_count, unsigned int * channels) { check_buffer_unused(index); buffers[index].read_file_channels(file, start_frame, frames, channel_count, channels); } void free_buffer(int index) { check_buffer_in_use(index); buffers[index].free(); } void zero_buffer(int index) { check_buffer_in_use(index); buffers[index].zero(); } buffer_wrapper & get_buffer(int index) { check_buffer_in_use(index); return buffers[index]; } template void set_samples(int index, unsigned int count, const size_t * indices, const float_type * values) { check_buffer_in_use(index); buffers[index].set_samples(count, indices, values); } template void set_samples(int index, size_t position, unsigned int count, const float_type * values) { check_buffer_in_use(index); buffers[index].set_samples(count, position, count, values); } template void fill_samples(int index, size_t position, unsigned int count, float_type value) { check_buffer_in_use(index); buffers[index].fill_samples(position, count, value); } void write_buffer(int index, const char * file, const char * header_format, const char * sample_format, size_t start_frame, size_t frames) { check_buffer_in_use(index); buffers[index].write_file(file, header_format, sample_format, start_frame, frames); } private: std::vector buffers; }; } /* namespace nova */ #endif /* SERVER_BUFFER_MANAGER_HPP */ SuperCollider-Source/server/supernova/server/dependency_graph_generator.hpp000644 000765 000024 00000017425 12756531745 030621 0ustar00crucialstaff000000 000000 // dependency graph generator // Copyright (C) 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_DEPENDENCY_GRAPH_GENERATOR_HPP #define SERVER_DEPENDENCY_GRAPH_GENERATOR_HPP #include "node_graph.hpp" #include "function_attributes.h" namespace nova { class dependency_graph_generator { typedef node_graph::dsp_thread_queue dsp_thread_queue; typedef thread_queue_item::successor_list successor_container; typedef std::vector > sequential_child_list; public: dsp_thread_queue * operator()(node_graph * graph) { bool has_parallelism = graph->root_group()->has_parallel_group_children(); /* pessimize: reserve enough memory for the worst case */ q = new node_graph::dsp_thread_queue(graph->synth_count_, has_parallelism); fill_queue(*graph->root_group()); // LATER: we could optimize the case when we do not have any paralleism return q; } private: dsp_thread_queue * q; void fill_queue(group & root_group) { if (root_group.has_synth_children()) fill_queue_recursive(root_group, successor_container(0), 0); } template HOT static inline int get_previous_activation_count(reverse_iterator it, reverse_iterator end, int previous_activation_limit) { reverse_iterator prev = it; for(;;) { ++prev; if (prev == end) return previous_activation_limit; // we are the first item, so we use the previous activiation limit server_node & node = *prev; if (node.is_synth()) return 1; else { abstract_group & grp = static_cast(node); int tail_nodes = grp.tail_nodes(); if (tail_nodes != 0) /* use tail nodes of previous group */ return tail_nodes; else /* skip empty groups */ continue; } } } successor_container fill_queue_recursive(abstract_group & grp, successor_container const & successors, size_t activation_limit) { if (grp.is_parallel()) return fill_queue_recursive(static_cast(grp), successors, activation_limit); else return fill_queue_recursive(static_cast(grp), successors, activation_limit); } HOT successor_container fill_queue_recursive(group & g, successor_container const & successors_from_parent, size_t previous_activation_limit) { assert (g.has_synth_children()); typedef server_node_list::reverse_iterator r_iterator; successor_container successors(successors_from_parent); size_t children = g.child_count(); sequential_child_list sequential_children; sequential_children.reserve(g.child_synth_count); for (r_iterator it = g.child_nodes.rbegin(); it != g.child_nodes.rend(); ++it) { server_node & node = *it; if (node.is_synth()) { r_iterator end_of_node = it; --end_of_node; // one element behind the last std::size_t node_count = 1; // we fill the child nodes in reverse order to an array for(;;) { sequential_children.push_back(&*it); ++it; if (it == g.child_nodes.rend()) break; // we found the beginning of this group if (!it->is_synth()) break; // we hit a child group, later we may want to add it's nodes, too? ++node_count; } --it; // we iterated one element too far, so we need to go back to the previous element assert(sequential_children.size() == node_count); auto seq_it = sequential_children.rbegin(); int activation_limit = get_previous_activation_count(it, g.child_nodes.rend(), previous_activation_limit); thread_queue_item * q_item = q->allocate_queue_item(queue_node(std::move(queue_node_data(static_cast(*seq_it++))), node_count), successors, activation_limit); queue_node & q_node = q_item->get_job(); // now we can add all nodes sequentially for(;seq_it != sequential_children.rend(); ++seq_it) q_node.add_node(static_cast(*seq_it)); sequential_children.clear(); assert(q_node.size() == node_count); /* advance successor list */ successors = successor_container(1); successors[0] = q_item; if (activation_limit == 0) q->add_initially_runnable(q_item); children -= node_count; } else { abstract_group & grp = static_cast(node); if (grp.has_synth_children()) { int activation_limit = get_previous_activation_count(it, g.child_nodes.rend(), previous_activation_limit); successors = fill_queue_recursive(grp, successors, activation_limit); } children -= 1; } } assert(children == 0); return successors; } HOT successor_container fill_queue_recursive(parallel_group & g, successor_container const & successors_from_parent, size_t previous_activation_limit) { assert (g.has_synth_children()); std::vector > collected_nodes; collected_nodes.reserve(g.child_synth_count + g.child_group_count * 16); // pessimize for (auto & node : g.child_nodes) { if (node.is_synth()) { thread_queue_item * q_item = q->allocate_queue_item(queue_node(std::move(queue_node_data(static_cast(&node)))), successors_from_parent, previous_activation_limit); if (previous_activation_limit == 0) q->add_initially_runnable(q_item); collected_nodes.push_back(q_item); } else { abstract_group & grp = static_cast(node); if (grp.has_synth_children()) { successor_container group_successors = fill_queue_recursive(grp, successors_from_parent, previous_activation_limit); for (unsigned int i = 0; i != group_successors.size(); ++i) collected_nodes.push_back(group_successors[i]); } } } successor_container ret(collected_nodes.size()); memcpy(ret.data->content, collected_nodes.data(), collected_nodes.size() * sizeof(thread_queue_item *)); return ret; } }; } /* namespacen nova */ #endif /* SERVER_DEPENDENCY_GRAPH_GENERATOR_HPP */ SuperCollider-Source/server/supernova/server/dsp_thread_queue_node.hpp000644 000765 000024 00000010163 12756531745 027572 0ustar00crucialstaff000000 000000 // dsp thread queue nodes // Copyright (C) 2008-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_DSP_THREAD_QUEUE_NODE_HPP #define SERVER_DSP_THREAD_QUEUE_NODE_HPP #include #include #include #include "server/synth.hpp" #include "../sc/sc_synth.hpp" #include "function_attributes.h" namespace nova { /* optimized for sc_synth, since we don't support other types of synths for now */ class queue_node_data { typedef std::uint_fast8_t thread_count_type; public: explicit queue_node_data(abstract_synth * node): node(static_cast(node)) {} explicit queue_node_data(queue_node_data const & rhs) = default; explicit queue_node_data(queue_node_data && rhs) = default; void operator()(thread_count_type index) { if (unlikely(!node->is_running())) return; node->perform(); } private: intrusive_ptr node; template friend class dsp_queue_node; }; /* implements runnable concept */ template > class dsp_queue_node { typedef std::vector::other> node_container; typedef std::uint_fast16_t node_count_type; typedef std::uint_fast8_t thread_count_type; public: explicit dsp_queue_node(queue_node_data && node): first( std::move(node) ) {} dsp_queue_node(queue_node_data && node, std::size_t container_size): first( std::move(node) ) { nodes.reserve(container_size-1); } HOT void operator()(thread_count_type thread_index) { first(thread_index); int remaining = node_count; if (remaining == 0) return; //fast-path queue_node_data * __restrict__ data = nodes.data(); if (remaining & 1) { (*data)(thread_index); if (remaining == 1) return; remaining -= 1; data += 1; } if (remaining & 2) { (*data)(thread_index); (*(data+1))(thread_index); if (remaining == 2) return; remaining -= 2; data += 2; } if (remaining & 4) { (*data)(thread_index); (*(data+1))(thread_index); (*(data+2))(thread_index); (*(data+3))(thread_index); if (remaining == 4) return; remaining -= 4; data += 4; } assert(remaining >= 8); assert((remaining % 8) == 0); for(;;) { (*data)(thread_index); (*(data+1))(thread_index); (*(data+2))(thread_index); (*(data+3))(thread_index); (*(data+4))(thread_index); (*(data+5))(thread_index); (*(data+6))(thread_index); (*(data+7))(thread_index); if (remaining == 8) return; remaining -= 8; data += 8; } } void add_node(abstract_synth * node) { nodes.emplace_back(std::move(queue_node_data(node))); ++node_count; } node_count_type size(void) const { return node_count + 1; } private: queue_node_data first; node_container nodes; node_count_type node_count = 0; }; } /* namespace nova */ #endif /* SERVER_DSP_THREAD_QUEUE_NODE_HPP */ SuperCollider-Source/server/supernova/server/group.hpp000644 000765 000024 00000031017 12756531745 024401 0ustar00crucialstaff000000 000000 // group // Copyright (C) 2008, 2009, 2010, 2011 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_GROUP_HPP #define SERVER_GROUP_HPP #include "memory_pool.hpp" #include "node_types.hpp" #include "dsp_thread_queue_node.hpp" #include "dsp_thread_queue/dsp_thread_queue.hpp" #include "utilities/exists.hpp" namespace nova { typedef nova::dsp_queue_node > queue_node; typedef nova::dsp_thread_queue_item >, rt_pool_allocator > thread_queue_item; typedef nova::dsp_thread_queue >, rt_pool_allocator > thread_queue; struct abstract_group_tag; typedef bi::list_base_hook, bi::tag > group_list_hook; typedef boost::intrusive::list, bi::base_hook > group_list; class abstract_group: public server_node, public group_list_hook { friend class dependency_graph_generator; protected: server_node_list child_nodes; group_list child_groups; const bool group_is_parallel; abstract_group(int node_id, bool is_parallel): server_node(node_id, false), group_is_parallel(is_parallel) {} public: virtual ~abstract_group(void); bool is_parallel(void) const { return group_is_parallel; } public: /* count the tail nodes to get activation count */ virtual int tail_nodes(void) const = 0; /* @{ */ /** pause/resume handling (set pause/resume on children) */ virtual void pause(void) override; virtual void resume(void) override; /* @} */ /* @{ */ /** child management */ void add_child(server_node * node); virtual void add_child(server_node * node, node_position_constraint const &) = 0; virtual void add_child(server_node * node, node_position) = 0; void replace_child(server_node * node, server_node * node_to_replace); bool has_child(const server_node * node) const; bool empty(void) const { return child_nodes.empty(); } /* returns true, if this or any of the child group has synth children */ bool has_synth_children(void) const { if (child_synth_count) return true; for (const auto & elem : child_groups) if (elem.has_synth_children()) return true; return false; } bool has_parallel_group_children(void) const { if (is_parallel()) return true; for (const auto & elem : child_groups) if (elem.has_parallel_group_children()) return true; return false; } std::size_t child_count(void) const { assert(child_group_count == child_groups.size()); assert(child_synth_count + child_group_count == child_nodes.size()); return child_synth_count + child_group_count; } template void apply_on_children(functor const & f) { for (auto & elem : child_nodes) f(elem); } template void apply_deep_on_children(functor const & f) { for (auto & elem : child_nodes) { if (elem.is_group()) { abstract_group & grp = static_cast(elem); grp.apply_deep_on_children(f); } f(elem); } } template void apply_on_children(functor const & f) const { for (const auto & elem : child_nodes) f(elem); } /* @} */ /* @{ */ void register_as_child(void) { parent_->child_groups.push_back(*this); } void unregister_as_child(void) { group_list_hook::unlink(); } /* @} */ public: server_node * next_node(server_node * node) { assert(has_child(node)); server_node_list::iterator next = ++server_node_list::s_iterator_to(*node); if (unlikely(next == child_nodes.end())) return nullptr; else return &(*next); } server_node * previous_node(server_node * node) { assert(has_child(node)); server_node_list::iterator it = server_node_list::s_iterator_to(*node); if (unlikely(it == child_nodes.begin())) return nullptr; else return &(*--it); } void free_children(void) { child_nodes.clear_and_dispose(std::mem_fn(&server_node::clear_parent)); assert(child_synth_count == 0); assert(child_group_count == 0); } void free_synths_deep(void) { child_nodes.remove_and_dispose_if(std::mem_fn(&server_node::is_synth), std::mem_fn(&server_node::clear_parent)); /* now there are only group classes */ for(auto & elem : child_nodes) { abstract_group * group = static_cast(&elem); group->free_synths_deep(); } assert(child_synth_count == 0); } /** remove node from child_nodes, clear node->parent */ void remove_child(server_node * node); /* @} */ void set(slot_index_t slot_id, float val) override; void set(const char * slot_str, float val) override; void set(const char * slot_str, size_t hashed_str, float val) override; void set_control_array(slot_index_t slot_str, size_t count, float * val) override; void set_control_array(const char * slot_str, size_t count, float * val) override; void set_control_array(const char * slot_str, size_t hashed_str, size_t count, float * val) override; void set_control_array_element(slot_index_t slot_str, size_t count, float val) override; void set_control_array_element(const char * slot_str, size_t count, float val) override; void set_control_array_element(const char * slot_str, size_t hashed_str, size_t count, float val) override; /* move node to head or tail of target */ template static void move_to_head_or_tail(server_node * node, abstract_group * target) { assert((Position == head) || (Position == tail)); server_node_list::const_iterator target_iterator = (Position == head) ? target->child_nodes.begin() : target->child_nodes.end(); server_node_list::const_iterator node_iterator = server_node_list::s_iterator_to(*node); abstract_group * node_parent = node->get_parent(); if (node_parent != target) { if (node->is_synth()) { node_parent->child_synth_count -= 1; target->child_synth_count += 1; } else { node_parent->child_group_count -= 1; target->child_group_count += 1; group_list::const_iterator group_target_iterator = (Position == head) ? target->child_groups.begin() : target->child_groups.end(); abstract_group * node_as_group = static_cast(node); target->child_groups.splice(group_target_iterator, node_parent->child_groups, group_list::s_iterator_to(*node_as_group)); } node->parent_ = target; } target->child_nodes.splice(target_iterator, node_parent->child_nodes, node_iterator); } template static void move_before_or_after(server_node * node, server_node * target) { assert((Relation == before) || (Relation == after)); abstract_group * target_parent = node->get_parent(); if (Relation == after && target->next_node() == nullptr) { // for the sake of simplicity, move the node to the tail of the target's parent group move_to_head_or_tail(node, target_parent); return; } server_node * node_behind = (Relation == before) ? target : target->next_node(); assert(node_behind); server_node_list::const_iterator target_iterator = server_node_list::s_iterator_to(*node_behind); server_node_list::const_iterator node_iterator = server_node_list::s_iterator_to(*node); abstract_group * node_parent = node->get_parent(); if (node_parent != target_parent) { if (node->is_synth()) { node_parent->child_synth_count -= 1; target_parent->child_synth_count += 1; } else { node_parent->child_group_count -= 1; target_parent->child_group_count += 1; group_list::const_iterator group_target_iterator = group_list::s_iterator_to(*static_cast(node)); target_parent->child_groups.splice(target_parent->child_groups.end(), node_parent->child_groups, group_target_iterator); } node->parent_ = target_parent; } target_parent->child_nodes.splice(target_iterator, node_parent->child_nodes, node_iterator); } friend class node_graph; std::size_t child_synth_count = 0, child_group_count = 0; }; inline void server_node::clear_parent(void) { if (is_synth()) --parent_->child_synth_count; else { --parent_->child_group_count; static_cast(this)->unregister_as_child(); } parent_ = nullptr; release(); } inline void server_node::set_parent(abstract_group * parent) { add_ref(); assert(parent_ == 0); parent_ = parent; if (is_synth()) ++parent->child_synth_count; else { ++parent->child_group_count; static_cast(this)->register_as_child(); } } inline server_node * server_node::previous_node(void) { return parent_->previous_node(this); } inline server_node * server_node::next_node(void) { return parent_->next_node(this); } inline const server_node * server_node::previous_node(void) const { return const_cast(this)->previous_node(); } inline const server_node * server_node::next_node(void) const { return const_cast(this)->next_node(); } class group: public abstract_group { public: group(int node_id): abstract_group(node_id, false) {} const server_node * head_node(void) const { return &*child_nodes.begin(); } const server_node * tail_node(void) const { return &*child_nodes.rbegin(); } private: void add_child(server_node * node, node_position_constraint const & constraint) override; void add_child(server_node * node, node_position) override; friend class dependency_graph_generator; virtual int tail_nodes(void) const override { if (empty()) return 0; for (server_node_list::const_reverse_iterator it = child_nodes.rbegin(); it != child_nodes.rend(); ++it) { const server_node * tail = &*it; if (tail->is_synth()) return 1; const abstract_group * tail_group = static_cast(tail); if (!tail_group->empty()) return tail_group->tail_nodes(); } return 0; } }; class parallel_group: public abstract_group { public: parallel_group(int node_id): abstract_group(node_id, true) {} private: void add_child(server_node * node, node_position_constraint const & constraint) override; void add_child(server_node * node, node_position) override; virtual int tail_nodes(void) const override; friend class dependency_graph_generator; }; } /* namespace nova */ #endif /* SERVER_GROUP_HPP */ SuperCollider-Source/server/supernova/server/main.cpp000644 000765 000024 00000027111 12766171707 024163 0ustar00crucialstaff000000 000000 // nova server // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include #include #include #include #include #include "server.hpp" #include "server_args.hpp" #include "SC_Version.hpp" #include "../sc/sc_ugen_factory.hpp" #include "../sc/sc_synth_definition.hpp" #include "../utilities/utils.hpp" #ifdef __linux__ #include #include #endif #ifdef __APPLE__ # include # include #endif #if (_POSIX_MEMLOCK - 0) >= 200112L # include # include #endif #include "SC_DirUtils.h" #ifndef _WIN32 const char pathSeparator[] = ":"; #else const char pathSeparator[] = ";"; #endif using namespace nova; using namespace std; namespace { /* signal handler */ void terminate(int i) { instance->terminate(); } void register_signal_handler(void) { void (*prev_fn)(int); prev_fn = ::signal (SIGINT, terminate); } #ifdef JACK_BACKEND void connect_jack_ports(void) { using namespace boost; using namespace boost::algorithm; const char * input_string = getenv("SC_JACK_DEFAULT_INPUTS"); if (input_string) { string input_port(input_string); if (input_port.find(",") == string::npos) instance->connect_all_inputs(input_port.c_str()); else { vector portnames; boost::split(portnames, input_port, is_any_of(",")); for (size_t i = 0; i != portnames.size(); ++i) instance->connect_input(i, portnames[i].c_str()); } } const char * output_string = getenv("SC_JACK_DEFAULT_OUTPUTS"); if (output_string) { string output_port(output_string); if (output_port.find(",") == string::npos) instance->connect_all_outputs(output_port.c_str()); else { vector portnames; boost::split(portnames, output_port, is_any_of(",")); for (size_t i = 0; i != portnames.size(); ++i) instance->connect_output(i, portnames[i].c_str()); } } } void get_jack_names(server_arguments const & args, string & server_name, string & client_name) { client_name = "supernova"; if (!args.hw_name.empty() && !args.hw_name[0].empty()) { vector names; boost::split(names, args.hw_name[0], boost::algorithm::is_any_of(":")); if (names.size() == 1) { server_name = names[0]; } else if (names.size() == 2) { server_name = names[0]; client_name = names[1]; } else { cout << "Error: cannot parse hardware device name. Using defaults." << endl; } } } void start_audio_backend(server_arguments const & args) { string server_name, client_name; get_jack_names(args, server_name, client_name); instance->open_client(server_name, client_name, args.input_channels, args.output_channels, args.blocksize); instance->prepare_backend(); instance->activate_audio(); unsigned int real_sampling_rate = instance->get_samplerate(); if (args.samplerate && args.samplerate != real_sampling_rate) { cout << "samplerate mismatch between command line argument and jack" << endl; cout << "forcing samplerate of " << real_sampling_rate << "Hz" << endl; server_arguments::set_samplerate((uint32_t)real_sampling_rate); sc_factory->reset_sampling_rate(real_sampling_rate); } connect_jack_ports(); } #elif defined(PORTAUDIO_BACKEND) void start_audio_backend(server_arguments const & args) { int input_channels = args.input_channels; int output_channels = args.output_channels; std::string input_device, output_device; if (args.hw_name.empty()) { boost::tie(input_device, output_device) = instance->default_device_names(); } else if (args.hw_name.size() == 1) { input_device = output_device = args.hw_name[0]; } else { input_device = args.hw_name[0]; output_device = args.hw_name[1]; } cout << "opening portaudio device name: "; cout << input_device << " / " << output_device << endl; if (input_device == "nil") { input_device.clear(); input_channels = 0; } if (output_device == "nil") { output_device.clear(); output_channels = 0; } cout << "opening portaudio device name: "; cout << input_device << " / " << output_device << endl; bool success = instance->open_stream(input_device, input_channels, output_device, output_channels, args.samplerate, args.blocksize, args.hardware_buffer_size); if (!success) { cout << "could not open portaudio device name: " << input_device << " / " << output_device << endl; exit(1); } cout << "opened portaudio device name: "; cout << input_device << " / " << output_device << endl; instance->report_latency(); instance->prepare_backend(); instance->activate_audio(); } #else void start_audio_backend(server_arguments const & args) {} #endif boost::filesystem::path resolve_home(void) { #ifdef __linux__ wordexp_t wexp; int status = wordexp("~", &wexp, 0); if (status || wexp.we_wordc != 1) throw runtime_error("cannot detect home directory"); path home (wexp.we_wordv[0]); wordfree(&wexp); return home; #elif defined(__APPLE__) path home(getenv("HOME")); return home; #elif defined(_WIN32) path home(getenv("USERPROFILE")); return home; #else #error platform not supported #endif } void set_plugin_paths(server_arguments const & args, nova::sc_ugen_factory * factory) { if (!args.ugen_paths.empty()) { for(path const & path1 : args.ugen_paths){ vector directories; boost::split(directories, path1.string(), boost::is_any_of(pathSeparator)); for(string const & path : directories){ factory->load_plugin_folder(path); } } } else { #ifdef __linux__ const path home = resolve_home(); std::vector folders = { "/usr/local/lib/SuperCollider/plugins", "/usr/lib/SuperCollider/plugins", home / "/.local/share/SuperCollider/Extensions", home / "share/SuperCollider/plugins" }; for (path const & folder : folders) factory->load_plugin_folder(folder); #else char plugin_dir[MAXPATHLEN]; sc_GetResourceDirectory(plugin_dir, MAXPATHLEN); factory->load_plugin_folder(path(plugin_dir) / "plugins"); char extension_dir[MAXPATHLEN]; sc_GetSystemExtensionDirectory(extension_dir, MAXPATHLEN); factory->load_plugin_folder(path(extension_dir) / "plugins"); sc_GetUserExtensionDirectory(extension_dir, MAXPATHLEN); factory->load_plugin_folder(path(extension_dir) / "plugins"); #endif } #ifndef NDEBUG cout << "Unit Generators initialized" << endl; #endif } void load_synthdef_folder(nova_server & server, path const & folder, bool verbose) { if (verbose) std::cout << "Loading synthdefs from path: " << folder.string() << std::endl; register_synthdefs(server, std::move(sc_read_synthdefs_dir(folder))); } void load_synthdefs(nova_server & server, server_arguments const & args) { using namespace std; #ifndef NDEBUG auto start_time = std::chrono::high_resolution_clock::now(); #endif if (args.load_synthdefs) { const char * env_synthdef_path = getenv("SC_SYNTHDEF_PATH"); vector directories; if (env_synthdef_path) { boost::split(directories, env_synthdef_path, boost::is_any_of(pathSeparator)); } else { char resourceDir[MAXPATHLEN]; if(sc_IsStandAlone()) sc_GetResourceDirectory(resourceDir, MAXPATHLEN); else sc_GetUserAppSupportDirectory(resourceDir, MAXPATHLEN); directories.push_back(path(resourceDir) / "synthdefs"); } for(path const & directory : directories) load_synthdef_folder(server, directory, args.verbosity > 0); } #ifndef NDEBUG auto end_time = std::chrono::high_resolution_clock::now(); cout << "SynthDefs loaded in " << std::chrono::duration_cast(end_time - start_time).count() << " ms" << endl; #endif } void drop_rt_scheduling() { bool success = nova::thread_set_priority(0); if (!success) cout << "Warning: cannot drop rt priority" << endl; } void enable_core_dumps(void) { #ifdef __LINUX__ rlimit core_limit = { RLIM_INFINITY, RLIM_INFINITY }; assert( setrlimit( RLIMIT_CORE, &core_limit ) == 0 ); // enable core dumps for debug builds #endif } void lock_memory(server_arguments const & args) { #if (_POSIX_MEMLOCK - 0) >= 200112L if (args.memory_locking) { bool lock_memory = false; rlimit limit; int failure = getrlimit(RLIMIT_MEMLOCK, &limit); if (failure) printf("getrlimit failure\n"); else { if (limit.rlim_cur == RLIM_INFINITY and limit.rlim_max == RLIM_INFINITY) lock_memory = true; else printf("memory locking disabled due to resource limiting\n"); if (lock_memory) { if (mlockall(MCL_FUTURE) != -1) printf("memory locking enabled.\n"); } } } #endif } } /* namespace */ int main(int argc, char * argv[]) { drop_rt_scheduling(); // when being called from sclang, we inherit a low rt-scheduling priority. but we don't want it! enable_core_dumps(); server_arguments::initialize(argc, argv); server_arguments const & args = server_arguments::instance(); if(args.dump_version){ cout << "supernova " << SC_VersionString() << " (" << SC_BuildString() << ")" << endl; return 0; } #ifdef __APPLE__ ProcessSerialNumber psn; if (GetCurrentProcess(&psn) == noErr) { TransformProcessType(&psn, kProcessTransformToUIElementApplication); } SC::Apple::disableAppNap(); #endif rt_pool.init(args.rt_pool_size * 1024, args.memory_locking); lock_memory(args); cout << "Supernova booting" << endl; #ifndef NDEBUG cout << "compiled for debugging" << endl; #endif server_shared_memory_creator::cleanup(args.port()); nova_server server(args); register_signal_handler(); set_plugin_paths(args, sc_factory.get()); load_synthdefs(server, args); if (!args.non_rt) { try { start_audio_backend(args); cout << "Supernova ready" << endl; } catch (exception const & e) { cout << "Error: " << e.what() << endl; exit(1); } server.run(); } else server.run_nonrt_synthesis(args); return 0; } SuperCollider-Source/server/supernova/server/memory_pool.cpp000644 000765 000024 00000001643 12321461511 025560 0ustar00crucialstaff000000 000000 // real-time memory pool, implementation // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include "memory_pool.hpp" namespace nova { simple_pool rt_pool; } /* namespace nova */ SuperCollider-Source/server/supernova/server/memory_pool.hpp000644 000765 000024 00000005727 12756531745 025617 0ustar00crucialstaff000000 000000 // real-time memory pool // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_MEMORY_POOL_HPP #define SERVER_MEMORY_POOL_HPP #include "../utilities/simple_pool.hpp" namespace nova { extern simple_pool rt_pool; /* real-time memory pool */ /** stl-compliant allocator class, using the rt_pool */ template class rt_pool_allocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef rt_pool_allocator other; }; rt_pool_allocator() throw() = default; rt_pool_allocator(const rt_pool_allocator&) throw() = default; ~rt_pool_allocator() throw() = default; template rt_pool_allocator(const rt_pool_allocator&) throw() {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } pointer allocate(size_type size, const void* hint = nullptr) { pointer ret = static_cast(rt_pool.malloc(size * sizeof(T))); if (ret == nullptr) throw std::bad_alloc(); return ret; } pointer reallocate(pointer p, size_type size, void* hint = nullptr) { return static_cast(rt_pool.realloc(p, size)); } void deallocate(pointer p, size_type n) { rt_pool.free(p); } size_type max_size() const throw() { return rt_pool.get_max_size(); } void construct(pointer p, const T& val = T()) { new(p) T(val); } template< class U, class... Args > void construct( U* p, Args&&... args ) { ::new((void *)p) U(std::forward(args)...); } void destroy(pointer p) { p->~T(); } bool operator==(rt_pool_allocator const & rhs) { return true; } template bool operator==(AllocatorType const & rhs) { return false; } }; } /* namespace nova */ #endif /* SERVER_MEMORY_POOL_HPP */ SuperCollider-Source/server/supernova/server/node_graph.cpp000644 000765 000024 00000015550 12756531745 025352 0ustar00crucialstaff000000 000000 // node graph, implementation // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include "dependency_graph_generator.hpp" #include "dsp_thread_queue_node.hpp" #include "node_graph.hpp" #include "synth.hpp" #include "utilities/exists.hpp" #include "dsp_thread_queue/dsp_thread_queue.hpp" namespace nova { void node_graph::add_node(server_node * n) { node_position_constraint to_root = std::make_pair(&root_group_, head); add_node(n, to_root, [](server_node & node){}); } void node_graph::add_node(server_node * n, node_position_constraint const & constraint) { add_node(n, constraint, [](server_node & node){}); } node_graph::dsp_thread_queue_ptr node_graph::generate_dsp_queue(void) { dependency_graph_generator gen; node_graph::dsp_thread_queue * ret = gen(this); return dsp_thread_queue_ptr(ret); } void node_graph::synth_reassign_id(int32_t node_id) { node_set_type::iterator it = node_set.find(node_id, hash_node(), equal_node()); if (it == node_set.end()) throw std::runtime_error("node id not found"); server_node * node = &(*it); if (!node->is_synth()) return; boost::hash hasher; int32_t hidden_id = -std::abs(node_id); while (!node_id_available(hidden_id)) hidden_id = -std::abs(hasher(node_id)); assert(hidden_id < 0); node_set.erase(*node); node->reset_id(hidden_id); node_set.insert(*node); } int32_t node_graph::generate_node_id(void) { int32_t new_id; do { for (;;) { new_id = -std::abs(server_node::hash(generated_id)); if (likely (new_id != generated_id)) break; generated_id -= 1; } } while (!node_id_available(new_id)); generated_id = new_id; return generated_id; } abstract_group::~abstract_group(void) { while (!child_nodes.empty()) { server_node & node = child_nodes.front(); remove_child(&node); } } void abstract_group::pause(void) { for (server_node & node : child_nodes) node.pause(); } void abstract_group::resume(void) { for (server_node & node : child_nodes) node.resume(); } void abstract_group::add_child(server_node * node) { assert (not has_child(node)); child_nodes.push_front(*node); node->set_parent(this); } void abstract_group::replace_child(server_node * node, server_node * node_to_replace) { assert (not has_child(node)); assert (has_child(node_to_replace)); server_node_list::iterator position_of_old_element = server_node_list::s_iterator_to(*node_to_replace); child_nodes.insert(position_of_old_element, *node); node->set_parent(this); remove_child(node_to_replace); } bool abstract_group::has_child(const server_node * node) const { if (!node->server_node::parent_hook::is_linked()) return false; /* find node in container */ for (const auto & elem : child_nodes) { if (&elem == node) return true; } return false; } void abstract_group::remove_child(server_node * node) { assert (has_child(node)); node->server_node::parent_hook::unlink(); node->clear_parent(); } void abstract_group::set(slot_index_t slot_id, float val) { for(auto & elem : child_nodes) elem.set(slot_id, val); } void abstract_group::set(const char * slot_str, float val) { size_t hashed_str = string_hash(slot_str); for(auto & elem : child_nodes) elem.set(slot_str, hashed_str, val); } void abstract_group::set(const char * slot_str, std::size_t hashed_str, float val) { for(auto & elem : child_nodes) elem.set(slot_str, hashed_str, val); } void abstract_group::set_control_array(const char * slot_str, size_t count, float * val) { size_t hashed_str = string_hash(slot_str); set_control_array(slot_str, hashed_str, count, val); } void abstract_group::set_control_array(const char * slot_str, std::size_t hashed_str, size_t count, float * val) { for(auto & elem : child_nodes) elem.set_control_array(slot_str, hashed_str, count, val); } void abstract_group::set_control_array(slot_index_t slot_id, size_t count, float * val) { for(auto & elem : child_nodes) elem.set_control_array(slot_id, count, val); } void abstract_group::set_control_array_element(const char * slot_str, size_t index, float val) { size_t hashed_str = string_hash(slot_str); set_control_array_element(slot_str, hashed_str, index, val); } void abstract_group::set_control_array_element(const char * slot_str, std::size_t hashed_str, size_t index, float val) { for(auto & elem : child_nodes) elem.set_control_array_element(slot_str, hashed_str, index, val); } void abstract_group::set_control_array_element(slot_index_t slot_id, size_t index, float val) { for(auto & elem : child_nodes) elem.set_control_array_element(slot_id, index, val); } int parallel_group::tail_nodes(void) const { int ret = child_synth_count; for(const auto & elem : child_groups) ret += elem.tail_nodes(); return ret; } void group::add_child(server_node * node, node_position_constraint const & constraint) { assert (not has_child(node)); server_node * ref = constraint.first; node_position position = constraint.second; assert ((position == after) || (position == before) || (position == insert)); server_node_list::const_iterator it = child_nodes.iterator_to(*ref); if (position == after) ++it; child_nodes.insert(it, *node); node->set_parent(this); } void parallel_group::add_child(server_node * node, node_position_constraint const & constraint) { abstract_group::add_child(node); /* later warn about this! */ } void group::add_child(server_node * node, node_position position) { assert (not has_child(node)); assert((position == head) || (position == tail)); if (position == head) child_nodes.push_front(*node); else child_nodes.push_back(*node); node->set_parent(this); } void parallel_group::add_child(server_node * node, node_position position) { abstract_group::add_child(node); /* later warn about this! */ } } /* namespace nova */ SuperCollider-Source/server/supernova/server/node_graph.hpp000644 000765 000024 00000020100 12756531745 025342 0ustar00crucialstaff000000 000000 // node graph // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_NODE_GRAPH_HPP #define SERVER_NODE_GRAPH_HPP #include #include #include "dsp_thread_queue_node.hpp" #include "group.hpp" #include "node_types.hpp" #include "dsp_thread_queue/dsp_thread_queue.hpp" namespace nova { class node_graph { private: group root_group_ = {0}; friend class dependency_graph_generator; static const std::size_t node_set_bucket_count = 4096; public: typedef thread_queue_item dsp_thread_queue_item; typedef thread_queue dsp_thread_queue; /** \brief ctor * * - initialize root node */ node_graph(void): node_set(node_set_type::bucket_traits(node_buckets, node_set_bucket_count)) { node_set.insert(root_group_); root_group_.add_ref(); } ~node_graph() { assert(root_group_.child_count() == 0); } uint32_t synth_count(void) const { return synth_count_; } uint32_t group_count(void) const { return group_count_; } template void add_node(server_node * node, node_position_constraint const & constraint, Functor const & doOnFree) { server_node * reference_node = constraint.first; node_position position = constraint.second; std::pair< node_set_type::iterator, bool > inserted = node_set.insert(*node); node->add_ref(); assert(inserted.second == true); /* node id already present (should be checked earlier)! */ switch (position) { case before: case after: { abstract_group * parent = reference_node->parent_; parent->add_child(node, constraint); break; } case head: case tail: { abstract_group * group = static_cast(reference_node); group->add_child(node, position); break; } case insert: { abstract_group * group = static_cast(reference_node); group->add_child(node); break; } case replace: { const bool reference_node_is_group = reference_node->is_group(); if (reference_node_is_group) { abstract_group * reference_group = static_cast(reference_node); reference_group->apply_deep_on_children( [&] (server_node & node) { doOnFree(node); }); } doOnFree(*reference_node); abstract_group * node_parent = reference_node->parent_; node_parent->replace_child(node, reference_node); if (reference_node_is_group) group_count_ -= 1; else synth_count_ -= 1; break; } default: assert(false); /* this point should not be reached! */ } if (node->is_synth()) synth_count_ += 1; else group_count_ += 1; } void add_node(server_node * node, node_position_constraint const & constraint); void add_node(server_node * s); void remove_node(server_node * n) { remove_node(n, [](server_node &){}); } template void remove_node(server_node * node, Functor const & doOnFree) { if (!node->is_synth()) group_free_all(static_cast(node), doOnFree); /** \todo recursively remove nodes from node_set * for now this is done by the auto-unlink hook * */ doOnFree(*node); abstract_group * parent = node->parent_; parent->remove_child(node); if (node->is_synth()) synth_count_ -= 1; else group_count_ -= 1; release_node_id(node); } void dump(std::string const & filename); group * root_group(void) { return &root_group_; } typedef std::unique_ptr dsp_thread_queue_ptr; dsp_thread_queue_ptr generate_dsp_queue(void); server_node * find_node(int32_t node_id) { node_set_type::iterator it = node_set.find(node_id, hash_node(), equal_node()); if (it == node_set.end()) return nullptr; return &(*it); } bool node_id_available(int32_t node_id) { node_set_type::iterator it = node_set.find(node_id, hash_node(), equal_node()); return (it == node_set.end()); } void synth_reassign_id(int32_t node_id); /** generate new hidden (negative) node id */ int32_t generate_node_id(void); private: int32_t generated_id = -2; public: abstract_group * find_group(int32_t node_id) { server_node * node = find_node(node_id); if (!node || node->is_synth()) return nullptr; else return static_cast(node); } abstract_synth * find_synth(int32_t node_id) { server_node * node = find_node(node_id); if (node && node->is_synth()) return static_cast(node); else return nullptr; } void group_free_all(abstract_group * group) { group_free_all(group, [](server_node &){}); } void group_free_deep(abstract_group * group) { group_free_deep(group, [](server_node &){}); } template void group_free_all(abstract_group * group, Functor const & doOnFree) { size_t synths = 0, groups = 0; group->apply_deep_on_children([&](server_node & node) { release_node_id(&node); if (node.is_synth()) synths += 1; else groups += 1; doOnFree(node); }); group->free_children(); synth_count_ -= synths; group_count_ -= groups; } template void group_free_deep(abstract_group * group, Functor const & doOnFree) { size_t synths = 0; group->apply_deep_on_children([&](server_node & node) { if (node.is_synth()) { release_node_id(&node); synths += 1; } doOnFree(node); }); group->free_synths_deep(); synth_count_ -= synths; } void release_node_id(server_node * node) { node_set.erase(*node); node->release(); } private: struct equal_node { bool operator()(server_node const & lhs, int32_t const & rhs) const { return lhs.node_id == rhs; } bool operator()(int32_t const &lhs, server_node const & rhs) const { return lhs == rhs.node_id; } }; struct hash_node { std::size_t operator()(int32_t value) { return server_node::hash(value); } }; typedef boost::intrusive::unordered_set< server_node, boost::intrusive::constant_time_size, boost::intrusive::power_2_buckets > node_set_type; uint32_t synth_count_ = 0, group_count_ = 0; node_set_type::bucket_type node_buckets[node_set_bucket_count]; node_set_type node_set; }; } /* namespace nova */ #endif /* SERVER_NODEGRAPH_HPP */ SuperCollider-Source/server/supernova/server/node_types.hpp000644 000765 000024 00000013263 12756531745 025421 0ustar00crucialstaff000000 000000 // node types // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_NODE_TYPES_HPP #define SERVER_NODE_TYPES_HPP #include #include #include #include "memory_pool.hpp" #include "synth_definition.hpp" #include "utilities/static_pool.hpp" namespace nova { class server_node; class abstract_group; class group; namespace bi = boost::intrusive; typedef boost::intrusive::list > server_node_list; class server_node: public bi::list_base_hook >, /* group member */ public bi::unordered_set_base_hook > /* for node_id mapping */ { protected: server_node(int32_t node_id, bool type): node_id(node_id), node_is_synth(type), use_count_(0) {} virtual ~server_node(void) { assert(parent_ == 0); } /* @{ */ /** node id handling */ void reset_id(int32_t new_id) { node_id = new_id; } public: int32_t node_id; int32_t id(void) const { return node_id; } /* @} */ typedef bi::list_base_hook > parent_hook; /* @{ */ /** node_id mapping */ friend std::size_t hash_value(server_node const & that) { return hash(that.id()); } static int32_t hash(int32_t id) { return id * 2654435761U; // knuth hash, 32bit should be enough } friend bool operator< (server_node const & lhs, server_node const & rhs) { return lhs.node_id < rhs.node_id; } friend bool operator== (server_node const & lhs, server_node const & rhs) { return lhs.node_id == rhs.node_id; } /* @} */ bool is_synth(void) const { return node_is_synth; } bool is_group(void) const { return !node_is_synth; } /* @{ */ /* set a scalar slot */ virtual void set(slot_index_t slot_id, float val) = 0; virtual void set(const char * slot_str, float val) = 0; virtual void set(const char * slot_str, size_t hashed_str, float val) = 0; /* @} */ /* @{ */ /* set an arrayed slot from array */ virtual void set_control_array(slot_index_t slot_str, size_t n, float * values) = 0; virtual void set_control_array(const char * slot_str, size_t n, float * values) = 0; virtual void set_control_array(const char * slot_str, size_t hashed_str, size_t n, float * values) = 0; /* @} */ /* @{ */ /* set an element of an arrayed slot */ virtual void set_control_array_element(slot_index_t slot_str, size_t n, float values) = 0; virtual void set_control_array_element(const char * slot_str, size_t n, float values) = 0; virtual void set_control_array_element(const char * slot_str, size_t hashed_str, size_t n, float values) = 0; /* @} */ /* @{ */ /** group traversing */ inline const server_node * previous_node(void) const; inline server_node * previous_node(void); inline const server_node * next_node(void) const; inline server_node * next_node(void); /* @} */ private: const bool node_is_synth; /** support for pausing node */ /* @{ */ bool running_ = true; public: virtual void pause(void) { running_ = false; } virtual void resume(void) { running_ = true; } bool is_running(void) const { return running_; } /* @} */ private: friend class node_graph; friend class abstract_group; friend class group; friend class parallel_group; public: /* @{ */ /** parent group handling */ const abstract_group * get_parent(void) const { return parent_; } abstract_group * get_parent(void) { return parent_; } inline void set_parent(abstract_group * parent); inline void clear_parent(void); /* @} */ private: abstract_group * parent_ = nullptr; public: /* memory management for server_nodes */ /* @{ */ inline void * operator new(std::size_t size) { return rt_pool.malloc(size); } inline void operator delete(void * p) { rt_pool.free(p); } /* @} */ public: /* refcountable */ /* @{ */ void add_ref(void) { ++use_count_; } void release(void) { if(unlikely(--use_count_ == 0)) delete this; } private: boost::detail::atomic_count use_count_; /* @} */ }; inline void intrusive_ptr_add_ref(server_node * p) { p->add_ref(); } inline void intrusive_ptr_release(server_node * p) { p->release(); } enum node_position { head = 0, tail = 1, before = 2, after = 3, replace = 4, insert = 5 /* for pgroups */ }; typedef std::pair node_position_constraint; } /* namespace nova */ #endif /* SERVER_NODE_TYPES_HPP */ SuperCollider-Source/server/supernova/server/nrt_synthesis.hpp000644 000765 000024 00000013605 12756531745 026164 0ustar00crucialstaff000000 000000 // Copyright (C) 2010-2013 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_NRT_SYNTHESIS_HPP #define SERVER_NRT_SYNTHESIS_HPP #include #include #include #include #include #include #include "server_args.hpp" #include "server.hpp" #include "audio_backend/sndfile_backend.hpp" #include "sc/sc_plugin_interface.hpp" #include "../../common/SC_SndFileHelpers.hpp" #include "../../include/plugin_interface/SC_InlineUnaryOp.h" namespace nova { struct non_rt_functor { static inline void init_thread(void) { realtime_engine_functor::init_thread(); } static inline void run_tick(void) { run_scheduler_tick(); instance->increment_logical_time(); } }; struct non_realtime_synthesis_engine { typedef std::string string; non_realtime_synthesis_engine(server_arguments const & args) { int format = headerFormatFromString(args.header_format.c_str()) | sampleFormatFromString(args.sample_format.c_str()); string input_file = args.input_file; if (input_file == string("_")) input_file.clear(); backend.open_client(input_file, args.output_file, args.samplerate, format, args.output_channels, args.blocksize); command_stream.open(args.command_file.c_str(), std::fstream::in | std::fstream::binary); has_inputs = !input_file.empty(); samples_per_block = args.blocksize; prepare_backend(args.blocksize, args.input_channels, args.output_channels); } void prepare_backend(int blocksize, int input_channels, int output_channels) { std::vector inputs, outputs; for (int channel = 0; channel != input_channels; ++channel) inputs.push_back(sc_factory->world.mAudioBus + (blocksize * (output_channels + channel))); backend.input_mapping(inputs.begin(), inputs.end()); for (int channel = 0; channel != output_channels; ++channel) outputs.push_back(sc_factory->world.mAudioBus + blocksize * channel); backend.output_mapping(outputs.begin(), outputs.end()); } void run(void) { using namespace std; using namespace std::chrono; const int reserved_packed_size = 16384; std::vector packet_vector(reserved_packed_size, 0); printf("\nPerforming non-rt synthesis:\n"); backend.activate_audio(); auto start_time = steady_clock::now(); while (!command_stream.eof()) { boost::endian::big_int32_t packet_size; command_stream.read((char*)&packet_size, sizeof(packet_size)); assert(packet_size > 0); const bool huge_packet = (packet_size >= reserved_packed_size); if (huge_packet) packet_vector.resize(packet_size); command_stream.read(packet_vector.data(), packet_size); time_tag bundle_time = instance->handle_bundle_nrt(packet_vector.data(), packet_size); size_t seconds = bundle_time.get_secs(); size_t nano_seconds = bundle_time.get_nanoseconds(); printf(" Next OSC bundle: %zu.%09zu\n", seconds, nano_seconds); while (instance->current_time() < bundle_time) { if (instance->quit_requested()) goto done; if (has_inputs) backend.audio_fn(samples_per_block); else backend.audio_fn_noinput(samples_per_block); } if (huge_packet) packet_vector.resize(16384); } done: backend.deactivate_audio(); auto end_time = steady_clock::now(); std::string elapsed_string = format_duration ( end_time - start_time ); printf("\nNon-rt synthesis finished in %s\n", elapsed_string.c_str()); auto peaks = backend.get_peaks(); printf("Peak summary:\n"); for (size_t channel = 0; channel != peaks.size(); ++channel) { auto amplitude = peaks[channel]; printf(" Channel %zu: %gdB\n", channel, sc_ampdb(amplitude)); } } template static std::string format_duration(Duration const & duration) { using namespace boost; using namespace std::chrono; auto elapsed_hours = duration_cast(duration); auto remain = duration - elapsed_hours; auto elapsed_minutes = duration_cast(remain); remain -= elapsed_minutes; auto elapsed_nanoseconds = duration_cast(remain); double seconds = elapsed_nanoseconds.count() * 1e-9; if (elapsed_hours.count()) return str( format("%|d|h %|d|m %|0.3f|s") % elapsed_hours.count() % elapsed_minutes.count() % seconds ); if (elapsed_minutes.count()) return str( format("%|d|m %|.3f|s") % elapsed_minutes.count() % seconds ); else return str( format("%|.3f|s") % seconds ); } private: sndfile_backend backend; std::fstream command_stream; int samples_per_block; bool has_inputs; }; } // namespace nova #endif /* SERVER_NRT_SYNTHESIS_HPP */ SuperCollider-Source/server/supernova/server/sample_types.hpp000644 000765 000024 00000003051 12321461511 025724 0ustar00crucialstaff000000 000000 // basic types for the ugen system // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SAMPLE_TYPES_HPP #define SERVER_SAMPLE_TYPES_HPP #ifdef __GNUC__ #define RESTRICTED_POINTERS #define ALIGNED_POINTERS #endif namespace nova { typedef float sample; #ifndef RESTRICTED_POINTERS #define __restrict__ /*__restrict__*/ #endif /* RESTRICTED_POINTERS */ #ifdef ALIGNED_POINTERS typedef sample aligned_sample __attribute__((aligned(4 * sizeof(sample)))); #else typedef sample aligned_sample; #endif /* ALIGNED_POINTERS */ typedef aligned_sample *__restrict__ restricted_sample_ptr; typedef const aligned_sample *__restrict__ const_restricted_sample_ptr; typedef aligned_sample * aligned_sample_ptr; typedef const aligned_sample * const_aligned_sample_ptr; } /* namespace nova */ #endif /* SERVER_SAMPLE_TYPES_HPP */ SuperCollider-Source/server/supernova/server/server.cpp000644 000765 000024 00000023335 12756531745 024552 0ustar00crucialstaff000000 000000 // nova server // Copyright (C) 2008 - 2012 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include "nova-tt/thread_affinity.hpp" #include "nova-tt/thread_priority.hpp" #include "nova-tt/name_thread.hpp" #include "server.hpp" #include "sync_commands.hpp" #include "nrt_synthesis.hpp" #include "sc/sc_synth_definition.hpp" #include "sc/sc_ugen_factory.hpp" #ifdef __APPLE__ #include #include #include #endif namespace nova { class nova_server * instance = nullptr; nova_server::nova_server(server_arguments const & args): server_shared_memory_creator(args.port(), args.control_busses), scheduler(args.threads, !args.non_rt), buffer_manager(args.buffers), sc_osc_handler(args) { assert(instance == 0); instance = this; use_system_clock = (args.use_system_clock == 1); smooth_samplerate = args.samplerate; if (!args.non_rt) io_interpreter.start_thread(); sc_factory.reset( new sc_ugen_factory ); sc_factory->initialize(args, server_shared_memory_creator::shm->get_control_busses()); /** first guess: needs to be updated, once the backend is started */ time_per_tick = time_tag::from_samples(args.blocksize, args.samplerate); if (!args.non_rt) start_receive_thread(); } void nova_server::prepare_backend(void) { /* register audio backend ports */ const int blocksize = get_audio_blocksize(); const int input_channels = get_input_count(); const int output_channels = get_output_count(); std::vector inputs, outputs; for (int channel = 0; channel != input_channels; ++channel) inputs.push_back(sc_factory->world.mAudioBus + (blocksize * (output_channels + channel))); audio_backend::input_mapping(inputs.begin(), inputs.end()); for (int channel = 0; channel != output_channels; ++channel) outputs.push_back(sc_factory->world.mAudioBus + blocksize * channel); audio_backend::output_mapping(outputs.begin(), outputs.end()); time_per_tick = time_tag::from_samples(blocksize, get_samplerate()); } nova_server::~nova_server(void) { //we should delete but get chrashes at the moment on linux and macosx //delete sc_factory; #if defined(JACK_BACKEND) || defined(PORTAUDIO_BACKEND) deactivate_audio(); #endif group_free_all(static_cast(find_node(0))); // free the root group scheduler::terminate(); io_interpreter.join_thread(); sc_factory.reset(); instance = nullptr; } void nova_server::perform_node_add(server_node *node, node_position_constraint const & constraints, bool update_dsp_queue) { node_graph::add_node(node, constraints, [&](server_node & node) { finalize_node(node); }); if (constraints.second == replace || update_dsp_queue) request_dsp_queue_update(); notification_node_started(node); } abstract_synth * nova_server::add_synth(const char * name, int id, node_position_constraint const & constraints) { abstract_synth * ret = synth_factory::create_instance(name, id); if (ret == nullptr) return nullptr; perform_node_add(ret, constraints, true); return ret; } group * nova_server::add_group(int id, node_position_constraint const & constraints) { group * g = new group(id); if (g == nullptr) return nullptr; perform_node_add(g, constraints, false); return g; } parallel_group * nova_server::add_parallel_group(int id, node_position_constraint const & constraints) { parallel_group * g = new parallel_group(id); if (g == nullptr) return nullptr; perform_node_add(g, constraints, false); return g; } void nova_server::set_node_slot(int node_id, slot_index_t slot, float value) { server_node * node = find_node(node_id); if (node) node->set(slot, value); } void nova_server::set_node_slot(int node_id, const char * slot, float value) { server_node * node = find_node(node_id); if (node) node->set(slot, value); } void nova_server::finalize_node(server_node & node) { if (node.is_synth()) { sc_synth & synth = static_cast(node); synth.finalize(); } notification_node_ended(&node); } void nova_server::free_node(server_node * node) { if (node->get_parent() == nullptr) return; // has already been freed by a different event node_graph::remove_node(node, [&] (server_node & node) { finalize_node(node); }); request_dsp_queue_update(); } void nova_server::group_free_all(abstract_group * group) { std::vector> nodes_to_free; group->apply_on_children( [&](server_node & node) { nodes_to_free.push_back(&node); }); for (server_node * node: nodes_to_free) free_node(node); } void nova_server::group_free_deep(abstract_group * group) { std::vector> nodes_to_free; group->apply_deep_on_children( [&](server_node & node) { if (node.is_synth()) nodes_to_free.push_back(&node); }); for (server_node * node: nodes_to_free) free_node(node); } void nova_server::run_nonrt_synthesis(server_arguments const & args) { start_dsp_threads(); non_realtime_synthesis_engine engine(args); engine.run(); } void nova_server::rebuild_dsp_queue(void) { assert(dsp_queue_dirty); node_graph::dsp_thread_queue_ptr new_queue = node_graph::generate_dsp_queue(); scheduler::reset_queue_sync(std::move(new_queue)); dsp_queue_dirty = false; } static void name_current_thread(int thread_index) { char buf[1024]; sprintf(buf, "DSP Thread %d", thread_index); name_thread(buf); } static void set_daz_ftz(void) { #ifdef __SSE__ /* denormal handling */ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _mm_setcsr(_mm_getcsr() | 0x40); #endif } static bool set_realtime_priority(int thread_index) { bool success = false; #ifdef NOVA_TT_PRIORITY_PERIOD_COMPUTATION_CONSTRAINT double blocksize = server_arguments::instance().blocksize; double samplerate = server_arguments::instance().samplerate; double ns_per_block = 1e9 / samplerate * blocksize; #ifdef __APPLE__ success = thread_set_priority_rt( 0, AudioConvertNanosToHostTime( ns_per_block - 5000 ), AudioConvertNanosToHostTime( ns_per_block ), true); #else success = thread_set_priority_rt(ns_per_block, ns_per_block - 2, ns_per_block - 1, false); #endif if (!success) std::cout << "Warning: initialize deadline scheduling" << std::endl; #endif if (!success) { #ifdef NOVA_TT_PRIORITY_RT #ifdef JACK_BACKEND int priority = instance->realtime_priority(); if (priority >= 0) success = true; #elif _WIN32 int priority = thread_priority_interval_rt().second; #else int min, max; boost::tie(min, max) = thread_priority_interval_rt(); int priority = max - 3; priority = std::max(min, priority); #endif if (success) success = thread_set_priority_rt(priority); #endif } if (!success) std::cout << "Warning: cannot raise thread priority" << std::endl; return success; } void thread_init_functor::operator()(int thread_index) { set_daz_ftz(); name_current_thread(thread_index); if (rt) set_realtime_priority(thread_index); #ifndef __APPLE__ if (!thread_set_affinity(thread_index)) std::cout << "Warning: cannot set thread affinity of audio helper thread" << std::endl; #endif } void io_thread_init_functor::operator()() const { #ifdef NOVA_TT_PRIORITY_RT int priority = thread_priority_interval_rt().first; thread_set_priority_rt(priority); #else int priority = thread_priority_interval().second; thread_set_priority(priority); #endif name_thread("Network Send"); } void synth_definition_deleter::dispose(synth_definition * ptr) { if (instance) /// todo: hack to fix test suite instance->add_system_callback(new delete_callback(ptr)); else delete ptr; } void realtime_engine_functor::init_thread(void) { set_daz_ftz(); #ifndef __APPLE__ if (!thread_set_affinity(0)) std::cout << "Warning: cannot set thread affinity of main audio thread" << std::endl; #endif #ifdef JACK_BACKEND set_realtime_priority(0); #endif if(instance->use_system_clock){ double nows = (uint64)(OSCTime(std::chrono::system_clock::now())) * kOSCtoSecs; instance->mDLL.Reset( sc_factory->world.mSampleRate, sc_factory->world.mBufLength, SC_TIME_DLL_BW, nows); } name_current_thread(0); } void realtime_engine_functor::log_(const char * str) { instance->log_printf(str); } void realtime_engine_functor::log_printf_(const char * fmt, ...) { va_list vargs; va_start(vargs, fmt); instance->log_printf(fmt, vargs); } } /* namespace nova */ SuperCollider-Source/server/supernova/server/server.hpp000644 000765 000024 00000023256 12756531745 024561 0ustar00crucialstaff000000 000000 // nova server // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_NOVA_SERVER_HPP #define SERVER_NOVA_SERVER_HPP #include #include "buffer_manager.hpp" #include "memory_pool.hpp" #include "node_graph.hpp" #include "../sc/sc_osc_handler.hpp" #include "server_args.hpp" #include "server_scheduler.hpp" #include "synth_factory.hpp" #include "../sc/sc_ugen_factory.hpp" #include "../utilities/callback_interpreter.hpp" #include "../utilities/static_pooled_class.hpp" #include "../utilities/asynchronous_log.hpp" #include "../../common/server_shm.hpp" #ifdef PORTAUDIO_BACKEND #include "audio_backend/portaudio_backend.hpp" #elif defined(JACK_BACKEND) #include "audio_backend/jack_backend.hpp" #endif #include "../../scsynth/SC_TimeDLL.hpp" #include "../../scsynth/SC_Time.hpp" namespace nova { struct realtime_engine_functor { static inline void sync_clock(void); static void init_thread(void); static inline void run_tick(void); static void log_(const char *); static void log_printf_(const char *, ...); }; extern class nova_server * instance; /** callback class for audio-thread to system-thread communcation * * the system_callback uses an internal memory pool for real-time safe * memory management. objects are only allowed to be allocated from * the real-time thread. * */ class system_callback: public static_pooled_class { public: virtual ~system_callback(void) = default; virtual void run(void) = 0; }; /** system_callback to delete object in the system thread. useful to avoid hitting the memory allocator * from within the real-time threads */ template class delete_callback: public system_callback { public: delete_callback (T * ptr): ptr_(ptr) {} private: virtual void run(void) override { delete ptr_; } const T * const ptr_; }; /** dsp thread init functor * * for the real-time use, it should acquire real-time scheduling and pin the thread to a certain CPU * * */ struct thread_init_functor { thread_init_functor(bool real_time): rt(real_time) {} void operator()(int thread_index); private: const bool rt; }; struct io_thread_init_functor { void operator()() const; }; namespace detail { #if defined(PORTAUDIO_BACKEND) typedef portaudio_backend audio_backend; #elif defined(JACK_BACKEND) typedef jack_backend audio_backend; #else #error "no audio backend selected" #endif } // detail class nova_server: public asynchronous_log_thread, public node_graph, public server_shared_memory_creator, public scheduler, public detail::audio_backend, public synth_factory, public buffer_manager, public sc_osc_handler { public: SC_TimeDLL mDLL; bool use_system_clock; double smooth_samplerate; typedef detail::audio_backend audio_backend; /* main nova_server function */ nova_server(server_arguments const & args); ~nova_server(void); void prepare_backend(void); /* @{ */ /** io interpreter */ void add_io_callback(system_callback * cb) { io_interpreter.add_callback(cb); } /* @} */ /* @{ */ /** system interpreter * \note: should only be called from the main audio thread */ void add_system_callback(system_callback * cb) { system_interpreter.add_callback(cb); } void run(void) { start_dsp_threads(); system_interpreter.run(); } void prepare_to_terminate() { server_shared_memory_creator::disconnect(); } void terminate(void) { system_interpreter.terminate(); quit_requested_ = true; } /* @} */ /** non-rt synthesis */ void run_nonrt_synthesis(server_arguments const & arguments); public: /* @{ */ /** node control */ abstract_synth * add_synth(const char * name, int id, node_position_constraint const & constraints); group * add_group(int id, node_position_constraint const & constraints); parallel_group * add_parallel_group(int id, node_position_constraint const & constraints); void free_node(server_node * node); void group_free_all(abstract_group * group); void group_free_deep(abstract_group * group); void node_pause(server_node * node) { node->pause(); notification_node_turned_off(node); } void node_resume(server_node * node) { node->resume(); notification_node_turned_on(node); } void set_node_slot(int node_id, slot_index_t slot, float value); void set_node_slot(int node_id, const char * slot, float value); /* @} */ void cpu_load(float & peak, float & average) const { audio_backend::get_cpuload(peak, average); } void increment_logical_time(void) { sc_osc_handler::increment_logical_time(time_per_tick); } void set_last_now(time_tag const & lasts, time_tag const & nows) { sc_osc_handler::set_last_now(lasts, nows); } public: HOT void tick() { sc_factory->apply_done_actions(); run_callbacks(); execute_scheduled_bundles(); if (unlikely(dsp_queue_dirty)) rebuild_dsp_queue(); compute_audio(); } void rebuild_dsp_queue(void); void request_dsp_queue_update(void) { dsp_queue_dirty = true; } bool quit_requested() { return quit_requested_.load(); } private: void perform_node_add(server_node * node, node_position_constraint const & constraints, bool update_dsp_queue); void finalize_node(server_node & node); std::atomic quit_requested_ = {false}; bool dsp_queue_dirty = false; callback_interpreter system_interpreter; // rt to system thread threaded_callback_interpreter io_interpreter; // for network IO }; inline void run_scheduler_tick(void) { const int blocksize = sc_factory->world.mBufLength; const int input_channels = sc_factory->world.mNumInputs; const int output_channels = sc_factory->world.mNumOutputs; const int buf_counter = ++sc_factory->world.mBufCounter; /* touch all input buffers */ for (int channel = 0; channel != input_channels; ++channel) sc_factory->world.mAudioBusTouched[output_channels + channel] = buf_counter; instance->tick(); /* wipe all untouched output buffers */ for (int channel = 0; channel != output_channels; ++channel) { if (sc_factory->world.mAudioBusTouched[channel] != buf_counter) zerovec(sc_factory->world.mAudioBus + blocksize * channel, blocksize); } } inline bool log_printf(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); return instance->log_printf(fmt, vargs); } inline void realtime_engine_functor::sync_clock(void) { if(instance->use_system_clock){ double nows = (uint64)(OSCTime(std::chrono::system_clock::now())) * kOSCtoSecs; instance->mDLL.Reset( sc_factory->world.mSampleRate, sc_factory->world.mBufLength, SC_TIME_DLL_BW, nows); time_tag oscTime = time_tag((uint64)((instance->mDLL.PeriodTime()) * kSecondsToOSCunits + .5)); time_tag oscInc = time_tag((uint64)((instance->mDLL.Period()) * kSecondsToOSCunits + .5)); instance->smooth_samplerate = instance->mDLL.SampleRate(); instance->set_last_now(oscTime,oscTime + oscInc); }else instance->update_time_from_system(); } inline void realtime_engine_functor::run_tick(void) { /* // debug timedll static int count = 0; if(count >= 44100/64){ count = 0; log_printf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f \n", instance->mDLL.PeriodTime(), instance->mDLL.Period(), instance->mDLL.SampleRate(), instance->mDLL.Error(), instance->mDLL.AvgError()); } count++; */ run_scheduler_tick(); if(instance->use_system_clock){ //time_tag nows = time_tag::from_ptime(boost::date_time::microsec_clock::universal_time()); double nows = (uint64)(OSCTime(std::chrono::system_clock::now())) * kOSCtoSecs; instance->mDLL.Update(nows); time_tag oscTime = time_tag((uint64)((instance->mDLL.PeriodTime()) * kSecondsToOSCunits + .5)); time_tag oscInc = time_tag((uint64)((instance->mDLL.Period()) * kSecondsToOSCunits + .5)); instance->smooth_samplerate = instance->mDLL.SampleRate(); instance->set_last_now(oscTime,oscTime + oscInc); }else instance->increment_logical_time(); } inline bool log(const char * string) { return instance->log(string); } inline bool log(const char * string, size_t length) { return instance->log(string, length); } } /* namespace nova */ #endif /* SERVER_NOVA_SERVER_HPP */ SuperCollider-Source/server/supernova/server/server_args.cpp000644 000765 000024 00000014536 12766171707 025570 0ustar00crucialstaff000000 000000 // server arguments, implementation // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include #include #include #include "server_args.hpp" namespace nova { server_arguments::server_arguments(int argc, char * argv[]) { using namespace boost::program_options; using namespace std; /* prepare options */ options_description options("general options"); options.add_options() ("help,h", "show this help") ("udp-port,u", value(&udp_port)->default_value(0), "udp port") ("tcp-port,t", value(&tcp_port)->default_value(0), "tdp port") ("control-busses,c", value(&control_busses)->default_value(16384), "number of control busses") ("audio-busses,a", value(&audio_busses)->default_value(1024), "number of audio busses") ("block-size,z", value(&blocksize)->default_value(64), "audio block size") ("hardware-buffer-size,Z", value(&hardware_buffer_size)->default_value(0), "hardware buffer size") ("use-system-clock,C", value(&use_system_clock)->default_value(0), "type of clock sampleclock=0 systemclock=1") ("samplerate,S", value(&samplerate)->default_value(44100), "hardware sample rate") ("buffers,b", value(&buffers)->default_value(1024), "number of sample buffers") ("max-nodes,n", value(&max_nodes)->default_value(1024), "maximum number of server nodes") ("max-synthdefs,d", value(&max_synthdefs)->default_value(1024), "maximum number of synthdefs") ("rt-memory,m", value(&rt_pool_size)->default_value(8192), "size of real-time memory pool in kb") ("wires,w", value(&wires)->default_value(64), "number of wire buffers") ("randomseeds,r", value(&rng_count)->default_value(64), "number of random number generators") ("load-synthdefs,D", value(&load_synthdefs)->default_value(1), "load synthdefs? (1 or 0)") ("rendezvous,R", value()->default_value(1), "publish to Rendezvous? (1 or 0)") ("max-logins,l", value()->default_value(64), "maximum number of named return addresses") ("password,p", value(&server_password)->default_value(""), "When using TCP, the session password must be the first command sent.\n" "The default is no password.\n" "UDP ports never require passwords, so for security use TCP.") ("nrt,N", value >()->multitoken(), "nrt synthesis ") ("memory-locking,L", "enable memory locking") ("version,v", "print the supercollider version and exit") ("hardware-device-name,H", value >()->multitoken(), "hardware device name") ("verbose,V", value(&verbosity)->default_value(0), "verbosity: 0 is normal behaviour\n-1 suppresses informational messages\n" "-2 suppresses informational and many error messages") ("ugen-search-path,U", value >(&ugen_paths), "a colon-separated list of paths\n" "if -U is specified, the standard paths are NOT searched for plugins.") ("restricted-path,P", value >(&restrict_paths), "if specified, prevents file-accessing OSC commands from accessing files outside ") ("threads,T", value(&threads)->default_value(boost::thread::physical_concurrency()), "number of audio threads") ; options_description audio_options("audio options"); audio_options.add_options() ("inchannels,i", value(&input_channels)->default_value(8), "number of input channels") ("outchannels,o", value(&output_channels)->default_value(8), "number of output channels") ; options_description cmdline_options; cmdline_options .add(options) .add(audio_options) ; /* parse options */ boost::program_options::variables_map vm; try { store(command_line_parser(argc, argv).options(cmdline_options).run(), vm); } catch(error const & e) { cout << "Error when parsing command line arguments:" << endl << e.what() << endl << endl; std::exit(EXIT_FAILURE); }; notify(vm); dump_version = vm.count("version"); memory_locking = vm.count("memory-locking"); if (vm.count("help")) { cout << cmdline_options << endl; std::exit(EXIT_SUCCESS); } non_rt = vm.count("nrt"); if (non_rt) { std::vector const & nrt_options = vm["nrt"].as >(); if (nrt_options.size() != 6) { cout << "Error when parsing command line:" << endl; std::exit(EXIT_FAILURE); } command_file = nrt_options[0]; input_file = nrt_options[1]; output_file = nrt_options[2]; samplerate = boost::lexical_cast(nrt_options[3]); header_format = nrt_options[4]; sample_format = nrt_options[5]; } if (vm.count("hardware-device-name")) hw_name = vm["hardware-device-name"].as >(); } std::unique_ptr server_arguments::instance_; } /* namespace nova */ SuperCollider-Source/server/supernova/server/server_args.hpp000644 000765 000024 00000004646 12756531745 025577 0ustar00crucialstaff000000 000000 // server arguments // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SERVER_ARGS_HPP #define SERVER_SERVER_ARGS_HPP #include #include #include #include namespace nova { class server_arguments { server_arguments(int argc, char * argv[]); public: static server_arguments const &initialize(int argc, char * argv[]) { instance_.reset(new server_arguments(argc, argv)); return instance(); } static server_arguments const & instance(void) { return *instance_; } /** set the sample rate (from the audio backend) */ static void set_samplerate(uint32_t samplerate) { instance_->samplerate = samplerate; } uint32_t port(void) const { if (udp_port) return udp_port; else return tcp_port; } uint32_t udp_port, tcp_port; uint32_t control_busses, audio_busses; uint32_t blocksize, samplerate; int32_t hardware_buffer_size; uint32_t buffers, max_nodes, max_synthdefs; uint16_t use_system_clock; uint32_t rt_pool_size; uint32_t wires, rng_count; uint16_t load_synthdefs; int16_t verbosity; bool dump_version; std::vector hw_name; bool memory_locking; uint16_t threads; std::vector ugen_paths, restrict_paths; uint16_t input_channels, output_channels; std::string server_password; /* for non-rt synthesis */ bool non_rt; std::string command_file, input_file, output_file, header_format, sample_format; private: static std::unique_ptr instance_; }; } /* namespace nova */ #endif /* SERVER_SERVER_ARGS_HPP */ SuperCollider-Source/server/supernova/server/server_scheduler.hpp000644 000765 000024 00000010074 12756531745 026611 0ustar00crucialstaff000000 000000 // server scheduler // Copyright (C) 2008, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SCHEDULER_HPP #define SERVER_SCHEDULER_HPP #include #include "dsp_thread_queue/dsp_thread.hpp" #include "group.hpp" #include "memory_pool.hpp" #include "utilities/branch_hints.hpp" #include "utilities/callback_system.hpp" #include "utilities/static_pooled_class.hpp" namespace nova { /** audio-thread synchronization callback * * callback for non-rt to rt thread synchronization. since it is using * a locked internal memory pool, instances should not be allocated * from the real-time thread * * */ struct audio_sync_callback: public static_pooled_class { virtual ~audio_sync_callback() = default; virtual void run(void) = 0; }; /** scheduler class of the nova server * * - provides a callback system to place callbacks in the scheduler * - manages dsp threads, which themselves manage the dsp queue interpreter * * scheduler_hook: functor to be called when after callbacks have been executed * and before the threads are executed * * thread_init_functor: helper thread initialization functor * * */ template class scheduler { typedef nova::dsp_thread_pool > dsp_thread_pool; typedef typename dsp_thread_pool::dsp_thread_queue_ptr dsp_thread_queue_ptr; typedef typename dsp_thread_pool::thread_count_t thread_count_t; struct reset_queue_cb: public audio_sync_callback { public: reset_queue_cb(scheduler * sched, dsp_thread_queue_ptr & qptr): sched(sched), qptr(qptr) {} void run(void) override { sched->reset_queue_sync(qptr); /** todo: later free the queue in a helper thread */ } private: scheduler * sched; dsp_thread_queue_ptr qptr; }; protected: /* called from the driver callback */ void reset_queue_sync(dsp_thread_queue_ptr && qptr) { threads.reset_queue(std::move(qptr)); } public: /* start thread_count - 1 scheduler threads */ scheduler(thread_count_t thread_count = 1, bool realtime = false): threads(thread_count, !realtime, thread_init_functor(realtime)) {} void start_dsp_threads(void) { threads.start_threads(); } void terminate() { cbs.run_callbacks(); // audio backend must be closed by now threads.terminate_threads(); } void add_sync_callback(audio_sync_callback * cb) { /* we need to guard, because it can be called from the main (system) thread and the network receiver thread */ std::lock_guard lock(sync_mutex); cbs.add_callback(cb); } /* called from the audio driver */ void run_callbacks() { cbs.run_callbacks(); } void compute_audio() { threads.run(); } /* schedule to set a new queue */ void reset_queue(dsp_thread_queue_ptr & qptr) { add_sync_callback(new reset_queue_cb(this, qptr)); } private: callback_system cbs; dsp_thread_pool threads; std::mutex sync_mutex; }; } /* namespace nova */ #endif /* SERVER_SCHEDULER_HPP */ SuperCollider-Source/server/supernova/server/sync_commands.hpp000644 000765 000024 00000003573 12756531745 026110 0ustar00crucialstaff000000 000000 // osc responder classes for the nova server // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SYNC_COMMANDS_HPP #define SERVER_SYNC_COMMANDS_HPP #include "server_scheduler.hpp" namespace nova { class set_cmd_index: public audio_sync_callback { public: set_cmd_index(int node_id, slot_index_t const & slot_id, float value): node_id(node_id), slot_id(slot_id), value(value) {} private: virtual void run(void) override { instance->set_node_slot(node_id, slot_id, value); } const int node_id; const slot_index_t slot_id; const float value; }; class set_cmd_str: public audio_sync_callback { public: set_cmd_str(int node_id, const char * name, float value): node_id(node_id), value(value) { slot_id = (char*)allocate(strlen(name) * sizeof(char)); strcpy(slot_id, name); } ~set_cmd_str(void) { deallocate(slot_id); } private: virtual void run(void) override { instance->set_node_slot(node_id, slot_id, value); } const int node_id; char * slot_id; const float value; }; } #endif /* SERVER_SYNC_COMMANDS_HPP */ SuperCollider-Source/server/supernova/server/synth.hpp000644 000765 000024 00000011224 12756531745 024410 0ustar00crucialstaff000000 000000 // synth // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SYNTH_HPP #define SERVER_SYNTH_HPP #include #include #include #include "node_types.hpp" #include "synth_definition.hpp" #include "utilities/time_tag.hpp" namespace nova { namespace detail { /** wrapper class implementing the functionality of synth, that accesses its prototype */ class synth_definition_instance { public: synth_definition_instance(synth_definition_ptr const & ptr): class_ptr(ptr) {} slot_index_t resolve_slot(const char * str) { return class_ptr->resolve_slot(str); } slot_index_t resolve_slot_with_size(const char * str, int & size_of_slot) { return class_ptr->resolve_slot_with_size(str, size_of_slot); } slot_index_t resolve_slot(const char * str, std::size_t hashed_str) { return class_ptr->resolve_slot(str, hashed_str); } slot_index_t resolve_slot_with_size(const char * str, std::size_t hashed_str, int & size_of_slot) { return class_ptr->resolve_slot_with_size(str, hashed_str, size_of_slot); } const char * definition_name(void) const { return class_ptr->name(); } size_t number_of_slots() const { return class_ptr->number_of_slots(); } const char * name_of_slot(size_t index) const { return class_ptr->name_of_slot(index); } protected: synth_definition_ptr class_ptr; }; } /* namespace detail */ class abstract_synth: public server_node, public detail::synth_definition_instance { public: typedef float sample; typedef std::uint_fast16_t samplecount_t; typedef detail::synth_definition_instance definition_instance; protected: abstract_synth(int node_id, synth_definition_ptr const & definition): server_node(node_id, true), definition_instance(definition) {} public: virtual void run(void) = 0; virtual float get(slot_index_t slot_id) const = 0; /** set a slot */ /* @{ */ virtual void set(slot_index_t slot_id, float val) override = 0; void set(const char * slot_str, sample val) override { set(slot_str, string_hash(slot_str), val); } void set(const char * slot_str, size_t hashed_str, sample val) override { slot_index_t slot_id = definition_instance::resolve_slot(slot_str, hashed_str); if (likely(slot_id >= 0)) this->set(slot_id, val); } void set_control_array(const char * slot_str, size_t count, sample * val) override { set_control_array(slot_str, string_hash(slot_str), count, val); } void set_control_array(const char * slot_str, size_t hashed_str, size_t count, sample * val) override { int size_of_parameter; slot_index_t slot_id = definition_instance::resolve_slot_with_size(slot_str, hashed_str, size_of_parameter); count = std::min(size_t(size_of_parameter), count); if (likely(slot_id >= 0)) for (size_t i = 0; i != count; ++i) this->set(slot_id+i, val[i]); } virtual void set_control_array(slot_index_t slot_id, size_t n, float * values) override = 0; virtual void set_control_array_element(slot_index_t slot_id, size_t index, float val) override { this->set(slot_id + index, val); } void set_control_array_element(const char * slot_str, size_t index, sample val) override { set_control_array_element(slot_str, string_hash(slot_str), index, val); } void set_control_array_element(const char * slot_str, size_t hashed_str, size_t index, sample val) override { int size_of_parameter; slot_index_t slot_id = definition_instance::resolve_slot_with_size(slot_str, hashed_str, size_of_parameter); if (likely( (slot_id >= 0) && (index < size_of_parameter) )) this->set(slot_id + index, val); } /* @} */ }; } /* namespace nova */ #endif /* SERVER_SYNTH_HPP */ SuperCollider-Source/server/supernova/server/synth_definition.hpp000644 000765 000024 00000012504 12756531745 026622 0ustar00crucialstaff000000 000000 // synth prototype // Copyright (C) 2008 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SYNTH_DEFINITION_HPP #define SERVER_SYNTH_DEFINITION_HPP #include #include #include #include #include "utilities/aligned_class.hpp" #include "utilities/named_hash_entry.hpp" #include "utilities/utils.hpp" namespace nova { typedef std::int32_t slot_index_t; typedef symbol slot_identifier_type; namespace detail { /** class to resolve alphanumeric string to slot id */ class slot_resolver { protected: struct map_type: public named_hash_entry { map_type(slot_identifier_type const & name, slot_index_t index, int number_of_values): named_hash_entry(name), index(index), number_of_values(number_of_values) {} const slot_index_t index; const int number_of_values; }; private: struct hash_value { hash_value(std::size_t v): value(v) {} std::size_t operator()(const char *) const { return value; } const std::size_t value; }; bool exists(const char * str) const { return slot_resolver_map.find(str, named_hash_hash(), named_hash_equal()) != slot_resolver_map.end(); } protected: slot_resolver(void): slot_resolver_map(slot_resolver_map_t::bucket_traits(buckets, resolver_map_bucket_count)) {} ~slot_resolver(void) { slot_resolver_map.clear_and_dispose(boost::checked_deleter()); } void register_slot(symbol const & str, slot_index_t i, int number_of_values) { assert(not exists(str.c_str())); map_type * elem = new map_type(str, i, number_of_values); bool success = slot_resolver_map.insert(*elem).second; assert(success); if (size_t(i) >= slot_names.size()) slot_names.resize(i+1, nullptr); slot_names[i] = elem->name(); } public: /*@{*/ /** resolve slot by symbolic name * * \return nonnegative index of slot * -1, if symbolic name cannot be resolved */ slot_index_t resolve_slot(const char * str) const { return resolve_slot(str, string_hash(str)); } slot_index_t resolve_slot_with_size(const char * str, int & number_of_values) const { return resolve_slot_with_size(str, string_hash(str), number_of_values); } slot_index_t resolve_slot(const char * str, std::size_t hashed_value) const { auto it = slot_resolver_map.find(str, hash_value(hashed_value), named_hash_equal()); if (it == slot_resolver_map.end()) return -1; else return it->index; } slot_index_t resolve_slot_with_size(const char * str, std::size_t hashed_value, int & number_of_values) const { auto it = slot_resolver_map.find(str, hash_value(hashed_value), named_hash_equal()); if (it == slot_resolver_map.end()) return -1; number_of_values = it->number_of_values; return it->index; } /*@}*/ size_t number_of_slots() const { return slot_names.size(); } const char * name_of_slot(size_t slot_index) const { assert(slot_index < slot_names.size()); return slot_names[slot_index]; } private: static const int resolver_map_bucket_count = 512; typedef boost::intrusive::unordered_set > slot_resolver_map_t; slot_resolver_map_t::bucket_type buckets[resolver_map_bucket_count]; slot_resolver_map_t slot_resolver_map; std::vector slot_names; }; } /* namespace detail */ class abstract_synth; struct synth_definition_deleter { template void operator()(T * ptr) { dispose (static_cast(ptr)); } void dispose(class synth_definition *); }; /** prototype of a synth * * - works as a synth factory * * */ class synth_definition: public aligned_class, public named_hash_entry, public intrusive_refcountable<>, public detail::slot_resolver { public: explicit synth_definition(symbol const & name): named_hash_entry(name) {} virtual ~synth_definition(void) = default; virtual abstract_synth * create_instance(int node_id) = 0; template static inline synth_t * allocate(void); }; typedef boost::intrusive_ptr synth_definition_ptr; } /* namespace nova */ #endif /* SERVER_SYNTH_DEFINITION_HPP */ SuperCollider-Source/server/supernova/server/synth_factory.hpp000644 000765 000024 00000005626 12766171707 026147 0ustar00crucialstaff000000 000000 // synth factory // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SYNTH_FACTORY_HPP #define SERVER_SYNTH_FACTORY_HPP #include #include #include "synth.hpp" #include "synth_definition.hpp" namespace nova { class synth_factory { public: void register_definition(synth_definition_ptr && prototype) { prototype_map_type::iterator it = definition_map.find(prototype->name(), named_hash_hash(), named_hash_equal()); if (it != definition_map.end()) { definition_map.erase(it); it->release(); } synth_definition_ptr ptr( std::forward(prototype) ); ptr->add_ref(); definition_map.insert(*ptr.get()); } abstract_synth * create_instance(const char * name, int node_id) { prototype_map_type::iterator it = definition_map.find(name, named_hash_hash(), named_hash_equal()); if (it == definition_map.end()) return nullptr; return it->create_instance(node_id); } void remove_definition(const char * name) { prototype_map_type::iterator it = definition_map.find(name, named_hash_hash(), named_hash_equal()); if (it == definition_map.end()) return; definition_map.erase(it); it->release(); } std::size_t definition_count(void) const { return definition_map.size(); } synth_factory(void): definition_map(prototype_map_type::bucket_traits(buckets, bucket_count)) {} ~synth_factory(void) { while(definition_map.begin() != definition_map.end()) { prototype_map_type::iterator it = definition_map.begin(); definition_map.erase(it); it->release(); } } private: static const int bucket_count = 2048; typedef boost::intrusive::unordered_set > prototype_map_type; prototype_map_type::bucket_type buckets[bucket_count]; prototype_map_type definition_map; }; } /* namespace nova */ #endif /* SERVER_SYNTH_FACTORY_HPP */ SuperCollider-Source/server/supernova/sc/CMakeLists.txt000644 000765 000024 00000000107 12321461511 024344 0ustar00crucialstaff000000 000000 set(supernova 1) add_subdirectory(supercollider/common/Source/plugins) SuperCollider-Source/server/supernova/sc/sc_osc_handler.cpp000644 000765 000024 00000343143 12766171707 025312 0ustar00crucialstaff000000 000000 // osc handler for supercollider-style communication, implementation // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include #include #include "osc/OscOutboundPacketStream.h" #include "osc/OscPrintReceivedElements.h" #include "sc_msg_iter.h" #include "sc_osc_handler.hpp" #include "../server/server.hpp" #include "utilities/sized_array.hpp" #include "SC_OSC_Commands.h" #ifdef _WIN32 #include "malloc.h" // for alloca #endif namespace nova { using namespace std; using nova::detail::nova_endpoint; using nova::detail::endpoint_ptr; namespace { int32_t last_generated = 0; server_node * find_node(int32_t target_id) { if (target_id == -1) target_id = last_generated; server_node * node = instance->find_node(target_id); if (node == nullptr) log_printf("node not found: %d\n", target_id); return node; } abstract_group * find_group(int32_t target_id) { if (target_id == -1) target_id = last_generated; abstract_group * node = instance->find_group(target_id); if (node == nullptr) log("node not found or not a group\n"); return node; } bool check_node_id(int node_id) { if (!instance->node_id_available(node_id)) { log_printf("node id %d already in use\n", node_id); return false; } return true; } void fill_notification(const server_node * node, osc::OutboundPacketStream & p) { p << node->id(); /* parent */ const abstract_group * parent_node = node->get_parent(); assert(parent_node); p << parent_node->id(); /* previous/next */ if (parent_node->is_parallel()) p << -2 << -2; /* we are in a parallel group, so we have no notion of previous/next */ else { const server_node * prev_node = node->previous_node(); if (prev_node) p << prev_node->id(); else p << -1; const server_node * next_node = node->next_node(); if (next_node) p << next_node->id(); else p << -1; } /* is_synth, head, tail */ if (node->is_synth()) p << 0; else { const abstract_group * node_group = static_cast(node); p << 1; if (node_group->is_parallel()) p << -2 << -2; else { const group * node_real_group = static_cast(node_group); if (node_real_group->empty()) p << -1 << -1; else p << node_real_group->head_node()->id() << node_real_group->tail_node()->id(); } } p << osc::EndMessage; } spin_lock system_callback_allocator_lock; struct movable_string { /** allocate new string, only allowed to be called from the rt context */ explicit movable_string(const char * str) { size_t length = strlen(str) + 1; /* terminating \0 */ char * data = (char*)system_callback::allocate(length); strcpy(data, str); data_ = data; } movable_string(movable_string const & rhs) = delete; movable_string operator=(movable_string const & rhs) = delete; movable_string(movable_string && rhs) { data_ = rhs.data_; const_cast(rhs).data_ = nullptr; } ~movable_string(void) { if (data_) system_callback::deallocate((char*)data_); } const char * c_str(void) const { return data_; } private: const char * data_ = nullptr; }; template struct movable_array { /** allocate new array, only allowed to be called from the rt context */ movable_array(size_t length, const T * data, bool locked = false): length_(length) { data_ = (T*)system_callback::allocate(length * sizeof(T)); for (size_t i = 0; i != length; ++i) data_[i] = data[i]; } movable_array& operator=(movable_array const & rhs) = delete; movable_array(movable_array const & rhs) = delete; movable_array(movable_array && rhs): length_(rhs.length_), data_ (rhs.data_) { rhs.data_ = nullptr; } movable_array& operator=(movable_array && rhs) { if (data_) system_callback::deallocate(data_); length_ = rhs.length_; data_ = rhs.data_; rhs.data_ = nullptr; } ~movable_array(void) { if (!data_) return; system_callback::deallocate(data_); data_ = nullptr; } const T * data(void) const { return data_; } const T & operator[](size_t index) const { return data_[index]; } size_t size(void) const { return length_; } private: size_t length_ = 0; T * data_; }; template static inline void consume( T && object ) { T sink( std::forward ( object ) ); // move object here (and destroy) } void send_done_message(endpoint_ptr const & endpoint) { char buffer[128]; osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage("/done") << osc::EndMessage; endpoint->send(p.Data(), p.Size()); } void send_done_message(endpoint_ptr const & endpoint, const char * cmd) { char buffer[128]; osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage("/done") << cmd << osc::EndMessage; endpoint->send(p.Data(), p.Size()); } void send_done_message(endpoint_ptr const & endpoint, const char * cmd, osc::int32 index) { char buffer[128]; osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage("/done") << cmd << index << osc::EndMessage; endpoint->send(p.Data(), p.Size()); } void send_fail_message(endpoint_ptr const & endpoint, const char * cmd, const char * content) { char buffer[8192]; osc::OutboundPacketStream p(buffer, 8192); p << osc::BeginMessage("/fail") << cmd << content << osc::EndMessage; endpoint->send(p.Data(), p.Size()); } void send_fail_message(endpoint_ptr const & endpoint, const char * cmd, const char * content, int id) { char buffer[8192]; osc::OutboundPacketStream p(buffer, 8192); p << osc::BeginMessage("/fail") << cmd << content << (osc::int32)id << osc::EndMessage; endpoint->send(p.Data(), p.Size()); } template struct fn_system_callback: public system_callback { fn_system_callback (Functor const & fn): fn_(fn) {} fn_system_callback (Functor && fn): fn_( std::forward( fn ) ) {} void run(void) override { fn_(); } Functor fn_; }; template struct fn_sync_callback: public audio_sync_callback { fn_sync_callback (Functor const & fn): fn_(fn) {} fn_sync_callback (Functor && fn): fn_( std::forward( fn )) {} void run(void) override { fn_(); } Functor fn_; }; /** helper class for dispatching real-time and non real-time osc command callbacks * * uses template specialization to avoid unnecessary callback rescheduling */ template struct cmd_dispatcher_base { template static void free_in_rt_thread( A && object ) { DerivedClass::fire_rt_callback( [object = std::move(object)] () mutable { consume( std::move( object ) ); } ); } template static void free_in_rt_thread( A && object1, B && object2 ) { DerivedClass::fire_rt_callback( [object1 = std::move(object1), object2 = std::move(object2)] () mutable { consume( std::move( object1 ) ); consume( std::move( object2 ) ); } ); } template static void free_in_rt_thread( A && object1, B && object2, C && object3 ) { DerivedClass::fire_rt_callback( [object1 = std::move(object1), object2 = std::move(object2), object3 = std::move(object3)] () mutable { consume( std::move( object1 ) ); consume( std::move( object2 ) ); consume( std::move( object3 ) ); } ); } template static void free_in_rt_thread( A && object1, B && object2, C && object3, D && object4 ) { DerivedClass::fire_rt_callback( [object1 = std::move(object1), object2 = std::move(object2), object3 = std::move(object3), object4 = std::move(object4)] () mutable { consume( std::move( object1 ) ); consume( std::move( object2 ) ); consume( std::move( object3 ) ); consume( std::move( object4 ) ); } ); } static void fire_done_message(endpoint_ptr const & endpoint_ref, const char * cmd, osc::int32 index) { if (endpoint_ref) { DerivedClass::fire_io_callback([=, endpoint = endpoint_ptr(endpoint_ref)]() { send_done_message(endpoint, cmd, index); }); } } static void fire_message(endpoint_ptr const & endpoint_ref, movable_array && message) { if (endpoint_ref) { DerivedClass::fire_io_callback([=, message=std::move(message), endpoint = endpoint_ptr(endpoint_ref)] () mutable { endpoint->send(message.data(), message.size()); DerivedClass::fire_rt_callback([=, message=std::move(message)] () mutable { consume( std::move(message) ); }); }); } } }; template struct cmd_dispatcher: public cmd_dispatcher_base< cmd_dispatcher > { template static void fire_system_callback(Functor const & f) { instance->add_system_callback(new fn_system_callback(f)); } template static void fire_system_callback(Functor && f) { instance->add_system_callback(new fn_system_callback(std::forward(f))); } template static void fire_io_callback(Functor const & f) { instance->add_io_callback(new fn_system_callback(f)); } template static void fire_io_callback(Functor && f) { instance->add_io_callback( new fn_system_callback( std::forward(f) ) ); } template static void fire_rt_callback(Functor const & f) { instance->add_sync_callback(new fn_sync_callback(f)); } template static void fire_rt_callback(Functor && f) { instance->add_sync_callback( new fn_sync_callback( std::forward(f) ) ); } }; template <> struct cmd_dispatcher: public cmd_dispatcher_base< cmd_dispatcher > { template static void fire_system_callback(Functor const & f) { f(); } template static void fire_system_callback(Functor && f) { Functor fn ( std::forward(f) ); fn(); } template static void fire_rt_callback(Functor const & f) { f(); } template static void fire_rt_callback(Functor && f) { Functor fn ( std::forward(f) ); fn(); } template static void fire_io_callback(Functor const & f) { f(); } template static void fire_io_callback(Functor && f) { Functor fn ( std::forward(f) ); fn(); } }; void report_failure(endpoint_ptr const & endpoint, std::exception const & error, const char * command) { std::cout << error.what() << std::endl; send_fail_message(endpoint, command, error.what()); } void report_failure(endpoint_ptr const & endpoint, std::exception const & error, const char * command, int bufnum) { std::cout << error.what() << std::endl; send_fail_message(endpoint, command, error.what(), bufnum); } } /* namespace */ namespace detail { using nova::log; int sc_notify_observers::add_observer(endpoint_ptr const & ep) { auto it = find(ep); if (it != observers.end()) return already_registered; observers.push_back(ep); return observers.size() - 1; } int sc_notify_observers::remove_observer(endpoint_ptr const & ep) { auto it = find(ep); if (it == observers.end()) return not_registered; const int observerIndex = it - observers.begin(); observers.erase(it); return observerIndex; } const char * sc_notify_observers::error_string(error_code error) { switch (error) { case no_error: return ""; case already_registered: return "notify: already registered"; case not_registered: return "notify: not registered"; default: assert(false); return ""; } } sc_notify_observers::observer_vector::iterator sc_notify_observers::find(endpoint_ptr const & ep) { for (auto it = observers.begin(); it != observers.end(); ++it) { udp_endpoint * elemUDP = dynamic_cast(it->get()); udp_endpoint * testUDP = dynamic_cast(ep.get()); if (elemUDP && testUDP) { if (*elemUDP == *testUDP) return it; } typedef sc_osc_handler::tcp_connection tcp_connection; tcp_connection * elemTCP = dynamic_cast(it->get()); tcp_connection * testTCP = dynamic_cast(ep.get()); if (elemTCP && testTCP) { if (*elemTCP == *testTCP) return it; } } return observers.end(); } void sc_notify_observers::notify(const char * address_pattern, const server_node * node) const { char buffer[128]; // 128 byte should be enough osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage(address_pattern); fill_notification(node, p); movable_array message(p.Size(), p.Data()); cmd_dispatcher::fire_io_callback( [ =, message = std::move(message) ] () mutable { instance->send_notification( message.data(), message.size() ); cmd_dispatcher::fire_rt_callback( [ =, message = std::move(message) ] () mutable { consume( std::move(message) ); }); }); } void fire_trigger(int32_t node_id, int32_t trigger_id, float value) { char buffer[128]; // 128 byte should be enough osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage("/tr") << osc::int32(node_id) << osc::int32(trigger_id) << value << osc::EndMessage; instance->send_notification(p.Data(), p.Size()); } void sc_notify_observers::send_trigger(int32_t node_id, int32_t trigger_id, float value) { cmd_dispatcher::fire_io_callback([=](){ fire_trigger(node_id, trigger_id, value); }); } void fire_node_reply(int32_t node_id, int reply_id, movable_string && cmd, movable_array && values) { size_t buffer_size = 1024 + strlen(cmd.c_str()) + values.size()*sizeof(float); char * buffer = (buffer_size < 2048) ? (char*)alloca(buffer_size) : (char*)malloc(buffer_size); try { osc::OutboundPacketStream p(buffer, buffer_size); p << osc::BeginMessage(cmd.c_str()) << osc::int32(node_id) << osc::int32(reply_id); for (int i = 0; i != values.size(); ++i) p << values[i]; p << osc::EndMessage; instance->send_notification(p.Data(), p.Size()); movable_array valus (std::move( values )); } catch (...) { } cmd_dispatcher::free_in_rt_thread( std::move(cmd), std::move(values) ); if (buffer_size >= 2048) free(buffer); } void sc_notify_observers::send_node_reply(int32_t node_id, int reply_id, const char* command_name, int argument_count, const float* values) { spin_lock::scoped_lock lock(system_callback_allocator_lock); // called from rt helper threads, so we need to lock the memory pool movable_string cmd(command_name); movable_array value_array(argument_count, values); cmd_dispatcher::fire_io_callback( [ =, value_array = std::move(value_array), cmd = std::move(cmd) ] () mutable { size_t buffer_size = 1024 + strlen(cmd.c_str()) + value_array.size()*sizeof(float); char * buffer = (buffer_size < 2048) ? (char*)alloca(buffer_size) : (char*)malloc(buffer_size); try { osc::OutboundPacketStream p(buffer, buffer_size); p << osc::BeginMessage(cmd.c_str()) << osc::int32(node_id) << osc::int32(reply_id); for (int i = 0; i != value_array.size(); ++i) p << value_array[i]; p << osc::EndMessage; instance->send_notification(p.Data(), p.Size()); } catch (...) { } cmd_dispatcher::free_in_rt_thread( std::move(value_array), std::move(cmd) ); if (buffer_size >= 2048) free(buffer); }); } void sc_notify_observers::send_notification(const char * data, size_t length) { for (auto & observer: observers) observer->send(data, length); } void udp_endpoint::send(const char *data, size_t length) { instance->sc_notify_observers::send_udp(data, length, endpoint_); } void sc_notify_observers::send_udp(const char * data, size_t size, udp::endpoint const & receiver) { std::lock_guard lock(udp_mutex); sc_notify_observers::udp_socket.send_to(boost::asio::buffer(data, size), receiver); } void sc_scheduled_bundles::bundle_node::run(void) { typedef osc::ReceivedBundleElement bundle_element; typedef osc::ReceivedBundle received_bundle; typedef osc::ReceivedMessage ReceivedMessage; bundle_element element(data_); if (element.IsBundle()) { received_bundle bundle(element); instance->handle_bundle(bundle, endpoint_); } else { ReceivedMessage message(element); instance->handle_message(message, element.Size(), endpoint_); } } void sc_scheduled_bundles::insert_bundle(time_tag const & timeout, const char * data, size_t length, endpoint_ptr const & endpoint) { /* allocate chunk from realtime pool */ void * chunk = rt_pool.malloc(sizeof(bundle_node) + length+4); bundle_node * node = (bundle_node*)chunk; char * cpy = (char*)chunk + sizeof(bundle_node); memcpy(cpy, data - 4, length+4); new(node) bundle_node(timeout, cpy, endpoint); bundle_q.insert(*node); } void sc_scheduled_bundles::execute_bundles(time_tag const & last, time_tag const & now) { World * world = &sc_factory->world; while(!bundle_q.empty()) { bundle_node & front = *bundle_q.top(); time_tag const & next_timestamp = front.timeout_; if (now < next_timestamp) break; if (last < next_timestamp) { // between last and now time_tag time_since_last = next_timestamp - last; float samples_since_last = time_since_last.to_samples(world->mSampleRate); float sample_offset; float subsample_offset = std::modf(samples_since_last, &sample_offset); world->mSampleOffset = (int)sample_offset; world->mSubsampleOffset = subsample_offset; } else world->mSampleOffset = world->mSubsampleOffset = 0; front.run(); bundle_q.erase_and_dispose(bundle_q.top(), &dispose_bundle); } world->mSampleOffset = world->mSubsampleOffset = 0; } void sc_osc_handler::open_tcp_acceptor(tcp const & protocol, unsigned int port) { tcp_acceptor_.open(protocol); tcp_acceptor_.bind(tcp::endpoint(protocol, port)); tcp_acceptor_.listen(); start_tcp_accept(); } void sc_osc_handler::open_udp_socket(udp const & protocol, unsigned int port) { sc_notify_observers::udp_socket.open(protocol); sc_notify_observers::udp_socket.bind(udp::endpoint(protocol, port)); } bool sc_osc_handler::open_socket(int family, int type, int protocol, unsigned int port) { if (protocol == IPPROTO_TCP) { if ( type != SOCK_STREAM ) return false; if (family == AF_INET) open_tcp_acceptor(tcp::v4(), port); else if (family == AF_INET6) open_tcp_acceptor(tcp::v6(), port); else return false; return true; } else if (protocol == IPPROTO_UDP) { if ( type != SOCK_DGRAM ) return false; if (family == AF_INET) open_udp_socket(udp::v4(), port); else if (family == AF_INET6) open_udp_socket(udp::v6(), port); else return false; start_receive_udp(); return true; } return false; } void sc_osc_handler::start_receive_udp() { using namespace boost; sc_notify_observers::udp_socket.async_receive_from( buffer(recv_buffer_), udp_remote_endpoint_, bind(&sc_osc_handler::handle_receive_udp, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); } void sc_osc_handler::handle_receive_udp(const boost::system::error_code& error, std::size_t bytes_transferred) { if (unlikely(error == error::operation_aborted)) return; /* we're done */ if (error) { std::cout << "sc_osc_handler received error code " << error << std::endl; start_receive_udp(); return; } handle_packet_async(recv_buffer_.begin(), bytes_transferred, make_shared(udp_remote_endpoint_)); start_receive_udp(); return; } void sc_osc_handler::tcp_connection::start(sc_osc_handler * self) { using namespace boost; typedef boost::endian::big_int32_t big_int32_t; asio::ip::tcp::no_delay option(true); socket_.set_option(option); const bool check_password = self->tcp_password_; if (check_password) { std::array password; big_int32_t msglen; for (unsigned int i=0; i!=4; ++i) { size_t size = socket_.receive(asio::buffer(&msglen, 4)); if (size != sizeof(big_int32_t)) return; if (msglen > password.size()) return; size = socket_.receive(asio::buffer(password.data(), msglen)); bool verified = true; if (size != msglen || strcmp(password.data(), self->tcp_password_) != 0) verified = false; if (!verified) throw std::runtime_error("cannot verify password"); } } osc_handler = self; async_read_msg_size(); } void sc_osc_handler::tcp_connection::send(const char *data, size_t length) { try { boost::endian::big_int32_t len(length); socket_.send(boost::asio::buffer(&len, sizeof(len))); size_t written = socket_.send(boost::asio::buffer(data, length)); assert(length == written); } catch (std::exception const & err) { std::cout << "Exception when sending message over TCP: " << err.what(); } } void sc_osc_handler::tcp_connection::async_read_msg_size() { namespace asio = boost::asio; pointer ptr = std::static_pointer_cast(shared_from_this()); asio::async_read(socket_, asio::buffer(&msg_size_, 4), [=] (const boost::system::error_code& error, std::size_t bytes_transferred) { if (error == boost::asio::error::eof) return; // connection closed if (error) { cout << "tcp_connection received error: " << error.message() << endl; return; } ptr->handle_message_size(); }); } void sc_osc_handler::tcp_connection::handle_message_size() { msg_buffer_.resize(msg_size_); namespace asio = boost::asio; pointer ptr = std::static_pointer_cast(shared_from_this()); asio::async_read(socket_, asio::buffer(msg_buffer_), [=] (const boost::system::error_code& error, std::size_t bytes_transferred) { if (error == boost::asio::error::eof) return; // connection closed if (error) { cout << "tcp_connection received error: " << error.message() << endl; return; } assert(bytes_transferred == ptr->msg_size_); ptr->handle_message(); }); } void sc_osc_handler::tcp_connection::handle_message() { assert(msg_size_ == msg_buffer_.size()); osc_handler->handle_packet_async( msg_buffer_.data(), msg_buffer_.size(), shared_from_this() ); async_read_msg_size(); } void sc_osc_handler::start_tcp_accept(void) { tcp_connection::pointer new_connection = tcp_connection::create(tcp_acceptor_.get_io_service()); tcp_acceptor_.async_accept(new_connection->socket(), boost::bind(&sc_osc_handler::handle_tcp_accept, this, new_connection, boost::asio::placeholders::error)); } void sc_osc_handler::handle_tcp_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error) { if (!error) new_connection->start(this); start_tcp_accept(); } void sc_osc_handler::handle_packet_async(const char * data, size_t length, endpoint_ptr const & endpoint) { received_packet * p = received_packet::alloc_packet(data, length, endpoint); if( !p ) return; if (dump_osc_packets == 1) { ReceivedPacket packet (data, length); if (packet.IsMessage()) { ReceivedMessage message (packet); const char * address = message.AddressPattern(); if (strcmp(address, "/status") != 0) // we ignore /status messages cout << "received osc message " << message << endl; } else cout << "received osc bundle " << packet << endl; } instance->add_sync_callback(p); } time_tag sc_osc_handler::handle_bundle_nrt(const char * data, size_t length) { ReceivedPacket packet(data, length); if (!packet.IsBundle()) throw std::runtime_error("packet needs to be an osc bundle"); ReceivedBundle bundle(packet); handle_bundle (bundle, nullptr); return bundle.TimeTag(); } sc_osc_handler::received_packet * sc_osc_handler::received_packet::alloc_packet(const char * data, size_t length, endpoint_ptr const & remote_endpoint) { /* received_packet struct and data array are located in one memory chunk */ void * chunk = received_packet::allocate(sizeof(received_packet) + length); if( !chunk ) { std::cerr << "Memory allocation failure: OSC message not handled\n"; return nullptr; } received_packet * p = (received_packet*)chunk; char * cpy = (char*)(chunk) + sizeof(received_packet); memcpy(cpy, data, length); new(p) received_packet(cpy, length, remote_endpoint); return p; } void sc_osc_handler::received_packet::run(void) { instance->handle_packet(data, length, endpoint_); } void sc_osc_handler::handle_packet(const char * data, std::size_t length, endpoint_ptr const & endpoint) { ReceivedPacket packet(data, length); if (packet.IsBundle()) { ReceivedBundle bundle(packet); handle_bundle (bundle, endpoint); } else { ReceivedMessage message(packet); handle_message (message, packet.Size(), endpoint); } } template void sc_osc_handler::handle_bundle(ReceivedBundle const & bundle, endpoint_ptr const & endpoint) { time_tag bundle_time = bundle.TimeTag(); typedef osc::ReceivedBundleElementIterator bundle_iterator; typedef osc::ReceivedBundleElement bundle_element; if (bundle_time <= now) { if (!bundle_time.is_immediate()) { time_tag late = now - bundle_time; log_printf("late: %f\n", late.to_seconds()); }; for (bundle_iterator it = bundle.ElementsBegin(); it != bundle.ElementsEnd(); ++it) { bundle_element const & element = *it; if (element.IsBundle()) { ReceivedBundle inner_bundle(element); handle_bundle(inner_bundle, endpoint); } else { ReceivedMessage message(element); handle_message(message, element.Size(), endpoint); } } } else { for (bundle_iterator it = bundle.ElementsBegin(); it != bundle.ElementsEnd(); ++it) { bundle_element const & element = *it; scheduled_bundles.insert_bundle(bundle_time, element.Contents(), element.Size(), endpoint); } } } template void sc_osc_handler::handle_message(ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint) { try { if (message.AddressPatternIsUInt32()) handle_message_int_address(message, msg_size, endpoint); else handle_message_sym_address(message, msg_size, endpoint); } catch (std::exception const & e) { log_printf("exception in handle_message: %s\n", e.what()); } } namespace { typedef osc::ReceivedMessage ReceivedMessage; int first_arg_as_int(ReceivedMessage const & message) { osc::ReceivedMessageArgumentStream args = message.ArgumentStream(); osc::int32 val; args >> val; return val; } template void handle_quit(endpoint_ptr endpoint) { instance->quit_received = true; cmd_dispatcher::fire_system_callback( [=] () { instance->prepare_to_terminate(); send_done_message(endpoint, "/quit"); instance->terminate(); }); } template void handle_notify(ReceivedMessage const & message, endpoint_ptr const & endpoint) { int enable = first_arg_as_int(message); cmd_dispatcher::fire_system_callback( [=, endpoint=endpoint_ptr(endpoint)]() { int observer = 0; if (enable) { observer = instance->add_observer(endpoint); if (observer < 0) send_fail_message(endpoint, "/notify", sc_notify_observers::error_string( (sc_notify_observers::error_code)observer )); } else { observer = instance->remove_observer(endpoint); if (observer < 0) send_fail_message(endpoint, "/notify", sc_notify_observers::error_string( (sc_notify_observers::error_code)observer )); } if (observer >= 0) send_done_message(endpoint, "/notify", observer); }); } template void handle_status(endpoint_ptr const & endpoint_ref) { cmd_dispatcher::fire_io_callback( [ =, endpoint=endpoint_ptr(endpoint_ref) ] () { if (unlikely(instance->quit_received)) // we don't reply once we are about to quit return; char buffer[1024]; typedef osc::int32 i32; float peak_load, average_load; instance->cpu_load(peak_load, average_load); osc::OutboundPacketStream p(buffer, 1024); p << osc::BeginMessage("/status.reply") << (i32)1 /* unused */ << (i32)sc_factory->ugen_count() /* ugens */ << (i32)instance->synth_count() /* synths */ << (i32)instance->group_count() /* groups */ << (i32)instance->definition_count() /* synthdefs */ << average_load /* average cpu % */ << peak_load /* peak cpu % */ << instance->get_samplerate() /* nominal samplerate */ << instance->smooth_samplerate /* actual samplerate */ << osc::EndMessage; endpoint->send(p.Data(), p.Size()); }); } void handle_dumpOSC(ReceivedMessage const & message) { int val = first_arg_as_int(message); val = min (1, val); /* we just support one way of dumping osc messages */ instance->dumpOSC(val); /* thread-safe */ } template void handle_sync(ReceivedMessage const & message, endpoint_ptr const & endpoint) { int id = first_arg_as_int(message); // ping pong: we go through the nrt->rt channel to ensure that earlier messages have been completely dispatched cmd_dispatcher::fire_system_callback([=, endpoint=endpoint_ptr(endpoint)]() { cmd_dispatcher::fire_rt_callback([=, endpoint=endpoint_ptr(endpoint)]() { cmd_dispatcher::fire_io_callback([=, endpoint=endpoint_ptr(endpoint)]() { char buffer[128]; osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage("/synced") << id << osc::EndMessage; endpoint->send(p.Data(), p.Size()); }); }); }); } void handle_clearSched(void) { instance->clear_scheduled_bundles(); } void handle_error(ReceivedMessage const & message) { int val = first_arg_as_int(message); instance->set_error_posting(val); /* thread-safe */ } void handle_unhandled_message(ReceivedMessage const & msg) { log_printf("unhandled message: %s\n", msg.AddressPattern()); } static bool node_position_sanity_check(node_position_constraint const & constraint) { switch (constraint.second) { case head: case tail: case insert: { server_node * target = constraint.first; if (!target->is_group()) { log_printf("Invalid position constraint (target: %d, addAction: %d)\n", target->id(), constraint.second); return false; } break; } case before: case after: case replace: break; } return true; } sc_synth * add_synth(const char * name, int node_id, int action, int target_id) { if (!check_node_id(node_id)) return nullptr; server_node * target = find_node(target_id); if (target == nullptr) return nullptr; node_position_constraint pos = make_pair(target, node_position(action)); if (!node_position_sanity_check(pos)) return nullptr; abstract_synth * synth = instance->add_synth(name, node_id, pos); if (!synth) log_printf("Cannot create synth (synthdef: %s, node id: %d)\n", name, node_id); last_generated = node_id; return static_cast(synth); } /* extract float or int32 as float from argument iterator */ inline float extract_float_argument(osc::ReceivedMessageArgumentIterator const & it) { if (it->IsFloat()) return it->AsFloatUnchecked(); if (it->IsInt32()) return float(it->AsInt32Unchecked()); if (it->IsInt64()) return float(it->AsInt64Unchecked()); throw std::runtime_error("type cannot be converted to float"); } inline void verify_argument(osc::ReceivedMessageArgumentIterator const & it, osc::ReceivedMessageArgumentIterator const & end) { if (it == end) throw std::runtime_error("unexpected end of argument list"); } template static void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index); template void set_control_array(server_node * node, control_id_type control, osc::ReceivedMessageArgumentIterator & it) { size_t array_size = it->ComputeArrayItemCount(); ++it; if (it->IsArrayBegin()) { // nested arrays are basically user errors, but we handle them like normal arrays log("Warning in /s_new handler: nested array argument detected"); set_control_array(node, control, it); return; } else { for (size_t i = 0; i != array_size; ++i) { if (it->IsString() || it->IsSymbol()) { char const * name = it->AsStringUnchecked(); ++it; int bus_id; switch (name[0]) { case 'c': bus_id = atoi(name+1); static_cast(node)->map_control_bus(control, i, bus_id); break; case 'a': bus_id = atoi(name+1); static_cast(node)->map_control_bus(control, i, bus_id); break; default: throw runtime_error("invalid name for control mapping"); } } else { float value = extract_float_argument(it++); node->set_control_array_element(control, i, value); } } } if (!it->IsArrayEnd()) throw runtime_error("missing array end tag"); ++it; // skip array end } template void set_control(server_node * node, ControlSpecifier const & control, osc::ReceivedMessageArgumentIterator & it) { if (it->IsArrayBegin()) set_control_array(node, control, it); else if (it->IsString() || it->IsSymbol()) { char const * name = it->AsStringUnchecked(); ++it; int bus_id; switch (name[0]) { case 'c': bus_id = atoi(name+1); apply_control_bus_mapping(*node, control, bus_id); break; case 'a': bus_id = atoi(name+1); apply_control_bus_mapping(*node, control, bus_id); break; default: throw runtime_error("invalid name for control mapping"); } } else { float value = extract_float_argument(it++); node->set(control, value); } } /* set control values of node from string/float or int/float pair */ void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it, osc::ReceivedMessageArgumentIterator end) { if (it->IsInt32()) { osc::int32 index = it->AsInt32Unchecked(); ++it; if (it == end) return; // sclang sometimes uses an integer instead of an empty argument list set_control(node, index, it); } else if (it->IsString()) { const char * str = it->AsStringUnchecked(); ++it; set_control(node, str, it); } else throw runtime_error("invalid argument"); } void handle_s_new(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin(), end = msg.ArgumentsEnd(); const char * def_name = args->AsString(); ++args; int32_t id = args->AsInt32(); ++args; if (id == -1) id = instance->generate_node_id(); int32_t action, target; if (args != end) { action = args->AsInt32(); ++args; } else action = 0; if (args != end) { target = args->AsInt32(); ++args; } else target = 0; sc_synth * synth = add_synth(def_name, id, action, target); if (synth == nullptr) return; try { while (args != end) set_control(synth, args, end); } catch(std::exception & e) { log_printf("exception in /s_new: %s\n", e.what()); } } void handle_g_new(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_id, action, target_id; args >> node_id >> action >> target_id; if (node_id == -1) node_id = instance->generate_node_id(); else if (!check_node_id(node_id)) continue; server_node * target = find_node(target_id); if (!target) continue; node_position_constraint pos = make_pair(target, node_position(action)); if (!node_position_sanity_check(pos)) continue; instance->add_group(node_id, pos); last_generated = node_id; } } void handle_g_freeall(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 id; args >> id; abstract_group * group = find_group(id); if (!group) continue; instance->group_free_all(group); } } void handle_g_deepFree(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 id; args >> id; abstract_group * group = find_group(id); if (!group) continue; instance->group_free_deep(group); } } void g_query_tree_fill_node(osc::OutboundPacketStream & p, bool flag, server_node const & node) { p << osc::int32(node.id()); if (node.is_synth()) p << -1; else p << osc::int32(static_cast(node).child_count()); if (node.is_synth()) { sc_synth const & scsynth = static_cast(node); p << scsynth.definition_name(); if (flag) { osc::int32 controls = scsynth.mNumControls; p << controls; for (int i = 0; i != controls; ++i) { p << osc::int32(i); /** \todo later we can return symbols */ if (scsynth.mMapControls[i] != (scsynth.mControls+i)) { /* we use a bus mapping */ int bus = (scsynth.mMapControls[i]) - (scsynth.mNode.mWorld->mControlBus); char str[10]; sprintf(str, "s%d", bus); p << str; } else p << scsynth.mControls[i]; } } } else { abstract_group const & group = static_cast(node); group.apply_on_children( [&](server_node const & node) { g_query_tree_fill_node(p, flag, node); }); } } template void g_query_tree(int node_id, bool flag, endpoint_ptr endpoint) { server_node * node = find_node(node_id); if (!node || node->is_synth()) return; abstract_group * group = static_cast(node); size_t max_msg_size = 1<<16; for(;;) { try { if (max_msg_size > 1<<22) return; sized_array > data(max_msg_size); osc::OutboundPacketStream p(data.c_array(), max_msg_size); p << osc::BeginMessage("/g_queryTree.reply") << (flag ? 1 : 0) << node_id << osc::int32(group->child_count()); group->apply_on_children([&](server_node const & node) { g_query_tree_fill_node(p, flag, node); }); p << osc::EndMessage; movable_array message(p.Size(), data.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); return; } catch(...) { max_msg_size *= 2; /* if we run out of memory, retry with doubled memory resources */ } } } template void handle_g_queryTree(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { try { osc::int32 id, flag; args >> id >> flag; g_query_tree(id, flag, endpoint); } catch (std::exception & e) { log_printf("exception in handle_g_queryTree: %s\n", e.what()); } } } typedef std::basic_stringstream /*, rt_pool_allocator*/ > rt_string_stream; void fill_spaces(rt_string_stream & stream, int level) { for (int i = 0; i != level*3; ++i) stream << ' '; } void dump_controls(rt_string_stream & stream, abstract_synth const & synth, int indentation_level) { const size_t number_of_slots = synth.number_of_slots(); bool eol_pending = false; for (size_t control_index = 0; control_index != number_of_slots; ++control_index) { const char * name_of_slot = synth.name_of_slot(control_index); if (name_of_slot) { if (eol_pending) { stream << endl; eol_pending = false; } fill_spaces(stream, indentation_level); stream << synth.name_of_slot(control_index) << ": "; eol_pending = true; } else stream << ", "; stream << synth.get(control_index); } if (eol_pending) stream << endl; } void g_dump_node(rt_string_stream & stream, server_node & node, bool flag, int level) { using namespace std; fill_spaces(stream, level); if (node.is_synth()) { abstract_synth const & synth = static_cast(node); stream << synth.id() << " " << synth.definition_name() << endl; if (flag) dump_controls(stream, synth, level + 1); } else { abstract_group & group = static_cast(node); stream << group.id(); if (group.is_parallel()) stream << " parallel group"; else stream << " group"; stream << endl; group.apply_on_children( [&](server_node & node) { g_dump_node(stream, node, flag, level + 1); }); } } void g_dump_tree(int id, bool flag) { server_node * node = find_node(id); if (!node) return; // FIXME: can we completely avoid all internal allocations? rt_string_stream stream; stream << "NODE TREE Group " << id << std::endl; g_dump_node(stream, *node, flag, 1); log(stream.str().c_str(), stream.str().size()); } void handle_g_dumpTree(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { try { osc::int32 id, flag; args >> id >> flag; g_dump_tree(id, flag); } catch (std::exception & e) { log_printf("exception in /g_dumpTree: %s\n", e.what()); } } } void handle_n_free(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { try { osc::int32 id; args >> id; server_node * node = find_node(id); if (!node) continue; instance->free_node(node); } catch (std::exception & e) { log_printf("exception in /n_free: %s\n", e.what()); } } } /** macro to define an os command handler with a starting node id * * it is mainly intended as decorator to avoid duplicate error handling code */ #define HANDLE_N_DECORATOR(cmd, function) \ void handle_n_##cmd(ReceivedMessage const & msg) \ { \ osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); \ osc::int32 id = it->AsInt32(); ++it; \ \ server_node * node = find_node(id); \ if (!node) \ return; \ \ try { \ while (it != msg.ArgumentsEnd()) \ function(node, it); \ } catch(std::exception & e) { \ log_printf("Exception during /n_" #cmd "handler: %s\n", e.what());\ } \ } void set_control(server_node * node, osc::ReceivedMessageArgumentIterator & it) { if (it->IsInt32()) { osc::int32 index = it->AsInt32Unchecked(); ++it; set_control(node, index, it); } else if (it->IsString()) { const char * str = it->AsStringUnchecked(); ++it; set_control(node, str, it); } else throw runtime_error("invalid argument"); } HANDLE_N_DECORATOR(set, set_control) void set_control_n(server_node * node, osc::ReceivedMessageArgumentIterator & it) { if (it->IsInt32()) { osc::int32 index = it->AsInt32Unchecked(); ++it; osc::int32 count = it->AsInt32(); ++it; for (int i = 0; i != count; ++i) node->set(index + i, extract_float_argument(it++)); } else if (it->IsString()) { const char * str = it->AsStringUnchecked(); ++it; osc::int32 count = it->AsInt32(); ++it; sized_array values(count); for (int i = 0; i != count; ++i) values[i] = extract_float_argument(it++); node->set_control_array(str, count, values.c_array()); } else throw runtime_error("invalid argument"); } HANDLE_N_DECORATOR(setn, set_control_n) void fill_control(server_node * node, osc::ReceivedMessageArgumentIterator & it) { if (it->IsInt32()) { osc::int32 index = it->AsInt32Unchecked(); ++it; osc::int32 count = it->AsInt32(); ++it; float value = extract_float_argument(it++); for (int i = 0; i != count; ++i) node->set(index + i, value); } else if (it->IsString()) { const char * str = it->AsStringUnchecked(); ++it; osc::int32 count = it->AsInt32(); ++it; float value = extract_float_argument(it++); sized_array values(count); for (int i = 0; i != count; ++i) values[i] = value; node->set_control_array(str, count, values.c_array()); } else throw runtime_error("invalid argument"); } HANDLE_N_DECORATOR(fill, fill_control) template void apply_control_bus_mapping(server_node & node, slot_type slot, int bus_index) { if (node.is_synth()) static_cast(node).map_control_bus(slot, bus_index); else { static_cast(node).apply_on_children( [&] (server_node & node) { apply_control_bus_mapping(node, slot, bus_index); }); } } template void apply_control_busn_mapping(server_node & node, slot_type slot, int bus_index, int count) { if (node.is_synth()) static_cast(node).map_control_buses(slot, bus_index, count); else { static_cast(node).apply_on_children( [&] (server_node & node) { apply_control_busn_mapping(node, slot, bus_index, count); }); } } template void map_control(server_node * node, osc::ReceivedMessageArgumentIterator & it) { if (it->IsInt32()) { osc::int32 control_index = it->AsInt32Unchecked(); ++it; osc::int32 control_bus_index = it->AsInt32(); ++it; apply_control_bus_mapping(*node, control_index, control_bus_index); } else if (it->IsString()) { const char * control_name = it->AsStringUnchecked(); ++it; osc::int32 control_bus_index = it->AsInt32(); ++it; apply_control_bus_mapping(*node, control_name, control_bus_index); } else throw runtime_error("invalid argument"); } template void mapn_control(server_node * node, osc::ReceivedMessageArgumentIterator & it) { if (it->IsInt32()) { osc::int32 control_index = it->AsInt32Unchecked(); ++it; osc::int32 bus_index = it->AsInt32(); ++it; osc::int32 count = it->AsInt32(); ++it; apply_control_busn_mapping(*node, control_index, bus_index, count); } else if (it->IsString()) { const char * control_name = it->AsStringUnchecked(); ++it; osc::int32 bus_index = it->AsInt32(); ++it; osc::int32 count = it->AsInt32(); ++it; apply_control_busn_mapping(*node, control_name, bus_index, count); } else throw runtime_error("invalid argument"); } HANDLE_N_DECORATOR(map, map_control) HANDLE_N_DECORATOR(mapa, map_control) HANDLE_N_DECORATOR(mapn, mapn_control) HANDLE_N_DECORATOR(mapan, mapn_control) template void handle_n_before_or_after(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_a, node_b; args >> node_a >> node_b; server_node * node = find_node(node_a); if (!node) continue; server_node * target_node = find_node(node_b); if (!target_node) continue; abstract_group::move_before_or_after(node, target_node); instance->notification_node_moved(node); } instance->request_dsp_queue_update(); } template void handle_g_head_or_tail(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_id, target_id; args >> target_id >> node_id; server_node * node = find_node(node_id); if (!node) continue; abstract_group * target_group = find_group(target_id); if (!target_group) continue; abstract_group::move_to_head_or_tail(node, target_group); instance->notification_node_moved(node); } instance->request_dsp_queue_update(); } template void handle_n_query(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_id; args >> node_id; server_node * node = find_node(node_id); if (!node) continue; char buffer[128]; // 128 byte should be enough osc::OutboundPacketStream p(buffer, 128); p << osc::BeginMessage("/n_info"); fill_notification(node, p); movable_array message(p.Size(), p.Data()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } } void handle_n_order(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); osc::int32 action, target_id; args >> action >> target_id; server_node * target = find_node(target_id); if (target == nullptr) return; abstract_group * target_parent; if (action == before || action == after) target_parent = target->get_parent(); else { if (target->is_synth()) throw std::runtime_error("invalid argument for n_order: argument is no synth"); target_parent = static_cast(target); } while (!args.Eos()) { osc::int32 node_id; args >> node_id; server_node * node = find_node(node_id); if (node == nullptr) continue; abstract_group * node_parent = node->get_parent(); /** TODO: this can be optimized if node_parent == target_parent */ node_parent->remove_child(node); if (action == before || action == after) target_parent->add_child(node, make_pair(target, node_position(action))); else target_parent->add_child(node, node_position(action)); instance->notification_node_moved(node); } instance->request_dsp_queue_update(); } void handle_n_run(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_id, run_flag; args >> node_id >> run_flag; server_node * node = find_node(node_id); if(!node) continue; if (run_flag) instance->node_resume(node); else instance->node_pause(node); } } void enable_tracing(server_node & node) { if (node.is_synth()) { sc_synth & synth = static_cast(node); synth.enable_tracing(); } else { abstract_group & group = static_cast(node); group.apply_on_children(enable_tracing); } } void handle_n_trace(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_id; args >> node_id; server_node * node = find_node(node_id); if (!node) continue; enable_tracing(*node); } } void handle_s_noid(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 node_id; args >> node_id; instance->synth_reassign_id(node_id); } } int32_t get_control_index(sc_synth * s, osc::ReceivedMessageArgumentIterator & it, osc::OutboundPacketStream & p) { int32_t control; if (it->IsInt32()) { control = it->AsInt32Unchecked(); ++it; p << control; } else if (it->IsString()) { const char * control_str = it->AsStringUnchecked(); ++it; control = s->resolve_slot(control_str); p << control_str; } else if (it->IsSymbol()) { const char * control_str = it->AsSymbolUnchecked(); ++it; control = s->resolve_slot(control_str); p << osc::Symbol(control_str); } else throw std::runtime_error("wrong argument type"); return control; } template void handle_s_get(ReceivedMessage const & msg, size_t msg_size, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); if (!it->IsInt32()) throw std::runtime_error("wrong argument type"); int32_t node_id = it->AsInt32Unchecked(); ++it; server_node * node = find_node(node_id); if (!node || !node->is_synth()) throw std::runtime_error("node is not a synth"); sc_synth * s = static_cast(node); size_t alloc_size = msg_size + sizeof(float) * (msg.ArgumentCount()-1) + 128; sized_array > return_message(alloc_size); osc::OutboundPacketStream p(return_message.c_array(), alloc_size); p << osc::BeginMessage("/n_set") << node_id; while (it != msg.ArgumentsEnd()) { int32_t control = get_control_index(s, it, p); p << s->get(control); } p << osc::EndMessage; movable_array message(p.Size(), return_message.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } template void handle_s_getn(ReceivedMessage const & msg, size_t msg_size, endpoint_ptr const & endpoint) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); if (!it->IsInt32()) throw std::runtime_error("wrong argument type"); int32_t node_id = it->AsInt32Unchecked(); ++it; server_node * node = find_node(node_id); if (!node || !node->is_synth()) throw std::runtime_error("node is not a synth"); sc_synth * s = static_cast(node); /* count argument values */ size_t argument_count = 0; for (osc::ReceivedMessageArgumentIterator local = it; local != msg.ArgumentsEnd(); ++local) { ++local; /* skip control */ if (local == msg.ArgumentsEnd()) break; if (!it->IsInt32()) throw std::runtime_error("invalid count"); argument_count += it->AsInt32Unchecked(); ++it; } size_t alloc_size = msg_size + sizeof(float) * (argument_count) + 128; sized_array > return_message(alloc_size); osc::OutboundPacketStream p(return_message.c_array(), alloc_size); p << osc::BeginMessage("/n_setn") << node_id; while (it != msg.ArgumentsEnd()) { int32_t control = get_control_index(s, it, p); if (!it->IsInt32()) throw std::runtime_error("integer argument expected"); int32_t control_count = it->AsInt32Unchecked(); ++it; if (control_count < 0) break; for (int i = 0; i != control_count; ++i) p << s->get(control + i); } p << osc::EndMessage; movable_array message(p.Size(), return_message.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } /** wrapper class for osc completion message */ struct completion_message { /** constructor should only be used from the real-time thread */ completion_message(size_t size, const void * data): size_(size) { if (size) { data_ = system_callback::allocate(size); memcpy(data_, data, size); } } /** default constructor creates uninitialized object */ completion_message(void): size_(0) {} completion_message( completion_message const & rhs) = delete; completion_message operator=( completion_message const & rhs) = delete; completion_message(completion_message && rhs) { operator=( std::forward( rhs ) ); } completion_message& operator=(completion_message && rhs) { size_ = rhs.size_; data_ = rhs.data_; rhs.size_ = 0; return *this; } ~completion_message(void) { if (size_) system_callback::deallocate(data_); } /** handle package in the rt thread * not to be called from the rt thread */ void trigger_async(endpoint_ptr const & endpoint) { if (size_) { sc_osc_handler::received_packet * p = sc_osc_handler::received_packet::alloc_packet((char*)data_, size_, endpoint); if( p ) instance->add_sync_callback(p); } } /** handle package directly * only to be called from the rt thread */ void handle(endpoint_ptr const & endpoint) const { if (size_) instance->handle_packet((char*)data_, size_, endpoint); } size_t size_; void * data_; }; completion_message extract_completion_message(osc::ReceivedMessageArgumentStream & args) { osc::Blob blob(nullptr, 0); if (!args.Eos()) { try { args >> blob; } catch (osc::WrongArgumentTypeException & e) {} } return completion_message (blob.size, blob.data); } completion_message extract_completion_message(osc::ReceivedMessageArgumentIterator & it) { const void * data = nullptr; osc::osc_bundle_element_size_t length = 0; if (it->IsBlob()) it->AsBlobUnchecked(data, length); ++it; return completion_message(length, data); } // must be called from rt thread void handle_completion_message( completion_message && message, endpoint_ptr endpoint ) { completion_message msg( std::forward( message ) ); msg.handle( endpoint ); } template void handle_b_alloc(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); osc::int32 bufferIndex, frames, channels; args >> bufferIndex >> frames; if (!args.Eos()) args >> channels; else channels = 1; completion_message message = extract_completion_message(args); cmd_dispatcher::fire_system_callback( [=, message = std::move(message) ] () mutable { sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard( bufferIndex )); try { sample * free_buf = sc_factory->get_nrt_mirror_buffer(bufferIndex); sc_factory->allocate_buffer(bufferIndex, frames, channels); cmd_dispatcher::fire_rt_callback( [=, message = std::move(message) ] () mutable { sc_factory->buffer_sync( bufferIndex ); handle_completion_message( std::move(message), endpoint ); cmd_dispatcher::fire_system_callback( [=]{ free_aligned(free_buf); send_done_message(endpoint, "/b_alloc", bufferIndex); }); }); } catch (std::exception const & error) { report_failure(endpoint, error, "/b_alloc", bufferIndex); cmd_dispatcher::free_in_rt_thread( std::move(message) ); } }); } template void handle_b_free(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); osc::int32 index; args >> index; completion_message message = extract_completion_message(args); cmd_dispatcher::fire_system_callback( [=, message = std::move(message) ] () mutable { sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(index)); sample * free_buf = sc_factory->get_nrt_mirror_buffer(index); sc_factory->free_buffer(index); cmd_dispatcher::fire_rt_callback( [=, message = std::move(message) ] () mutable { sc_factory->buffer_sync(index); handle_completion_message( std::move(message), endpoint ); cmd_dispatcher::fire_system_callback( [=] { free_aligned(free_buf); send_done_message(endpoint, "/b_free", index); }); }); }); } template void handle_b_allocRead(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); osc::int32 bufferIndex; const char * filenameString; osc::int32 start = 0; osc::int32 frames = 0; args >> bufferIndex >> filenameString; if (!args.Eos()) args >> start; if (!args.Eos()) args >> frames; completion_message message = extract_completion_message(args); movable_string filename( filenameString ); cmd_dispatcher::fire_system_callback([ =, filename = std::move(filename), message = std::move(message) ] () mutable { sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard( bufferIndex )); sample * free_buf = sc_factory->get_nrt_mirror_buffer(bufferIndex); try { sc_factory->buffer_read_alloc(bufferIndex, filename.c_str(), start, frames); cmd_dispatcher::fire_rt_callback( [ =, filename = std::move(filename), message = std::move(message) ] () mutable { sc_factory->buffer_sync(bufferIndex); handle_completion_message( std::move(message), endpoint ); consume( std::move(filename) ); cmd_dispatcher::fire_system_callback( [=] { free_aligned(free_buf); send_done_message(endpoint, "/b_allocRead", bufferIndex); }); }); } catch (std::exception const & error) { cmd_dispatcher::free_in_rt_thread( std::move( message ), std::move( filename ) ); report_failure(endpoint, error, "/b_allocRead", bufferIndex); } }); } template void handle_b_allocReadChannel(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin(); osc::int32 bufnum = arg->AsInt32(); arg++; const char * filenameString = arg->AsString(); arg++; osc::int32 start = arg->AsInt32(); arg++; size_t frames = arg->AsInt32(); arg++; size_t channel_args = msg.ArgumentCount() - 4; /* we already consumed 4 elements */ size_t channel_count = 0; sized_array > channels(channel_args); // sclang formats the last completion message as int, so we skip the last element for (uint i = 0; i != channel_args - 1; ++i) { if (arg->IsInt32()) { channels[i] = arg->AsInt32Unchecked(); arg++; ++channel_count; } } /* we reached the message blob */ completion_message message = extract_completion_message(arg); movable_array channel_mapping(channel_count, channels.c_array()); movable_string filename(filenameString); cmd_dispatcher::fire_system_callback( [ =, message=std::move(message), channel_mapping=std::move(channel_mapping), filename=std::move(filename) ] () mutable { sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(bufnum)); sample * free_buf = sc_factory->get_nrt_mirror_buffer(bufnum); try { sc_factory->buffer_alloc_read_channels(bufnum, filename.c_str(), start, frames, channel_mapping.size(), channel_mapping.data()); cmd_dispatcher::fire_rt_callback( [=, message=std::move(message), channel_mapping=std::move(channel_mapping), filename=std::move(filename) ] () mutable { sc_factory->buffer_sync(bufnum); consume( std::move( channel_mapping ) ); consume( std::move( filename ) ); handle_completion_message( std::move(message), endpoint ); cmd_dispatcher::fire_system_callback( [=] { free_aligned(free_buf); send_done_message(endpoint, "/b_allocReadChannel", bufnum); }); }); } catch (std::exception const & error) { cmd_dispatcher::free_in_rt_thread( std::move( message ), std::move( channel_mapping ), std::move( filename ) ); report_failure(endpoint, error, "/b_allocReadChannel", bufnum); } }); } const char * b_write = "/b_write"; void fire_b_write_exception(void) { throw std::runtime_error("wrong arguments for /b_write"); } template void handle_b_write(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin(); osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd(); /* required args */ osc::int32 bufnum = arg->AsInt32(); arg++; const char * filename = arg->AsString(); arg++; const char * header_format = arg->AsString(); arg++; const char * sample_format = arg->AsString(); arg++; /* optional args */ osc::int32 frames = -1; osc::int32 start = 0; osc::int32 leave_open = 0; completion_message message; if (arg != end) { if (!arg->IsInt32()) fire_b_write_exception(); frames = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_write_exception(); start = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_write_exception(); leave_open = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) message = extract_completion_message(arg); fire_callback: movable_string filenameString(filename); movable_string headerString(header_format); movable_string sampleString(sample_format); cmd_dispatcher::fire_system_callback( [=, message = std::move(message), filenameString = std::move(filenameString), headerString = std::move(headerString), sampleString = std::move(sampleString) ] () mutable { sc_ugen_factory::buffer_lock_t buffer_lock(sc_factory->buffer_guard(bufnum)); try { sc_factory->buffer_write(bufnum, filenameString.c_str(), headerString.c_str(), sampleString.c_str(), start, frames, leave_open); message.trigger_async( endpoint ); cmd_dispatcher::fire_done_message( endpoint, b_write, bufnum ); } catch (std::exception const & error) { report_failure(endpoint, error, b_write, bufnum); } cmd_dispatcher::free_in_rt_thread( std::move(message), std::move(filenameString), std::move(headerString), std::move(sampleString)); }); } const char * b_read = "/b_read"; void fire_b_read_exception(void) { throw std::runtime_error("wrong arguments for /b_read"); } template void handle_b_read(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin(); osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd(); /* required args */ osc::int32 bufnum = arg->AsInt32(); arg++; const char * filename = arg->AsString(); arg++; /* optional args */ osc::int32 start_file = 0; osc::int32 frames = -1; osc::int32 start_buffer = 0; osc::int32 leave_open = 0; completion_message message; if (arg != end) { if (!arg->IsInt32()) fire_b_read_exception(); start_file = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_read_exception(); frames = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_read_exception(); start_buffer = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_read_exception(); leave_open = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) message = std::move( extract_completion_message(arg) ); fire_callback: movable_string fname(filename); cmd_dispatcher::fire_system_callback( [=, filename = std::move(fname), message = std::move(message) ] () mutable { sc_ugen_factory::buffer_lock_t buffer_lock( sc_factory->buffer_guard(bufnum) ); try { sc_factory->buffer_read(bufnum, filename.c_str(), start_file, frames, start_buffer, leave_open); cmd_dispatcher::fire_rt_callback([=, filename = std::move(filename), message = std::move(message) ] () mutable { sc_factory->buffer_sync( bufnum ); handle_completion_message( std::move( message ), endpoint ); consume( std::move(filename) ); cmd_dispatcher::fire_done_message( endpoint, b_read, bufnum ); }); } catch (std::exception const & error) { report_failure( endpoint, error, b_read, bufnum ); cmd_dispatcher::free_in_rt_thread( std::move( message), std::move(filename) ); } }); } const char * b_readChannel = "/b_readChannel"; void fire_b_readChannel_exception(void) { throw std::runtime_error("wrong arguments for /b_readChannel"); } template void handle_b_readChannel(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentIterator arg = msg.ArgumentsBegin(); osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd(); /* required args */ osc::int32 bufnum = arg->AsInt32(); arg++; const char * filename = arg->AsString(); arg++; /* optional args */ osc::int32 start_file = 0; osc::int32 frames = -1; osc::int32 start_buffer = 0; osc::int32 leave_open = 0; sized_array > channel_mapping(int32_t(msg.ArgumentCount())); /* larger than required */ uint32_t channel_count = 0; completion_message message; if (arg != end) { if (!arg->IsInt32()) fire_b_read_exception(); start_file = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_read_exception(); frames = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_write_exception(); start_buffer = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; if (arg != end) { if (!arg->IsInt32()) fire_b_write_exception(); leave_open = arg->AsInt32Unchecked(); arg++; } else goto fire_callback; while (arg != end) { if (arg->IsBlob()) { message = extract_completion_message(arg); goto fire_callback; } else if (arg->IsInt32()) { channel_mapping[channel_count] = arg->AsInt32Unchecked(); ++arg; } else fire_b_readChannel_exception(); } fire_callback: movable_string fname(filename); movable_array channel_map(channel_count, channel_mapping.c_array()); cmd_dispatcher::fire_system_callback( [ =, message=std::move(message), filename = std::move(fname), channel_map = std::move( channel_map ) ] () mutable { try { sc_factory->buffer_read_channel(bufnum, filename.c_str(), start_file, frames, start_buffer, leave_open, channel_map.size(), channel_map.data()); cmd_dispatcher::fire_rt_callback( [ =, message=std::move(message), filename = std::move(filename), channel_map = std::move( channel_map ) ] () mutable { sc_factory->buffer_sync(bufnum); handle_completion_message( std::move( message ), endpoint ); consume( std::move(filename) ); consume( std::move(channel_map) ); cmd_dispatcher::fire_done_message(endpoint, b_readChannel, bufnum); }); } catch (std::exception const & error) { report_failure(endpoint, error, b_readChannel, bufnum); cmd_dispatcher::free_in_rt_thread( std::move(filename), std::move(channel_map), std::move(message) ); } }); } const char * b_zero = "/b_zero"; template void handle_b_zero(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); osc::int32 index; args >> index; completion_message message = extract_completion_message(args); cmd_dispatcher::fire_system_callback( [ =, message = std::move(message) ] () mutable { sc_factory->buffer_zero(index); cmd_dispatcher::fire_rt_callback( [ =, message = std::move(message) ] () mutable { sc_factory->increment_write_updates(index); handle_completion_message( std::move( message), endpoint ); cmd_dispatcher::fire_done_message( endpoint, b_zero, index ); }); }); } void handle_b_set(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd(); verify_argument(it, end); osc::int32 buffer_index = it->AsInt32(); ++it; buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index); if( !data ) { log_printf("/b_set called on unallocated buffer"); return; } while (it != end) { osc::int32 index = it->AsInt32(); ++it; float value = extract_float_argument(it++); data[index] = value; } } void handle_b_setn(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd(); verify_argument(it, end); osc::int32 buffer_index = it->AsInt32(); ++it; buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index); if( !data ) { log_printf("/b_setn called on unallocated buffer"); return; } while (it != end) { osc::int32 index = it->AsInt32(); ++it; verify_argument(it, end); osc::int32 samples = it->AsInt32(); ++it; for (int i = 0; i != samples; ++i) { verify_argument(it, end); float value = extract_float_argument(it++); data[index+i] = value; } } } void handle_b_fill(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); osc::ReceivedMessageArgumentIterator end = msg.ArgumentsEnd(); verify_argument(it, end); osc::int32 buffer_index = it->AsInt32(); ++it; buffer_wrapper::sample_t * data = sc_factory->get_buffer(buffer_index); if( !data ) { log_printf("/b_fill called on unallocated buffer"); return; } while (it != end) { osc::int32 index = it->AsInt32(); ++it; verify_argument(it, end); osc::int32 samples = it->AsInt32(); ++it; verify_argument(it, end); float value = extract_float_argument(it++); for (int i = 0; i != samples; ++i) data[index] = value; } } template void handle_b_query(ReceivedMessage const & msg, endpoint_ptr endpoint) { const size_t elem_size = 3*sizeof(int) * sizeof(float); osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); size_t arg_count = msg.ArgumentCount(); size_t size = elem_size * arg_count + 128; /* should be more than required */ sized_array > data(size); osc::OutboundPacketStream p(data.c_array(), size); p << osc::BeginMessage("/b_info"); while (!args.Eos()) { osc::int32 buffer_index; args >> buffer_index; SndBuf * buf = sc_factory->get_buffer_struct(buffer_index); p << buffer_index << osc::int32(buf->frames) << osc::int32(buf->channels) << float (buf->samplerate); } p << osc::EndMessage; movable_array message(p.Size(), data.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } template void handle_b_close(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); osc::int32 index; args >> index; completion_message message = extract_completion_message(args); cmd_dispatcher::fire_system_callback( [ =, message = std::move(message) ] () mutable { sc_factory->buffer_close(index); cmd_dispatcher::fire_rt_callback( [ =, message = std::move(message) ] () mutable { handle_completion_message( std::move(message), endpoint ); cmd_dispatcher::fire_done_message( endpoint, "/b_close", index ); }); }); } template void handle_b_get(ReceivedMessage const & msg, endpoint_ptr endpoint) { const size_t elem_size = sizeof(int) * sizeof(float); osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); const size_t index_count = msg.ArgumentCount() - 1; const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */ sized_array > return_message(alloc_size); osc::int32 buffer_index; args >> buffer_index; const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index); const sample * data = buf->data; if( !data ) { log_printf("/b_get called on unallocated buffer"); return; } const int max_sample = buf->frames * buf->channels; osc::OutboundPacketStream p(return_message.c_array(), alloc_size); p << osc::BeginMessage("/b_set") << buffer_index; while (!args.Eos()) { osc::int32 index; args >> index; p << index; if (index < max_sample) p << data[index]; else p << 0.f; } p << osc::EndMessage; movable_array message(p.Size(), return_message.c_array()); cmd_dispatcher::fire_message( endpoint, std::move( message ) ); } template struct getn_data { getn_data(int start, int count, const float * data): start_index_(start), data_(count) { data_.reserve(count); for (int i = 0; i != count; ++i) data_[i] = data[i]; } int start_index_; std::vector data_; }; template void handle_b_getn(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); typedef getn_data > getn_data; std::vector > return_data; osc::int32 buffer_index; args >> buffer_index; const SndBuf * buf = sc_factory->get_buffer_struct(buffer_index); const sample * data = buf->data; if( !data ) { log_printf("/b_getn called on unallocated buffer"); return; } const int max_sample = buf->frames * buf->channels; while (!args.Eos()) { osc::int32 index, sample_count; args >> index >> sample_count; if (index + sample_count <= max_sample) return_data.push_back(getn_data(index, sample_count, data + index)); } size_t alloc_size = 128; for (size_t i = 0; i != return_data.size(); ++i) alloc_size += return_data[i].data_.size() * (sizeof(float) + sizeof(int)) + 2*sizeof(int); sized_array > return_message(alloc_size); osc::OutboundPacketStream p(return_message.c_array(), alloc_size); p << osc::BeginMessage("/b_setn") << buffer_index; for (size_t i = 0; i != return_data.size(); ++i) { p << osc::int32(return_data[i].start_index_) << osc::int32(return_data[i].data_.size()); for (size_t j = 0; j != return_data[i].data_.size(); ++j) p << return_data[i].data_[j]; } p << osc::EndMessage; movable_array message(p.Size(), return_message.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } template void handle_b_gen(ReceivedMessage const & msg, size_t msg_size, endpoint_ptr endpoint) { movable_array cmd (msg_size, msg.AddressPattern()); cmd_dispatcher::fire_system_callback( [=, message=std::move(cmd)] () mutable { const char * data = (char*)message.data(); const char * msg_data = OSCstrskip(data); // skip address size_t diff = msg_data - data; sc_msg_iter msg(message.size() - diff, msg_data); char nextTag = msg.nextTag(); if (nextTag != 'i') { printf("/b_gen handler: invalid buffer index type %c\n", nextTag); return; } int index = msg.geti(); const char * generator = (const char*)msg.gets4(); if (!generator) { if (nextTag += 'i') { printf("/b_gen handler: invalid bufgen name\n"); return; } } sample * free_buf = sc_factory->buffer_generate(index, generator, msg); cmd_dispatcher::fire_rt_callback( [=, message=std::move(message)] () mutable { consume( std::move(message) ); sc_factory->buffer_sync(index); cmd_dispatcher::fire_system_callback([=] { free_aligned(free_buf); send_done_message(endpoint, "/b_gen", index); }); }); }); } void handle_c_set(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); while (it != msg.ArgumentsEnd()) { osc::int32 bus_index = it->AsInt32(); ++it; if( it == msg.ArgumentsEnd() ) return; float value = extract_float_argument(it++); sc_factory->controlbus_set(bus_index, value); } } void handle_c_setn(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); while (it != msg.ArgumentsEnd()) { osc::int32 bus_index, bus_count; bus_index = it->AsInt32(); ++it; bus_count = it->AsInt32(); ++it; for (int i = 0; i != bus_count; ++i) { float value = extract_float_argument(it++); sc_factory->controlbus_set(bus_index + i, value); } } } void handle_c_fill(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentIterator it = msg.ArgumentsBegin(); while (it != msg.ArgumentsEnd()) { osc::int32 bus_index, bus_count; bus_index = it->AsInt32(); ++it; bus_count = it->AsInt32(); ++it; float value = extract_float_argument(it++); sc_factory->controlbus_fill(bus_index, bus_count, value); } } template void handle_c_get(ReceivedMessage const & msg, endpoint_ptr endpoint) { const size_t elem_size = sizeof(int) + sizeof(float); osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); const size_t index_count = msg.ArgumentCount(); const size_t alloc_size = index_count * elem_size + 128; /* hopefully enough */ sized_array > return_message(alloc_size); osc::OutboundPacketStream p(return_message.c_array(), alloc_size); p << osc::BeginMessage("/c_set"); while (!args.Eos()) { osc::int32 index; args >> index; p << index << sc_factory->controlbus_get(index); } p << osc::EndMessage; movable_array message(p.Size(), return_message.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } template void handle_c_getn(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); /* we pessimize, but better to allocate too much than too little */ const size_t alloc_size = 128 + (2 * sizeof(int) + 128*sizeof(float)) * msg.ArgumentCount(); sized_array > return_message(alloc_size); osc::OutboundPacketStream p(return_message.c_array(), alloc_size); p << osc::BeginMessage("/c_setn"); while (!args.Eos()) { osc::int32 bus_index, bus_count; args >> bus_index >> bus_count; p << bus_index << bus_count; for (int i = 0; i != bus_count; ++i) { float value = sc_factory->controlbus_get(bus_index + i); p << value; } } p << osc::EndMessage; movable_array message(p.Size(), return_message.c_array()); cmd_dispatcher::fire_message( endpoint, std::move(message) ); } static std::vector wrapSynthdefs( std::vector && synthdefs ) { std::vector wrappedSynthdefs; wrappedSynthdefs.reserve( synthdefs.size() ); for( sc_synthdef & synthdef : synthdefs ) { sc_synth_definition_ptr ptr( new sc_synth_definition( std::move(synthdef) ) ); wrappedSynthdefs.emplace_back( std::move( ptr ) ); } return std::move( wrappedSynthdefs ); } template void handle_d_recv(ReceivedMessage const & msg, endpoint_ptr endpoint) { const void * synthdef_data; osc::osc_bundle_element_size_t synthdef_size; osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin(); args->AsBlob(synthdef_data, synthdef_size); ++args; movable_array def(synthdef_size, (const char*)synthdef_data); completion_message message = extract_completion_message(args); cmd_dispatcher::fire_system_callback( [ =, def = std::move(def), message = std::move(message) ] () mutable { std::vector wrappedSynthdefs = wrapSynthdefs( read_synthdefs(def.data(), def.data() + def.size()) ); cmd_dispatcher::fire_rt_callback( [ =, def = std::move(def), message = std::move(message), wrappedSynthdefs = std::move(wrappedSynthdefs) ] () mutable { for( sc_synth_definition_ptr & definition : wrappedSynthdefs ) instance->register_definition( std::move(definition) ); handle_completion_message( std::move(message), endpoint ); consume( std::move(def) ); cmd_dispatcher::fire_system_callback( [=, wrappedSynthdefs = std::move(wrappedSynthdefs)] { consume( std::move(wrappedSynthdefs) ); send_done_message(endpoint, "/d_recv"); } ); }); }); } template void handle_d_load(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentIterator args = msg.ArgumentsBegin(); const char * path = args->AsString(); args++; completion_message message = extract_completion_message(args); movable_string path_string (path); cmd_dispatcher::fire_system_callback( [=, message=std::move(message), path_string=std::move(path_string) ] () mutable { /* TODO: we need to implment some file name pattern matching */ std::vector wrappedSynthdefs = wrapSynthdefs( sc_read_synthdefs_file( path_string.c_str() ) ); cmd_dispatcher::fire_rt_callback( [=, message=std::move(message), path_string=std::move(path_string), wrappedSynthdefs=std::move(wrappedSynthdefs)] () mutable { for( sc_synth_definition_ptr & definition : wrappedSynthdefs ) instance->register_definition( std::move(definition) ); handle_completion_message( std::move(message) , endpoint ); consume( std::move(path_string) ); cmd_dispatcher::fire_system_callback( [=,wrappedSynthdefs=std::move(wrappedSynthdefs)] { consume( std::move(wrappedSynthdefs) ); send_done_message(endpoint, "/d_load"); }); } ); }); } template void handle_d_loadDir(ReceivedMessage const & msg, endpoint_ptr endpoint) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); const char * path; args >> path; completion_message message = extract_completion_message(args); movable_string path_string(path); cmd_dispatcher::fire_system_callback( [=, message=std::move(message), path_string=std::move(path_string)] () mutable { std::vector wrappedSynthdefs = wrapSynthdefs( sc_read_synthdefs_dir( path_string.c_str() ) ); cmd_dispatcher::fire_rt_callback( [=, message=std::move(message), path_string=std::move(path_string), wrappedSynthdefs=std::move(wrappedSynthdefs)] () mutable { for( sc_synth_definition_ptr & definition : wrappedSynthdefs ) instance->register_definition( std::move(definition) ); handle_completion_message( std::move(message), endpoint ); consume( std::move(path_string) ); cmd_dispatcher::fire_system_callback( [=, wrappedSynthdefs=std::move(wrappedSynthdefs)] { consume( std::move(wrappedSynthdefs) ); send_done_message(endpoint, "/d_loadDir"); }); }); }); } void handle_d_free(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { const char * defname; args >> defname; instance->remove_definition(defname); } } void insert_parallel_group(int node_id, int action, int target_id) { if (node_id == -1) node_id = instance->generate_node_id(); else if (!check_node_id(node_id)) return; server_node * target = find_node(target_id); if(!target) return; node_position_constraint pos = make_pair(target, node_position(action)); if (!node_position_sanity_check(pos)) return; instance->add_parallel_group(node_id, pos); last_generated = node_id; } void handle_p_new(ReceivedMessage const & msg) { osc::ReceivedMessageArgumentStream args = msg.ArgumentStream(); while(!args.Eos()) { osc::int32 id, action, target; args >> id >> action >> target; insert_parallel_group(id, action, target); } } void handle_u_cmd(ReceivedMessage const & msg, int size) { sc_msg_iter args(size, msg.AddressPattern()); int node_id = args.geti(); server_node * target_synth = find_node(node_id); if (target_synth == nullptr || target_synth->is_group()) return; sc_synth * synth = static_cast(target_synth); int ugen_index = args.geti(); const char * cmd_name = args.gets(); synth->apply_unit_cmd(cmd_name, ugen_index, &args); } void handle_cmd(ReceivedMessage const & msg, int size, endpoint_ptr endpoint, int skip_bytes) { sc_msg_iter args(size, msg.AddressPattern() + skip_bytes); const char * cmd = args.gets(); sc_factory->run_cmd_plugin(&sc_factory->world, cmd, &args, endpoint.get()); } } /* namespace */ template void sc_osc_handler::handle_message_int_address(ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint) { uint32_t address = message.AddressPatternAsUInt32(); switch (address) { case cmd_none: break; case cmd_quit: handle_quit(endpoint); break; case cmd_s_new: handle_s_new(message); break; case cmd_s_noid: handle_s_noid(message); break; case cmd_s_get: handle_s_get(message, msg_size, endpoint); break; case cmd_s_getn: handle_s_getn(message, msg_size, endpoint); break; case cmd_notify: handle_notify(message, endpoint); break; case cmd_status: handle_status(endpoint); break; case cmd_dumpOSC: handle_dumpOSC(message); break; case cmd_sync: handle_sync(message, endpoint); break; case cmd_clearSched: handle_clearSched(); break; case cmd_error: handle_error(message); break; case cmd_g_new: handle_g_new(message); break; case cmd_g_head: handle_g_head_or_tail(message); break; case cmd_g_tail: handle_g_head_or_tail(message); break; case cmd_g_freeAll: handle_g_freeall(message); break; case cmd_g_deepFree: handle_g_deepFree(message); break; case cmd_g_queryTree: handle_g_queryTree(message, endpoint); break; case cmd_g_dumpTree: handle_g_dumpTree(message); break; case cmd_n_free: handle_n_free(message); break; case cmd_n_set: handle_n_set(message); break; case cmd_n_setn: handle_n_setn(message); break; case cmd_n_fill: handle_n_fill(message); break; case cmd_n_map: handle_n_map(message); break; case cmd_n_mapn: handle_n_mapn(message); break; case cmd_n_mapa: handle_n_mapa(message); break; case cmd_n_mapan: handle_n_mapan(message); break; case cmd_n_query: handle_n_query(message, endpoint); break; case cmd_n_order: handle_n_order(message); break; case cmd_n_run: handle_n_run(message); break; case cmd_n_before: handle_n_before_or_after(message); break; case cmd_n_after: handle_n_before_or_after(message); break; case cmd_n_trace: handle_n_trace(message); break; case cmd_b_alloc: handle_b_alloc(message, endpoint); break; case cmd_u_cmd: handle_u_cmd(message, msg_size); break; case cmd_b_free: handle_b_free(message, endpoint); break; case cmd_b_allocRead: handle_b_allocRead(message, endpoint); break; case cmd_b_allocReadChannel: handle_b_allocReadChannel(message, endpoint); break; case cmd_b_read: handle_b_read(message, endpoint); break; case cmd_b_readChannel: handle_b_readChannel(message, endpoint); break; case cmd_b_write: handle_b_write(message, endpoint); break; case cmd_b_zero: handle_b_zero(message, endpoint); break; case cmd_b_set: handle_b_set(message); break; case cmd_b_setn: handle_b_setn(message); break; case cmd_b_fill: handle_b_fill(message); break; case cmd_b_query: handle_b_query(message, endpoint); break; case cmd_b_get: handle_b_get(message, endpoint); break; case cmd_b_getn: handle_b_getn(message, endpoint); break; case cmd_b_gen: handle_b_gen(message, msg_size, endpoint); break; case cmd_b_close: handle_b_close(message, endpoint); break; case cmd_c_set: handle_c_set(message); break; case cmd_c_setn: handle_c_setn(message); break; case cmd_c_fill: handle_c_fill(message); break; case cmd_c_get: handle_c_get(message, endpoint); break; case cmd_c_getn: handle_c_getn(message, endpoint); break; case cmd_d_recv: handle_d_recv(message, endpoint); break; case cmd_d_load: handle_d_load(message, endpoint); break; case cmd_d_loadDir: handle_d_loadDir(message, endpoint); break; case cmd_d_free: handle_d_free(message); break; case cmd_p_new: handle_p_new(message); break; case cmd_cmd: handle_cmd(message, msg_size, endpoint, 4); break; default: handle_unhandled_message(message); } } namespace { template void dispatch_group_commands(const char * address, ReceivedMessage const & message, endpoint_ptr const & endpoint) { assert(address[1] == 'g'); assert(address[2] == '_'); if (strcmp(address+3, "new") == 0) { handle_g_new(message); return; } if (strcmp(address+3, "head") == 0) { handle_g_head_or_tail(message); return; } if (strcmp(address+3, "tail") == 0) { handle_g_head_or_tail(message); return; } if (strcmp(address+3, "freeAll") == 0) { handle_g_freeall(message); return; } if (strcmp(address+3, "deepFree") == 0) { handle_g_deepFree(message); return; } if (strcmp(address+3, "queryTree") == 0) { handle_g_queryTree(message, endpoint); return; } if (strcmp(address+3, "dumpTree") == 0) { handle_g_dumpTree(message); return; } } template void dispatch_node_commands(const char * address, ReceivedMessage const & message, endpoint_ptr const & endpoint) { assert(address[1] == 'n'); assert(address[2] == '_'); if (strcmp(address+3, "free") == 0) { handle_n_free(message); return; } if (strcmp(address+3, "set") == 0) { handle_n_set(message); return; } if (strcmp(address+3, "setn") == 0) { handle_n_setn(message); return; } if (strcmp(address+3, "fill") == 0) { handle_n_fill(message); return; } if (strcmp(address+3, "map") == 0) { handle_n_map(message); return; } if (strcmp(address+3, "mapn") == 0) { handle_n_mapn(message); return; } if (strcmp(address+3, "mapa") == 0) { handle_n_mapa(message); return; } if (strcmp(address+3, "mapan") == 0) { handle_n_mapan(message); return; } if (strcmp(address+3, "run") == 0) { handle_n_run(message); return; } if (strcmp(address+3, "before") == 0) { handle_n_before_or_after(message); return; } if (strcmp(address+3, "after") == 0) { handle_n_before_or_after(message); return; } if (strcmp(address+3, "order") == 0) { handle_n_order(message); return; } if (strcmp(address+3, "query") == 0) { handle_n_query(message, endpoint); return; } if (strcmp(address+3, "trace") == 0) { handle_n_trace(message); return; } } template void dispatch_buffer_commands(const char * address, ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint) { assert(address[1] == 'b'); assert(address[2] == '_'); if (strcmp(address+3, "alloc") == 0) { handle_b_alloc(message, endpoint); return; } if (strcmp(address+3, "free") == 0) { handle_b_free(message, endpoint); return; } if (strcmp(address+3, "allocRead") == 0) { handle_b_allocRead(message, endpoint); return; } if (strcmp(address+3, "allocReadChannel") == 0) { handle_b_allocReadChannel(message, endpoint); return; } if (strcmp(address+3, "read") == 0) { handle_b_read(message, endpoint); return; } if (strcmp(address+3, "readChannel") == 0) { handle_b_readChannel(message, endpoint); return; } if (strcmp(address+3, "write") == 0) { handle_b_write(message, endpoint); return; } if (strcmp(address+3, "zero") == 0) { handle_b_zero(message, endpoint); return; } if (strcmp(address+3, "set") == 0) { handle_b_set(message); return; } if (strcmp(address+3, "setn") == 0) { handle_b_setn(message); return; } if (strcmp(address+3, "fill") == 0) { handle_b_fill(message); return; } if (strcmp(address+3, "query") == 0) { handle_b_query(message, endpoint); return; } if (strcmp(address+3, "get") == 0) { handle_b_get(message, endpoint); return; } if (strcmp(address+3, "getn") == 0) { handle_b_getn(message, endpoint); return; } if (strcmp(address+3, "gen") == 0) { handle_b_gen(message, msg_size, endpoint); return; } if (strcmp(address+3, "close") == 0) { handle_b_close(message, endpoint); return; } } template void dispatch_control_bus_commands(const char * address, ReceivedMessage const & message, endpoint_ptr const & endpoint) { assert(address[1] == 'c'); assert(address[2] == '_'); if (strcmp(address+3, "set") == 0) { handle_c_set(message); return; } if (strcmp(address+3, "setn") == 0) { handle_c_setn(message); return; } if (strcmp(address+3, "fill") == 0) { handle_c_fill(message); return; } if (strcmp(address+3, "get") == 0) { handle_c_get(message, endpoint); return; } if (strcmp(address+3, "getn") == 0) { handle_c_getn(message, endpoint); return; } } template void dispatch_synthdef_commands(const char * address, ReceivedMessage const & message, endpoint_ptr const & endpoint) { assert(address[1] == 'd'); assert(address[2] == '_'); if (strcmp(address+3, "recv") == 0) { handle_d_recv(message, endpoint); return; } if (strcmp(address+3, "load") == 0) { handle_d_load(message, endpoint); return; } if (strcmp(address+3, "loadDir") == 0) { handle_d_loadDir(message, endpoint); return; } if (strcmp(address+3, "free") == 0) { handle_d_free(message); return; } } template void dispatch_synth_commands(const char * address, ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint) { assert(address[1] == 's'); assert(address[2] == '_'); if (strcmp(address+3, "new") == 0) { handle_s_new(message); return; } if (strcmp(address+3, "noid") == 0) { handle_s_noid(message); return; } if (strcmp(address+3, "get") == 0) { handle_s_get(message, msg_size, endpoint); return; } if (strcmp(address+3, "getn") == 0) { handle_s_getn(message, msg_size, endpoint); return; } } } /* namespace */ template void sc_osc_handler::handle_message_sym_address(ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint) { const char * address = message.AddressPattern(); /* scsynth doesn't require the leading / */ if(address[0] != '/') address -= 1; if (address[2] == '_') { if (address[1] == 'g') { dispatch_group_commands(address, message, endpoint); return; } if (address[1] == 'n') { dispatch_node_commands(address, message, endpoint); return; } if (address[1] == 'b') { dispatch_buffer_commands(address, message, msg_size, endpoint); return; } if (address[1] == 'c') { dispatch_control_bus_commands(address, message, endpoint); return; } if (address[1] == 'd') { dispatch_synthdef_commands(address, message, endpoint); return; } if (address[1] == 's') { dispatch_synth_commands(address, message, msg_size, endpoint); return; } } if (strcmp(address+1, "p_new") == 0) { handle_p_new(message); return; } if (strcmp(address+1, "u_cmd") == 0) { handle_u_cmd(message, msg_size); return; } if (strcmp(address+1, "status") == 0) { handle_status(endpoint); return; } if (strcmp(address+1, "sync") == 0) { handle_sync(message, endpoint); return; } if (strcmp(address+1, "quit") == 0) { handle_quit(endpoint); return; } if (strcmp(address+1, "notify") == 0) { handle_notify(message, endpoint); return; } if (strcmp(address+1, "dumpOSC") == 0) { handle_dumpOSC(message); return; } if (strcmp(address+1, "clearSched") == 0) { handle_clearSched(); return; } if (strcmp(address+1, "error") == 0) { handle_error(message); return; } if (strcmp(address+1, "cmd") == 0) { handle_cmd(message, msg_size, endpoint, 8); return; } if (strcmp(address+1, "none") == 0) return; handle_unhandled_message(message); } template void handle_asynchronous_command( World * world, const char* cmdName, void *cmdData, AsyncStageFn stage2, AsyncStageFn stage3, AsyncStageFn stage4, AsyncFreeFn cleanup, completion_message && message, endpoint_ptr endpoint) { cmd_dispatcher::fire_system_callback( [=, message=std::move(message), endpoint=std::move(endpoint)] () mutable { if (stage2) (stage2)(world, cmdData); cmd_dispatcher::fire_rt_callback( [=, message=std::move(message), endpoint=std::move(endpoint)] () mutable { if (stage3) { bool success = (stage3)(world, cmdData); if (success) message.handle(endpoint); } consume( std::move( message ) ); cmd_dispatcher::fire_system_callback( [=, endpoint=std::move(endpoint)] { if (stage4) (stage4)(world, cmdData); send_done_message(endpoint, cmdName); cmd_dispatcher::fire_rt_callback( [=, endpoint=std::move(endpoint)] { if (cleanup) (cleanup)(world, cmdData); }); }); }); }); } void sc_osc_handler::do_asynchronous_command(World * world, void* replyAddr, const char* cmdName, void *cmdData, AsyncStageFn stage2, AsyncStageFn stage3, AsyncStageFn stage4, AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData) { completion_message msg(completionMsgSize, completionMsgData); endpoint_ptr shared_endpoint; nova_endpoint * endpoint = replyAddr ? static_cast(replyAddr) : nullptr; if (endpoint) shared_endpoint = endpoint->shared_from_this(); if (world->mRealTime) handle_asynchronous_command( world, cmdName, cmdData, stage2, stage3, stage4, cleanup, std::move(msg), shared_endpoint ); else handle_asynchronous_command( world, cmdName, cmdData, stage2, stage3, stage4, cleanup, std::move(msg), shared_endpoint ); } } /* namespace detail */ } /* namespace nova */ SuperCollider-Source/server/supernova/sc/sc_osc_handler.hpp000644 000765 000024 00000026733 12766171707 025322 0ustar00crucialstaff000000 000000 // osc handler for supercollider-style communication // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SERVER_SC_OSC_HANDLER_HPP #define SERVER_SC_OSC_HANDLER_HPP #include #include #include #ifndef BOOST_ASIO_HAS_STD_ARRAY #ifdef __clang__ // clang workaround #define BOOST_ASIO_HAS_STD_ARRAY #endif #endif #include #include #include #include #include #include "osc/OscReceivedElements.h" #include "../server/memory_pool.hpp" #include "../server/server_args.hpp" #include "../server/server_scheduler.hpp" #include "../utilities/osc_server.hpp" #include "../utilities/sized_array.hpp" #include "../utilities/static_pool.hpp" #include "../utilities/time_tag.hpp" namespace nova { typedef bool (*AsyncStageFn)(World *inWorld, void* cmdData); typedef void (*AsyncFreeFn)(World *inWorld, void* cmdData); namespace detail { using namespace boost::asio; using namespace boost::asio::ip; struct nova_endpoint: public std::enable_shared_from_this { virtual void send(const char * data, size_t length) = 0; }; class udp_endpoint: public nova_endpoint { public: udp_endpoint(udp::endpoint const & ep): endpoint_(ep) {} bool operator ==(udp_endpoint const & rhs) const { return endpoint_ == rhs.endpoint_; } private: void send(const char * data, size_t length) override final; udp::endpoint endpoint_; }; typedef std::shared_ptr endpoint_ptr; /** * observer to receive osc notifications * */ class sc_notify_observers { typedef std::vector observer_vector; public: typedef enum { no_error = 0, already_registered = -1, not_registered = -2 } error_code; sc_notify_observers(boost::asio::io_service & io_service): udp_socket(io_service) {} int add_observer(endpoint_ptr const & ep); int remove_observer(endpoint_ptr const & ep); /* @{ */ /** notifications, should be called from the real-time thread */ void notification_node_started(const server_node * node) { notify("/n_go", node); } void notification_node_ended(const server_node * node) { notify("/n_end", node); } void notification_node_turned_off(const server_node * node) { notify("/n_off", node); } void notification_node_turned_on(const server_node * node) { notify("/n_on", node); } void notification_node_moved(const server_node * node) { notify("/n_move", node); } void send_trigger(int32_t node_id, int32_t trigger_id, float value); void send_node_reply(int32_t node_id, int reply_id, const char* command_name, int argument_count, const float* values); /* @} */ /** send notifications, should not be called from the real-time thread */ void send_notification(const char * data, size_t length); void send_udp(const char * data, size_t size, udp::endpoint const & receiver); static const char * error_string(error_code); private: observer_vector::iterator find(endpoint_ptr const & ep); void notify(const char * address_pattern, const server_node * node) const; void send_notification(const char * data, size_t length, nova_endpoint * endpoint); observer_vector observers; protected: udp::socket udp_socket; std::mutex udp_mutex; }; class sc_scheduled_bundles { public: struct bundle_node: public boost::intrusive::bs_set_base_hook<> { bundle_node(time_tag const & timeout, const char * data, endpoint_ptr const & endpoint): timeout_(timeout), data_(data), endpoint_(endpoint) {} void run(void); const time_tag timeout_; const char * const data_; endpoint_ptr endpoint_; friend bool operator< (const bundle_node & lhs, const bundle_node & rhs) { return priority_order(lhs, rhs); } friend bool priority_order (const bundle_node & lhs, const bundle_node & rhs) { return lhs.timeout_ < rhs.timeout_; // lower value, higher priority } }; typedef boost::intrusive::treap_multiset bundle_queue_t; void insert_bundle(time_tag const & timeout, const char * data, size_t length, endpoint_ptr const & endpoint); void execute_bundles(time_tag const & last, time_tag const & now); void clear_bundles(void) { bundle_q.clear_and_dispose(dispose_bundle); } static void dispose_bundle(bundle_node * node) { node->~bundle_node(); rt_pool.free(node); } private: bundle_queue_t bundle_q; }; class sc_osc_handler: private detail::network_thread, public sc_notify_observers { /* @{ */ /** constructor helpers */ void open_tcp_acceptor(tcp const & protocol, unsigned int port); void open_udp_socket(udp const & protocol, unsigned int port); bool open_socket(int family, int type, int protocol, unsigned int port); /* @} */ public: sc_osc_handler(server_arguments const & args): sc_notify_observers(detail::network_thread::io_service_), tcp_acceptor_(detail::network_thread::io_service_), tcp_password_(args.server_password.size() ? args.server_password.c_str() : nullptr) { if (!args.non_rt) { if (args.tcp_port && !open_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP, args.tcp_port)) throw std::runtime_error("cannot open socket"); if (args.udp_port && !open_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, args.udp_port)) throw std::runtime_error("cannot open socket"); } } void start_receive_thread(void) { detail::network_thread::start_receive(); } typedef osc::ReceivedPacket ReceivedPacket; typedef osc::ReceivedBundle ReceivedBundle; typedef osc::ReceivedMessage ReceivedMessage; class received_packet: public audio_sync_callback { received_packet(const char * dat, size_t length, endpoint_ptr const & endpoint): data(dat), length(length), endpoint_(endpoint) {} void * operator new(std::size_t size, void* ptr) { return ::operator new(size, ptr); } public: static received_packet * alloc_packet(const char * data, size_t length, endpoint_ptr const & remote_endpoint); void run(void) override final; const char * const data; const size_t length; endpoint_ptr endpoint_; }; private: /* @{ */ /** udp socket handling */ void start_receive_udp(); void handle_receive_udp(const boost::system::error_code& error, std::size_t bytes_transferred); /* @} */ /* @{ */ /** tcp connection handling */ public: class tcp_connection: public nova_endpoint { public: typedef std::shared_ptr pointer; static pointer create(boost::asio::io_service& io_service) { return pointer(new tcp_connection(io_service)); } tcp::socket& socket() { return socket_; } void start(sc_osc_handler * self); bool operator==(tcp_connection const & rhs) const { return &rhs == this; } private: tcp_connection(boost::asio::io_service& io_service) : socket_(io_service) {} void send(const char *data, size_t length) override final; void async_read_msg_size(); void handle_message_size(); void handle_message(); tcp::socket socket_; sc_osc_handler * osc_handler; boost::endian::big_int32_t msg_size_; std::vector msg_buffer_; }; private: void start_tcp_accept(void); void handle_tcp_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error); /* @} */ public: void dumpOSC(int i) { dump_osc_packets = i; } private: int dump_osc_packets = 0; /* @{ */ public: /** \todo how to handle temporary message error suppression? */ void set_error_posting(int val) { error_posting = val; } private: int error_posting = 1; /* @} */ /* @{ */ /** packet handling */ public: void handle_packet_async(const char* data, size_t length, endpoint_ptr const & endpoint); void handle_packet(const char* data, size_t length, endpoint_ptr const & endpoint); time_tag handle_bundle_nrt(const char * data_, std::size_t length); private: template void handle_bundle(ReceivedBundle const & bundle, endpoint_ptr const & endpoint); template void handle_message(ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint); template void handle_message_int_address(ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint); template void handle_message_sym_address(ReceivedMessage const & message, size_t msg_size, endpoint_ptr const & endpoint); friend struct sc_scheduled_bundles::bundle_node; /* @} */ /* @{ */ /** bundle scheduling */ public: void clear_scheduled_bundles(void) { scheduled_bundles.clear_bundles(); } void execute_scheduled_bundles(void) { scheduled_bundles.execute_bundles(last, now); } void increment_logical_time(time_tag const & diff) { last = now; now += diff; } void set_last_now(time_tag const & lasts, time_tag const & nows) { now = nows; last = lasts; } void update_time_from_system(void) { now = time_tag::from_ptime(boost::date_time::microsec_clock::universal_time()); last = now - time_per_tick; } time_tag const & current_time(void) const { return now; } sc_scheduled_bundles scheduled_bundles; time_tag now, last; time_tag time_per_tick; /* @} */ void do_asynchronous_command(World * world, void* replyAddr, const char* cmdName, void *cmdData, AsyncStageFn stage2, AsyncStageFn stage3, AsyncStageFn stage4, AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData); bool quit_received = false; private: /* @{ */ udp::endpoint udp_remote_endpoint_; tcp::acceptor tcp_acceptor_; const char * tcp_password_; /* we are not owning this! */ std::array recv_buffer_; /* @} */ }; } /* namespace detail */ using detail::sc_osc_handler; } /* namespace nova */ #endif /* SERVER_SC_OSC_HANDLER_HPP */ SuperCollider-Source/server/supernova/sc/sc_plugin_interface.cpp000644 000765 000024 00000101060 12756531745 026336 0ustar00crucialstaff000000 000000 // interface for supercollider plugins // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include "sndfile.hh" #include "sc_plugin_interface.hpp" #include "sc_ugen_factory.hpp" #include "sc_synth.hpp" #include "nova-simd/simd_memory.hpp" #include "../server/server_args.hpp" #include "../server/memory_pool.hpp" #include "../server/server.hpp" #include "../utilities/malloc_aligned.hpp" #include "../utilities/sized_array.hpp" #include "SC_Prototypes.h" #include "SC_Unit.h" #include "SC_Lock.h" #include "clz.h" #include "SC_fftlib.h" #include "SC_Lock.h" #include "../../common/Samp.hpp" #include "../../common/SC_SndFileHelpers.hpp" #include // undefine the shadowed scfft functions #undef scfft_create #undef scfft_dofft #undef scfft_doifft #undef scfft_destroy namespace nova { spin_lock log_guard; // needs to be acquired for logging from the helper threads! namespace { spin_lock rt_pool_guard; inline Node * as_Node(server_node * node) { if (node == nullptr) return nullptr; // hack!!! we only assume that the 32bit integer mID member can be accessed via Node if (node->is_synth()) { sc_synth * s = static_cast(node); return &s->mNode; } else { void * nodePointer = &node->node_id; return (Node*)nodePointer; } } void pause_node(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_pause_node(node); } void free_node(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); } void free_node_and_preceding(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of preceding nodes\n"); return; } server_node * preceding = node->previous_node(); if (preceding) sc_factory->add_done_node(preceding); } void free_node_and_pause_preceding(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of preceding nodes\n"); return; } server_node * preceding = node->previous_node(); if (preceding) sc_factory->add_pause_node(preceding); } void free_node_and_preceding_children(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of preceding nodes"); return; } server_node * preceding = node->previous_node(); if (!preceding) return; if (preceding->is_synth()) sc_factory->add_done_node(preceding); else { abstract_group * preceding_group = static_cast(preceding); sc_factory->add_freeAll_node(preceding_group); } } void free_node_and_preceding_deep(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { log("parallel groups have no notion of preceding nodes\n"); return; } server_node * preceding = node->previous_node(); if (!preceding) return; if (preceding->is_synth()) sc_factory->add_done_node(preceding); else { abstract_group * preceding_group = static_cast(preceding); sc_factory->add_freeDeep_node(preceding_group); } } void free_node_and_all_preceding(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of preceding nodes\n"); return; } for(;;) { node = node->previous_node(); if (node) sc_factory->add_done_node(node); else return; } } void free_node_and_following(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of following nodes\n"); return; } server_node * next = node->next_node(); if (next) sc_factory->add_done_node(next); } void free_node_and_pause_following(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of following nodes\n"); return; } server_node * next = node->next_node(); if (next) sc_factory->add_pause_node(next); } void free_node_and_following_children(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of following nodes\n"); return; } server_node * following = node->previous_node(); if (!following) return; if (following->is_synth()) sc_factory->add_done_node(following); else { abstract_group * following_group = static_cast(following); sc_factory->add_freeAll_node(following_group); } } void free_node_and_following_deep(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of following nodes\n"); return; } server_node * following = node->previous_node(); if (!following) return; if (following->is_synth()) sc_factory->add_done_node(following); else { abstract_group * following_group = static_cast(following); sc_factory->add_freeDeep_node(following_group); } } void free_node_and_all_following(Unit * unit) { server_node * node = static_cast(unit->mParent); sc_factory->add_done_node(node); if (node->get_parent()->is_parallel()) { spin_lock::scoped_lock lock(log_guard); log("parallel groups have no notion of following nodes\n"); return; } for(;;) { node = node->previous_node(); if (node) sc_factory->add_done_node(node); else return; } } void free_group_members(Unit * unit) { server_node * node = static_cast(unit->mParent); abstract_group * group = const_cast(node->get_parent()); sc_factory->add_freeAll_node(group); } void free_parent_group(Unit * unit) { server_node * node = static_cast(unit->mParent); abstract_group * group = const_cast(node->get_parent()); sc_factory->add_done_node(group); } bool get_scope_buffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd) { scope_buffer_writer writer = instance->get_scope_buffer_writer( index, channels, maxFrames ); if( writer.valid() ) { hnd.internalData = writer.buffer; hnd.data = writer.data(); hnd.channels = channels; hnd.maxFrames = maxFrames; return true; } else { hnd.internalData = nullptr; return false; } } void push_scope_buffer(World *inWorld, ScopeBufferHnd &hnd, int frames) { scope_buffer_writer writer(reinterpret_cast(hnd.internalData)); writer.push(frames); hnd.data = writer.data(); } void release_scope_buffer(World *inWorld, ScopeBufferHnd &hnd) { scope_buffer_writer writer(reinterpret_cast(hnd.internalData)); instance->release_scope_buffer_writer( writer ); } } /* namespace */ } /* namespace nova */ extern "C" { bool define_unit(const char *inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags) { try { nova::sc_factory->register_ugen(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags); return true; } catch(...) { return false; } } bool define_bufgen(const char * name, BufGenFunc func) { try { nova::sc_factory->register_bufgen(name, func); return true; } catch(...) { return false; } } bool define_unitcmd(const char * unitClassName, const char * cmdName, UnitCmdFunc inFunc) { return nova::sc_factory->register_ugen_command_function(unitClassName, cmdName, inFunc); } bool define_plugincmd(const char * name, PlugInCmdFunc func, void * user_data) { return nova::sc_factory->register_cmd_plugin(name, func, user_data); } void * rt_alloc(World * dummy, size_t size) { nova::spin_lock::scoped_lock lock(nova::rt_pool_guard); if (size) return nova::rt_pool.malloc(size); else return nullptr; } void * rt_realloc(World * dummy, void * ptr, size_t size) { nova::spin_lock::scoped_lock lock(nova::rt_pool_guard); return nova::rt_pool.realloc(ptr, size); } void rt_free(World * dummy, void * ptr) { nova::spin_lock::scoped_lock lock(nova::rt_pool_guard); if (ptr) nova::rt_pool.free(ptr); } void * nrt_alloc(size_t size) { return malloc(size); } void * nrt_realloc(void * ptr, size_t size) { return realloc(ptr, size); } void nrt_free(void * ptr) { free(ptr); } void * nrt_alloc_2(World * dummy, size_t size) { return malloc(size); } void * nrt_realloc_2(World * dummy, void * ptr, size_t size) { return realloc(ptr, size); } void nrt_free_2(World * dummy, void * ptr) { free(ptr); } void clear_outputs(Unit *unit, int samples) { const uint32_t outputs = unit->mNumOutputs; if( (samples & 63) == 0 ) { const uint32_t loops = samples / 64; for( int i=0; i != outputs; ++i ) { float * buffer = unit->mOutBuf[i]; for( int loop = 0; loop != loops; ++loop ) { nova::zerovec_simd<64>( buffer + loop * 64 ); } } return; } if( (samples & 15) == 0 ) { for( int i=0; i != outputs; ++i ) nova::zerovec_simd(unit->mOutBuf[i], samples); return; } for( int i=0; i != outputs; ++i ) nova::zerovec(unit->mOutBuf[i], samples); } void node_end(struct Node * node) { nova::server_node * s = nova::instance->find_node(node->mID); nova::sc_factory->add_done_node(s); } void node_set_run(struct Node * node, int run) { using namespace nova; server_node * s = instance->find_node(node->mID); if (run == 0) sc_factory->add_pause_node(s); else sc_factory->add_resume_node(s); } int print(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); nova::log_guard.lock(); bool status = nova::instance->log_printf(fmt, vargs); nova::log_guard.unlock(); va_end(vargs); return (status == true) ? 0 : -1; } /* todo: we need to implement most of the done actions */ void done_action(int done_action, struct Unit *unit) { using namespace nova; switch(done_action) { case 0: // do nothing when the UGen is finished return; case 1: // pause the enclosing synth, but do not free it nova::pause_node(unit); return; case 2: // free the enclosing synth nova::free_node(unit); return; case 3: // free both this synth and the preceding node nova::free_node_and_preceding(unit); return; case 4: // free both this synth and the following node nova::free_node_and_following(unit); return; case 5: // free this synth; if the preceding node is a group then do g_freeAll on it, else free it nova::free_node_and_preceding_children(unit); return; case 6: nova::free_node_and_following_children(unit); // free this synth; if the following node is a group then do g_freeAll on it, else free it return; case 7: //free this synth and all preceding nodes in this group nova::free_node_and_all_preceding(unit); return; case 8: //free this synth and all following nodes in this group nova::free_node_and_all_following(unit); return; case 9: // free this synth and pause the preceding node nova::free_node_and_pause_preceding(unit); return; case 10: // free this synth and pause the following node nova::free_node_and_pause_following(unit); return; case 11: // free this synth and if the preceding node is a group then do g_deepFree on it, else free it nova::free_node_and_preceding_deep(unit); return; case 12: // free this synth and if the following node is a group then do g_deepFree on it, else free it nova::free_node_and_following_deep(unit); return; case 13: // free this synth and all other nodes in this group (before and after) nova::free_group_members(unit); return; case 14: // free the enclosing group and all nodes within it (including this synth) nova::free_parent_group(unit); return; default: return; } } int buf_alloc(SndBuf * buf, int channels, int frames, double samplerate) { try { nova::sc_factory->allocate_buffer(buf, channels, frames, samplerate); return kSCErr_None; } catch(std::exception const & e) { std::cout << e.what() << std::endl; return kSCErr_Failed; } } void send_trigger(Node * unit, int trigger_id, float value) { nova::instance->send_trigger(unit->mID, trigger_id, value); } void world_lock(World *world) { reinterpret_cast(world->mNRTLock)->lock(); } void world_unlock(World *world) { reinterpret_cast(world->mNRTLock)->unlock(); } Node * get_node(World *world, int id) { nova::server_node * node = nova::instance->find_node(id); return nova::as_Node(node); } void send_node_reply(Node* node, int reply_id, const char* command_name, int argument_count, const float* values) { if (!nova::sc_factory->world.mRealTime) return; nova::instance->send_node_reply(node->mID, reply_id, command_name, argument_count, values); } int do_asynchronous_command(World *inWorld, void* replyAddr, const char* cmdName, void *cmdData, AsyncStageFn stage2, // stage2 is non real time AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData) { nova::instance->do_asynchronous_command(inWorld, replyAddr, cmdName, cmdData, stage2, stage3, stage4, cleanup, completionMsgSize, completionMsgData); return 0; } } /* extern "C" */ namespace nova { inline void initialize_rate(Rate & rate, double sample_rate, int blocksize) { rate.mSampleRate = sample_rate; rate.mSampleDur = 1. / sample_rate; rate.mRadiansPerSample = 2 * boost::math::constants::pi() / sample_rate; rate.mBufLength = blocksize; rate.mBufDuration = blocksize / sample_rate; rate.mBufRate = sample_rate / blocksize; rate.mSlopeFactor = 1. / blocksize; div_t div_result = std::div(blocksize, 3); rate.mFilterLoops = div_result.quot; rate.mFilterRemain = div_result.rem; if (rate.mFilterLoops == 0.) rate.mFilterSlope = 0.; else rate.mFilterSlope = 1. / rate.mFilterLoops; } void sc_plugin_interface::initialize(server_arguments const & args, float * control_busses) { const bool nrt_mode = args.non_rt; done_nodes.reserve(64); pause_nodes.reserve(16); resume_nodes.reserve(16); freeAll_nodes.reserve(16); freeDeep_nodes.reserve(16); /* define functions */ sc_interface.fDefineUnit = &define_unit; sc_interface.fDefineBufGen = &define_bufgen; sc_interface.fDefinePlugInCmd = &define_plugincmd; sc_interface.fDefineUnitCmd = &define_unitcmd; /* interface functions */ sc_interface.fNodeEnd = &node_end; sc_interface.fGetNode = &get_node; sc_interface.fNodeRun = &node_set_run; sc_interface.fPrint = &print; sc_interface.fDoneAction = &done_action; /* sndfile functions */ #ifdef NO_LIBSNDFILE sc_interface.fSndFileFormatInfoFromStrings = nullptr; #else sc_interface.fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings; #endif /* wave tables */ sc_interface.mSine = gSine; sc_interface.mCosecant = gInvSine; sc_interface.mSineSize = kSineSize; sc_interface.mSineWavetable = gSineWavetable; /* memory allocation */ if (!nrt_mode) { sc_interface.fRTAlloc = &rt_alloc; sc_interface.fRTRealloc = &rt_realloc; sc_interface.fRTFree = &rt_free; } else { sc_interface.fRTAlloc = &nrt_alloc_2; sc_interface.fRTRealloc = &nrt_realloc_2; sc_interface.fRTFree = &nrt_free_2; } sc_interface.fNRTAlloc = &nrt_alloc; sc_interface.fNRTRealloc = &nrt_realloc; sc_interface.fNRTFree = &nrt_free; /* ugen functions */ sc_interface.fClearUnitOutputs = clear_outputs; /* buffer functions */ sc_interface.fBufAlloc = &buf_alloc; /* trigger functions */ sc_interface.fSendTrigger = &send_trigger; sc_interface.fSendNodeReply = &send_node_reply; /* world locks */ sc_interface.fNRTLock = &world_lock; sc_interface.fNRTUnlock = &world_unlock; world.mNRTLock = new SC_Lock(); /* fft library */ sc_interface.fSCfftCreate = &scfft_create; sc_interface.fSCfftDestroy = &scfft_destroy; sc_interface.fSCfftDoFFT = &scfft_dofft; sc_interface.fSCfftDoIFFT = &scfft_doifft; /* scope API */ sc_interface.fGetScopeBuffer = &get_scope_buffer; sc_interface.fPushScopeBuffer = &push_scope_buffer; sc_interface.fReleaseScopeBuffer = &release_scope_buffer; /* osc plugins */ sc_interface.fDoAsynchronousCommand = &do_asynchronous_command; /* initialize world */ /* control busses */ world.mControlBus = control_busses; world.mNumControlBusChannels = args.control_busses; world.mControlBusTouched = new int32[args.control_busses]; std::fill(world.mControlBusTouched, world.mControlBusTouched + args.control_busses, -1); /* audio busses */ audio_busses.initialize(args.audio_busses, args.blocksize); world.mAudioBus = audio_busses.buffers; world.mNumAudioBusChannels = args.audio_busses; world.mAudioBusTouched = new int32[args.audio_busses]; world.mAudioBusLocks = audio_busses.locks; world.mControlBusLock = new spin_lock(); std::fill(world.mAudioBusTouched, world.mAudioBusTouched + args.audio_busses, -1); /* audio buffers */ world.mNumSndBufs = args.buffers; world.mSndBufs = new SndBuf[world.mNumSndBufs]; world.mSndBufsNonRealTimeMirror = new SndBuf[world.mNumSndBufs]; world.mSndBufUpdates = new SndBufUpdates[world.mNumSndBufs]; memset(world.mSndBufs, 0, world.mNumSndBufs*sizeof(SndBuf)); memset(world.mSndBufsNonRealTimeMirror, 0, world.mNumSndBufs*sizeof(SndBuf)); memset(world.mSndBufUpdates, 0, world.mNumSndBufs*sizeof(SndBufUpdates)); world.mBufCounter = 0; async_buffer_guards.reset(new std::mutex[world.mNumSndBufs]); /* audio settings */ world.mBufLength = args.blocksize; world.mSampleRate = args.samplerate; initialize_rate(world.mFullRate, args.samplerate, args.blocksize); initialize_rate(world.mBufRate, double(args.samplerate)/args.blocksize, 1); world.mNumInputs = args.input_channels; world.mNumOutputs = args.output_channels; world.mRealTime = !args.non_rt; world.mVerbosity = args.verbosity; /* rngs */ world.mNumRGens = args.rng_count; world.mRGen = new RGen[world.mNumRGens]; std::vector seeds(world.mNumRGens); try { std::random_device rd; std::seed_seq seq({ rd(), rd(), rd() }); seq.generate(seeds.begin(), seeds.end()); } catch (...) { auto now = std::chrono::high_resolution_clock::now(); auto seconds = std::chrono::duration_cast(now.time_since_epoch()); std::seed_seq seq({ seconds.count() }); seq.generate(seeds.begin(), seeds.end()); } for (int i=0; ifree_node(node); done_nodes.clear(); for (server_node * node : resume_nodes) instance->node_resume(node); resume_nodes.clear(); for (server_node * node : pause_nodes) instance->node_pause(node); pause_nodes.clear(); for (abstract_group * group : freeDeep_nodes) instance->group_free_deep(group); freeDeep_nodes.clear(); for (abstract_group * group : freeAll_nodes) instance->group_free_all(group); freeAll_nodes.clear(); } sc_plugin_interface::~sc_plugin_interface(void) { delete[] world.mAudioBusTouched; delete[] world.mControlBusTouched; delete[] world.mSndBufs; delete[] world.mSndBufsNonRealTimeMirror; delete[] world.mSndBufUpdates; delete[] world.mRGen; delete reinterpret_cast(world.mNRTLock); } namespace { sample * allocate_buffer(size_t samples) { const size_t alloc_size = samples * sizeof(sample); sample * ret = (sample*)calloc_aligned(alloc_size); if (ret) mlock(ret, alloc_size); return ret; } inline int32 bufmask(int32 x) { return (1 << (31 - CLZ(x))) - 1; } inline void sndbuf_init(SndBuf * buf) { buf->samplerate = 0; buf->sampledur = 0; buf->data = nullptr; buf->channels = 0; buf->samples = 0; buf->frames = 0; buf->mask = 0; buf->mask1 = 0; buf->coord = 0; buf->sndfile = nullptr; buf->isLocal = false; } inline void sndbuf_copy(SndBuf * dest, const SndBuf * src) { dest->samplerate = src->samplerate; dest->sampledur = src->sampledur; dest->data = src->data; dest->channels = src->channels; dest->samples = src->samples; dest->frames = src->frames; dest->mask = src->mask; dest->mask1 = src->mask1; dest->coord = src->coord; dest->sndfile = src->sndfile; dest->isLocal = src->isLocal; } static inline size_t compute_remaining_samples(size_t frames_per_read, size_t already_read, size_t total_frames) { int remain = frames_per_read; if (already_read + frames_per_read > total_frames) remain = total_frames - already_read; return remain; } void read_channel(SndfileHandle & sf, uint32_t channel_count, const uint32_t * channel_data, uint32 total_frames, sample * data) { const unsigned int frames_per_read = 1024; sized_array read_frame(sf.channels() * frames_per_read); if (channel_count == 1) { // fast-path for single-channel read for (size_t i = 0; i < total_frames; i += frames_per_read) { int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames); size_t read = sf.readf(read_frame.c_array(), remaining_samples); size_t channel_mapping = channel_data[0]; for (size_t frame = 0; frame != read; ++frame) { data[0] = read_frame[frame * sf.channels() + channel_mapping]; data += channel_count; } } } else { for (size_t i = 0; i < total_frames; i += frames_per_read) { int remaining_samples = compute_remaining_samples(frames_per_read, i, total_frames); size_t read = sf.readf(read_frame.c_array(), remaining_samples); for (size_t frame = 0; frame != read; ++frame) { for (size_t c = 0; c != channel_count; ++c) { size_t channel_mapping = channel_data[c]; data[c] = read_frame[frame * sf.channels() + channel_mapping]; } data += channel_count; } } } } } /* namespace */ void sc_plugin_interface::allocate_buffer(SndBuf * buf, uint32_t frames, uint32_t channels, double samplerate) { const uint32_t samples = frames * channels; if (samples == 0) throw std::runtime_error( "invalid buffer size" ); sample * data = nova::allocate_buffer(samples); if (data == nullptr) throw std::runtime_error( "could not allocate memory" ); buf->data = data; buf->channels = channels; buf->frames = frames; buf->samples = samples; buf->mask = bufmask(samples); /* for delay lines */ buf->mask1 = buf->mask - 1; /* for oscillators */ buf->samplerate = samplerate; buf->sampledur = 1.0 / samplerate; buf->isLocal = false; } SndBuf * sc_plugin_interface::allocate_buffer(uint32_t index, uint32_t frames, uint32_t channels) { SndBuf * buf = World_GetNRTBuf(&world, index); allocate_buffer(buf, frames, channels, world.mFullRate.mSampleRate); return buf; } void sc_plugin_interface::buffer_read_alloc(uint32_t index, const char * filename, uint32_t start, uint32_t frames) { SndfileHandle f(filename); if (f.rawHandle() == nullptr) throw std::runtime_error(f.strError()); const size_t sf_frames = f.frames(); if (start > sf_frames) start = sf_frames; if (frames == 0 || frames > sf_frames - start) frames = sf_frames - start; SndBuf * buf = World_GetNRTBuf(&world, index); allocate_buffer(buf, frames, f.channels(), f.samplerate()); f.seek(start, SEEK_SET); f.readf(buf->data, frames); } void sc_plugin_interface::buffer_alloc_read_channels(uint32_t index, const char * filename, uint32_t start, uint32_t frames, uint32_t channel_count, const uint32_t * channel_data) { SndfileHandle f(filename); if (f.rawHandle() == nullptr) throw std::runtime_error(f.strError()); uint32_t sf_channels = uint32_t(f.channels()); const uint32_t * max_chan = std::max_element(channel_data, channel_data + channel_count); if (*max_chan >= sf_channels) throw std::runtime_error("Channel out of range"); const size_t sf_frames = f.frames(); if (start > sf_frames) start = sf_frames; if (frames == 0 || frames > sf_frames - start) frames = sf_frames - start; SndBuf * buf = World_GetNRTBuf(&world, index); allocate_buffer(buf, frames, channel_count, f.samplerate()); f.seek(start, SEEK_SET); read_channel(f, channel_count, channel_data, frames, buf->data); } int sc_plugin_interface::buffer_write(uint32_t index, const char * filename, const char * header_format, const char * sample_format, uint32_t start, uint32_t frames, bool leave_open) { SndBuf * buf = World_GetNRTBuf(&world, index); int format = headerFormatFromString(header_format) | sampleFormatFromString(sample_format); SndfileHandle sf(filename, SFM_WRITE, format, buf->channels, buf->samplerate); if (!sf) return -1; if (frames == 0xffffffff) frames = buf->frames; const uint32_t remain = uint32_t(buf->frames) > start ? buf->frames - start : 0; const uint32_t frames_to_write = std::min(remain, frames); if (frames_to_write) sf.writef(buf->data + start * buf->channels, frames_to_write); if (leave_open && !buf->sndfile) buf->sndfile = sf.takeOwnership(); return 0; } static void buffer_read_verify(SndfileHandle & sf, size_t min_length, size_t samplerate, bool check_samplerate) { if (sf.rawHandle() == nullptr) throw std::runtime_error(sf.strError()); if (sf.frames() < min_length) throw std::runtime_error("no more frames to read"); if (check_samplerate && (sf.samplerate() != samplerate)) throw std::runtime_error("sample rate mismatch"); } void sc_plugin_interface::buffer_read(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames, uint32_t start_buffer, bool leave_open) { SndBuf * buf = World_GetNRTBuf(&world, index); if (uint32_t(buf->frames) < start_buffer) throw std::runtime_error("buffer already full"); SndfileHandle sf(filename, SFM_READ); buffer_read_verify(sf, start_file, buf->samplerate, !leave_open); if (sf.channels() != buf->channels) throw std::runtime_error("channel count mismatch"); const uint32_t buffer_remain = buf->frames - start_buffer; const uint32_t file_remain = sf.frames() - start_file; const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain)); sf.seek(start_file, SEEK_SET); sf.readf(buf->data + start_buffer*buf->channels, frames_to_read); if (leave_open) buf->sndfile = sf.takeOwnership(); } void sc_plugin_interface::buffer_read_channel(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames, uint32_t start_buffer, bool leave_open, uint32_t channel_count, const uint32_t * channel_data) { SndBuf * buf = World_GetNRTBuf(&world, index); if (channel_count != uint32_t(buf->channels)) throw std::runtime_error("channel count mismatch"); if (uint32_t(buf->frames) >= start_buffer) throw std::runtime_error("buffer already full"); SndfileHandle sf(filename, SFM_READ); buffer_read_verify(sf, start_file, buf->samplerate, !leave_open); uint32_t sf_channels = uint32_t(sf.channels()); const uint32_t * max_chan = std::max_element(channel_data, channel_data + channel_count); if (*max_chan >= sf_channels) throw std::runtime_error("channel count mismatch"); const uint32_t buffer_remain = buf->frames - start_buffer; const uint32_t file_remain = sf.frames() - start_file; const uint32_t frames_to_read = std::min(frames, std::min(buffer_remain, file_remain)); sf.seek(start_file, SEEK_SET); read_channel(sf, channel_count, channel_data, frames_to_read, buf->data); if (leave_open) buf->sndfile = sf.takeOwnership(); } void sc_plugin_interface::buffer_close(uint32_t index) { SndBuf * buf = World_GetNRTBuf(&world, index); if (buf->sndfile == nullptr) return; sf_close(buf->sndfile); buf->sndfile = nullptr; } void sc_plugin_interface::buffer_zero(uint32_t index) { SndBuf * buf = World_GetNRTBuf(&world, index); uint32_t length = buf->frames * buf->channels; uint32_t unrolled = length & ~63; uint32_t remain = length & 63; zerovec_simd(buf->data, unrolled); zerovec(buf->data + unrolled, remain); } sample * sc_plugin_interface::buffer_generate(uint32_t buffer_index, const char* cmd_name, struct sc_msg_iter & msg) { return sc_factory->run_bufgen(&world, cmd_name, buffer_index, &msg); } void sc_plugin_interface::buffer_sync(uint32_t index) noexcept { sndbuf_copy(world.mSndBufs + index, world.mSndBufsNonRealTimeMirror + index); increment_write_updates(index); } void sc_plugin_interface::free_buffer(uint32_t index) { SndBuf * buf = world.mSndBufsNonRealTimeMirror + index; if (buf->sndfile) sf_close(buf->sndfile); sndbuf_init(buf); } } /* namespace nova */ SuperCollider-Source/server/supernova/sc/sc_plugin_interface.hpp000644 000765 000024 00000015151 12756531745 026350 0ustar00crucialstaff000000 000000 // interface for supercollider plugins // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SC_PLUGIN_INTERFACE_HPP #define SC_PLUGIN_INTERFACE_HPP #include #include #include "../server/audio_bus_manager.hpp" #include "../server/node_types.hpp" #include "../server/synth.hpp" #include "../server/memory_pool.hpp" #include "SC_InterfaceTable.h" #include "SC_World.h" #include namespace nova { class sc_done_action_handler { public: void add_pause_node(server_node * node) { spin_lock::scoped_lock lock(cmd_lock); pause_nodes.push_back(node); } void add_resume_node(server_node * node) { spin_lock::scoped_lock lock(cmd_lock); resume_nodes.push_back(node); } void add_done_node(server_node * node) { spin_lock::scoped_lock lock(cmd_lock); if (std::find(done_nodes.begin(), done_nodes.end(), node) != done_nodes.end()) return; done_nodes.push_back(node); } void add_freeDeep_node(abstract_group * node) { spin_lock::scoped_lock lock(cmd_lock); if (std::find(freeDeep_nodes.begin(), freeDeep_nodes.end(), node) != freeDeep_nodes.end()) return; freeDeep_nodes.push_back(node); } void add_freeAll_node(abstract_group * node) { spin_lock::scoped_lock lock(cmd_lock); if (std::find(freeAll_nodes.begin(), freeAll_nodes.end(), node) != freeAll_nodes.end()) return; freeAll_nodes.push_back(node); } void apply_done_actions(void); protected: typedef rt_pool_allocator server_node_alloc; typedef rt_pool_allocator abstract_group_alloc; std::vector done_nodes, pause_nodes, resume_nodes; std::vector freeAll_nodes, freeDeep_nodes; private: spin_lock cmd_lock; /* multiple synths can be scheduled for removal, so we need to guard this later we can try different approaches like a lockfree stack or bitmask */ }; class sc_plugin_interface: public sc_done_action_handler { public: void initialize(class server_arguments const & args, float * control_busses); void reset_sampling_rate(int sr); sc_plugin_interface(void) = default; ~sc_plugin_interface(void); InterfaceTable sc_interface; World world; audio_bus_manager audio_busses; int buf_counter(void) const { return world.mBufCounter; } /* @{ */ /* audio buffer handling */ SndBuf* allocate_buffer(uint32_t index, uint32_t frames, uint32_t channels); void allocate_buffer(SndBuf * buf, uint32_t frames, uint32_t channels, double samplerate); void buffer_read_alloc(uint32_t index, const char * filename, uint32_t start, uint32_t frames); void buffer_alloc_read_channels(uint32_t index, const char * filename, uint32_t start, uint32_t frames, uint32_t channel_count, const uint32_t * channel_data); void buffer_read(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames, uint32_t start_buffer, bool leave_open); void buffer_read_channel(uint32_t index, const char * filename, uint32_t start_file, uint32_t frames, uint32_t start_buffer, bool leave_open, uint32_t channel_count, const uint32_t * channel_data); sample * get_nrt_mirror_buffer(uint32_t index) { return world.mSndBufsNonRealTimeMirror[index].data; } sample * get_buffer(uint32_t index) { return world.mSndBufs[index].data; } SndBuf * get_buffer_struct(uint32_t index) { return world.mSndBufs + index; } int buffer_write(uint32_t index, const char * filename, const char * header_format, const char * sample_format, uint32_t start, uint32_t frames, bool leave_open); void buffer_zero(uint32_t index); void buffer_close(uint32_t index); sample * buffer_generate(uint32_t index, const char * cmd_name, struct sc_msg_iter & msg); void increment_write_updates(uint32_t index) { world.mSndBufUpdates[index].writes++; } void free_buffer(uint32_t index); typedef std::lock_guard buffer_lock_t; std::mutex & buffer_guard(size_t index) { return async_buffer_guards[index]; } bool is_realtime_synthesis() const { return world.mRealTime; } private: boost::scoped_array async_buffer_guards; /* @} */ public: /* copies nrt mirror to rt buffers */ void buffer_sync(uint32_t index) noexcept; /* @{ */ /* control bus handling */ private: void controlbus_set_unchecked(uint32_t bus, float value) { world.mControlBus[bus] = value; world.mControlBusTouched[bus] = world.mBufCounter; } public: void controlbus_set(uint32_t bus, float value) { if (bus < world.mNumControlBusChannels) controlbus_set_unchecked(bus, value); } void controlbus_fill(uint32_t bus, size_t count, float value) { if (bus + count >= world.mNumControlBusChannels) count = world.mNumAudioBusChannels - bus; for (size_t i = 0; i != count; ++i) controlbus_set_unchecked(bus + i, value); } sample controlbus_get(uint32_t bus) { if (bus < world.mNumControlBusChannels) return world.mControlBus[bus]; else return 0.f; } void controlbus_getn(uint32_t bus, size_t count, size_t * r_count, float * r_values) { size_t remain = count; if (bus + count >= world.mNumControlBusChannels) remain = world.mNumAudioBusChannels - bus; *r_count = remain; for (size_t i = 0; i != remain; ++i) r_values[i] = world.mControlBus[i]; } /* @}*/ }; } /* namespace nova */ #endif /* SC_PLUGIN_INTERFACE_HPP */ SuperCollider-Source/server/supernova/sc/sc_synth.cpp000644 000765 000024 00000024203 12756531745 024170 0ustar00crucialstaff000000 000000 // synth based on supercollider-style synthdef // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include "sc_synth.hpp" #include "sc_ugen_factory.hpp" #include "../server/server.hpp" namespace nova { sc_synth::sc_synth(int node_id, sc_synth_definition_ptr const & prototype): abstract_synth(node_id, prototype) { World const & world = sc_factory->world; const bool rt_synthesis = world.mRealTime; mNode.mWorld = &sc_factory->world; rgen.init((uint32_t)(uint64_t)this); /* initialize sc wrapper class */ mRGen = &rgen; mSubsampleOffset = world.mSubsampleOffset; mSampleOffset = world.mSampleOffset; mLocalAudioBusUnit = nullptr; mLocalControlBusUnit = nullptr; localBufNum = 0; localMaxBufNum = 0; mNode.mID = node_id; sc_synthdef const & synthdef = *prototype; const size_t parameter_count = synthdef.parameter_count(); const size_t constants_count = synthdef.constants.size(); /* we allocate one memory chunk */ const size_t wire_buffer_alignment = 64 * 8; // align to cache line boundaries const size_t alloc_size = prototype->memory_requirement(); const size_t sample_alloc_size = world.mBufLength * synthdef.buffer_count + wire_buffer_alignment /* for alignment */; const size_t total_alloc_size = alloc_size + sample_alloc_size*sizeof(sample); char * raw_chunk = rt_synthesis ? (char*)rt_pool.malloc(total_alloc_size) : (char*)malloc(total_alloc_size); if (raw_chunk == nullptr) throw std::bad_alloc(); linear_allocator allocator(raw_chunk); /* prepare controls */ mNumControls = parameter_count; mControls = allocator.alloc(parameter_count); mControlRates = allocator.alloc(parameter_count); mMapControls = allocator.alloc(parameter_count); /* initialize controls */ for (size_t i = 0; i != parameter_count; ++i) { mControls[i] = synthdef.parameters[i]; /* initial parameters */ mMapControls[i] = &mControls[i]; /* map to control values */ mControlRates[i] = 0; /* init to 0*/ } /* allocate constant wires */ mWire = allocator.alloc(constants_count); for (size_t i = 0; i != synthdef.constants.size(); ++i) { Wire * wire = mWire + i; wire->mFromUnit = nullptr; wire->mCalcRate = 0; wire->mBuffer = nullptr; wire->mScalarValue = get_constant(i); } unit_count = prototype->unit_count(); calc_unit_count = prototype->calc_unit_count(); units = allocator.alloc(unit_count); calc_units = allocator.alloc(calc_unit_count + 1); // over-allocate to allow prefetching unit_buffers = allocator.alloc(sample_alloc_size); unit_buffers = static_cast( boost::alignment::align_up( unit_buffers, wire_buffer_alignment ) ); /* allocate unit generators */ sc_factory->allocate_ugens(synthdef.graph.size()); for (size_t i = 0; i != synthdef.graph.size(); ++i) { sc_synthdef::unit_spec_t const & spec = synthdef.graph[i]; units[i] = spec.prototype->construct(spec, this, &sc_factory->world, allocator); } for (size_t i = 0; i != synthdef.calc_unit_indices.size(); ++i) { int32_t index = synthdef.calc_unit_indices[i]; calc_units[i] = units[index]; } assert((char*)mControls + alloc_size <= allocator.alloc()); // ensure the memory boundaries } sc_synth::~sc_synth(void) { assert(!initialized); } // FIXME: for some reason, we cannot initialize multiple synths in parallel static spin_lock scsynth_preparation_lock; void sc_synth::prepare(void) { assert(!initialized); scsynth_preparation_lock.lock(); std::for_each(units, units + unit_count, [](Unit * unit) { sc_ugen_def * def = reinterpret_cast(unit->mUnitDef); def->initialize(unit); }); scsynth_preparation_lock.unlock(); initialized = true; } void sc_synth::finalize() { if (initialized) { std::for_each(units, units + unit_count, [](Unit * unit) { sc_ugen_def * def = reinterpret_cast(unit->mUnitDef); def->destruct(unit); }); } sc_factory->free_ugens(unit_count); if (sc_factory->is_realtime_synthesis()) rt_pool.free(mControls); else free(mControls); initialized = false; } void sc_synth::set(slot_index_t slot_index, sample val) { if (slot_index >= mNumControls) { log("argument number out of range\n"); return; } mControlRates[slot_index] = 0; mMapControls[slot_index] = &mControls[slot_index]; mControls[slot_index] = val; } void sc_synth::set_control_array(slot_index_t slot_index, size_t count, sample * val) { if (slot_index+count >= mNumControls) return; for (size_t i = 0; i != count; ++i) set(slot_index+i, val[i]); } float sc_synth::get(slot_index_t slot_index) const { return mControls[slot_index]; } void sc_synth::map_control_bus_control (unsigned int slot_index, int control_bus_index) { if (slot_index >= mNumControls) return; World *world = mNode.mWorld; if (control_bus_index < 0) { mControlRates[slot_index] = 0; mMapControls[slot_index] = mControls + slot_index; } else if (uint32(control_bus_index) < world->mNumControlBusChannels) { mControlRates[slot_index] = 1; mMapControls[slot_index] = world->mControlBus + control_bus_index; } } void sc_synth::map_control_buses_control (unsigned int slot_index, int control_bus_index, int count) { if (slot_index >= mNumControls) return; int slots_to_set = std::min(count, int(mNumControls - slot_index)); for (int i = 0; i != slots_to_set; ++i) map_control_bus_control(slot_index+i, control_bus_index+i); } void sc_synth::map_control_bus_audio (unsigned int slot_index, int audio_bus_index) { if (slot_index >= mNumControls) return; World *world = mNode.mWorld; if (audio_bus_index < 0) { mControlRates[slot_index] = 0; mMapControls[slot_index] = mControls + slot_index; } else if (uint(audio_bus_index) < world->mNumAudioBusChannels) { mControlRates[slot_index] = 2; mMapControls[slot_index] = world->mAudioBus + (audio_bus_index * world->mBufLength); } } void sc_synth::map_control_buses_audio (unsigned int slot_index, int audio_bus_index, int count) { if (slot_index >= mNumControls) return; int slots_to_set = std::min(count, int(mNumControls - slot_index)); for (int i = 0; i != slots_to_set; ++i) map_control_bus_audio(slot_index+i, audio_bus_index+i); } void sc_synth::apply_unit_cmd(const char * unit_cmd, unsigned int unit_index, struct sc_msg_iter *args) { Unit * unit = units[unit_index]; sc_ugen_def * def = reinterpret_cast(unit->mUnitDef); def->run_unit_command(unit_cmd, unit, args); } void sc_synth::run(void) { perform(); } extern spin_lock log_guard; #if defined(__GNUC__) && !defined(__APPLE__) #define thread_local __thread #endif #ifdef thread_local static thread_local std::array trace_scratchpad; #else static std::array trace_scratchpad; #endif struct scratchpad_printer { scratchpad_printer(char * str): string(str), position(0) { clear(); } void printf(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); printf(fmt, vargs); } const char * data(void) const { return string; } bool shouldFlush(void) const { return position + 1024 > 32768; } void clear(void) { position = 0; string[0] = '\0'; // zero-terminated } private: void printf(const char *fmt, va_list vargs) { position += vsprintf(string + position, fmt, vargs); } char * string; int position; }; void sc_synth::run_traced(void) { trace = 0; #ifndef thread_local spin_lock::scoped_lock lock (log_guard); #endif scratchpad_printer printer(trace_scratchpad.data()); printer.printf("\nTRACE %d %s #units: %d\n", id(), this->definition_name(), calc_unit_count); for (size_t calc_unit_index = 0; calc_unit_index != calc_unit_count; ++calc_unit_index) { Unit * unit = calc_units[calc_unit_index]; sc_ugen_def * def = reinterpret_cast(unit->mUnitDef); printer.printf(" unit %zd %s\n in ", calc_unit_index, def->name()); for (uint16_t j=0; j!=unit->mNumInputs; ++j) { printer.printf(" %g", unit->mInBuf[j][0]); if (printer.shouldFlush()) { #ifdef thread_local spin_lock::scoped_lock lock (log_guard); #endif log(printer.data()); printer.clear(); } } printer.printf("\n"); (unit->mCalcFunc)(unit, unit->mBufLength); printer.printf(" out"); for (int j=0; jmNumOutputs; ++j) { printer.printf(" %g", unit->mOutBuf[j][0]); if (printer.shouldFlush()) { #ifdef thread_local spin_lock::scoped_lock lock (log_guard); #endif log(printer.data()); printer.clear(); } } printer.printf("\n"); } printer.printf("\n"); #ifdef thread_local spin_lock::scoped_lock lock (log_guard); #endif log(printer.data()); } } /* namespace nova */ SuperCollider-Source/server/supernova/sc/sc_synth.hpp000644 000765 000024 00000015574 12756531745 024210 0ustar00crucialstaff000000 000000 // synth based on supercollider-style synthdef // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SC_SYNTH_HPP #define SC_SYNTH_HPP #include "SC_Unit.h" #include "SC_Graph.h" #include "SC_Rate.h" #include "SC_RGen.h" #include "SC_Wire.h" #include "sc_synth_definition.hpp" #include "../server/synth.hpp" #include "../server/memory_pool.hpp" namespace nova { class sc_synth: public abstract_synth, public Graph { typedef std::vector > unit_vector; typedef sc_synthdef::graph_t graph_t; friend class sc_synth_definition; public: sc_synth(int node_id, sc_synth_definition_ptr const & prototype); ~sc_synth(void); /** run ugen constructors and initialize first sample * * to be executed after preparing the synth and setting the controls */ void prepare(void); void finalize(void); HOT inline void perform(void) { if (unlikely (!initialized)) prepare(); if (likely(trace == 0)) { const size_t count = calc_unit_count; Unit ** units = calc_units; const size_t preroll = count & 7; for (size_t i = 0; i != preroll; ++i) { Unit * unit = units[i]; prefetch(units[i+1]); (unit->mCalcFunc)(unit, unit->mBufLength); } units += preroll; const size_t unroll = count / 8; if (unroll == 0) return; for (size_t i = 0; i != unroll; ++i) { Unit * unit = units[0]; prefetch(units[1]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[1]; prefetch(units[2]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[2]; prefetch(units[3]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[3]; prefetch(units[4]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[4]; prefetch(units[5]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[5]; prefetch(units[6]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[6]; prefetch(units[7]); (unit->mCalcFunc)(unit, unit->mBufLength); unit = units[7]; prefetch(units[8]); (unit->mCalcFunc)(unit, unit->mBufLength); units += 8; } } else run_traced(); } void prefetch(Unit * unit) { char * ptr = (char*) unit; char * end = (char*) unit + sizeof(Unit) + 2 * sizeof(Wire)/* + 4 * sizeof(void*)*/; static const size_t cacheline_size = 64; for ( ; ptr < end; ptr += cacheline_size) #ifdef __GNUC__ __builtin_prefetch(ptr, 0, 0); #endif } void run(void) override; void set(slot_index_t slot_index, sample val) override; float get(slot_index_t slot_index) const override; void set_control_array(slot_index_t slot_index, size_t count, sample * val) override; sample get(slot_index_t slot_index) { return mControls[slot_index]; } /* @{ */ /** control mapping */ private: void map_control_bus_control(unsigned int slot_index, int control_bus_index); void map_control_buses_control(unsigned int slot_index, int control_bus_index, int count); void map_control_bus_audio(unsigned int slot_index, int audio_bus_index); void map_control_buses_audio(unsigned int slot_index, int audio_bus_index, int count); public: template void map_control_bus(unsigned int slot_index, int bus_index) { if (ControlBusIsAudio) map_control_bus_audio(slot_index, bus_index); else map_control_bus_control(slot_index, bus_index); } template void map_control_buses(unsigned int slot_index, int bus_index, int count) { if (ControlBusIsAudio) map_control_buses_audio(slot_index, bus_index, count); else map_control_buses_control(slot_index, bus_index, count); } template void map_control_bus(const char * slot_name, int bus_index) { int slot_index = resolve_slot(slot_name); if (slot_index == -1) return; map_control_bus(slot_index, bus_index); } template void map_control_buses(const char * slot_name, int bus_index, int count) { int controls_per_slot; int slot_index = resolve_slot_with_size(slot_name, controls_per_slot); if (slot_index == -1) return; count = std::min(count, controls_per_slot); map_control_buses(slot_index, bus_index, count); } template void map_control_bus(unsigned int slot_index, size_t arrayed_slot_index, int bus_index) { map_control_bus(slot_index + arrayed_slot_index, bus_index); } template void map_control_bus(const char * slot_name, size_t arrayed_slot_index, int bus_index) { int slot_base_index = resolve_slot(slot_name); if (slot_base_index == -1) return; size_t slot_index = slot_base_index + arrayed_slot_index; map_control_bus(slot_index, bus_index); } /* @} */ void enable_tracing(void) { trace = 1; } void apply_unit_cmd(const char * unit_cmd, unsigned int unit_index, struct sc_msg_iter *args); private: void run_traced(void); sample get_constant(size_t index) { return static_cast(class_ptr.get())->constants[index]; } friend class sc_ugen_def; bool initialized = false; int_fast8_t trace = 0; Unit ** calc_units; sample * unit_buffers = nullptr; int32_t calc_unit_count, unit_count; RGen rgen; Unit ** units; }; } /* namespace nova */ #endif /* SC_SYNTH_HPP */ SuperCollider-Source/server/supernova/sc/sc_synth_definition.cpp000644 000765 000024 00000007514 12766171707 026405 0ustar00crucialstaff000000 000000 // prototype of a supercollider-synthdef-based synth prototype, implementation // Copyright (C) 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include #include #include "sc_synth.hpp" #include "sc_ugen_factory.hpp" #include "sc_synth_definition.hpp" #include "server/synth_factory.hpp" namespace nova { using namespace std; void register_synthdefs(synth_factory & factory, std::vector && defs) { for (sc_synthdef & def : defs) { sc_synth_definition_ptr sp = new sc_synth_definition( std::move(def) ); factory.register_definition( std::move(sp) ); } } std::vector sc_read_synthdefs_file(path const & file) { try { return read_synthdef_file(file.string()); } catch(std::exception const & e) { cout << "Exception when parsing synthdef file " << file.string() << ": " << e.what() << endl; return std::vector(); } } std::vector sc_read_synthdefs_dir(path const & dir) { using namespace boost::filesystem; using namespace std; typedef vector def_vector; def_vector ret; if (!exists(dir)) return ret; // FIXME: some kind of threadpool would be nice! auto launch_policy = thread::hardware_concurrency() > 1 ? launch::async : launch::deferred; vector > futures; for( auto const & entry : boost::make_iterator_range( recursive_directory_iterator(dir), recursive_directory_iterator() )) { if (!is_directory( entry.status() )) { auto path_name = entry.path(); futures.emplace_back( std::move(async(launch_policy, [=]() { return sc_read_synthdefs_file(path_name);} )) ); } } for (future & synthdef_future : futures) { for (sc_synthdef & definition : synthdef_future.get()) ret.emplace_back( std::move(definition) ); } return ret; } sc_synth_definition::sc_synth_definition(sc_synthdef && sd): synth_definition(sd.name()), sc_synthdef( std::forward(sd) ) { std::map reversed_parameter_map; for( auto const & elem : parameter_map) reversed_parameter_map.insert( std::make_pair(elem.second, elem.first)); for (auto const & entry : parameter_map) { const symbol name = entry.first; const int32_t current_index = entry.second; int controls_per_parameter = 1; for(int32_t next_index = current_index + 1; next_index != parameter_count(); ++next_index) { if (reversed_parameter_map.find(next_index) != reversed_parameter_map.end()) break; controls_per_parameter += 1; } slot_resolver::register_slot(name, current_index, controls_per_parameter); } } abstract_synth * sc_synth_definition::create_instance(int node_id) { sc_synth * synth = new sc_synth(node_id, this); return synth; } } /* namespace nova */ SuperCollider-Source/server/supernova/sc/sc_synth_definition.hpp000644 000765 000024 00000003327 12766171707 026410 0ustar00crucialstaff000000 000000 // prototype of a supercollider-synthdef-based synth prototype // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SC_SYNTH_DEFINITION_HPP #define SC_SYNTH_DEFINITION_HPP #include #include "sc_synthdef.hpp" #include "server/synth_definition.hpp" #include "utilities/sized_array.hpp" namespace nova { using boost::filesystem::path; /* read synthdefs from path pattern */ std::vector sc_read_synthdefs_file(path const & filename); std::vector sc_read_synthdefs_dir(path const & dir); class sc_synth_definition: public synth_definition, public sc_synthdef { public: sc_synth_definition(sc_synthdef && sd); private: friend class sc_synth; virtual abstract_synth * create_instance(int) override; }; typedef boost::intrusive_ptr sc_synth_definition_ptr; void register_synthdefs(class synth_factory & factory, std::vector &&); } /* namespace nova */ #endif /* SC_SYNTH_DEFINITION_HPP */ SuperCollider-Source/server/supernova/sc/sc_synthdef.cpp000644 000765 000024 00000031103 12756531745 024644 0ustar00crucialstaff000000 000000 // supercollider-style synthdef // Copyright (C) 2008, 2009, 2010 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #include #include #include #include #include #include #include "sc_synthdef.hpp" #include "sc_ugen_factory.hpp" #include "utilities/sized_array.hpp" #include "utilities/exists.hpp" namespace nova { typedef std::int16_t int16; typedef std::int32_t int32; typedef std::int8_t int8; using boost::endian::big_int32_t; using boost::endian::big_int16_t; using boost::endian::big_int8_t; using std::size_t; namespace { void verify_synthdef_buffer(const char * buffer, const char *buffer_end) { if (buffer >= buffer_end) throw std::runtime_error("corrupted synthdef"); } std::string read_pstring(const char *& buffer, const char *buffer_end) { verify_synthdef_buffer(buffer, buffer_end); char str[256+1]; char name_size = *buffer++; verify_synthdef_buffer(buffer + name_size, buffer_end); memcpy(str, buffer, name_size); str[int(name_size)] = 0; buffer += name_size; return std::string(str); } float read_float(const char *& buffer, const char *buffer_end) { verify_synthdef_buffer(buffer, buffer_end); big_int32_t data = *(big_int32_t*)buffer; buffer += 4; union { int32_t i; float f; } cast; cast.i = data; return cast.f; } int8_t read_int8(const char *& buffer, const char *buffer_end) { verify_synthdef_buffer(buffer, buffer_end); big_int8_t data = *(big_int8_t*)buffer; buffer += 1; return data; } int16_t read_int16(const char *& buffer, const char *buffer_end) { verify_synthdef_buffer(buffer, buffer_end); big_int16_t data = *(big_int16_t*)buffer; buffer += 2; return data; } int32_t read_int32(const char *& buffer, const char *buffer_end) { verify_synthdef_buffer(buffer, buffer_end); big_int32_t data = *(big_int32_t*)buffer; buffer += 4; return data; } int32_t read_int(const char *& buffer, const char *buffer_end, int size) { if (size == 32) return read_int32(buffer, buffer_end); if (size == 16) return read_int16(buffer, buffer_end); assert(false); return 0; } } /* namespace */ std::vector read_synthdefs(const char * buffer, const char * buffer_end) { /* int32 header = */ read_int32(buffer, buffer_end); int32 version = read_int32(buffer, buffer_end); int16 definition_count = read_int16(buffer, buffer_end); std::vector ret; for (int i = 0; i != definition_count; ++i) { try { #ifdef __clang__ // clang does not like to emplace_back sc_synthdef def(buffer, buffer_end, version); ret.push_back(def); #else ret.emplace_back(buffer, buffer_end, version); #endif } catch (std::exception const & e) { std::cout << "Exception when reading synthdef: " << e.what() << std::endl; } } return ret; } std::vector read_synthdef_file(boost::filesystem::path const & filename) { using namespace std; ifstream stream; stream.open(filename.string().c_str()); if (!stream.is_open()) { cout << "cannot open file " << filename << endl; return std::vector(); } /* get length of file */ stream.seekg (0, ios::end); size_t length = stream.tellg(); stream.seekg (0, ios::beg); sized_array buffer(length); stream.read(buffer.c_array(), length); stream.close(); return read_synthdefs(buffer.begin(), buffer.end()); } sc_synthdef::unit_spec_t::unit_spec_t(const char *& buffer, const char * buffer_end, int version) { const int short_int_size = (version == 1) ? 16 : 32; name = symbol(read_pstring(buffer, buffer_end)); rate = read_int8(buffer, buffer_end); int32_t input_count = read_int(buffer, buffer_end, short_int_size); int32_t output_count = read_int(buffer, buffer_end, short_int_size); special_index = read_int16(buffer, buffer_end); for (int i = 0; i != input_count; ++i) { int32_t source = read_int(buffer, buffer_end, short_int_size); int32_t index = read_int(buffer, buffer_end, short_int_size); input_spec spec(source, index); input_specs.push_back(spec); } for (int i = 0; i != output_count; ++i) { char rate = read_int8(buffer, buffer_end); output_specs.push_back(rate); } } sc_synthdef::sc_synthdef(const char*& buffer, const char* buffer_end, int version) { read_synthdef(buffer, buffer_end, version); } void sc_synthdef::read_synthdef(const char *& buffer, const char* buffer_end, int version) { using namespace std; const int short_int_size = (version == 1) ? 16 : 32; /* read name */ name_ = symbol(read_pstring(buffer, buffer_end)); /* read constants */ int32_t constant_count = read_int(buffer, buffer_end, short_int_size); constants.reserve( constant_count ); for (int i = 0; i != constant_count; ++i) { float data = read_float(buffer, buffer_end); constants.push_back(data); } /* read parameters */ int32_t par_count = read_int(buffer, buffer_end, short_int_size); parameters.reserve( par_count ); for (int i = 0; i != par_count; ++i) { float data = read_float(buffer, buffer_end); parameters.push_back(data); } /* read parameter names */ int32_t parameter_names_count = read_int(buffer, buffer_end, short_int_size); for (int i = 0; i != parameter_names_count; ++i) { symbol data = symbol(read_pstring(buffer, buffer_end)); int32_t index = read_int(buffer, buffer_end, short_int_size); parameter_map[data] = index; } int32_t ugen_count = read_int(buffer, buffer_end, short_int_size); graph.reserve(ugen_count); for (int i = 0; i != ugen_count; ++i) { unit_spec_t data(buffer, buffer_end, version); graph.push_back(data); } prepare(); } namespace { template > class buffer_allocator { std::vector buffers; /* index: buffer id, value: last reference */ public: buffer_allocator(size_t size_hint) { buffers.reserve(size_hint); } /** allocate buffer for current ugen * * reuse buffers, which are not used after the current ugen */ int32_t allocate_buffer(size_t current_ugen) { for (size_t i = 0; i != buffers.size(); ++i) { if (buffers[i] <= current_ugen) return i; } buffers.push_back(current_ugen); return buffers.size() - 1; } /** allocate buffer for current ugen * * reuse the buffers, which have been used before the current ugen */ int32_t allocate_buffer_noalias(size_t current_ugen) { for (size_t i = 0; i != buffers.size(); ++i) { if (buffers[i] < current_ugen) return i; } buffers.push_back(current_ugen); return buffers.size() - 1; } size_t buffer_count (void) const { return buffers.size(); } void set_last_reference (int32_t buffer_id, size_t ugen_index) { buffers[buffer_id] = ugen_index; } }; } /* namespace */ void sc_synthdef::prepare(void) { // FIXME: this currently has quadratic complexity, as buffer_allocator::allocate has linear complexity memory_requirement_ = 0; const size_t number_of_ugens = graph.size(); calc_unit_indices.reserve(number_of_ugens); // store the last references to each output buffer inside a std::map for faster lookup std::map last_buffer_references; for (auto it = graph.rbegin(); it != graph.rend(); ++it) { for (size_t i = 0; i != it->input_specs.size(); ++i) { input_spec const & in_spec = it->input_specs[i]; if (it->rate == calc_DemandRate) { size_t ugen_index = number_of_ugens; // audio-inputs to demand-rate ugens will never be reused! last_buffer_references[in_spec] = ugen_index; } else { if (!exists(last_buffer_references, in_spec)) { size_t ugen_index = std::distance(it, graph.rend()) - 1; last_buffer_references.insert(std::make_pair(in_spec, ugen_index)); } } } } buffer_allocator<> allocator (number_of_ugens / 8); for (size_t ugen_index = 0; ugen_index != number_of_ugens; ++ugen_index) { unit_spec_t & current_ugen_spec = graph[ugen_index]; /* calc units are stored in an additional vector */ switch (current_ugen_spec.rate) { case calc_BufRate: case calc_FullRate: calc_unit_indices.push_back(ugen_index); } memory_requirement_ += current_ugen_spec.memory_requirement(); current_ugen_spec.buffer_mapping.resize(current_ugen_spec.output_specs.size()); sc_ugen_def * ugen = sc_factory->find_ugen(current_ugen_spec.name); if (unlikely(ugen == nullptr)) { /* we cannot prepare the synthdef, if the ugens are not installed */ boost::format frmt("Cannot load synth %1%: Unit generator %2% not installed"); frmt % name_.c_str() % current_ugen_spec.name.c_str(); throw std::runtime_error(frmt.str()); } current_ugen_spec.prototype = ugen; const bool can_alias = !ugen->cant_alias(); memory_requirement_ += ugen->memory_requirement(); for (size_t output_index = 0; output_index != current_ugen_spec.output_specs.size(); ++output_index) { int32_t buffer_id; if (current_ugen_spec.output_specs[output_index] == 2) { /* find last reference to this buffer */ size_t last_ref = ugen_index; input_spec this_input_spec(ugen_index, output_index); if (exists(last_buffer_references, this_input_spec)) last_ref = last_buffer_references[this_input_spec]; buffer_id = can_alias ? allocator.allocate_buffer(ugen_index) : allocator.allocate_buffer_noalias(ugen_index); allocator.set_last_reference(buffer_id, last_ref); } else buffer_id = -1; current_ugen_spec.buffer_mapping[output_index] = buffer_id; } } memory_requirement_ += (graph.size() + calc_unit_indices.size() + 1) * sizeof(Unit*); // reserves space for units (one more to allor prefetching) // memory that is required to fill the sc_synth data structure const size_t ctor_alloc_size = parameter_count() * (sizeof(float) + sizeof(int) + sizeof(float*)) + constants.size() * sizeof(Wire); memory_requirement_ += ctor_alloc_size; buffer_count = uint32_t(allocator.buffer_count()); calc_unit_indices.shrink_to_fit(); } std::string sc_synthdef::dump(void) const { using namespace std; stringstream stream; stream << "name " << name().c_str() << endl; stream << "constant: " << endl; for (uint i = 0; i != constants.size(); ++i) stream << "\t" << constants[i] << endl; stream << "parameters: " << endl; for (uint i = 0; i != parameters.size(); ++i) stream << "\t" << parameters[i] << endl; stream << "parameter names: " << endl; for (const auto & elem : parameter_map) stream << "\t" << elem.first.c_str() << " " << elem.second << endl; stream << "ugens: " << endl; for (uint i = 0; i != graph.size(); ++i) { stream << "\t" << graph[i].name.c_str() << ": rate " << graph[i].rate << endl; stream << "\tinputs:" << endl; for (uint j = 0; j != graph[i].input_specs.size(); ++j) { stream << "\t\t" << graph[i].input_specs[j].source << " " << graph[i].input_specs[j].index << endl; } } return stream.str(); } } /* namespace nova */ SuperCollider-Source/server/supernova/sc/sc_synthdef.hpp000644 000765 000024 00000012425 12760322424 024642 0ustar00crucialstaff000000 000000 // supercollider-style synthdef // Copyright (C) 2008-2012 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SC_SYNTHDEF_HPP #define SC_SYNTHDEF_HPP #include #include #include #include #include #include #include "utilities/named_hash_entry.hpp" #include "SC_Types.h" #include "SC_Wire.h" namespace nova { class sc_synthdef { typedef std::vector > float_vector; typedef std::vector > char_vector; #if BOOST_VERSION > 107000 typedef std::map, boost::alignment::aligned_allocator, 64>> parameter_index_map_t; #else typedef std::map> parameter_index_map_t; #endif public: struct input_spec { input_spec(int32_t source, int32_t index): source(source), index(index) {} bool operator<(input_spec const & rhs) const { if (source < rhs.source) return true; if (source > rhs.source) return false; return index < rhs.index; } int32_t source; /* index of ugen or -1 for constant */ int32_t index; /* number of output or constant index */ }; typedef std::vector > input_spec_vector; struct unit_spec_t { explicit unit_spec_t(const char *& buffer, const char * buffer_end, int version); unit_spec_t(symbol const & name, int16_t rate, int16_t special_index, input_spec_vector const & in_specs, char_vector const & out_specs): name(name), rate(rate), special_index(special_index), input_specs(in_specs), output_specs(out_specs) {} unit_spec_t(unit_spec_t && rhs) = default; unit_spec_t(unit_spec_t const & rhs) = default; unit_spec_t & operator=(unit_spec_t const & rhs) = default; symbol name; int16_t rate; /* 0: scalar rate, 1: buffer rate, 2: full rate, 3: demand rate */ int16_t special_index; input_spec_vector input_specs; char_vector output_specs; /* calculation rates */ std::vector > buffer_mapping; std::size_t memory_requirement(void) const { return input_specs.size() * (sizeof(Wire*) + sizeof(float*)) + output_specs.size() * (sizeof(Wire*) + sizeof(float*)) + output_specs.size() * sizeof(Wire); } class sc_ugen_def * prototype; }; friend class sc_synth_definition; friend class sc_synth; friend class sc_ugen_factory; friend class sc_ugen_def; typedef std::vector > graph_t; typedef std::vector > calc_units_t; sc_synthdef(const char *& buffer, const char * buffer_end, int version); sc_synthdef(sc_synthdef && rhs) = default; sc_synthdef(sc_synthdef const & rhs) = default; sc_synthdef& operator=(sc_synthdef const & rhs) = default; std::string dump(void) const; symbol const & name(void) const { return name_; } std::size_t parameter_count(void) const { return parameters.size(); } std::size_t unit_count(void) const { return graph.size(); } std::size_t calc_unit_count(void) const { return calc_unit_indices.size(); } std::size_t memory_requirement(void) const { assert(memory_requirement_); return memory_requirement_; } private: void read_synthdef(const char *& data, const char * end, int version); /** assign buffers, collect memory requirement & cache ugen prototype */ void prepare(void); symbol name_; float_vector constants; float_vector parameters; parameter_index_map_t parameter_map; graph_t graph; unsigned int buffer_count; calc_units_t calc_unit_indices; /**< indices of the units, that need to be calculated */ std::size_t memory_requirement_; }; std::vector read_synthdefs(const char * buffer, const char * buffer_end); std::vector read_synthdef_file(boost::filesystem::path const & filename); } /* namespace nova */ #endif /* SC_SYNTHDEF_HPP */ SuperCollider-Source/server/supernova/sc/sc_ugen_factory.cpp000644 000765 000024 00000026301 12756531745 025511 0ustar00crucialstaff000000 000000 // prototype of a supercollider-synthdef-based synth prototype // Copyright (C) 2009-2013 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. /* \todo for now we use dlopen, later we want to become cross-platform */ #ifdef DLOPEN #include #elif defined(_WIN32) #include "Windows.h" #endif #include #include "sc_ugen_factory.hpp" #include "SC_World.h" #include "SC_Wire.h" namespace nova { std::unique_ptr sc_factory; Unit * sc_ugen_def::construct(sc_synthdef::unit_spec_t const & unit_spec, sc_synth * s, World * world, linear_allocator & allocator) { const int buffer_length = world->mBufLength; const size_t output_count = unit_spec.output_specs.size(); /* size for wires and buffers */ uint8_t * chunk = allocator.alloc(memory_requirement()); memset(chunk, 0, memory_requirement()); Unit * unit = (Unit*) (std::uintptr_t(chunk + 63) & (~63)); // align on 64 byte boundary unit->mInBuf = allocator.alloc(unit_spec.input_specs.size()); unit->mOutBuf = allocator.alloc(unit_spec.output_specs.size()); unit->mInput = allocator.alloc(unit_spec.input_specs.size()); unit->mOutput = allocator.alloc(unit_spec.output_specs.size()); unit->mNumInputs = unit_spec.input_specs.size(); unit->mNumOutputs = unit_spec.output_specs.size(); /* initialize members */ unit->mCalcRate = unit_spec.rate; unit->mSpecialIndex = unit_spec.special_index; unit->mDone = false; unit->mUnitDef = reinterpret_cast(this); /* we abuse this field to store our reference */ unit->mWorld = world; /* initialize members from synth */ unit->mParent = static_cast(s); if (unit_spec.rate == 2) unit->mRate = &world->mFullRate; else unit->mRate = &world->mBufRate; unit->mBufLength = unit->mRate->mBufLength; float * buffer_base = s->unit_buffers; /* allocate buffers */ for (size_t i = 0; i != output_count; ++i) { Wire * w = allocator.alloc(); w->mFromUnit = unit; w->mCalcRate = unit->mCalcRate; w->mBuffer = nullptr; w->mScalarValue = 0; if (unit->mCalcRate == 2) { /* allocate a new buffer */ assert(unit_spec.buffer_mapping[i] >= 0); std::size_t buffer_id = unit_spec.buffer_mapping[i]; unit->mOutBuf[i] = buffer_base + buffer_length * buffer_id; w->mBuffer = unit->mOutBuf[i]; } else unit->mOutBuf[i] = &w->mScalarValue; unit->mOutput[i] = w; } /* prepare inputs */ for (size_t i = 0; i != unit_spec.input_specs.size(); ++i) { int source = unit_spec.input_specs[i].source; int index = unit_spec.input_specs[i].index; if (source == -1) unit->mInput[i] = &unit->mParent->mWire[index]; else { Unit * prev = s->units[source]; unit->mInput[i] = prev->mOutput[index]; } if (unit->mInput[i]->mCalcRate == 2) unit->mInBuf[i] = unit->mInput[i]->mBuffer; else unit->mInBuf[i] = &unit->mInput[i]->mScalarValue; } return unit; } bool sc_ugen_def::add_command(const char* cmd_name, UnitCmdFunc func) { sc_unitcmd_def * def = new sc_unitcmd_def(cmd_name, func); unitcmd_set.insert(*def); return true; } void sc_ugen_def::run_unit_command(const char * cmd_name, Unit * unit, struct sc_msg_iter *args) { unitcmd_set_type::iterator it = unitcmd_set.find(cmd_name, named_hash_hash(), named_hash_equal()); if (it != unitcmd_set.end()) it->run(unit, args); } sample * sc_bufgen_def::run(World * world, uint32_t buffer_index, struct sc_msg_iter *args) { SndBuf * buf = World_GetNRTBuf(world, buffer_index); sample * data = buf->data; (func)(world, buf, args); if (data == buf->data) return nullptr; else return data; } void sc_plugin_container::register_ugen(const char *inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags) { sc_ugen_def * def = new sc_ugen_def(inUnitClassName, inAllocSize, inCtor, inDtor, inFlags); ugen_set.insert(*def); } void sc_plugin_container::register_bufgen(const char * name, BufGenFunc func) { sc_bufgen_def * def = new sc_bufgen_def(name, func); bufgen_set.insert(*def); } sc_ugen_def * sc_plugin_container::find_ugen(symbol const & name) { ugen_set_type::iterator it = ugen_set.find(name, named_hash_hash(), named_hash_equal()); if (it == ugen_set.end()) return nullptr; return &*it; } bool sc_plugin_container::register_ugen_command_function(const char * ugen_name, const char * cmd_name, UnitCmdFunc func) { sc_ugen_def * def = find_ugen(symbol(ugen_name)); if (def) return false; return def->add_command(cmd_name, func); } bool sc_plugin_container::register_cmd_plugin(const char * cmd_name, PlugInCmdFunc func, void * user_data) { cmdplugin_set_type::iterator it = cmdplugin_set.find(cmd_name, named_hash_hash(), named_hash_equal()); if (it != cmdplugin_set.end()) { std::cout << "cmd plugin already registered: " << cmd_name << std::endl; return false; } sc_cmdplugin_def * def = new sc_cmdplugin_def(cmd_name, func, user_data); cmdplugin_set.insert(*def); return true; } sample * sc_plugin_container::run_bufgen(World * world, const char * name, uint32_t buffer_index, struct sc_msg_iter *args) { bufgen_set_type::iterator it = bufgen_set.find(name, named_hash_hash(), named_hash_equal()); if (it == bufgen_set.end()) { std::cout << "unable to find buffer generator: " << name << std::endl; return nullptr; } return it->run(world, buffer_index, args); } bool sc_plugin_container::run_cmd_plugin(World * world, const char * name, struct sc_msg_iter *args, void *replyAddr) { cmdplugin_set_type::iterator it = cmdplugin_set.find(name, named_hash_hash(), named_hash_equal()); if (it == cmdplugin_set.end()) { std::cout << "unable to find cmd plugin: " << name << std::endl; return false; } it->run(world, args, replyAddr); return true; } void sc_ugen_factory::load_plugin_folder (boost::filesystem::path const & path) { using namespace boost::filesystem; directory_iterator end; if (!is_directory(path)) return; for (directory_iterator it(path); it != end; ++it) { if (is_regular_file(it->status())) load_plugin(it->path()); if (is_directory(it->status())) load_plugin_folder(it->path()); } } #ifdef DLOPEN void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path ) { using namespace std; void * handle = dlopen(path.string().c_str(), RTLD_NOW | RTLD_LOCAL); if (handle == nullptr) return; typedef int (*info_function)(); info_function api_version = reinterpret_cast(dlsym(handle, "api_version")); int plugin_api_version = 1; // default if (api_version) plugin_api_version = (*api_version)(); if (plugin_api_version != sc_api_version) { cout << "API Version Mismatch: " << path << endl; dlclose(handle); return; } info_function supernova_check = reinterpret_cast(dlsym(handle, "server_type")); if (!supernova_check || (*supernova_check)() == sc_server_scsynth) { // silently ignore dlclose(handle); return; } void * load_symbol = dlsym(handle, "load"); if (!load_symbol) { cout << "Problem when loading plugin: \"load\" function undefined" << path << endl; dlclose(handle); return; } open_handles.push_back(handle); LoadPlugInFunc load_func = reinterpret_cast(load_symbol); (*load_func)(&sc_interface); /* don't close the handle */ return; } void sc_ugen_factory::close_handles(void) { for(void * handle : open_handles){ void *ptr = dlsym(handle, "unload"); if(ptr){ UnLoadPlugInFunc unloadFunc = (UnLoadPlugInFunc)ptr; (*unloadFunc)(); } dlclose(handle); } } #elif defined(_WIN32) void sc_ugen_factory::load_plugin ( boost::filesystem::path const & path ) { //std::cout << "try open plugin: " << path << std::endl; const char * filename = path.string().c_str(); HINSTANCE hinstance = LoadLibrary( path.string().c_str() ); if (!hinstance) { char *s; DWORD lastErr = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, lastErr , MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&s, 0, NULL ); std::cout << "Cannot open plugin: " << path << s << std::endl; LocalFree( s ); return; } typedef int (*info_function)(); info_function api_version = reinterpret_cast(GetProcAddress( hinstance, "api_version" )); if ((*api_version)() != sc_api_version) { std::cout << "API Version Mismatch: " << filename << std::endl; FreeLibrary(hinstance); return; } typedef int (*info_function)(); info_function server_type = reinterpret_cast(GetProcAddress( hinstance, "server_type" )); if (!server_type) { FreeLibrary(hinstance); return; } if ((*server_type)() != sc_server_supernova) { FreeLibrary(hinstance); return; } void *ptr = (void *)GetProcAddress( hinstance, "load" ); if (!ptr) { char *s; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError() , MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&s, 0, NULL ); std::cout << "*** ERROR: GetProcAddress err " << s << std::endl; LocalFree( s ); FreeLibrary(hinstance); return; } open_handles.push_back(hinstance); LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr; (*loadFunc)(&sc_interface); return; } void sc_ugen_factory::close_handles(void) { for(void * ptrhinstance : open_handles){ HINSTANCE hinstance = (HINSTANCE)ptrhinstance; void *ptr = (void *)GetProcAddress( hinstance, "unload" ); if(ptr){ UnLoadPlugInFunc unloadFunc = (UnLoadPlugInFunc)ptr; (*unloadFunc)(); } FreeLibrary(hinstance); } } #else #endif } /* namespace nova */ SuperCollider-Source/server/supernova/sc/sc_ugen_factory.hpp000644 000765 000024 00000016516 12756531745 025525 0ustar00crucialstaff000000 000000 // prototype of a supercollider-synthdef-based synth prototype // Copyright (C) 2009 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef SC_UGEN_FACTORY_HPP #define SC_UGEN_FACTORY_HPP #include #include #include #include "sc_synthdef.hpp" #include "sc_synth.hpp" #include "sc_plugin_interface.hpp" #include "SC_InterfaceTable.h" #include "SC_Unit.h" #include "utilities/named_hash_entry.hpp" namespace nova { namespace bi = boost::intrusive; struct sc_unitcmd_def: public named_hash_entry { const UnitCmdFunc func; sc_unitcmd_def(const char * cmd_name, UnitCmdFunc func): named_hash_entry(cmd_name), func(func) {} void run(Unit * unit, struct sc_msg_iter *args) { (func)(unit, args); } }; class sc_ugen_def: public aligned_class, public named_hash_entry { private: const size_t alloc_size; const UnitCtorFunc ctor; const UnitDtorFunc dtor; const uint32_t flags; static const std::size_t unitcmd_set_bucket_count = 4; typedef bi::unordered_set< sc_unitcmd_def, bi::constant_time_size, bi::power_2_buckets, bi::store_hash > unitcmd_set_type; unitcmd_set_type::bucket_type unitcmd_set_buckets[unitcmd_set_bucket_count]; unitcmd_set_type unitcmd_set; public: sc_ugen_def(const char *inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags): named_hash_entry(inUnitClassName), alloc_size(inAllocSize), ctor(inCtor), dtor(inDtor), flags(inFlags), unitcmd_set(unitcmd_set_type::bucket_traits(unitcmd_set_buckets, unitcmd_set_bucket_count)) {} Unit * construct(sc_synthdef::unit_spec_t const & unit_spec, sc_synth * s, World * world, linear_allocator & allocator); void initialize(Unit * unit) { (*ctor)(unit); } void destruct(Unit * unit) { if (dtor) (*dtor)(unit); } bool cant_alias(void) const { return flags & kUnitDef_CantAliasInputsToOutputs; } std::size_t memory_requirement(void) const { return alloc_size + 64; // overallocate to allow alignment } bool add_command(const char * cmd_name, UnitCmdFunc func); void run_unit_command(const char * cmd_name, Unit * unit, struct sc_msg_iter *args); }; struct sc_bufgen_def: public named_hash_entry { const BufGenFunc func; sc_bufgen_def(const char * name, BufGenFunc func): named_hash_entry(name), func(func) {} sample * run(World * world, uint32_t buffer_index, struct sc_msg_iter *args); }; struct sc_cmdplugin_def: public named_hash_entry { const PlugInCmdFunc func; void * user_data; sc_cmdplugin_def(const char * name, PlugInCmdFunc func, void * user_data): named_hash_entry(name), func(func), user_data(user_data) {} void run(World * world, struct sc_msg_iter *args, void *replyAddr) { (func)(world, user_data, args, replyAddr); } }; class sc_plugin_container { static const std::size_t ugen_set_bucket_count = 512; typedef bi::unordered_set< sc_ugen_def, bi::constant_time_size, bi::power_2_buckets, bi::store_hash > ugen_set_type; static const std::size_t bufgen_set_bucket_count = 64; typedef bi::unordered_set< sc_bufgen_def, bi::constant_time_size, bi::power_2_buckets, bi::store_hash > bufgen_set_type; static const std::size_t cmdplugin_set_bucket_count = 8; typedef bi::unordered_set< sc_cmdplugin_def, bi::constant_time_size, bi::power_2_buckets, bi::store_hash > cmdplugin_set_type; ugen_set_type::bucket_type ugen_set_buckets[ugen_set_bucket_count]; ugen_set_type ugen_set; bufgen_set_type::bucket_type bufgen_set_buckets[bufgen_set_bucket_count]; bufgen_set_type bufgen_set; cmdplugin_set_type::bucket_type cmdplugin_set_buckets[cmdplugin_set_bucket_count]; cmdplugin_set_type cmdplugin_set; protected: sc_plugin_container (void): ugen_set(ugen_set_type::bucket_traits(ugen_set_buckets, ugen_set_bucket_count)), bufgen_set(bufgen_set_type::bucket_traits(bufgen_set_buckets, bufgen_set_bucket_count)), cmdplugin_set(cmdplugin_set_type::bucket_traits(cmdplugin_set_buckets, cmdplugin_set_bucket_count)) {} ~sc_plugin_container (void) { ugen_set.clear_and_dispose(boost::checked_delete); bufgen_set.clear_and_dispose(boost::checked_delete); cmdplugin_set.clear_and_dispose(boost::checked_delete); } public: void register_ugen(const char *inUnitClassName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags); void register_bufgen(const char * name, BufGenFunc func); sc_ugen_def * find_ugen(symbol const & name); bool register_ugen_command_function(const char * ugen_name, const char * cmd_name, UnitCmdFunc); bool register_cmd_plugin(const char * cmd_name, PlugInCmdFunc func, void * user_data); sample * run_bufgen(World * world, const char * name, uint32_t buffer_index, struct sc_msg_iter *args); bool run_cmd_plugin(World * world , const char * name, struct sc_msg_iter *args, void *replyAddr); }; /** factory class for supercollider ugens * * \todo do we need to take care of thread safety? */ class sc_ugen_factory: public sc_plugin_interface, public sc_plugin_container { public: sc_ugen_factory() = default; ~sc_ugen_factory(void) { close_handles(); } /* @{ */ /** ugen count handling */ void allocate_ugens(uint32_t count) { ugen_count_ += count; } void free_ugens(uint32_t count) { ugen_count_ -= count; } uint32_t ugen_count(void) const { return ugen_count_; } /* @} */ void load_plugin_folder(boost::filesystem::path const & path); void load_plugin(boost::filesystem::path const & path); private: void close_handles(void); uint32_t ugen_count_ = 0; std::vector open_handles; }; extern std::unique_ptr sc_factory; } /* namespace nova */ #endif /* SC_UGEN_FACTORY_HPP */ SuperCollider-Source/server/supernova/dsp_thread_queue/dsp_thread.hpp000644 000765 000024 00000015564 12756531745 027406 0ustar00crucialstaff000000 000000 // dsp thread // Copyright (C) 2007-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef DSP_THREAD_QUEUE_DSP_THREAD_HPP #define DSP_THREAD_QUEUE_DSP_THREAD_HPP #include #include #include #include #include #include #include "dsp_thread_queue.hpp" #include "../utilities/malloc_aligned.hpp" #include "nova-tt/mlock.hpp" namespace nova { using std::uint16_t; struct nop_thread_init { nop_thread_init(void) {} template nop_thread_init(Arg const &) {} void operator()(int thread_index) {} }; #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 #define SUPERNOVA_USE_PTHREAD #endif /** dsp helper thread * * the dsp helper threads are running with a high real-time priority and are * pinned to a specific cpu */ template > class dsp_thread: public thread_init_functor { typedef nova::dsp_queue_interpreter dsp_queue_interpreter; public: dsp_thread(dsp_queue_interpreter & interpreter, uint16_t index, thread_init_functor const & thread_init = thread_init_functor()): thread_init_functor(thread_init), interpreter(interpreter), index(index) { #ifdef SUPERNOVA_USE_PTHREAD if (stack_size) { stack_ = malloc_aligned(stack_size); if (stack_ == nullptr) throw std::bad_alloc(); // touch stack to avoid page faults for (size_t i = 0; i != stack_size; ++i) stack_[i] = 0; mlock(stack_, stack_size); } #endif } dsp_thread(dsp_thread const &) = delete; dsp_thread& operator=(dsp_thread const &) = delete; ~dsp_thread(void) { #ifdef SUPERNOVA_USE_PTHREAD if (stack_) free_aligned(stack_); #endif } void start() { stop = false; #ifdef SUPERNOVA_USE_PTHREAD pthread_attr_t attr; pthread_attr_init(&attr); int err = pthread_attr_setstack(&attr, stack_, stack_size); if (err) throw std::logic_error("Cannot set stack of DSP helper thread"); err = pthread_create( &thread_id, &attr, run_static, this ); if (err) throw std::runtime_error("Cannot create DSP helper thread"); pthread_attr_destroy(&attr); #else thread = std::thread([this] {this->run();}); #endif } void join() { stop.store( true, std::memory_order_relaxed ); wake_thread(); #ifdef SUPERNOVA_USE_PTHREAD void * ret; int err = pthread_join( thread_id, &ret ); if (err) printf("Error when joining helper thread\n"); #else thread.join(); #endif } void wake_thread(void) { cycle_sem.post(); } private: /** thread function * */ void run(void) { thread_init_functor::operator()(index); for (;;) { cycle_sem.wait(); if (unlikely(stop.load(std::memory_order_relaxed))) return; interpreter.tick(index); } } static void * run_static(void* arg) { dsp_thread * self = static_cast(arg); self->run(); return nullptr; } private: boost::sync::semaphore cycle_sem; dsp_queue_interpreter & interpreter; std::atomic stop = {false}; uint16_t index; #ifdef SUPERNOVA_USE_PTHREAD pthread_t thread_id; static const size_t stack_size = 524288; char * stack_ = nullptr; #else std::thread thread; #endif }; /** \brief container for all dsp threads * * - no care is taken, that dsp_thread_pool::run is executed on a valid instance * * */ template > class dsp_thread_pool { typedef nova::dsp_queue_interpreter dsp_queue_interpreter; typedef nova::dsp_thread dsp_thread; public: typedef typename dsp_queue_interpreter::node_count_t node_count_t; typedef typename dsp_queue_interpreter::thread_count_t thread_count_t; typedef std::unique_ptr > dsp_thread_queue_ptr; dsp_thread_pool( thread_count_t count, bool yield_if_busy = false, thread_init_functor const & init_functor = thread_init_functor() ): interpreter(std::min(count, (thread_count_t)std::thread::hardware_concurrency()), yield_if_busy) { set_dsp_thread_count(interpreter.get_thread_count(), init_functor); } void run(void) { const bool run_tick = interpreter.init_tick(); if( likely(run_tick) ) { wake_threads(); interpreter.tick_master(); } } /** reset queue * * don't call, if threads are currently accessing the queue * */ dsp_thread_queue_ptr reset_queue(dsp_thread_queue_ptr && new_queue) { dsp_thread_queue_ptr ret = interpreter.reset_queue(std::move(new_queue)); return std::move(ret); } dsp_thread_queue_ptr release_queue(void) { return interpreter.release_queue(); } public: /** thread handling */ /* @{ */ void start_threads(void) { for (auto & thread : threads) thread->start(); } void terminate_threads(void) { for (auto & thread : threads) thread->join(); } /* @} */ private: void set_dsp_thread_count(thread_count_t count, thread_init_functor const & init_functor) { for (thread_count_t i = 1; i != count; ++i) threads.emplace_back( new dsp_thread( interpreter, i, init_functor ) ); } /** wake dsp threads */ void wake_threads(void) { for (thread_count_t i = 0; i != interpreter.get_used_helper_threads(); ++i) threads[i]->wake_thread(); } dsp_queue_interpreter interpreter; std::vector> threads; }; } /* namespace nova */ #endif /* DSP_THREAD_QUEUE_DSP_THREAD_HPP */ SuperCollider-Source/server/supernova/dsp_thread_queue/dsp_thread_queue.hpp000644 000765 000024 00000044433 12756531745 030607 0ustar00crucialstaff000000 000000 // dsp thread queue // Copyright (C) 2007-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef DSP_THREAD_QUEUE_DSP_THREAD_QUEUE_HPP #define DSP_THREAD_QUEUE_DSP_THREAD_QUEUE_HPP #include #include #include #include #include #include #include #include #include #include #include #include "nova-tt/pause.hpp" #include "utilities/branch_hints.hpp" #include "utilities/utils.hpp" namespace nova { template class dsp_queue_interpreter; /* concept runnable { runnable(const & runnable); operator()(uint threadindex); }; */ /** item of a dsp thread queue * * \tparam Alloc allocator for successor list * */ template > class dsp_thread_queue_item: private Alloc { typedef nova::dsp_queue_interpreter dsp_queue_interpreter; typedef typename Alloc::template rebind::other new_allocator; public: typedef std::uint_fast16_t activation_limit_t; struct successor_list { struct data_t { uint32_t count; uint32_t size; dsp_thread_queue_item* content[0]; }; typedef typename Alloc::template rebind::other array_allocator; /* create instance */ explicit successor_list(uint32_t size = 0) { data = array_allocator().allocate( 2*sizeof(uint32_t) + size * sizeof(dsp_thread_queue_item*) ); data->count = 1; data->size = size; } successor_list(successor_list const & rhs): data(rhs.data) { data->count++; } successor_list & operator=(successor_list const & rhs) { if (--data->count == 0) array_allocator().deallocate( data, 2 * sizeof(uint32_t) + data->size * sizeof(dsp_thread_queue_item*) ); data = rhs.data; data->count++; return *this; } std::size_t size(void) const { return data->size; } bool empty(void) const { return size() == 0; } dsp_thread_queue_item *& operator[](std::size_t index) { assert (index < size()); return data->content[index]; } dsp_thread_queue_item * const& operator[](std::size_t index) const { assert (index < size()); return data->content[index]; } ~successor_list(void) { if (--data->count == 0) array_allocator().deallocate( data, 2*sizeof(uint32_t) + data->size * sizeof(dsp_thread_queue_item*) ); } data_t * data; }; dsp_thread_queue_item(runnable const & job, successor_list const & successors, activation_limit_t activation_limit): activation_count(0), job(job), successors(successors), activation_limit(activation_limit) {} dsp_thread_queue_item * run(dsp_queue_interpreter & interpreter, std::uint8_t thread_index) { assert(activation_count == 0); job(thread_index); dsp_thread_queue_item * next = update_dependencies(interpreter); reset_activation_count(); return next; } /** called from the run method or once, when dsp queue is initialized */ void reset_activation_count(void) { assert(activation_count == 0); activation_count.store(activation_limit, std::memory_order_release); } runnable const & get_job(void) const { return job; } runnable & get_job(void) { return job; } #ifdef DEBUG_DSP_THREADS void dump_item(void) { using namespace std; printf("\titem %p\n", this); printf("\tactivation limit %d\n", int(activation_limit)); if (!successors.empty()) { printf("\tsuccessors:\n"); for (size_t i = 0; i != successors.size(); ++i) { printf("\t\t%p\n", successors[i]); } } printf("\n"); } #endif private: /** \brief update all successors and possibly mark them as runnable */ dsp_thread_queue_item * update_dependencies(dsp_queue_interpreter & interpreter) { dsp_thread_queue_item * next_item_to_run; std::size_t i = 0; for (;;) { if (i == successors.size()) return nullptr; next_item_to_run = successors[i++]->decrement_activation_count(); if (next_item_to_run) break; // no need to update the next item to run } // push remaining items to scheduler queue while( i != successors.size() ) { dsp_thread_queue_item * next = successors[i++]->decrement_activation_count(); if (next) interpreter.mark_as_runnable(next); } return next_item_to_run; } /** \brief decrement activation count and return this, if it drops to zero */ inline dsp_thread_queue_item * decrement_activation_count() { activation_limit_t current = activation_count--; assert(current > 0); if (current == 1) return this; else return nullptr; } std::atomic activation_count; /**< current activation count */ runnable job; const successor_list successors; /**< list of successing nodes */ const activation_limit_t activation_limit; /**< number of precedessors */ }; template class raw_vector: Alloc { public: explicit raw_vector( size_t elements, Alloc const & alloc = Alloc() ): Alloc(alloc), capacity_(elements) { data = elements ? Alloc::allocate(capacity_ * sizeof(T)) : nullptr; } template< class... Args > T * emplace_back( Args&&... args ) { assert( size() != capacity_ ); T * element = data + size_; Alloc::construct( element, std::forward(args)... ); size_ += 1; return element; } T & operator[](std::size_t index) { assert( index < size_ ); return data[index]; } T * begin() { return data; } T * end() { return data + size_; } bool empty() const { return size_ == 0; } size_t size() const { return size_; } size_t capacity() const { return capacity_; } ~raw_vector() { for (std::size_t i = 0; i != size_; ++i) Alloc::destroy( data + i ); if (data) Alloc::deallocate (data, capacity_ * sizeof(Alloc) ); } private: T * data = nullptr; const size_t capacity_ = 0; size_t size_ = 0; }; template > class dsp_thread_queue { typedef std::uint_fast16_t node_count_t; typedef nova::dsp_thread_queue_item dsp_thread_queue_item; typedef std::vector< dsp_thread_queue_item*, typename Alloc::template rebind::other > item_vector_t; typedef typename Alloc::template rebind::other item_allocator; public: #ifdef DEBUG_DSP_THREADS void dump_queue(void) { using namespace std; printf("queue %p\n items:\n", this); for (std::size_t i = 0; i != total_node_count; ++i) queue_items[i].dump_item(); printf("\ninitial items:\n", this); for(dsp_thread_queue_item * item : initially_runnable_items) item->dump_item(); printf("\n"); std::cout << std::endl; } #endif /** preallocate node_count nodes */ dsp_thread_queue(std::size_t node_count, bool has_parallelism = true): has_parallelism_(has_parallelism), items( node_count ) { initially_runnable_items.reserve(node_count); } ~dsp_thread_queue(void) = default; void add_initially_runnable(dsp_thread_queue_item * item) { initially_runnable_items.push_back(item); } /** return initialized queue item */ dsp_thread_queue_item * allocate_queue_item(runnable const & job, typename dsp_thread_queue_item::successor_list const & successors, typename dsp_thread_queue_item::activation_limit_t activation_limit) { return items.emplace_back( job, successors, activation_limit ); } void reset_activation_counts(void) { for( dsp_thread_queue_item & item : items) item.reset_activation_count(); } bool empty() const { return items.empty(); } node_count_t total_node_count(void) const { return node_count_t(items.size()); } bool has_parallelism(void) const { return has_parallelism_; } private: item_vector_t initially_runnable_items; /* nodes without precedessor */ const bool has_parallelism_; friend class dsp_queue_interpreter; raw_vector items; }; template > class dsp_queue_interpreter { protected: typedef nova::dsp_thread_queue dsp_thread_queue; typedef nova::dsp_thread_queue_item dsp_thread_queue_item; typedef typename dsp_thread_queue_item::successor_list successor_list; typedef std::size_t size_t; public: typedef boost::uint_fast8_t thread_count_t; typedef boost::uint_fast16_t node_count_t; typedef std::unique_ptr dsp_thread_queue_ptr; dsp_queue_interpreter(thread_count_t tc, bool yield_if_busy = false): yield_if_busy(yield_if_busy) { if (!runnable_items.is_lock_free()) std::cout << "Warning: scheduler queue is not lockfree!" << std::endl; calibrate_backoff(10); set_thread_count(tc); } /** prepares queue and queue interpreter for dsp tick * * \return true, if dsp queue is valid * false, if no dsp queue is available or queue is empty */ bool init_tick(void) { if (unlikely( !queue || queue->empty() )) return false; /* reset node count */ assert(node_count == 0); assert(runnable_items.empty()); node_count.store(queue->total_node_count(), std::memory_order_release); for( auto * item : queue->initially_runnable_items ) mark_as_runnable( item ); return true; } dsp_thread_queue_ptr release_queue(void) { dsp_thread_queue_ptr ret(queue.release()); return ret; } dsp_thread_queue_ptr reset_queue(dsp_thread_queue_ptr && new_queue) { dsp_thread_queue_ptr ret(std::move(queue)); queue = std::move(new_queue); if (queue.get() == nullptr) return ret; queue->reset_activation_counts(); #ifdef DEBUG_DSP_THREADS queue->dump_queue(); #endif if (queue->has_parallelism()) { thread_count_t thread_number = std::min(thread_count_t(std::min(total_node_count(), node_count_t(std::numeric_limits::max()))), thread_count); used_helper_threads = thread_number - 1; /* this thread is not waked up */ } else used_helper_threads = 0; return ret; } node_count_t total_node_count(void) const { return queue->total_node_count(); } void set_thread_count(thread_count_t i) { assert (i < std::numeric_limits::max()); i = std::max(thread_count_t(1u), i); thread_count = i; } thread_count_t get_thread_count(void) const { return thread_count; } thread_count_t get_used_helper_threads(void) const { return used_helper_threads; } void tick(thread_count_t thread_index) { if (yield_if_busy) run_item(thread_index); else run_item(thread_index); } private: static const int max_backup_loops = 16384; struct backoff { backoff(int min, int max): min(min), max(max), loops(min) {} void run() { for (int i = 0; i != loops; ++i) nova::detail::pause(); loops = std::min(loops * 2, max); } void reset() { loops = min; } const int min, max; int loops; }; struct yield_backoff { yield_backoff(int dummy_min, int dummy_max){} void run() { std::this_thread::yield(); } void reset(){} }; template struct select_backoff { typedef typename boost::mpl::if_c::type type; }; void calibrate_backoff(int timeout_in_seconds) { using namespace std; using namespace std::chrono; const int backoff_iterations = 100; vector measured_values; generate_n(back_inserter(measured_values), 16, [] { backoff b( max_backup_loops, max_backup_loops ); auto start = high_resolution_clock::now(); for (int i = 0; i != backoff_iterations; ++i) b.run(); auto end = high_resolution_clock::now(); auto diff = duration_cast(end - start); return diff; }); std::sort(measured_values.begin(), measured_values.end()); auto median = measured_values[measured_values.size()/2]; watchdog_iterations = (seconds(timeout_in_seconds) / median) * backoff_iterations; } template void run_item(thread_count_t index) { // note: in future we can avoid the watchdog on osx and linux, as they provide proper // deadline scheduling policies typedef typename select_backoff::type backoff_t; backoff_t b(8, max_backup_loops); int poll_counts = 0; for (;;) { if (!node_count.load(std::memory_order_acquire)) return; /* we still have some nodes to process */ int state = run_next_item(index); switch (state) { case no_remaining_items: return; case fifo_empty: b.run(); ++poll_counts; break; case remaining_items: b.reset(); poll_counts = 0; } if( YieldBackoff ) continue; if( poll_counts == watchdog_iterations ) { if( index == 0 ) { std::printf("nova::dsp_queue_interpreter::run_item: possible lookup detected in main audio thread\n"); abort(); } else { std::printf("nova::dsp_queue_interpreter::run_item: possible lookup detected in dsp helper thread\n"); return; } } } } public: void tick_master(void) { if (yield_if_busy) run_item_master(); else run_item_master(); } private: template void run_item_master(void) { run_item(0); wait_for_end(); assert(runnable_items.empty()); } template void wait_for_end(void) { typedef typename select_backoff::type backoff_t; backoff_t b(8, max_backup_loops); const int iterations = watchdog_iterations * 2; int count = 0; while (node_count.load(std::memory_order_acquire) != 0) { b.run(); ++count; if( !YieldBackoff && (count == iterations) ) { std::printf("nova::dsp_queue_interpreter::wait_for_end: possible lookup detected\n"); } } // busy-wait for helper threads to finish } HOT int run_next_item(thread_count_t index) { dsp_thread_queue_item * item; bool success = runnable_items.pop(item); if (!success) return fifo_empty; node_count_t consumed = 0; do { item = item->run(*this, index); consumed += 1; } while (item != nullptr); node_count_t remaining = node_count.fetch_sub(consumed, std::memory_order_release); assert (remaining >= consumed); if (remaining == consumed) return no_remaining_items; else return remaining_items; } void mark_as_runnable(dsp_thread_queue_item * item) { runnable_items.push(item); } friend class nova::dsp_thread_queue_item; private: enum { no_remaining_items, fifo_empty, remaining_items }; dsp_thread_queue_ptr queue; thread_count_t thread_count; /* number of dsp threads to be used by this queue */ thread_count_t used_helper_threads; /* number of helper threads, which are actually used */ boost::lockfree::stack > runnable_items; std::atomic node_count = {0}; /* number of nodes, that need to be processed during this tick */ int watchdog_iterations; bool yield_if_busy; }; } /* namespace nova */ #endif /* DSP_THREAD_QUEUE_DSP_THREAD_QUEUE_HPP */ SuperCollider-Source/server/supernova/audio_backend/audio_backend_common.hpp000644 000765 000024 00000013254 12756531745 030632 0ustar00crucialstaff000000 000000 // audio backend helpers // Copyright (C) 2010-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef AUDIO_BACKEND_AUDIO_BACKEND_COMMON_HPP #define AUDIO_BACKEND_AUDIO_BACKEND_COMMON_HPP #include #include #include #include "nova-simd/simd_memory.hpp" #include "nova-tt/dummy_mutex.hpp" #include "nova-tt/spin_lock.hpp" #include "utilities/malloc_aligned.hpp" namespace nova { namespace detail { template class audio_backend_base: boost::mpl::if_c::type { typedef typename boost::mpl::if_c::type lock_t; typedef std::size_t size_t; public: /* @{ */ /** buffers can be directly mapped to the io regions of the host application */ template void input_mapping(Iterator const & buffer_begin, Iterator const & buffer_end) { static_assert(!managed_memory, "audio_backend_common: managed_memory == true"); size_t input_count = buffer_end - buffer_begin; input_samples.resize(input_count); std::copy(buffer_begin, buffer_end, input_samples.begin()); } template void output_mapping(Iterator const & buffer_begin, Iterator const & buffer_end) { static_assert(!managed_memory, "audio_backend_common: managed_memory == true"); size_t output_count = buffer_end - buffer_begin; output_samples.resize(output_count); std::copy(buffer_begin, buffer_end, output_samples.begin()); } /* @} */ protected: void clear_inputs(size_t frames_per_tick) { for (uint16_t channel = 0; channel != input_samples.size(); ++channel) zerovec_simd(input_samples[channel].get(), frames_per_tick); } void clear_outputs(size_t frames_per_tick) { for (uint16_t channel = 0; channel != output_samples.size(); ++channel) zerovec_simd(output_samples[channel].get(), frames_per_tick); } void prepare_helper_buffers(size_t input_channels, size_t output_channels, size_t frames) { static_assert(managed_memory, "audio_backend_common: managed_memory == false"); input_samples.resize(input_channels); output_samples.resize(output_channels); std::generate(input_samples.begin(), input_samples.end(), std::bind(calloc_aligned, frames)); std::generate(output_samples.begin(), output_samples.end(), std::bind(calloc_aligned, frames)); } void fetch_inputs(const float ** inputs, size_t frames, int input_channels) { if (is_multiple_of_vectorsize(frames)) { for (uint16_t i = 0; i != input_channels; ++i) { if (is_aligned(inputs[i])) nova::copyvec_simd(input_samples[i].get(), inputs[i], frames); else nova::copyvec(input_samples[i].get(), inputs[i], frames); inputs[i] += frames; } } else { for (uint16_t i = 0; i != input_channels; ++i) { nova::copyvec(input_samples[i].get(), inputs[i], frames); inputs[i] += frames; } } } void deliver_outputs(float ** outputs, size_t frames, int output_channels) { if (is_multiple_of_vectorsize(frames)) { for (uint16_t i = 0; i != output_channels; ++i) { if (is_aligned(outputs[i])) nova::copyvec_simd(outputs[i], output_samples[i].get(), frames); else nova::copyvec(outputs[i], output_samples[i].get(), frames); outputs[i] += frames; } } else { for (uint16_t i = 0; i != output_channels; ++i) { nova::copyvec(outputs[i], output_samples[i].get(), frames); outputs[i] += frames; } } } static bool is_aligned(const void * arg) { size_t mask = sizeof(vec::size) * sizeof(float) * 8 - 1; return !((size_t)arg & mask); } static bool is_multiple_of_vectorsize(size_t count) { return !(count & (vec::objects_per_cacheline - 1)); } std::vector, boost::alignment::aligned_allocator, 64>> input_samples, output_samples; }; class audio_settings_basic { protected: float samplerate_ = 0.f; uint16_t input_channels = 0; uint16_t output_channels = 0; public: audio_settings_basic(void) {} float get_samplerate(void) const { return samplerate_; } uint16_t get_input_count(void) const { return input_channels; } uint16_t get_output_count(void) const { return output_channels; } }; } /* namespace detail */ } /* namespace nova */ #endif /* AUDIO_BACKEND_AUDIO_BACKEND_COMMON_HPP */ SuperCollider-Source/server/supernova/audio_backend/cpu_time_info.hpp000644 000765 000024 00000003625 12756531745 027333 0ustar00crucialstaff000000 000000 // cpu time info // Copyright (C) 2011-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef AUDIO_BACKEND_CPU_TIME_INFO_HPP #define AUDIO_BACKEND_CPU_TIME_INFO_HPP #include #include #include "nova-simd/simd_horizontal_functions.hpp" namespace nova { class cpu_time_info { typedef std::vector> ringbuffer; public: cpu_time_info() {} void resize( int sampleRate, int blockSize, int seconds = 1 ) { const size_t blocks = sampleRate * seconds / blockSize; size = std::max( size_t(1), blocks ); buffer.resize( size, 0.f ); index = size - 1; } void update(float f) { ++index; if (index == size) index = 0; buffer[index] = f; } void get(float & peak, float & average) const { const float average_factor = 1.f/size; float sum; horizontal_maxsum_vec_simd(peak, sum, buffer.data(), size); average = sum * average_factor; } private: std::size_t size = 0; std::size_t index = 0; ringbuffer buffer; }; } #endif /* AUDIO_BACKEND_CPU_TIME_INFO_HPP */ SuperCollider-Source/server/supernova/audio_backend/jack_backend.hpp000644 000765 000024 00000026335 12766171707 027074 0ustar00crucialstaff000000 000000 // native jack backend // Copyright (C) 2009-2015 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef AUDIO_BACKEND_JACK_BACKEND_HPP #define AUDIO_BACKEND_JACK_BACKEND_HPP #include #include #include #include #include #ifdef SC_JACK_USE_METADATA_API # include # include # include #endif #include "utilities/branch_hints.hpp" #include "audio_backend_common.hpp" #include "cpu_time_info.hpp" namespace nova { /** jack backend * * the jack callback thread is pinned to the first cpu of the system * * \todo later it may be interesting to directly map the io busses to the jack port regions * \todo rethink the use of output port lock */ template class jack_backend: public detail::audio_backend_base, public detail::audio_settings_basic, protected engine_functor { typedef detail::audio_backend_base super; public: jack_backend(void) = default; ~jack_backend(void) { if (audio_is_active()) deactivate_audio(); close_client(); } uint32_t get_audio_blocksize(void) const { return blocksize_; } public: void open_client(std::string const & server_name, std::string const & name, uint32_t input_port_count, uint32_t output_port_count, uint32_t blocksize) { blocksize_ = blocksize; /* open client */ client = server_name.empty() ? jack_client_open(name.c_str(), JackNoStartServer, &status) : jack_client_open(name.c_str(), jack_options_t(JackNoStartServer | JackServerName), &status, server_name.c_str()); std::atomic_thread_fence(std::memory_order_release); // ensure visibility on other threads if (status & JackServerFailed) throw std::runtime_error("Unable to connect to JACK server"); if (status & JackNameNotUnique) { const char * client_name = jack_get_client_name(client); std::cout << "unique client name: " << client_name << std::endl; } /* initialize callbacks */ jack_set_thread_init_callback (client, jack_thread_init_callback, this); jack_set_process_callback (client, jack_process_callback, this); jack_set_xrun_callback(client, jack_xrun_callback, this); jack_on_info_shutdown(client, (JackInfoShutdownCallback)jack_on_info_shutdown_callback, nullptr); /* register ports */ input_ports.clear(); for (uint32_t i = 0; i != input_port_count; ++i) { std::string portname ("input_"); portname += std::to_string(i+1); jack_port_t * port = jack_port_register(client, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); input_ports.push_back(port); #ifdef SC_JACK_USE_METADATA_API jack_uuid_t uuid = jack_port_uuid(port); if(!jack_uuid_empty(uuid)) { std::string prettyname ("Input "); prettyname += std::to_string(i+1); jack_set_property(client, uuid, JACK_METADATA_PRETTY_NAME, prettyname.c_str(), "text/plain"); std::string order (""); order += std::to_string(i); jack_set_property(client, uuid, JACKEY_ORDER, order.c_str(), "http://www.w3.org/2001/XMLSchema#integer"); } #endif } input_channels = input_port_count; super::input_samples.resize(input_port_count); output_ports.clear(); for (uint32_t i = 0; i != output_port_count; ++i) { std::string portname ("output_"); portname += std::to_string(i+1); jack_port_t * port = jack_port_register(client, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); output_ports.push_back(port); #ifdef SC_JACK_USE_METADATA_API jack_uuid_t uuid = jack_port_uuid(port); if(!jack_uuid_empty(uuid)) { std::string prettyname ("Output "); prettyname += std::to_string(i+1); jack_set_property(client, uuid, JACK_METADATA_PRETTY_NAME, prettyname.c_str(), "text/plain"); std::string order (""); order += std::to_string(input_port_count + i); jack_set_property(client, uuid, JACKEY_ORDER, order.c_str(), "http://www.w3.org/2001/XMLSchema#integer"); } #endif } output_channels = output_port_count; super::output_samples.resize(output_port_count); samplerate_ = jack_get_sample_rate(client); jack_frames = jack_get_buffer_size(client); if (jack_frames % blocksize_) throw std::runtime_error("Jack buffer size is not a multiple of blocksize"); cpu_time_accumulator.resize( samplerate_, jack_frames, 1 ); } void close_client(void) { if (client) { jack_client_close(client); client = nullptr; } } bool audio_is_opened(void) { return client != nullptr; } bool audio_is_active(void) { return is_active; } void activate_audio(void) { is_active = true; jack_activate(client); } void deactivate_audio(void) { if (is_active) { jack_deactivate(client); is_active = false; } } void get_cpuload(float & peak, float & average) const { cpu_time_accumulator.get(peak, average); } int connect_input(size_t channel, const char * portname) { if (channel >= input_ports.size()) return -1; return jack_connect(client, portname, jack_port_name(input_ports[channel])); } int connect_output(size_t channel, const char * portname) { if (channel >= output_ports.size()) return -1; return jack_connect(client, jack_port_name(output_ports[channel]), portname); } int connect_all_inputs(const char * client_name) { const char **ports = jack_get_ports (client, client_name, nullptr, JackPortIsOutput); if (!ports) return -1; std::size_t i = 0; while (ports[i]) { if (i == input_ports.size()) break; int err = jack_connect(client, ports[i], jack_port_name(input_ports[i])); if (err) return err; ++i; } free(ports); return 0; } int connect_all_outputs(const char * client_name) { const char **ports = jack_get_ports (client, client_name, nullptr, JackPortIsInput); if (!ports) return -1; std::size_t i = 0; while (ports[i]) { if (i == output_ports.size()) break; int err = jack_connect(client, jack_port_name(output_ports[i]), ports[i]); if (err) return err; ++i; } free(ports); return 0; } int max_realtime_priority(void) const { return jack_client_max_real_time_priority(client); } int realtime_priority(void) const { return jack_client_real_time_priority(client); } private: static void jack_thread_init_callback(void * arg) { std::atomic_thread_fence(std::memory_order_acquire); jack_backend * self = static_cast(arg); if (jack_client_thread_id(self->client) == pthread_self()) engine_functor::init_thread(); else name_thread("Jack Helper"); } static int jack_process_callback(jack_nframes_t frames, void * arg) { return static_cast(arg)->perform(frames); } static int jack_on_info_shutdown_callback(jack_status_t code, const char *reason, void *arg) { std::cerr << "Jack server was shut down: " << reason << std::endl; std::cerr << "Exiting ..." << std::endl; exit(0); // TODO: later we may want to call a function } static int jack_xrun_callback(void * arg) { return static_cast(arg)->handle_xrun(); } int handle_xrun(void) { time_is_synced = false; engine_functor::log_("Jack: xrun detected - resyncing clock\n"); return 0; } int perform(jack_nframes_t frames) { if (unlikely(!time_is_synced)) { engine_functor::sync_clock(); time_is_synced = true; } /* get port regions */ jack_default_audio_sample_t ** inputs = (jack_default_audio_sample_t **)alloca(input_channels * sizeof(jack_default_audio_sample_t*)); jack_default_audio_sample_t ** outputs = (jack_default_audio_sample_t **)alloca(output_channels * sizeof(jack_default_audio_sample_t*)); for (uint16_t i = 0; i != input_channels; ++i) inputs[i] = (jack_default_audio_sample_t*) jack_port_get_buffer(input_ports[i], frames); for (uint16_t i = 0; i != output_channels; ++i) outputs[i] = (jack_default_audio_sample_t*) jack_port_get_buffer(output_ports[i], frames); jack_nframes_t processed = 0; while (processed != frames) { super::fetch_inputs((const float**)inputs, blocksize_, input_channels); engine_functor::run_tick(); super::deliver_outputs(outputs, blocksize_, output_channels); processed += blocksize_; } cpu_time_accumulator.update(jack_cpu_load(client)); return 0; } static int jack_buffersize_callback(jack_nframes_t frames, void * arg) { return static_cast(arg)->buffer_size_callback(frames); } int buffer_size_callback(jack_nframes_t frames) { jack_frames = frames; if (jack_frames % blocksize_) /* we need a multiple of the blocksize */ return 1; return 0; } jack_client_t * client = nullptr; jack_status_t status; bool is_active = false; bool time_is_synced = false; uint32_t blocksize_; std::vector input_ports, output_ports; jack_nframes_t jack_frames; cpu_time_info cpu_time_accumulator; }; } /* namespace nova */ #endif /* AUDIO_BACKEND_JACK_BACKEND_HPP */ SuperCollider-Source/server/supernova/audio_backend/portaudio_backend.hpp000644 000765 000024 00000025157 12756531745 030174 0ustar00crucialstaff000000 000000 // portaudio backend // Copyright (C) 2006 - 2013 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef _PORTAUDIO_HPP #define _PORTAUDIO_HPP #include #include #include #include "portaudio.h" #ifdef HAVE_PORTAUDIO_CONFIG_H #include "portaudio/portaudio_config.h" #endif /* HAVE_PORTAUDIO_CONFIG_H */ #include "audio_backend_common.hpp" #include "utilities/branch_hints.hpp" #include "cpu_time_info.hpp" namespace nova { /** \brief portaudio backend for supernova * * */ template class portaudio_backend: public detail::audio_backend_base, public detail::audio_settings_basic, protected engine_functor { typedef detail::audio_backend_base super; public: portaudio_backend(void) { int err = Pa_Initialize(); report_error(err, true); list_devices(); #ifdef PA_HAVE_JACK PaJack_SetClientName("SuperNova"); #endif } ~portaudio_backend(void) { if (audio_is_active()) deactivate_audio(); close_stream(); int err = Pa_Terminate(); report_error(err); } uint32_t get_audio_blocksize(void) const { return blocksize_; } private: static void report_error(int err, bool throw_exception = false) { if (err < 0) { engine_functor::log_printf_("PortAudio error: %s\n", Pa_GetErrorText( err )); if (throw_exception) throw std::runtime_error("PortAudio error"); } } public: static void list_devices(void) { int device_number = Pa_GetDeviceCount(); if (device_number < 0) report_error(device_number); printf("Available Audio Devices:\n"); for (int i = 0; i != device_number; ++i) { const PaDeviceInfo * device_info = Pa_GetDeviceInfo(i); if (device_info) { printf("%d: %s (%d inputs, %d outputs)\n", i, device_info->name, device_info->maxInputChannels, device_info->maxOutputChannels); } } printf("\n"); } bool match_device (std::string const & device, int & r_device_index) { if (device.empty()) return true; int device_number = Pa_GetDeviceCount(); if (device_number < 0) { report_error(device_number); return false; } for (int i = 0; i != device_number; ++i) { if (device_name(i) == device) { r_device_index = i; return true; } } return false; } void report_latency() { const PaStreamInfo *psi = Pa_GetStreamInfo(stream); if (psi){ fprintf(stdout," Sample rate: %.3f\n", psi->sampleRate); fprintf(stdout," Latency (in/out): %.3f / %.3f sec\n", psi->inputLatency, psi->outputLatency); } } bool open_stream(std::string const & input_device, unsigned int inchans, std::string const & output_device, unsigned int outchans, unsigned int samplerate, unsigned int pa_blocksize, int h_blocksize) { int input_device_index, output_device_index; if (!match_device(input_device, input_device_index) || !match_device(output_device, output_device_index)) return false; PaStreamParameters in_parameters, out_parameters; PaTime suggestedLatencyIn, suggestedLatencyOut; #ifdef __APPLE__ suggestedLatencyIn = Pa_GetDeviceInfo(input_device_index)->defaultHighInputLatency; suggestedLatencyOut = Pa_GetDeviceInfo(output_device_index)->defaultHighOutputLatency; #else if (h_blocksize == 0){ if (inchans) suggestedLatencyIn = Pa_GetDeviceInfo(input_device_index)->defaultHighInputLatency; if (outchans) suggestedLatencyOut = Pa_GetDeviceInfo(output_device_index)->defaultHighOutputLatency; }else{ if(h_blocksize < 0){ if (inchans) suggestedLatencyIn = Pa_GetDeviceInfo(input_device_index)->defaultLowInputLatency; if (outchans) suggestedLatencyOut = Pa_GetDeviceInfo(output_device_index)->defaultLowOutputLatency; }else suggestedLatencyIn = suggestedLatencyOut = (double)h_blocksize / (double)samplerate; } #endif if (inchans) { const PaDeviceInfo* device_info = Pa_GetDeviceInfo(input_device_index); inchans = std::min(inchans, (unsigned int)device_info->maxInputChannels); in_parameters.device = input_device_index; in_parameters.channelCount = inchans; in_parameters.sampleFormat = paFloat32 | paNonInterleaved; in_parameters.suggestedLatency = suggestedLatencyIn; in_parameters.hostApiSpecificStreamInfo = nullptr; } if (outchans) { const PaDeviceInfo* device_info = Pa_GetDeviceInfo(output_device_index); outchans = std::min(outchans, (unsigned int)device_info->maxOutputChannels); out_parameters.device = output_device_index; out_parameters.channelCount = outchans; out_parameters.sampleFormat = paFloat32 | paNonInterleaved; out_parameters.suggestedLatency = suggestedLatencyOut; out_parameters.hostApiSpecificStreamInfo = nullptr; } PaStreamParameters * in_stream_parameters = inchans ? &in_parameters : nullptr; PaStreamParameters * out_stream_parameters = outchans ? &out_parameters : nullptr; PaError supported = Pa_IsFormatSupported(in_stream_parameters, out_stream_parameters, samplerate); report_error(supported); if (supported != 0) return false; engine_initalised = false; blocksize_ = pa_blocksize; PaError opened = Pa_OpenStream(&stream, in_stream_parameters, out_stream_parameters, samplerate, pa_blocksize, paNoFlag, &portaudio_backend::pa_process, this); report_error(opened); if (opened != paNoError) return false; input_channels = inchans; super::input_samples.resize(inchans); output_channels = outchans; super::output_samples.resize(outchans); samplerate_ = samplerate; cpu_time_accumulator.resize( samplerate_, blocksize_, 1 ); return true; } void close_stream(void) { if (stream == nullptr) return; deactivate_audio(); int err = Pa_CloseStream(stream); report_error(err); stream = nullptr; } void activate_audio() { assert(stream); int err = Pa_StartStream(stream); report_error(err); } bool audio_is_active(void) { int is_active = Pa_IsStreamActive(stream); if (is_active == 1) return true; if (is_active == 0) return false; report_error(is_active); return false; } void deactivate_audio() { if (audio_is_active()) { PaError err = Pa_StopStream(stream); report_error(err); } } bool audiostream_ready(void) { return stream; } void get_cpuload(float & peak, float & average) const { cpu_time_accumulator.get(peak, average); } std::pair default_device_names() { const PaDeviceIndex default_input = Pa_GetDefaultInputDevice(); const PaDeviceIndex default_output = Pa_GetDefaultOutputDevice(); std::cout << default_input << " " << default_output; return std::make_pair(device_name(default_input), device_name(default_output)); } private: std::string device_name(PaDeviceIndex device_index) { const PaDeviceInfo * device_info = Pa_GetDeviceInfo(device_index); return std::string(device_info->name); } int perform(const void *inputBuffer, void *outputBuffer, unsigned long frames, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags) { if ( unlikely(!engine_initalised) ) { engine_functor::init_thread(); engine_functor::sync_clock(); engine_initalised = true; } if (statusFlags & (paInputOverflow | paInputUnderflow | paOutputOverflow | paOutputUnderflow)) engine_functor::sync_clock(); const float * inputs[input_channels]; float * const *in = static_cast(inputBuffer); for (uint16_t i = 0; i != input_channels; ++i) inputs[i] = in[i]; float * outputs[output_channels]; float **out = static_cast(outputBuffer); for (uint16_t i = 0; i != output_channels; ++i) outputs[i] = out[i]; unsigned long processed = 0; while (processed != frames) { super::fetch_inputs(inputs, blocksize_, input_channels); engine_functor::run_tick(); super::deliver_outputs(outputs, blocksize_, output_channels); processed += blocksize_; } cpu_time_accumulator.update(Pa_GetStreamCpuLoad(stream) * 100.0); return paContinue; } static int pa_process(const void *input, void *output, unsigned long frame_count, const PaStreamCallbackTimeInfo *time_info, PaStreamCallbackFlags status_flags, void * user_data) { portaudio_backend * self = static_cast(user_data); return self->perform(input, output, frame_count, time_info, status_flags); } PaStream *stream = nullptr; uint32_t blocksize_ = 0; bool engine_initalised = false; cpu_time_info cpu_time_accumulator; }; } /* namespace nova */ #endif /* _PORTAUDIO_HPP */ SuperCollider-Source/server/supernova/audio_backend/sndfile_backend.hpp000644 000765 000024 00000026507 12756531745 027612 0ustar00crucialstaff000000 000000 // file-based backend (via libsndfile) // Copyright (C) 2010-2013 Tim Blechmann // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; see the file COPYING. If not, write to // the Free Software Foundation, Inc., 59 Temple Place - Suite 330, // Boston, MA 02111-1307, USA. #ifndef AUDIO_BACKEND_SNDFILE_BACKEND_HPP #define AUDIO_BACKEND_SNDFILE_BACKEND_HPP #include #include #include #include #include #include #include #include #include #include #include #include "nova-tt/name_thread.hpp" #include "utilities/branch_hints.hpp" #include "audio_backend_common.hpp" namespace nova { /** sndfile backend * * audio backend, reading/writing sound files via libsndfile * */ template class sndfile_backend: public detail::audio_backend_base, public detail::audio_settings_basic, private engine_functor { typedef detail::audio_backend_base super; typedef std::size_t size_t; static const size_t queue_size = 10*1024*1024; // 30 MB public: sndfile_backend(void): read_frames(queue_size), write_frames(queue_size) {} size_t get_audio_blocksize(void) const { return block_size_; } std::vector const & get_peaks() const { return max_peaks; } public: void open_client(std::string const & input_file_name, std::string const & output_file_name, float samplerate, int format, uint32_t output_channel_count, size_t block_size) { output_channels = output_channel_count; max_peaks.assign(output_channels, 0); samplerate_ = samplerate = std::floor(samplerate); block_size_ = block_size; if (!input_file_name.empty()) { input_file = SndfileHandle(input_file_name.c_str(), SFM_READ); if (!input_file) throw std::runtime_error("cannot open input file"); if (input_file.samplerate() != samplerate) throw std::runtime_error("input file: samplerate mismatch"); input_channels = input_file.channels(); super::input_samples.resize(input_channels); } else input_channels = 0; read_position = 0; output_file = SndfileHandle(output_file_name.c_str(), SFM_WRITE, format, output_channel_count, samplerate); if (!output_file) throw std::runtime_error("cannot open output file"); output_file.command(SFC_SET_CLIPPING, nullptr, SF_TRUE); super::output_samples.resize(output_channel_count); temp_buffer.reset(calloc_aligned(std::max(input_channels, output_channels) * block_size)); } void close_client(void) { output_file.writeSync(); input_file = output_file = SndfileHandle(); } bool audio_is_opened(void) { return output_file; } bool audio_is_active(void) { return running.load(std::memory_order_acquire); } void activate_audio(void) { running.store(true); if (input_file) { reader_running.store(true); reader_thread = std::thread(std::bind(&sndfile_backend::sndfile_read_thread, this)); } writer_running.store(true); writer_thread = std::thread(std::bind(&sndfile_backend::sndfile_write_thread, this)); } void deactivate_audio(void) { running.store(false); if (input_file) { reader_running.store(false); reader_thread.join(); } writer_running.store(false); write_semaphore.post(); writer_thread.join(); } private: /* read input fifo from the rt context */ void read_input_buffers(size_t frames_per_tick) { if (reader_running.load(std::memory_order_acquire)) { const size_t total_samples = input_channels * frames_per_tick; size_t remaining = total_samples; read_semaphore.wait(); do { remaining -= read_frames.pop(temp_buffer.get(), remaining); if (unlikely(read_frames.empty() && !reader_running.load(std::memory_order_acquire))) { /* at the end, we are not able to read a full sample block, clear the final parts */ const size_t last_frame = (total_samples - remaining) / input_channels; const size_t remaining_per_channel = remaining / input_channels; assert(remaining % input_channels == 0); assert(remaining_per_channel % input_channels == 0); for (uint16_t channel = 0; channel != input_channels; ++channel) zerovec(super::input_samples[channel].get() + last_frame, remaining_per_channel); break; } } while (remaining); const size_t frames = (total_samples - remaining) / input_channels; for (size_t frame = 0; frame != frames; ++frame) { for (uint16_t channel = 0; channel != input_channels; ++channel) super::input_samples[channel].get()[frame] = temp_buffer.get()[frame * input_channels + channel]; } } else super::clear_inputs(frames_per_tick); } void sndfile_read_thread(void) { nova::name_thread("sndfile reader"); assert(input_file); const size_t frames_per_tick = get_audio_blocksize(); // something like autobuffer might be good std::vector > data_to_read(input_channels * frames_per_tick, 0.f); for (;;) { if (unlikely(reader_running.load(std::memory_order_acquire) == false)) return; if (read_position < (size_t)input_file.frames()) { size_t frames = input_file.frames() - read_position; if (frames > frames_per_tick) frames = frames_per_tick; input_file.readf(data_to_read.data(), frames); read_position += frames; const size_t item_to_enqueue = input_channels * frames; size_t remaining = item_to_enqueue; do { remaining -= read_frames.push(data_to_read.data(), remaining); } while(remaining); read_semaphore.post(); } else reader_running.store(false, std::memory_order_release); } } /* write output fifo from rt context */ void write_output_buffers(size_t frames_per_tick) { for (size_t frame = 0; frame != frames_per_tick; ++frame) { for (uint16_t channel = 0; channel != output_channels; ++channel) temp_buffer.get()[frame * output_channels + channel] = super::output_samples[channel].get()[frame]; } const size_t total_samples = output_channels * frames_per_tick; sample_type * buffer = temp_buffer.get(); size_t count = total_samples; do { size_t consumed = write_frames.push(buffer, count); count -= consumed; buffer += consumed; write_semaphore.post(); if (!consumed) std::this_thread::sleep_for(std::chrono::milliseconds(50)); } while (count); } void sndfile_write_thread(void) { nova::name_thread("sndfile writer"); const size_t frames_per_tick = get_audio_blocksize(); const size_t deque_per_tick = output_channels * frames_per_tick * 64; aligned_storage_ptr data_to_write(deque_per_tick); size_t pending_samples = 0; for (;;) { write_semaphore.wait(); poll_writer_queue(data_to_write.get(), deque_per_tick, pending_samples); if (unlikely(writer_running.load(std::memory_order_acquire) == false)) break; } while (poll_writer_queue(data_to_write.get(), deque_per_tick, pending_samples)) {} } bool poll_writer_queue(sample_type * data_to_write, const size_t buffer_samples, size_t & pending_samples) { bool consumed_item = false; for (;;) { const size_t available_samples = write_frames.read_available(); const size_t available_frames = available_samples / output_channels; if (available_frames == 0) return consumed_item; const size_t buffer_frames = buffer_samples / output_channels; const size_t frames_to_read = std::min(available_frames, buffer_frames); const size_t samples_to_read = frames_to_read * output_channels; const size_t dequeued = write_frames.pop(data_to_write, samples_to_read); assert(dequeued == samples_to_read); consumed_item = true; const sf_count_t written_frames = output_file.writef(data_to_write, frames_to_read); assert(frames_to_read == written_frames); if (written_frames == -1) throw std::runtime_error(std::string("sndfile write failed: ") + output_file.strError()); for (size_t frame = 0; frame != frames_to_read; ++frame) { for (size_t channel = 0; channel != output_channels; ++channel) { const sample_type current_sample = data_to_write[frame * output_channels + channel]; sample_type current_peak = max_peaks[channel]; max_peaks[channel] = std::max(current_peak, std::abs(current_sample)); } } } return consumed_item; } public: void audio_fn_noinput(size_t frames_per_tick) { engine_functor::run_tick(); write_output_buffers(frames_per_tick); } void audio_fn(size_t frames_per_tick) { super::clear_outputs(frames_per_tick); read_input_buffers(frames_per_tick); engine_functor::run_tick(); write_output_buffers(frames_per_tick); } private: SndfileHandle input_file, output_file; std::size_t read_position; int block_size_; aligned_storage_ptr temp_buffer; std::thread reader_thread, writer_thread; boost::lockfree::spsc_queue< sample_type > read_frames, write_frames; boost::sync::semaphore read_semaphore, write_semaphore; std::atomic running = {false}, reader_running = {false}, writer_running = {false}; std::vector max_peaks; }; } /* namespace nova */ #endif /* AUDIO_BACKEND_SNDFILE_BACKEND_HPP */ SuperCollider-Source/server/scsynth/CMakeLists.txt000644 000765 000024 00000020411 12766171707 023432 0ustar00crucialstaff000000 000000 find_package(Sndfile) # Here we work out which audio API to use, from system type and/or user option. if(AUDIOAPI STREQUAL "default") if(APPLE) set(AUDIOAPI coreaudio) elseif(WIN32) set(AUDIOAPI portaudio) else() set(AUDIOAPI jack) endif(APPLE) endif() if(NOT AUDIOAPI MATCHES "^(jack|coreaudio|portaudio)$") message(FATAL_ERROR "Unrecognised audio API: ${AUDIOAPI}") endif() if(AUDIOAPI STREQUAL jack) find_package(Jack) if(NOT JACK_FOUND) message(FATAL_ERROR "Jack selected as audio API, but development files not found") endif() elseif(AUDIOAPI STREQUAL portaudio AND NOT MINGW AND NOT MSVC) # MSYS like Apple find_package(Portaudio) if(NOT PORTAUDIO_FOUND) message(FATAL_ERROR "Portaudio selected as audio API, but development files not found") endif() endif() message(STATUS "Audio API: ${AUDIOAPI}") if (NOT Boost_FOUND) file(GLOB boost_system_sources ../../external_libraries/boost/libs/system/src/*cpp) endif() set(scsynth_sources SC_BufGen.cpp SC_ComPort.cpp SC_CoreAudio.cpp SC_Graph.cpp SC_GraphDef.cpp SC_Group.cpp SC_HiddenWorld.h SC_Lib_Cintf.cpp SC_Lib.cpp SC_MiscCmds.cpp SC_Node.cpp SC_Rate.cpp SC_SequencedCommand.cpp SC_Str4.cpp SC_Unit.cpp SC_UnitDef.cpp SC_World.cpp Rendezvous.cpp ${CMAKE_SOURCE_DIR}/common/SC_fftlib.cpp ${CMAKE_SOURCE_DIR}/common/SC_AllocPool.cpp ${CMAKE_SOURCE_DIR}/common/SC_DirUtils.cpp ${CMAKE_SOURCE_DIR}/common/SC_Errors.cpp ${CMAKE_SOURCE_DIR}/common/SC_Reply.cpp ${CMAKE_SOURCE_DIR}/common/SC_StandAloneInfo_Darwin.cpp ${CMAKE_SOURCE_DIR}/common/SC_StringBuffer.cpp ${CMAKE_SOURCE_DIR}/common/SC_StringParser.cpp ${CMAKE_SOURCE_DIR}/common/Samp.cpp ${CMAKE_SOURCE_DIR}/common/sc_popen.cpp ${boost_system_sources} ) if(APPLE) set_property(SOURCE ${CMAKE_SOURCE_DIR}/common/SC_DirUtils.cpp PROPERTY COMPILE_FLAGS -xobjective-c++) list(APPEND scsynth_sources ${CMAKE_SOURCE_DIR}/common/SC_Apple.mm ) set_source_files_properties( ${CMAKE_SOURCE_DIR}/common/SC_Apple.mm PROPERTIES COMPILE_FLAGS "-x objective-c++ -fobjc-exceptions" ) endif() if(WIN32) list(APPEND scsynth_sources ${CMAKE_SOURCE_DIR}/common/SC_Win32Utils.cpp) endif() if (FFT_GREEN) list(APPEND scsynth_sources ../../common/fftlib.c) endif() include_directories(${CMAKE_SOURCE_DIR}/include/common ${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/include/server ${CMAKE_SOURCE_DIR}/include/plugin_interface . ) include_directories (${CMAKE_SOURCE_DIR}/external_libraries/boost_sync/include) if (AUDIOAPI STREQUAL jack) list(APPEND scsynth_sources SC_Jack.cpp) add_definitions("-DSC_AUDIO_API=SC_AUDIO_API_JACK" ${JACK_DEFINITIONS}) include_directories(${JACK_INCLUDE_DIRS}) elseif (AUDIOAPI STREQUAL portaudio) list(APPEND scsynth_sources SC_PortAudio.cpp) add_definitions("-DSC_AUDIO_API=SC_AUDIO_API_PORTAUDIO" ${PORTAUDIO_DEFINITIONS}) include_directories(${PORTAUDIO_INCLUDE_DIRS}) endif() set (FINAL_BUILD 0) # disable final build for scsynth if (LIBSCSYNTH) set (LIBSCSYNTH_TYPE SHARED) else() set (LIBSCSYNTH_TYPE STATIC) endif() file(GLOB_RECURSE all_headers ./*.h*) if (FINAL_BUILD) CREATE_FINAL_FILE(libscsynth_final.cpp ${scsynth_sources} ${all_headers}) add_library(libscsynth ${LIBSCSYNTH_TYPE} libscsynth_final.cpp) else() add_library(libscsynth ${LIBSCSYNTH_TYPE} ${scsynth_sources} ${all_headers}) endif() if(LIBSCSYNTH) target_compile_definitions(libscsynth PRIVATE BUILDING_SCSYNTH) target_compile_definitions(libscsynth INTERFACE BUILDING_SCSYNTH) endif() target_compile_definitions(libscsynth PUBLIC SC_MEMORY_ALIGNMENT=32) target_link_libraries(libscsynth tlsf) find_library(DL NAMES dl) if(DL) target_link_libraries(libscsynth ${DL}) endif() if(NOVA_SIMD) target_compile_definitions(libscsynth PUBLIC NOVA_SIMD) endif() if(SNDFILE_FOUND) target_link_libraries(libscsynth ${SNDFILE_LIBRARIES}) target_include_directories(libscsynth PUBLIC ${SNDFILE_INCLUDE_DIR}) elseif(NOT NO_LIBSNDFILE) message(SEND_ERROR "Cannot find libsndfile") endif(SNDFILE_FOUND) if(UNIX AND NOT APPLE) target_compile_definitions(libscsynth PUBLIC "SC_PLUGIN_DIR=\"${CMAKE_INSTALL_PREFIX}/lib/SuperCollider/plugins\"") endif() if(NOT NO_AVAHI) if(APPLE) target_compile_definitions(libscsynth PUBLIC USE_RENDEZVOUS=1) else() find_package(Avahi) if(AVAHI_FOUND) target_compile_definitions(libscsynth PUBLIC USE_RENDEZVOUS=1 HAVE_AVAHI=1) target_link_libraries(libscsynth ${AVAHI_LIBRARIES}) target_include_directories(libscsynth PUBLIC ${AVAHI_INCLUDE_DIRS}) endif() endif() endif() if (AUDIOAPI STREQUAL jack) target_link_libraries(libscsynth ${JACK_LIBRARIES}) elseif(AUDIOAPI STREQUAL portaudio) if(WIN32 AND NOT MSYS) target_link_libraries(libscsynth portaudio) else() target_link_libraries(libscsynth ${PORTAUDIO_LIBRARIES}) endif() elseif(AUDIOAPI STREQUAL coreaudio) target_link_libraries(libscsynth "-framework CoreAudio") endif() if (Boost_FOUND) target_link_libraries(libscsynth ${Boost_SYSTEM_LIBRARY}) else() target_link_libraries(libscsynth boost_system) endif() if (WIN32) target_link_libraries(libscsynth wsock32 ws2_32 winmm) endif() if(NOT WIN32) set_property(TARGET libscsynth PROPERTY OUTPUT_NAME scsynth) endif() if (LIBSCSYNTH) # These two properties are ABI version info, not sc version: set_property(TARGET libscsynth PROPERTY VERSION 1.0.0) set_property(TARGET libscsynth PROPERTY SOVERSION 1) endif() if (FFTW3F_FOUND) target_include_directories(libscsynth PUBLIC ${FFTW3F_INCLUDE_DIR}) target_link_libraries(libscsynth ${FFTW3F_LIBRARY}) endif() if (APPLE) target_link_libraries(libscsynth "-framework Accelerate -framework CoreServices -framework Foundation") endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") target_link_libraries(libscsynth rt) endif() add_executable(scsynth scsynth_main.cpp) target_link_libraries(scsynth libscsynth) if (PTHREADS_FOUND) target_link_libraries(scsynth ${PTHREADS_LIBRARIES}) endif() if(LTO) set_property(TARGET scsynth libscsynth APPEND PROPERTY COMPILE_FLAGS "-flto -flto-report") set_property(TARGET scsynth APPEND PROPERTY LINK_FLAGS "-flto -flto-report -fwhole-program") set_property(TARGET libscsynth APPEND PROPERTY LINK_FLAGS "-flto -flto-report") endif() if (LIBSCSYNTH) set(INSTALL_TARGETS scsynth libscsynth) else() set(INSTALL_TARGETS scsynth) endif() if(APPLE) add_custom_command(TARGET scsynth POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/../Resources/ COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/../Resources) elseif(WIN32) if(NOT MSVC) set_target_properties(scsynth libscsynth PROPERTIES RUNTIME_OUTPUT_DIRECTORY "$") endif(NOT MSVC) if(FFTW3F_FOUND) file(GLOB FFTW3F_DLL "${FFTW3F_LIBRARY_DIR}/*fftw3f*.dll") add_custom_command(TARGET scsynth POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${FFTW3F_DLL}" $ ) endif(FFTW3F_FOUND) if(SNDFILE_FOUND) file(GLOB SNDFILE_DLL "${SNDFILE_LIBRARY_DIR}/*sndfile*.dll") add_custom_command(TARGET scsynth POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SNDFILE_DLL}" $ ) endif(SNDFILE_FOUND) add_custom_command(TARGET scsynth POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory $ $ COMMENT "Adding scynth to target sclang" ) if(SC_IDE) add_custom_command(TARGET scsynth POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory $ $ COMMENT "Adding scynth to target SuperCollider" ) endif(SC_IDE) install(TARGETS ${INSTALL_TARGETS} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION "${SC_WIN_BUNDLE_NAME}" ) else() install(TARGETS ${INSTALL_TARGETS} RUNTIME DESTINATION "bin" LIBRARY DESTINATION "lib" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() if(${JACK_USE_METADATA_API}) target_compile_definitions(libscsynth PUBLIC "-DSC_JACK_USE_METADATA_API") endif() SuperCollider-Source/server/scsynth/HashTable.h000644 000765 000024 00000017714 12756531745 022713 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _HashTable_ #define _HashTable_ #include "SC_Types.h" #include "SC_BoundsMacros.h" #include "SC_Str4.h" #include "Hash.h" #include #include #include template class HashTable { Allocator *mPool; int32 mNumItems, mMaxItems, mTableSize, mHashMask; T** mItems; bool mCanResize; public: HashTable(Allocator *inPool, int32 inMaxItems, bool inCanResize = true) : mPool(inPool) { mNumItems = 0; mMaxItems = inMaxItems; mTableSize = mMaxItems << 1; mItems = AllocTable(mTableSize); mHashMask = mTableSize - 1; mCanResize = inCanResize; } ~HashTable() { mPool->Free(mItems); } int32 TableSize() const { return mTableSize; } int32 MaxItems() const { return mMaxItems; } int32 NumItems() const { return mNumItems; } T** AllocTable(int inTableSize) { size_t size = inTableSize * sizeof(T*); T** items = static_cast(mPool->Alloc(size)); for (int i=0; i> 1; mHashMask = mTableSize - 1; mNumItems = 0; for (int i=0; iFree(oldItems); //printf("mMaxItems %d mTableSize %d newSize %d\n", mMaxItems, mTableSize, newSize); } bool Add(T* inItem) { //printf("mNumItems %d\n", mNumItems); //printf("mMaxItems %d\n", mMaxItems); //printf("mCanResize %d\n", mCanResize); if (mNumItems >= mMaxItems) { if (!mCanResize) return false; Resize(); } //printf("GetHash(inItem) %d\n", GetHash(inItem)); //printf("GetKey(inItem) %s\n", GetKey(inItem)); int32 index = IndexFor(GetHash(inItem), (int32*)GetKey(inItem)); //printf("index %d\n", index); T *item = mItems[index]; if (item) return item == inItem; mItems[index] = inItem; mNumItems++; return true; } bool Remove(T* inItem) { int32 index = IndexFor(GetHash(inItem), (int32*)GetKey(inItem)); if (mItems[index] != inItem) return false; mItems[index] = 0; FixCollisionsFrom(index); mNumItems--; return true; } bool RemoveKey(int32* inKey) { T* item = Get(inKey); if (!item) return false; return Remove(item); } int32 IndexFor(int32 inHashID, int32* inKey) const { int index = inHashID & mHashMask; for(;;) { T *item = mItems[index]; if (!item) return index; if (GetHash(item) == inHashID && str4eq(inKey, GetKey(item))) return index; index = (index + 1) & mHashMask; } } T* Get(int32* inKey) const { return Get(Hash(inKey), inKey); } T* Get(int32 inHashID, int32* inKey) const { //printf("Get hash %d %s\n", inHashID, inKey); int32 index = IndexFor(inHashID, inKey); //printf("index %d\n", index); return mItems[index]; } bool Includes(T* inItem) const { return Get(GetHash(inItem), GetKey(inItem)) == inItem; } T* AtIndex(int32 inIndex) const { return mItems[inIndex]; } private: void FixCollisionsFrom(int32 inIndex) { int oldIndex = inIndex; for (;;) { oldIndex = (oldIndex + 1) & mHashMask; T *oldItem = mItems[oldIndex]; if (!oldItem) break; int newIndex = IndexFor(GetHash(oldItem), (int32*)GetKey(oldItem)); if (oldIndex != newIndex) { mItems[oldIndex] = mItems[newIndex]; mItems[newIndex] = oldItem; } } } }; template class IntHashTable { Allocator *mPool; int32 mNumItems, mMaxItems, mTableSize, mHashMask; T** mItems; bool mCanResize; public: IntHashTable(Allocator *inPool, int32 inMaxItems, bool inCanResize = true) : mPool(inPool) { mNumItems = 0; mMaxItems = inMaxItems; mTableSize = mMaxItems << 1; mItems = AllocTable(mTableSize); mHashMask = mTableSize - 1; mCanResize = inCanResize; } ~IntHashTable() { mPool->Free(mItems); } int32 TableSize() const { return mTableSize; } int32 MaxItems() const { return mMaxItems; } int32 NumItems() const { return mNumItems; } T** AllocTable(int inTableSize) { size_t size = inTableSize * sizeof(T*); T** items = static_cast(mPool->Alloc(size)); for (int i=0; i> 1; mHashMask = mTableSize - 1; mPool->Free(oldItems); //printf("mMaxItems %d mTableSize %d newSize %d\n", mMaxItems, mTableSize, newSize); } bool Add(T* inItem) { //printf("mNumItems %d\n", mNumItems); //printf("mMaxItems %d\n", mMaxItems); //printf("mCanResize %d\n", mCanResize); if (mNumItems >= mMaxItems) { if (!mCanResize) return false; Resize(); } //printf("GetHash(inItem) %d\n", GetHash(inItem)); //printf("GetKey(inItem) %d\n", GetKey(inItem)); int32 index = IndexFor(GetHash(inItem), GetKey(inItem)); //printf("index %d\n", index); T *item = mItems[index]; if (item) return item == inItem; mItems[index] = inItem; mNumItems++; return true; } bool Remove(T* inItem) { int32 index = IndexFor(GetHash(inItem), GetKey(inItem)); //printf("rmv index %d hash %d key %d\n", index, GetHash(inItem), GetKey(inItem)); if (mItems[index] != inItem) return false; mItems[index] = 0; FixCollisionsFrom(index); mNumItems--; return true; } bool RemoveKey(int32 inKey) { T* item = Get(inKey); if (!item) return false; return Remove(item); } int32 IndexFor(int32 inHashID, int32 inKey) const { int index = inHashID & mHashMask; for(;;) { T *item = mItems[index]; if (!item) return index; if (GetHash(item) == inHashID && inKey == GetKey(item)) return index; index = (index + 1) & mHashMask; } } T* Get(int32 inKey) const { //printf("Get key %d\n", inKey); return Get(Hash(inKey), inKey); } T* Get(int32 inHashID, int32 inKey) const { int32 index = IndexFor(inHashID, inKey); //printf("Get index %d hash %d key %d\n", index, inHashID, inKey); return mItems[index]; } bool Includes(T* inItem) const { return Get(GetHash(inItem), GetKey(inItem)) == inItem; } T* AtIndex(int32 inIndex) const { return mItems[inIndex]; } void Dump() { for (int i=0; i #include #include #define SANITYCHECK 0 const int64 kMaxInt64 = std::numeric_limits::max(); template class PriorityQueueT { public: PriorityQueueT() { Empty(); } bool Add(Event& inEvent) { if (mSize >= N) return false; inEvent.mStabilityCount = mStabilityCounter++; long mom = mSize++; long me = mom; for (; mom>0;) { /* percolate up heap */ mom = (mom - 1) >> 1; if (inEvent.key() < mEvents[mom].key()) { mEvents[me] = mEvents[mom]; me = mom; } else break; } mEvents[me] = inEvent; #if SANITYCHECK SanityCheck(); #endif return true; } void Perform(int64 inTime) { while (NextTime() <= inTime) { Event event = Remove(); event.Perform(); } } int64 NextTime() { return mEvents[0].mTime; } bool Ready(int64 inTime) { return NextTime() <= inTime; } void Flush() { Perform(kMaxInt64); } void Empty() { mSize = 0; SetEmptyTime(); } void SetEmptyTime() { mEvents[0].mTime = kMaxInt64; mStabilityCounter = 0; } int Size() { return mSize; } Event Remove() { Event event = mEvents[0]; if (--mSize == 0) SetEmptyTime(); else { Event temp = mEvents[mSize]; long mom = 0; long me = 1; for (;me < mSize;) { /* demote heap */ if (me+1 < mSize && mEvents[me].key() > mEvents[me+1].key() ) { me ++; } if (temp.key() > mEvents[me].key()) { mEvents[mom] = mEvents[me]; mom = me; me = (me << 1) + 1; } else break; } mEvents[mom] = temp; } #if SANITYCHECK SanityCheck(); #endif return event; } void SanityCheck() { for (int i=0; i mEvents[j].mTime) throw std::runtime_error("priority queue unsorted"); //if (k mEvents[k].mTime) throw std::runtime_error("priority queue unsorted"); } } void DebugDump() { for (int i=0; i #include #include inline int32 readInt8(FILE *file) { int32 res = fgetc(file); return res; } inline uint32 readUInt8(FILE *file) { uint8 res = (uint8)fgetc(file); return (uint32)res; } inline int32 readInt16_be(FILE *file) { int32 c = fgetc(file); int32 d = fgetc(file); int32 res = ((c & 255) << 8) | (d & 255); return res; } inline int32 readInt32_be(FILE *file) { int32 a = fgetc(file); int32 b = fgetc(file); int32 c = fgetc(file); int32 d = fgetc(file); int32 res = ((a & 255) << 24) | ((b & 255) << 16) | ((c & 255) << 8) | (d & 255); return res; } inline float readFloat_be(FILE *file) { union { float f; int32 i; } u; u.i = readInt32_be(file); //post("readFloat %g\n", u.f); return u.f; } inline void readData(FILE *file, char *outData, size_t inLength) { size_t read = fread(outData, 1, inLength, file); if (read != inLength) throw std::runtime_error("readData: read != inLength"); } inline int32 readInt8(char *&buf) { int32 res = *buf++; return res; } inline uint32 readUInt8(char *&buf) { uint8 res = (uint8)*buf++; return (uint32)res; } inline int32 readInt16_be(char *&buf) { int32 c = readInt8(buf); int32 d = readInt8(buf); int32 res = ((c & 255) << 8) | (d & 255); return res; } inline int32 readInt32_be(char *&buf) { int32 a = readInt8(buf); int32 b = readInt8(buf); int32 c = readInt8(buf); int32 d = readInt8(buf); int32 res = ((a & 255) << 24) | ((b & 255) << 16) | ((c & 255) << 8) | (d & 255); return res; } inline float readFloat_be(char *&buf) { union { float f; int32 i; } u; u.i = readInt32_be(buf); //post("readFloat %g\n", u.f); return u.f; } inline void readData(char *&buf, char *outData, size_t inLength) { memcpy(outData, buf, inLength); buf += inLength; } #endif SuperCollider-Source/server/scsynth/Rendezvous.cpp000644 000765 000024 00000024007 12756531745 023550 0ustar00crucialstaff000000 000000 /* * Rendezvous.cpp * SC3synth * * Created by C. Ramakrishnan on Wed Dec 18 2002. * Illposed Software * * Avahi implementation (c) 2006 stefan kersten * Howl implementation (c) 2005 2006 stefan kersten */ /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "Rendezvous.h" #include "SC_Export.h" SCSYNTH_DLLEXPORT_C int scprintf(const char *fmt, ...); #ifndef __APPLE__ static const char* kSCRendezvousServiceName = "SuperCollider"; static const char* SCRendezvousProtocolString(SCRendezvousProtocol proto) { switch (proto) { case kSCRendezvous_UDP: return "_osc._udp."; case kSCRendezvous_TCP: return "_osc._tcp."; default: return 0; }; } #endif #if defined(__APPLE__) && !defined(SC_IPHONE) #include void PublishPortToRendezvous(SCRendezvousProtocol protocol, short portNum) { scprintf("PublishPortToRendezvous %d %hu\n", protocol, portNum); CFStringRef serviceType = 0; switch (protocol) { case kSCRendezvous_UDP: serviceType = CFSTR("_osc._udp."); break; case kSCRendezvous_TCP: serviceType = CFSTR("_osc._tcp."); break; } CFNetServiceRef netServiceRef = CFNetServiceCreate(NULL, // use default allocator CFSTR(""), // use default domain serviceType, CFSTR("SuperCollider"), portNum); // DEBUG if (!netServiceRef) { scprintf("Couldn't create a Rendezvous net service.\n"); return; } CFNetServiceRegisterWithOptions(netServiceRef, 0, NULL); // don't care about the error CFRelease( netServiceRef ); } #elif HAVE_AVAHI # include # include # include # include # include # include # include # include # include # include struct AvahiEntry { AvahiEntry* mNext; SCRendezvousProtocol mProto; short mPort; bool mRegistered; }; struct AvahiSession { AvahiSession(); ~AvahiSession(); void PublishPort(SCRendezvousProtocol proto, short port); void CreateServices(AvahiClient* client); void CreateServices() { CreateServices(mClient); } void ResetServices(); void RenameService(); static void client_cb(AvahiClient* client, AvahiClientState state, void* data); static void group_cb(AVAHI_GCC_UNUSED AvahiEntryGroup*, AvahiEntryGroupState state, void* data); static void modify_cb(AVAHI_GCC_UNUSED AvahiTimeout*, void* data); AvahiThreadedPoll* mPoll; AvahiClient* mClient; AvahiEntryGroup* mGroup; AvahiEntry* mEntries; SC_Lock mMutex; char* mServiceName; }; struct AvahiSessionInstance { AvahiSessionInstance() : mSession(0) { } ~AvahiSessionInstance() { if (mSession) { delete mSession; } } AvahiSession* GetSession() { if (!mSession) { mSession = new AvahiSession(); } return mSession; } private: AvahiSession* mSession; }; static AvahiSessionInstance gAvahiSession; AvahiSession::AvahiSession() : mPoll(0), mClient(0), mGroup(0), mEntries(0), mServiceName(0) { int err; mServiceName = avahi_strdup(kSCRendezvousServiceName); mPoll = avahi_threaded_poll_new(); if (!mPoll) { scprintf("Zeroconf: failed to create poll API\n"); return; } mClient = avahi_client_new( avahi_threaded_poll_get(mPoll), (AvahiClientFlags)0, client_cb, this, &err); if (!mClient) { scprintf("Zeroconf: failed to create client: %s\n", avahi_strerror(err)); avahi_threaded_poll_free(mPoll); mPoll = 0; return; } avahi_threaded_poll_start(mPoll); } AvahiSession::~AvahiSession() { if (mClient) { avahi_threaded_poll_stop(mPoll); avahi_client_free(mClient); avahi_threaded_poll_free(mPoll); AvahiEntry* entry = mEntries; while (entry) { AvahiEntry* next = entry->mNext; delete entry; entry = next; } } free(mServiceName); } void AvahiSession::client_cb(AvahiClient* client, AvahiClientState state, void* data) { AvahiSession* self = (AvahiSession*)data; switch (state) { case AVAHI_CLIENT_S_RUNNING: self->CreateServices(client); break; case AVAHI_CLIENT_S_COLLISION: self->ResetServices(); break; case AVAHI_CLIENT_FAILURE: scprintf("Zeroconf: client failure: %s\n", avahi_strerror(avahi_client_errno(self->mClient))); break; case AVAHI_CLIENT_CONNECTING: case AVAHI_CLIENT_S_REGISTERING: break; } } void AvahiSession::group_cb(AVAHI_GCC_UNUSED AvahiEntryGroup*, AvahiEntryGroupState state, void* data) { AvahiSession* self = (AvahiSession*)data; switch (state) { case AVAHI_ENTRY_GROUP_ESTABLISHED: scprintf("Zeroconf: registered service '%s'\n", self->mServiceName); break; case AVAHI_ENTRY_GROUP_COLLISION: { self->RenameService(); self->CreateServices(); break; } case AVAHI_ENTRY_GROUP_FAILURE: case AVAHI_ENTRY_GROUP_UNCOMMITED: case AVAHI_ENTRY_GROUP_REGISTERING: break; } } void AvahiSession::modify_cb(AVAHI_GCC_UNUSED AvahiTimeout* e, void* data) { AvahiSession* self = (AvahiSession*)data; if (avahi_client_get_state(self->mClient) == AVAHI_CLIENT_S_RUNNING) self->CreateServices(); } void AvahiSession::PublishPort(SCRendezvousProtocol proto, short port) { if (!mClient) return; AvahiEntry* entry = new AvahiEntry; entry->mProto = proto; entry->mPort = port; entry->mRegistered = false; mMutex.lock(); entry->mNext = mEntries; mEntries = entry; mMutex.unlock(); avahi_threaded_poll_lock(mPoll); struct timeval tv; avahi_threaded_poll_get(mPoll)->timeout_new( avahi_threaded_poll_get(mPoll), avahi_elapse_time(&tv, 0, 0), modify_cb, this); avahi_threaded_poll_unlock(mPoll); } void AvahiSession::CreateServices(AvahiClient* client) { int err; if (mGroup) { avahi_entry_group_reset(mGroup); } else { mGroup = avahi_entry_group_new(client, group_cb, this); if (!mGroup) { scprintf("Zeroconf: failed to create entry group: %s\n", avahi_strerror(avahi_client_errno(client))); return; } } mMutex.lock(); AvahiEntry* entry = mEntries; while (entry) { const char* type = SCRendezvousProtocolString(entry->mProto); err = avahi_entry_group_add_service( mGroup, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, mServiceName, type, NULL, NULL, entry->mPort, NULL); if (err == AVAHI_ERR_COLLISION) { // BUG: shouldn't this actually be triggered in the entry // group callback? RenameService(); err = avahi_entry_group_add_service( mGroup, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, mServiceName, type, NULL, NULL, entry->mPort, NULL); } if (err < 0) { scprintf("Zeroconf: failed to register service '%s': %s\n", mServiceName, avahi_strerror(err)); } entry = entry->mNext; } mMutex.unlock(); if (!avahi_entry_group_is_empty(mGroup)) { err = avahi_entry_group_commit(mGroup); if (err < 0) { scprintf("Zeroconf: failed to commit entry group: %s\n", avahi_strerror(err)); return; } } } void AvahiSession::ResetServices() { if (mGroup) avahi_entry_group_reset(mGroup); } void AvahiSession::RenameService() { char* name = avahi_alternative_service_name(mServiceName); avahi_free(mServiceName); mServiceName = name; } void PublishPortToRendezvous(SCRendezvousProtocol proto, short port) { gAvahiSession.GetSession()->PublishPort(proto, port); } #elif HAVE_HOWL # include # include # include struct HowlSession { HowlSession(); ~HowlSession(); void PublishPort(SCRendezvousProtocol protocol, short portNum); void PublishPort(sw_discovery session, SCRendezvousProtocol protocol, short portNum); sw_discovery mSession; SC_Lock mMutex; }; struct HowlSessionInstance { HowlSessionInstance() : mSession(0) { } ~HowlSessionInstance() { if (mSession) { delete mSession; } } HowlSession* GetSession() { if (!mSession) { mSession = new HowlSession(); } return mSession; } private: HowlSession* mSession; }; static HowlSessionInstance gHowlSession; HowlSession::HowlSession() : mSession(0) {} HowlSession::~HowlSession() { if (mSession) sw_discovery_fina(mSession); } void HowlSession::PublishPort(SCRendezvousProtocol protocol, short portNum) { mMutex.lock(); if (!mSession) sw_discovery_init(&mSession); if (mSession) PublishPort(mSession, protocol, portNum); mMutex.unlock(); } sw_result howl_publish_reply_func( sw_discovery, sw_discovery_oid, sw_discovery_publish_status, sw_opaque ) { return SW_OKAY; } void HowlSession::PublishPort(sw_discovery session, SCRendezvousProtocol protocol, short portNum) { const char* serviceType = SCRendezvousProtocolString(protocol); sw_discovery_oid oid; sw_result res = sw_discovery_publish( session, 0, // interface kSCRendezvousServiceName, // name serviceType, // type 0, // domain (.local) 0, // host portNum, // port 0, 0, // text records howl_publish_reply_func, 0, // reply func &oid // request id ); scprintf( "Zeroconf: publishing service %s on port %hu %s\n", serviceType, portNum, res == SW_OKAY ? "succeeded" : "failed" ); } void PublishPortToRendezvous(SCRendezvousProtocol protocol, short portNum) { gHowlSession.GetSession()->PublishPort(protocol, portNum); } #else // !__APPLE__ && !HAVE_AVAHI && !HAVE_HOWL void PublishPortToRendezvous(SCRendezvousProtocol protocol, short portNum) { } #endif // __APPLE__ || HAVE_AVAHI || HAVE_HOWL SuperCollider-Source/server/scsynth/Rendezvous.h000644 000765 000024 00000002250 12321461511 023166 0ustar00crucialstaff000000 000000 /* * Rendezvous.h * SC3synth * * Created by C. Ramakrishnan on Wed Dec 18 2002. * Illposed Software * */ /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _Rendezvous_ #define _Rendezvous_ typedef enum { kSCRendezvous_UDP, kSCRendezvous_TCP } SCRendezvousProtocol; void PublishPortToRendezvous(SCRendezvousProtocol protocol, short portNum); #endif SuperCollider-Source/server/scsynth/SC_AU.cpp000644 000765 000024 00000004463 12321461511 022257 0ustar00crucialstaff000000 000000 /* AudioUnits driver interface. Copyright (c) 2006-2008 Gerard Roma. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS #include "SC_AU.h" void AUCallback(SC_AUAudioDriver *driver,AudioBufferList* in, AudioBufferList* out, AudioTimeStamp* inTimeStamp, UInt32 inFramesToProcess, Float64 sampleRate, int64 oscTime){ driver->Callback(in, out, inTimeStamp, inFramesToProcess, sampleRate, oscTime); } void sc_SetDenormalFlags(); SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld) { return new SC_AUAudioDriver(inWorld); } SC_AUAudioDriver::SC_AUAudioDriver(struct World *inWorld): SC_CoreAudioDriver(inWorld){} SC_AUAudioDriver::~SC_AUAudioDriver(){} bool SC_AUAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate) { // params are set into the wolrd options at AU initialize if(!mPreferredSampleRate && !mPreferredHardwareBufferFrameSize) return false; *outSampleRate = mPreferredSampleRate; *outNumSamples = mPreferredHardwareBufferFrameSize; return true; } bool SC_AUAudioDriver::DriverStart() { return true; } bool SC_AUAudioDriver::DriverStop() { return true; } void SC_AUAudioDriver::Callback(const AudioBufferList* in, AudioBufferList* out, AudioTimeStamp* inTimeStamp, UInt32 inFramesToProcess, Float64 sampleRate, int64 oscTime){ this->mNumSamplesPerCallback = inFramesToProcess; this->mOSCincrement = (int64)(this->mOSCincrementNumerator / sampleRate); this->Run(in, out, oscTime); } #endifSuperCollider-Source/server/scsynth/SC_AU.h000644 000765 000024 00000003263 12756531745 021744 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #if SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS #ifndef _SC_AU_ #define _SC_AU_ #include "SC_CoreAudio.h" #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include class SC_AUAudioDriver : public SC_CoreAudioDriver { protected: virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate); virtual bool DriverStart(); virtual bool DriverStop(); public: SC_AUAudioDriver(struct World *inWorld); virtual ~SC_AUAudioDriver(); void Callback (const AudioBufferList* in, AudioBufferList* out, AudioTimeStamp* inTimeStamp, UInt32 inFramesToProcess, Float64 sampleRate, int64 oscTime); }; extern "C" { void AUCallback(SC_AUAudioDriver *driver,AudioBufferList* in, AudioBufferList* out, AudioTimeStamp* inTimeStamp, UInt32 inFramesToProcess, Float64 sampleRate, int64 oscTime); } #endif #endif SuperCollider-Source/server/scsynth/SC_Audio_Android.cpp000644 000765 000024 00000014722 12321461511 024452 0ustar00crucialstaff000000 000000 /* SuperCollider audio driver for Android Copyright (c) 2010 Dan Stowell. All rights reserved. Incorporating code from SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_CoreAudio.h" #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include SC_AndroidJNIAudioDriver::SC_AndroidJNIAudioDriver(struct World *inWorld) : SC_AudioDriver(inWorld) { } SC_AndroidJNIAudioDriver::~SC_AndroidJNIAudioDriver() { } bool SC_AndroidJNIAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate) { // Here we are setting these to the values that were originally passed in as options. // In current android impl, these values came directly from java as args to scsynth_android_start(). *outNumSamplesPerCallback = mPreferredHardwareBufferFrameSize; *outSampleRate = mPreferredSampleRate; int audioDataSize = mPreferredHardwareBufferFrameSize * mWorld->mNumOutputs * sizeof(float); #ifndef NDEBUG scprintf("SC_AndroidJNIAudioDriver::DriverSetup: allocating %i bytes for %i frames\n", audioDataSize, mPreferredHardwareBufferFrameSize); #endif if(mWorld->mVerbosity >= 0){ scprintf("<-SC_AndroidJNIAudioDriver::Setup world %p, mPreferredHardwareBufferFrameSize %i, mPreferredSampleRate %i, outNumSamplesPerCallback %i, outSampleRate %g\n", mWorld, mPreferredHardwareBufferFrameSize, mPreferredSampleRate, *outNumSamplesPerCallback, *outSampleRate); } return true; } bool SC_AndroidJNIAudioDriver::DriverStart() { if(mWorld->mVerbosity >= 0){ scprintf("SC_AndroidJNIAudioDriver::DriverStart\n"); } // no-op, nothing to do here return true; } bool SC_AndroidJNIAudioDriver::DriverStop() { if(mWorld->mVerbosity >= 0){ scprintf("SC_AndroidJNIAudioDriver::DriverStop\n"); } // TODO: send a message back to java to say stop the audio loop return true; } // NB numSamplesPassed genuinely is num samples (not num frames as sometimes in sc code) void SC_AndroidJNIAudioDriver::genaudio(short* arri, int numSamplesPassed) { //scprintf("->SC_AndroidJNIAudioDriver::genaudio()\n"); World *world = mWorld; int numFramesPerCallback = NumSamplesPerCallback(); // mOSCbuftime = oscTime; // TODO, how do we set this? mFromEngine.Free(); mToEngine.Perform(); mOscPacketsToEngine.Perform(); int numInputs = world->mNumInputs; int numOutputs = world->mNumOutputs; int bufFrames = mWorld->mBufLength; int numBufs = numFramesPerCallback / bufFrames; #ifndef NDEBUG if((numFramesPerCallback * numOutputs) != numSamplesPassed) scprintf("(numFramesPerCallback * numOutputs) != numSamplesPassed, %i %i\n", numFramesPerCallback, numOutputs, numSamplesPassed); #endif float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames; float *outBuses = mWorld->mAudioBus; int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs; int32 *outTouched = mWorld->mAudioBusTouched; int minInputs = std::min(numInputs, mWorld->mNumInputs); int minOutputs = std::min(numOutputs, mWorld->mNumOutputs); int bufFramePos = 0; int64 oscTime = mOSCbuftime; int64 oscInc = mOSCincrement; double oscToSamples = mOSCtoSamples; // main loop for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) { int32 bufCounter = mWorld->mBufCounter; int32 *tch; // copy+touch inputs tch = inTouched; for (int k = 0; k < minInputs; ++k) { float *dst = inBuses + k * bufFrames; // OK, so source is an interleaved array of ints, target is noninterleaved floats for (int frame = 0; frame < bufFrames; ++frame) *dst++ = (1.f/32767.f) * (float)arri[(bufFramePos+frame) * minInputs + k]; *tch++ = bufCounter; } // run engine int64 schedTime; int64 nextTime = oscTime + oscInc; while ((schedTime = mScheduler.NextTime()) <= nextTime) { float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5; float diffTimeFloor = floor(diffTime); world->mSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1; SC_ScheduledEvent event = mScheduler.Remove(); event.Perform(); } world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; World_Run(world); // copy touched outputs tch = outTouched; for (int k = 0; k < minOutputs; ++k) { // OK, so the source is noninterleaved floats, target is an interleaved array of ints if (*tch++ == bufCounter) { float *src = outBuses + k * bufFrames; for (int frame = 0; frame < bufFrames; ++frame) arri[(bufFramePos+frame) * minOutputs + k] = (short)((*src++) * 32767.f); } else { for (int frame = 0; frame < bufFrames; ++frame) arri[(bufFramePos+frame) * minOutputs + k] = 0; } } // update buffer time oscTime = mOSCbuftime = nextTime; } mAudioSync.Signal(); } int64 gOSCoffset = 0; static inline int64 GetCurrentOSCTime() { struct timeval tv; uint64 s, f; gettimeofday(&tv, 0); s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970; f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits); return (s << 32) + f; } int64 oscTimeNow() { return GetCurrentOSCTime(); } int32 server_timeseed() { int64 time = GetCurrentOSCTime(); return Hash((int32)(time >> 32) + Hash((int32)time)); } void initializeScheduler() { gOSCoffset = GetCurrentOSCTime(); } SuperCollider-Source/server/scsynth/SC_BufGen.cpp000644 000765 000024 00000002703 12321461511 023113 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_BufGen.h" #include "SC_World.h" #include "SC_Unit.h" #include "SC_InterfaceTable.h" #include #include #ifndef _MSC_VER #include #endif //_MSC_VER #include #include "SC_Prototypes.h" #include "SC_Str4.h" extern InterfaceTable gInterfaceTable; bool BufGen_Create(const char *inName, BufGenFunc inFunc) { BufGen *bufGen = (BufGen*)malloc(sizeof(BufGen)); str4cpy(bufGen->mBufGenName, inName); bufGen->mHash = Hash(bufGen->mBufGenName); bufGen->mBufGenFunc = inFunc; if (!AddBufGen(bufGen)) { free(bufGen); return false; } return true; } SuperCollider-Source/server/scsynth/SC_ComPort.cpp000644 000765 000024 00000033513 12760322424 023341 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Endian.h" #include "SC_HiddenWorld.h" #include "SC_WorldOptions.h" #include "sc_msg_iter.h" #include "SC_OscUtils.hpp" #include #include #include #include #include #include "OSC_Packet.h" #include #include #include #include #include #include "SC_Lock.h" #include "nova-tt/semaphore.hpp" #include "nova-tt/thread_priority.hpp" #ifdef USE_RENDEZVOUS #include "Rendezvous.h" #endif bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket); namespace scsynth { const size_t kMaxUDPSize = 65535; ////////////////////////////////////////////////////////////////////////////////////////////////////////// static bool UnrollOSCPacket(World *inWorld, int inSize, char *inData, OSC_Packet *inPacket) { if (!strcmp(inData, "#bundle")) { // is a bundle char *data; char *dataEnd = inData + inSize; int len = 16; bool hasNestedBundle = false; // get len of nested messages only, without len of nested bundle(s) data = inData + 16; // skip bundle header while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); if (strcmp(data, "#bundle")) // is a message len += sizeof(int32) + msgSize; else hasNestedBundle = true; data += msgSize; } if (hasNestedBundle) { if (len > 16) { // not an empty bundle // add nested messages to bundle buffer char *buf = (char*)malloc(len); inPacket->mSize = len; inPacket->mData = buf; memcpy(buf, inData, 16); // copy bundle header data = inData + 16; // skip bundle header while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); if (strcmp(data, "#bundle")) { // is a message memcpy(buf, data-sizeof(int32), sizeof(int32) + msgSize); buf += msgSize; } data += msgSize; } // process this packet without its nested bundle(s) if(!ProcessOSCPacket(inWorld, inPacket)) { free(buf); return false; } } // process nested bundle(s) data = inData + 16; // skip bundle header while (data < dataEnd) { int32 msgSize = OSCint(data); data += sizeof(int32); if (!strcmp(data, "#bundle")) { // is a bundle OSC_Packet* packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); memcpy(packet, inPacket, sizeof(OSC_Packet)); // clone inPacket if(!UnrollOSCPacket(inWorld, msgSize, data, packet)) { free(packet); return false; } } data += msgSize; } } else { // !hasNestedBundle char *buf = (char*)malloc(inSize); inPacket->mSize = inSize; inPacket->mData = buf; memcpy(buf, inData, inSize); if(!ProcessOSCPacket(inWorld, inPacket)) { free(buf); return false; } } } else { // is a message char *buf = (char*)malloc(inSize); inPacket->mSize = inSize; inPacket->mData = buf; memcpy(buf, inData, inSize); if(!ProcessOSCPacket(inWorld, inPacket)) { free(buf); return false; } } return true; } ///////////////////////////////////////////////////////////////////////////////////////////////////////// thread gAsioThread; boost::asio::io_service ioService; const int kTextBufSize = 65536; static void udp_reply_func(struct ReplyAddress *addr, char* msg, int size) { using namespace boost::asio; ip::udp::socket * socket = reinterpret_cast(addr->mReplyData); ip::udp::endpoint endpoint (addr->mAddress, addr->mPort); boost::system::error_code errc; socket->send_to( buffer(msg, size), endpoint, 0, errc); if (errc) printf("%s\n", errc.message().c_str()); } static void tcp_reply_func(struct ReplyAddress *addr, char* msg, int size) { // Write size as 32bit unsigned network-order integer uint32 u = sc_htonl(size) ; using namespace boost::asio; // FIXME: connection could be destroyed! ip::tcp::socket * socket = reinterpret_cast(addr->mReplyData); #if 0 ip::tcp::socket::message_flags flags = 0; #ifdef MSG_NOSIGNAL flags = MSG_NOSIGNAL; #endif #endif boost::system::error_code errc; write( *socket, buffer(&u, sizeof(uint32) ), errc ); if (errc) printf("%s\n", errc.message().c_str()); write( *socket, buffer(msg, size), errc ); if (errc) printf("%s\n", errc.message().c_str()); } class SC_UdpInPort { struct World * mWorld; int mPortNum; std::string mbindTo; boost::array recvBuffer; boost::asio::ip::udp::endpoint remoteEndpoint; #ifdef USE_RENDEZVOUS thread mRendezvousThread; #endif void handleReceivedUDP(const boost::system::error_code& error, std::size_t bytes_transferred) { if (error == boost::asio::error::operation_aborted) return; /* we're done */ if (error) { printf("SC_UdpInPort: received error - %s", error.message().c_str()); startReceiveUDP(); return; } if (mWorld->mDumpOSC) dumpOSC(mWorld->mDumpOSC, bytes_transferred, recvBuffer.data()); OSC_Packet * packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); packet->mReplyAddr.mProtocol = kUDP; packet->mReplyAddr.mAddress = remoteEndpoint.address(); packet->mReplyAddr.mPort = remoteEndpoint.port(); packet->mReplyAddr.mSocket = udpSocket.native_handle(); packet->mReplyAddr.mReplyFunc = udp_reply_func; packet->mReplyAddr.mReplyData = (void*)&udpSocket; packet->mSize = bytes_transferred; if (!UnrollOSCPacket(mWorld, bytes_transferred, recvBuffer.data(), packet)) free(packet); startReceiveUDP(); } void startReceiveUDP() { using namespace boost; udpSocket.async_receive_from(asio::buffer(recvBuffer), remoteEndpoint, boost::bind(&SC_UdpInPort::handleReceivedUDP, this, asio::placeholders::error, asio::placeholders::bytes_transferred)); } public: boost::asio::ip::udp::socket udpSocket; SC_UdpInPort(struct World * world, std::string bindTo, int inPortNum): mWorld(world), mPortNum(inPortNum), mbindTo(bindTo), udpSocket(ioService) { using namespace boost::asio; BOOST_AUTO(protocol, ip::udp::v4()); udpSocket.open(protocol); udpSocket.bind(ip::udp::endpoint(boost::asio::ip::address::from_string(bindTo), inPortNum)); boost::asio::socket_base::send_buffer_size option(65536); udpSocket.set_option(option); #ifdef USE_RENDEZVOUS if (world->mRendezvous) { thread thread( boost::bind( PublishPortToRendezvous, kSCRendezvous_UDP, sc_htons(mPortNum) ) ); mRendezvousThread = std::move(thread); } #endif startReceiveUDP(); } }; class SC_TcpConnection: public boost::enable_shared_from_this { public: struct World * mWorld; typedef boost::shared_ptr pointer; boost::asio::ip::tcp::socket socket; SC_TcpConnection(struct World * world, boost::asio::io_service & ioService, class SC_TcpInPort * parent): mWorld(world), socket(ioService), mParent(parent) {} ~SC_TcpConnection(); void start() { const int kMaxPasswordLen = 32; char buf[kMaxPasswordLen]; int32 size; int32 msglen; // first message must be the password. 4 tries. bool validated = mWorld->hw->mPassword[0] == 0; for (int i=0; !validated && i<4; ++i) { // FIXME: error handling! size = boost::asio::read(socket, boost::asio::buffer((void*)&msglen, sizeof(int32)) ); if (size < 0) return; msglen = sc_ntohl(msglen); if (msglen > kMaxPasswordLen) break; size = boost::asio::read(socket, boost::asio::buffer((void*)buf, msglen) ); if (size < 0) return; validated = strcmp(buf, mWorld->hw->mPassword) == 0; std::this_thread::sleep_for(std::chrono::seconds(i + 1)); // thwart cracking. } if (validated) startReceiveMessage(); } private: void startReceiveMessage() { namespace ba = boost::asio; async_read(socket, ba::buffer(&OSCMsgLength, sizeof(OSCMsgLength)), boost::bind(&SC_TcpConnection::handleLengthReceived, shared_from_this(), ba::placeholders::error, ba::placeholders::bytes_transferred) ); } int32 OSCMsgLength; char * data; class SC_TcpInPort * mParent; void handleLengthReceived(const boost::system::error_code& error, size_t bytes_transferred) { if (error) { if (error == boost::asio::error::eof) return; // connection closed printf("handleLengthReceived: error %s", error.message().c_str()); return; } namespace ba = boost::asio; // msglen is in network byte order OSCMsgLength = sc_ntohl(OSCMsgLength); data = (char*)malloc(OSCMsgLength); async_read(socket, ba::buffer(data, OSCMsgLength), boost::bind(&SC_TcpConnection::handleMsgReceived, shared_from_this(), ba::placeholders::error, ba::placeholders::bytes_transferred)); } void handleMsgReceived(const boost::system::error_code& error, size_t bytes_transferred) { if (error) { free(data); if (error == boost::asio::error::eof) return; // connection closed printf("handleMsgReceived: error %s", error.message().c_str()); return; } assert(bytes_transferred == OSCMsgLength); if (mWorld->mDumpOSC) dumpOSC(mWorld->mDumpOSC, bytes_transferred, data); OSC_Packet * packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); packet->mReplyAddr.mProtocol = kTCP; packet->mReplyAddr.mReplyFunc = tcp_reply_func; packet->mReplyAddr.mReplyData = (void*)&socket; packet->mSize = OSCMsgLength; if (!UnrollOSCPacket(mWorld, bytes_transferred, data, packet)) free(packet); startReceiveMessage(); } }; class SC_TcpInPort { struct World * mWorld; boost::asio::ip::tcp::acceptor acceptor; #ifdef USE_RENDEZVOUS thread mRendezvousThread; #endif std::atomic mAvailableConnections; friend class SC_TcpConnection; public: SC_TcpInPort(struct World * world, std::string bindTo, int inPortNum, int inMaxConnections, int inBacklog): mWorld(world), acceptor(ioService, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(bindTo), inPortNum)), mAvailableConnections(inMaxConnections) { // FIXME: backlog??? #ifdef USE_RENDEZVOUS if (world->mRendezvous) { thread thread( boost::bind( PublishPortToRendezvous, kSCRendezvous_TCP, sc_htons(inPortNum) ) ); mRendezvousThread = std::move(thread); } #endif startAccept(); } void startAccept() { if (mAvailableConnections > 0) { --mAvailableConnections; SC_TcpConnection::pointer newConnection (new SC_TcpConnection(mWorld, ioService, this)); acceptor.async_accept(newConnection->socket, boost::bind(&SC_TcpInPort::handleAccept, this, newConnection, boost::asio::placeholders::error)); } } void handleAccept(SC_TcpConnection::pointer newConnection, const boost::system::error_code& error) { if (!error) newConnection->start(); startAccept(); } void connectionDestroyed() { if (!mWorld->mRunning) return; mAvailableConnections += 1; startAccept(); } }; SC_TcpConnection::~SC_TcpConnection() { mParent->connectionDestroyed(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// static void asioFunction() { #ifdef NOVA_TT_PRIORITY_RT std::pair priorities = nova::thread_priority_interval_rt(); nova::thread_set_priority_rt((priorities.first + priorities.second)/2); #else std::pair priorities = nova::thread_priority_interval(); nova::thread_set_priority(priorities.second); #endif boost::asio::io_service::work work(ioService); ioService.run(); } void startAsioThread() { thread asioThread (&asioFunction); gAsioThread = std::move(asioThread); } void stopAsioThread() { ioService.stop(); gAsioThread.join(); } } using namespace scsynth; ////////////////////////////////////////////////////////////////////////////////////////////////////////// SCSYNTH_DLLEXPORT_C bool World_SendPacketWithContext(World *inWorld, int inSize, char *inData, ReplyFunc inFunc, void *inContext) { if (inSize > 0) { if (inWorld->mDumpOSC) dumpOSC(inWorld->mDumpOSC, inSize, inData); OSC_Packet* packet = (OSC_Packet*)malloc(sizeof(OSC_Packet)); packet->mReplyAddr.mAddress = boost::asio::ip::address(); packet->mReplyAddr.mReplyFunc = inFunc; packet->mReplyAddr.mReplyData = inContext; packet->mReplyAddr.mSocket = 0; if(!UnrollOSCPacket(inWorld, inSize, inData, packet)) { free(packet); return false; } } return true; } SCSYNTH_DLLEXPORT_C bool World_SendPacket(World *inWorld, int inSize, char *inData, ReplyFunc inFunc) { return World_SendPacketWithContext(inWorld, inSize, inData, inFunc, 0); } SCSYNTH_DLLEXPORT_C int World_OpenUDP(struct World *inWorld, const char *bindTo, int inPort) { try { new SC_UdpInPort(inWorld, bindTo, inPort); return true; } catch (std::exception& exc) { scprintf("Exception in World_OpenUDP: %s\n", exc.what()); } catch (...) { } return false; } SCSYNTH_DLLEXPORT_C int World_OpenTCP(struct World *inWorld, const char *bindTo, int inPort, int inMaxConnections, int inBacklog) { try { new SC_TcpInPort(inWorld, bindTo, inPort, inMaxConnections, inBacklog); return true; } catch (std::exception& exc) { scprintf("Exception in World_OpenTCP: %s\n", exc.what()); } catch (...) { } return false; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/scsynth/SC_CoreAudio.cpp000644 000765 000024 00000234420 12756531745 023645 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_CoreAudio.h" #include #include "SC_SequencedCommand.h" #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include "SC_WorldOptions.h" #include "SC_Endian.h" #include "SC_Lib_Cintf.h" #include "SC_Lock.h" #include "SC_Time.hpp" #include #include #ifndef _WIN32 #include #endif #ifdef SC_IPHONE #include "SC_VFP11.h" #endif #include "nova-tt/thread_priority.hpp" int64 gStartupOSCTime = -1; double gSampleRate, gSampleDur; void sc_SetDenormalFlags(); // ===================================================================== // Timing (CoreAudio) #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS int64 gOSCoffset = 0; int32 server_timeseed() { static int32 count = 0; int64 time = AudioGetCurrentHostTime(); return (int32)(time >> 32) ^ (int32)time ^ count--; } inline int64 CoreAudioHostTimeToOSC(int64 hostTime) { return (int64)((double)AudioConvertHostTimeToNanos(hostTime) * kNanosToOSCunits) + gOSCoffset; } int64 oscTimeNow() { return CoreAudioHostTimeToOSC(AudioGetCurrentHostTime()); } static void syncOSCOffsetWithTimeOfDay() { // generate a value gOSCoffset such that // (gOSCOffset + systemTimeInOSCunits) // is equal to gettimeofday time in OSCunits. // Then if this machine is synced via NTP, we are synced with the world. // more accurate way to do this?? using namespace std::chrono; struct timeval tv; nanoseconds systemTimeBefore, systemTimeAfter; int64 diff, minDiff = 0x7fffFFFFffffFFFFLL; // take best of several tries const int numberOfTries = 5; int64 newOffset = gOSCoffset; for (int i=0; i priorities = nova::thread_priority_interval_rt(); nova::thread_set_priority_rt((priorities.first + priorities.second)/2); #else std::pair priorities = nova::thread_priority_interval(); nova::thread_set_priority(priorities.second); #endif while (true) { sleep(20); syncOSCOffsetWithTimeOfDay(); } } void initializeScheduler() { syncOSCOffsetWithTimeOfDay(); thread resyncThread(resyncThreadFunc); resyncThread.detach(); } #endif // SC_AUDIO_API_COREAUDIO // ===================================================================== // Timing (CoreAudioIPHONE) #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE int64 gOSCoffset = 0; static inline int64 GetMicroseconds() { struct timeval tv; gettimeofday(&tv, 0); return (int64) tv.tv_sec * 1000000 + tv.tv_usec; } static inline int64 GetCurrentOSCTime() { struct timeval tv; uint64 s, f; gettimeofday(&tv, 0); s = (uint64)tv.tv_sec + (uint64)kSECONDS_FROM_1900_to_1970; f = (uint64)((double)tv.tv_usec * kMicrosToOSCunits); return (s << 32) + f; } int32 server_timeseed() { int64 time = GetCurrentOSCTime(); return Hash((int32)(time >> 32) + Hash((int32)time)); } int64 oscTimeNow() { return GetCurrentOSCTime(); } void initializeScheduler() { gOSCoffset = GetCurrentOSCTime(); } #endif // SC_AUDIO_API_COREAUDIO // ===================================================================== // Packets (Common) bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket); void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket); int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc); void Perform_ToEngine_Msg(FifoMsg *inMsg); void FreeOSCPacket(FifoMsg *inMsg); struct IsBundle { IsBundle() { str4cpy(s, "#bundle"); } bool checkIsBundle(int32 *in) { return in[0] == s[0] && in[1] == s[1]; } int32 s[2]; }; IsBundle gIsBundle; bool ProcessOSCPacket(World *inWorld, OSC_Packet *inPacket) { //scprintf("ProcessOSCPacket %d, '%s'\n", inPacket->mSize, inPacket->mData); if (!inPacket) return false; bool result; static_cast(inWorld->mDriverLock)->lock(); SC_AudioDriver *driver = AudioDriver(inWorld); if (!driver) { static_cast(inWorld->mDriverLock)->unlock(); return false; } inPacket->mIsBundle = gIsBundle.checkIsBundle((int32*)inPacket->mData); FifoMsg fifoMsg; fifoMsg.Set(inWorld, Perform_ToEngine_Msg, FreeOSCPacket, (void*)inPacket); result = driver->SendOscPacketMsgToEngine(fifoMsg); static_cast(inWorld->mDriverLock)->unlock(); if (!result) scprintf("command FIFO full\n"); return result; } int PerformOSCMessage(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { // scprintf("->PerformOSCMessage %d\n", inData[0]); SC_LibCmd *cmdObj; int cmdNameLen; if (inData[0] == 0) { cmdNameLen = 4; uint32 index = inData[3]; if (index >= NUMBER_OF_COMMANDS) cmdObj = 0; else cmdObj = gCmdArray[index]; } else { cmdNameLen = OSCstrlen(inData); cmdObj = gCmdLib->Get((int32*)inData); } if (!cmdObj) { CallSendFailureCommand(inWorld, inData, "Command not found", inReply); scprintf("FAILURE IN SERVER: %s Command not found\n", inData); return kSCErr_NoSuchCommand; } int err = cmdObj->Perform(inWorld, inSize - cmdNameLen, inData + cmdNameLen, inReply); //scprintf("<-PerformOSCMessage %d\n", inData[0]); return err; } void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket) { //scprintf("->PerformOSCBundle %d\n", inPacket->mSize); char *data = inPacket->mData + 16; char* dataEnd = inPacket->mData + inPacket->mSize; while (data < dataEnd) { int32 msgSize = sc_ntohl(*(int32*)data); data += sizeof(int32); //scprintf("msgSize %d\n", msgSize); PerformOSCMessage(inWorld, msgSize, data, &inPacket->mReplyAddr); data += msgSize; } // reset so next command uses permanent error notification status inWorld->mLocalErrorNotification = 0; //scprintf("<-PerformOSCBundle %d\n", inPacket->mSize); } PacketStatus PerformOSCPacket(World *world, OSC_Packet *packet, SC_ScheduledEvent::PacketFreeFunc freeFunc) { SC_AudioDriver *driver = world->hw->mAudioDriver; if (!packet->mIsBundle) { PerformOSCMessage(world, packet->mSize, packet->mData, &packet->mReplyAddr); world->mLocalErrorNotification = 0; return PacketPerformed; } else { // in real time engine, schedule the packet int64 time = OSCtime(packet->mData + 8); if (time == 0 || time == 1) { PerformOSCBundle(world, packet); return PacketPerformed; } else { if ((time < driver->mOSCbuftime) && (world->mVerbosity >= 0)) { double seconds = (driver->mOSCbuftime - time)*kOSCtoSecs; scprintf("late %.9f\n", seconds); //FifoMsg outMsg; //ReportLateness(packet->mReply, seconds) } // DEBUG // else //scprintf("scheduled in %.6f at time %.6f\n", // (time-driver->mOSCbuftime)*kOSCtoSecs, // (time-gStartupOSCTime)*kOSCtoSecs); SC_ScheduledEvent event(world, time, packet, freeFunc); driver->AddEvent(event); return PacketScheduled; } } } //////////////////////////////////////////////////////////////////////////// void Perform_ToEngine_Msg(FifoMsg *inMsg) { World *world = inMsg->mWorld; OSC_Packet *packet = (OSC_Packet*)inMsg->mData; if (!packet) return; PacketStatus status = PerformOSCPacket(world, packet, SC_ScheduledEvent::FreeInNRT); if (status == PacketScheduled) { // Transfer ownership inMsg->mData = 0; inMsg->mFreeFunc = 0; } } PacketStatus PerformCompletionMsg(World *inWorld, const OSC_Packet& inPacket) { OSC_Packet* packet = (OSC_Packet*)World_Alloc(inWorld, sizeof(OSC_Packet)); *packet = inPacket; packet->mIsBundle = gIsBundle.checkIsBundle((int32*)packet->mData); PacketStatus status = PerformOSCPacket(inWorld, packet, SC_ScheduledEvent::FreeInRT); if (status == PacketPerformed) { World_Free(inWorld, packet); } return status; } void FreeOSCPacket(FifoMsg *inMsg) { OSC_Packet *packet = (OSC_Packet*)inMsg->mData; if (packet) { inMsg->mData = 0; #if _MSC_VER == 1310 #pragma message("$$$todo fixme hack for the 'uninitialized packet->mData ptr when using MSVC 7.1 debug") if (packet->mData != reinterpret_cast(0xcdcdcdcd)) free(packet->mData); #else //#ifdef _MSC_VER free(packet->mData); #endif //#ifdef _MSC_VER free(packet); } } void Free_FromEngine_Msg(FifoMsg *inMsg); void Free_FromEngine_Msg(FifoMsg *inMsg) { World_Free(inMsg->mWorld, inMsg->mData); } // ===================================================================== // Audio driver (Common) SC_AudioDriver::SC_AudioDriver(struct World *inWorld) : mWorld(inWorld) , mSampleTime(0) , mNumSamplesPerCallback(0) { } SC_AudioDriver::~SC_AudioDriver() { mRunThreadFlag = false; mAudioSync.Signal(); mThread.join(); } void SC_AudioDriver::RunThread() { #ifdef NOVA_TT_PRIORITY_RT std::pair priorities = nova::thread_priority_interval_rt(); nova::thread_set_priority_rt((priorities.first + priorities.second)/2); #else std::pair priorities = nova::thread_priority_interval(); nova::thread_set_priority(priorities.second); #endif TriggersFifo *trigfifo = &mWorld->hw->mTriggers; NodeReplyFifo *nodereplyfifo = &mWorld->hw->mNodeMsgs; NodeEndsFifo *nodeendfifo = &mWorld->hw->mNodeEnds; DeleteGraphDefsFifo *deletegraphfifo = &mWorld->hw->mDeleteGraphDefs; while (mRunThreadFlag) { // wait for sync mAudioSync.WaitNext(); reinterpret_cast(mWorld->mNRTLock)->lock(); // send /tr messages trigfifo->Perform(); // send node reply messages nodereplyfifo->Perform(); // send node status messages nodeendfifo->Perform(); // free GraphDefs deletegraphfifo->Perform(); // perform messages mFromEngine.Perform(); reinterpret_cast(mWorld->mNRTLock)->unlock(); } } bool SC_AudioDriver::SendMsgFromEngine(FifoMsg& inMsg) { return mFromEngine.Write(inMsg); } bool SC_AudioDriver::SendMsgToEngine(FifoMsg& inMsg) { mToEngine.Free(); return mToEngine.Write(inMsg); } bool SC_AudioDriver::SendOscPacketMsgToEngine(FifoMsg& inMsg) { mOscPacketsToEngine.Free(); return mOscPacketsToEngine.Write(inMsg); } void SC_ScheduledEvent::FreeInRT(struct World* world, OSC_Packet* packet) { World_Free(world, packet->mData); World_Free(world, packet); } void SC_ScheduledEvent::FreeInNRT(struct World* world, OSC_Packet* packet) { FifoMsg msg; msg.Set(world, FreeOSCPacket, 0, (void*)packet); world->hw->mAudioDriver->SendMsgFromEngine(msg); } void SC_ScheduledEvent::Perform() { PerformOSCBundle(mWorld, mPacket); (*mPacketFreeFunc)(mWorld, mPacket); } bool SC_AudioDriver::Setup() { mRunThreadFlag = true; thread thread(std::bind(&SC_AudioDriver::RunThread, this)); mThread = std::move(thread); int numSamples; double sampleRate; if (!DriverSetup(&numSamples, &sampleRate)) return false; mNumSamplesPerCallback = numSamples; //scprintf("mNumSamplesPerCallback %d\n", mNumSamplesPerCallback); //scprintf("mHardwareBufferSize %lu\n", mHardwareBufferSize); // compute a per sample increment to the OpenSoundControl Time mOSCincrementNumerator = (double)mWorld->mBufLength * pow(2.,32.); mOSCincrement = (int64)(mOSCincrementNumerator / sampleRate); mOSCtoSamples = sampleRate / pow(2.,32.); World_SetSampleRate(mWorld, sampleRate); mSampleRate = mSmoothSampleRate = sampleRate; mBuffersPerSecond = sampleRate / mNumSamplesPerCallback; mMaxPeakCounter = (int)mBuffersPerSecond; if(mWorld->mVerbosity >= 0){ scprintf("SC_AudioDriver: sample rate = %f, driver's block size = %d\n", sampleRate, mNumSamplesPerCallback); } return true; } bool SC_AudioDriver::Start() { mAvgCPU = 0.; mPeakCPU = 0.; mPeakCounter = 0; mStartHostSecs = 0.; mPrevHostSecs = 0.; mStartSampleTime = 0.; mPrevSampleTime = 0.; World_Start(mWorld); gStartupOSCTime = oscTimeNow(); return DriverStart(); } bool SC_AudioDriver::Stop() { if (!DriverStop()) return false; return true; } // ===================================================================== // Audio driver (CoreAudio) #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld) { return new SC_CoreAudioDriver(inWorld); } #endif #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS SC_CoreAudioDriver::SC_CoreAudioDriver(struct World *inWorld) : SC_AudioDriver(inWorld) , mInputBufList(0) { } SC_CoreAudioDriver::~SC_CoreAudioDriver() { if (mInputBufList) { int i; for (i=0; imNumberBuffers; i++) { free(mInputBufList->mBuffers[i].mData); } free(mInputBufList); } } std::vector GetAvailableNominalSampleRates(const AudioDeviceID& device) { std::vector result; OSStatus err; UInt32 size; UInt32 count; std::auto_ptr validSampleRateRanges; AudioObjectPropertyAddress addr = { kAudioDevicePropertyAvailableNominalSampleRates, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; err = AudioObjectGetPropertyDataSize(device, &addr, 0, NULL, &size); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyAvailableNominalSampleRates data size error %4.4s\n", (char*)&err); } else { if (size > 0) { count = size / sizeof(AudioValueRange); validSampleRateRanges.reset(new AudioValueRange[count]); err = AudioObjectGetPropertyData(device, &addr, 0, NULL, &size, validSampleRateRanges.get()); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyAvailableNominalSampleRates error %4.4s\n", (char*)&err); } else { for (int i = 0; i < count; i++) { result.push_back(validSampleRateRanges.get()[i]); } } } } return result; } bool SC_CoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate) { OSStatus err = kAudioHardwareNoError; UInt32 count; mOutputDevice = kAudioDeviceUnknown; mInputDevice = kAudioDeviceUnknown; AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; //scprintf("SC_CoreAudioDriver::Setup world %p\n", mWorld); //////////////////////////////////////////////////////////////////////////////////////////////// do { // err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &count, 0); propertyAddress.mSelector = kAudioHardwarePropertyDevices; err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count); if (err != noErr) { scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err); break; } AudioDeviceID *devices = (AudioDeviceID*)malloc(count); // err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, devices); if (err != kAudioHardwareNoError) { scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err); free(devices); break; } int numdevices = count / sizeof(AudioDeviceID); if(mWorld->mVerbosity >= 0){ scprintf("Number of Devices: %d\n", numdevices); } for (int i = 0; i < numdevices; ++i) { propertyAddress.mSelector = kAudioDevicePropertyDeviceName; // err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0); err = AudioObjectGetPropertyDataSize(devices[i], &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]); break; } char *name = (char*)malloc(count); // err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name); err = AudioObjectGetPropertyData(devices[i], &propertyAddress, 0, NULL, &count, name); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyDeviceName error %4.4s A %d %p\n", (char*)&err, i, devices[i]); free(name); break; } if(mWorld->mVerbosity >= 0){ scprintf(" %d : \"%s\"\n", i, name); } free(name); } free(devices); if(mWorld->mVerbosity >= 0){ scprintf("\n"); } } while (false); if (mWorld->hw->mInDeviceName || mWorld->hw->mOutDeviceName) { propertyAddress.mSelector = kAudioHardwarePropertyDevices; // err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &count, 0); err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err); return false; } AudioDeviceID *devices = (AudioDeviceID*)malloc(count); // err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &count, devices); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, devices); if (err != kAudioHardwareNoError) { scprintf("get kAudioHardwarePropertyDevices error %4.4s\n", (char*)&err); return false; } int numdevices = count / sizeof(AudioDeviceID); for (int i = 0; i < numdevices; ++i) { // err = AudioDeviceGetPropertyInfo(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, 0); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; err = AudioObjectGetPropertyDataSize(devices[i], &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]); break; } char *name = (char*)malloc(count); // err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &count, name); err = AudioObjectGetPropertyData(devices[i], &propertyAddress, 0, NULL, &count, name); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyDeviceName error %4.4s B %d %p\n", (char*)&err, i, devices[i]); return false; } if (strcmp(name, mWorld->hw->mInDeviceName) == 0) { mInputDevice = devices[i]; } if (strcmp(name, mWorld->hw->mOutDeviceName) == 0) { mOutputDevice = devices[i]; } free(name); if (mInputDevice!=kAudioDeviceUnknown && mOutputDevice!=kAudioDeviceUnknown) break; } free(devices); if (mOutputDevice==kAudioDeviceUnknown || mInputDevice==kAudioDeviceUnknown) goto getDefault; } else { getDefault: // get the default output device for the HAL if (mOutputDevice==kAudioDeviceUnknown) { count = sizeof(mOutputDevice); //get the output device: // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) & mOutputDevice); propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, (void*) & mOutputDevice); if (err != kAudioHardwareNoError) { scprintf("get kAudioHardwarePropertyDefaultOutputDevice error %4.4s\n", (char*)&err); return false; } } //get the input device if (mInputDevice==kAudioDeviceUnknown) { count = sizeof(mInputDevice); // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &count, (void *) & mInputDevice); propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &count, (void*) & mInputDevice); //get the input device: if (err != kAudioHardwareNoError) { scprintf("get kAudioHardwarePropertyDefaultInputDevice error %4.4s\n", (char*)&err); return false; } } } //////////////////////////////////////////////////////////////////////////////////////////////// AudioTimeStamp now; now.mFlags = kAudioTimeStampHostTimeValid; now.mHostTime = AudioGetCurrentHostTime(); if (mPreferredHardwareBufferFrameSize) { count = sizeof(UInt32); // err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize); propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSize; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, count, &mPreferredHardwareBufferFrameSize); if (err != kAudioHardwareNoError) { scprintf("set kAudioDevicePropertyBufferFrameSize error %4.4s\n", (char*)&err); //return false; } if (UseSeparateIO()) { count = sizeof(UInt32); //err = AudioDeviceSetProperty(mOutputDevice, &now, 0, false, kAudioDevicePropertyBufferFrameSize, count, &mPreferredHardwareBufferFrameSize); propertyAddress.mSelector = kAudioDevicePropertyBufferFrameSize; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectSetPropertyData(mInputDevice, &propertyAddress, 0, NULL, count, &mPreferredHardwareBufferFrameSize); if (err != kAudioHardwareNoError) { scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err); //return false; } } } if (mPreferredSampleRate) { Float64 sampleRate = mPreferredSampleRate; count = sizeof(Float64); bool sampleRateSupported = false; auto availableSampleRates = GetAvailableNominalSampleRates(mOutputDevice); // If we've got two devices, we need to use a sample rate list from both // This won't account for cases where there are overlapping ranges, but // that seems sufficiently edge-case to ignore for now. if (UseSeparateIO()) { auto inputSampleRates = GetAvailableNominalSampleRates(mInputDevice); std::vector availableSampleRatesInputOutput(std::min(availableSampleRates.size(), inputSampleRates.size())); auto rateListIter = std::set_union( availableSampleRates.begin(), availableSampleRates.end(), inputSampleRates.begin(), inputSampleRates.end(), availableSampleRatesInputOutput.begin(), [](const AudioValueRange& lhs, const AudioValueRange& rhs) { return (lhs.mMaximum != rhs.mMaximum) ? (lhs.mMaximum < rhs.mMaximum) : (lhs.mMinimum < rhs.mMinimum); } ); availableSampleRatesInputOutput.resize(rateListIter - availableSampleRatesInputOutput.begin()); availableSampleRates = availableSampleRatesInputOutput; } for (const AudioValueRange& range : availableSampleRates) { if (mPreferredSampleRate >= range.mMinimum && mPreferredSampleRate <= range.mMaximum) { sampleRateSupported = true; break; } } if (!sampleRateSupported) { #define SR_MAX_VALUE 9999999 #define SR_MIN_VALUE -9999999 Float64 nextHighestMatch = SR_MAX_VALUE; Float64 nextLowestMatch = SR_MIN_VALUE; for (const AudioValueRange& range : availableSampleRates) { if (range.mMinimum > mPreferredSampleRate && range.mMinimum < nextHighestMatch) { nextHighestMatch = range.mMinimum; } if (range.mMaximum < mPreferredSampleRate && range.mMaximum > nextLowestMatch) { nextLowestMatch = range.mMaximum; } } if (nextHighestMatch != SR_MAX_VALUE) { sampleRate = nextHighestMatch; sampleRateSupported = true; } else if(nextLowestMatch != SR_MIN_VALUE) { sampleRate = nextLowestMatch; sampleRateSupported = true; } else { sampleRateSupported = false; } if (sampleRateSupported) { scprintf("Requested sample rate %f was not available - attempting to use sample rate of %f\n", (double)mPreferredSampleRate, (double)sampleRate); } else { scprintf("Could not set requested sample rate of %f\n", (double)mPreferredSampleRate); scprintf("Available sample rates:\n"); for (const AudioValueRange& range : availableSampleRates) { if (range.mMaximum == range.mMinimum) { scprintf("\t%f\n", range.mMaximum); } else { scprintf("\t%f - %f\n", range.mMinimum, range.mMaximum); } } } } // Requested sample rate is available - we're going to set and, if we don't hit an error, // assume that our set was successful. if (sampleRateSupported) { bool sampleRateSetSuccess = true; propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, count, &sampleRate); if (err != kAudioHardwareNoError) { sampleRateSetSuccess = false; scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err); } if (UseSeparateIO()) { count = sizeof(Float64); propertyAddress.mSelector = kAudioDevicePropertyNominalSampleRate; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectSetPropertyData(mInputDevice, &propertyAddress, 0, NULL, count, &sampleRate); if (err != kAudioHardwareNoError) { sampleRateSetSuccess = false; scprintf("set kAudioDevicePropertyNominalSampleRate error %4.4s\n", (char*)&err); } } if (sampleRateSetSuccess) { mExplicitSampleRate = sampleRate; } else { return false; } } } // get the buffersize for the out device count = sizeof(mHardwareBufferSize); // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyBufferSize, &count, &mHardwareBufferSize); propertyAddress.mSelector = kAudioDevicePropertyBufferSize; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, &mHardwareBufferSize); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyBufferSize error %4.4s\n", (char*)&err); return false; } //scprintf("mHardwareBufferSize = %ld\n", mHardwareBufferSize); // get a description of the data format used by the output device count = sizeof(AudioStreamBasicDescription); // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyStreamFormat, &count, &outputStreamDesc); propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, &outputStreamDesc); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamFormat error %4.4s\n", (char*)&err); return false; } if (mInputDevice != kAudioDeviceUnknown) { // get a description of the data format used by the input device count = sizeof(AudioStreamBasicDescription); // err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamFormat, &count, &inputStreamDesc); propertyAddress.mSelector = kAudioDevicePropertyStreamFormat; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, &inputStreamDesc); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamFormat error on input %4.4s\n", (char*)&err); return false; } if (!mExplicitSampleRate && inputStreamDesc.mSampleRate != outputStreamDesc.mSampleRate) { scprintf("input and output sample rates do not match. %g != %g\n", inputStreamDesc.mSampleRate, outputStreamDesc.mSampleRate); return false; } } //////////////////////////////////////////////////////////////////////////////////////////////// do { // err = AudioDeviceGetPropertyInfo(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice); break; } char *name = (char*)malloc(count); //err = AudioDeviceGetProperty(mInputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name); err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, name); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyDeviceName error %4.4s C %p\n", (char*)&err, mInputDevice); free(name); break; } if(mWorld->mVerbosity >= 0){ scprintf("\"%s\" Input Device\n", name); } free(name); Boolean writeable; // err = AudioDeviceGetPropertyInfo(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration, &count, &writeable); propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writeable); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyStreamConfiguration settable error %4.4s\n", (char*)&err); break; } err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyStreamConfiguration size error %4.4s\n", (char*)&err); break; } AudioBufferList *bufList = (AudioBufferList*)malloc(count); // err = AudioDeviceGetProperty(mInputDevice, 0, 1, kAudioDevicePropertyStreamConfiguration, &count, bufList); propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, bufList); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err); free(bufList); break; } if(mWorld->mVerbosity >= 0){ scprintf(" Streams: %d\n", bufList->mNumberBuffers); for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) { scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels); } } free(bufList); } while (false); if(mWorld->mVerbosity >= 0){ scprintf("\n"); } //////////////////////////////////////////////////////////////////////////////////////////////// do { // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &count); char *name = (char*)malloc(count); // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, name); err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, name); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyDeviceName error %4.4s\n", (char*)&err); free(name); break; } if(mWorld->mVerbosity >= 0){ scprintf("\"%s\" Output Device\n", name); } free(name); Boolean writeable; // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration, &count, &writeable); propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writeable); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyStreamConfiguration settable error %4.4s\n", (char*)&err); break; } err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyStreamConfiguration size error %4.4s\n", (char*)&err); break; } AudioBufferList *bufList = (AudioBufferList*)malloc(count); // err = AudioDeviceGetProperty(mOutputDevice, 0, 0, kAudioDevicePropertyStreamConfiguration, &count, bufList); propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration ; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, bufList); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err); free(bufList); break; } if(mWorld->mVerbosity >= 0){ scprintf(" Streams: %d\n", bufList->mNumberBuffers); for (unsigned int j = 0; j < bufList->mNumberBuffers; ++j) { scprintf(" %d channels %d\n", j, bufList->mBuffers[j].mNumberChannels); } } free(bufList); } while (false); if(mWorld->mVerbosity >= 0){ scprintf("\n"); } //////////////////////////////////////////////////////////////////////////////////////////////// if (UseSeparateIO()) { count = sizeof(UInt32); //err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertySafetyOffset, &count, &mSafetyOffset); propertyAddress.mSelector = kAudioDevicePropertySafetyOffset; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, &mSafetyOffset); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertySafetyOffset error %4.4s\n", (char*)&err); return false; } if(mWorld->mVerbosity >= 1){ scprintf("mSafetyOffset %lu\n", mSafetyOffset); } Boolean writeable; // err = AudioDeviceGetPropertyInfo(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, &writeable); propertyAddress.mSelector = kAudioDevicePropertyStreamConfiguration; propertyAddress.mScope = kAudioDevicePropertyScopeInput; err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writeable); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamConfiguration writeable error %4.4s\n", (char*)&err); return false; } err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamConfiguration size error %4.4s\n", (char*)&err); return false; } mInputBufList = (AudioBufferList*)malloc(count); //err = AudioDeviceGetProperty(mInputDevice, 0, true, kAudioDevicePropertyStreamConfiguration, &count, mInputBufList); err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &count, mInputBufList); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyStreamConfiguration error %4.4s\n", (char*)&err); return false; } if(mWorld->mVerbosity >= 1){ scprintf("mNumberBuffers %lu\n", mInputBufList->mNumberBuffers); } for (uint32 i=0; imNumberBuffers; ++i) { if(mWorld->mVerbosity >= 1){ scprintf(" mDataByteSize %d %lu\n", i, mInputBufList->mBuffers[i].mDataByteSize); } mInputBufList->mBuffers[i].mData = zalloc(1, mInputBufList->mBuffers[i].mDataByteSize); } /* AudioTimeStamp now; now.mFlags = kAudioTimeStampHostTimeValid; now.mHostTime = AudioGetCurrentHostTime(); err = AudioDeviceSetProperty(mInputDevice, &now, 0, true, kAudioDevicePropertyRegisterBufferList, count, mInputBufList); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyRegisterBufferList error %4.4s\n", (char*)&err); return false; } */ } *outNumSamplesPerCallback = mHardwareBufferSize / outputStreamDesc.mBytesPerFrame; if (mExplicitSampleRate) { *outSampleRate = mExplicitSampleRate.get(); } else { *outSampleRate = outputStreamDesc.mSampleRate; } if(mWorld->mVerbosity >= 1){ scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld); } //check if using built-in output, and thus whether there could be headphone plug/un-plug issues //our assumption otherwise is that we don't respond, and SC will stay with the pre-arranged or default device, and not restart just because headphones switched // err = AudioDeviceGetPropertyInfo(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, 0); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &count); if (err != kAudioHardwareNoError) { scprintf("info kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice); return false; } char *outputname = (char*)malloc(count); const char *testname = "Built-in Output"; // err = AudioDeviceGetProperty(mOutputDevice, 0, false, kAudioDevicePropertyDeviceName, &count, outputname); err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &count, outputname); if (err != kAudioHardwareNoError) { scprintf("get kAudioDevicePropertyDeviceName error %4.4s %p\n", (char*)&err, mOutputDevice); return false; } builtinoutputflag_ = 0; if (strcmp(testname, outputname) == 0) { builtinoutputflag_ = 1; } // else { // // //check for an Aggregate Devices with a subdevice which is Built-in Output // //http://lists.apple.com/archives/coreaudio-api/2009/Oct/msg00182.html // // // } free(outputname); return true; } /* OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr); OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr) { SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr; int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime); AudioTimeStamp readTime; readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback(); readTime.mFlags = kAudioTimeStampSampleTimeValid; AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList()); def->Run(def->GetInputBufferList(), outOutputData, oscTime); return kAudioHardwareNoError; } */ OSStatus appIOProcSeparateIn (AudioDeviceID device, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr) { SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr; // copy input data to driver's private buffer list int i; for (i=0; imNumberBuffers; i++) { memcpy(def->mInputBufList->mBuffers[i].mData, inInputData->mBuffers[i].mData, inInputData->mBuffers[i].mDataByteSize); } return kAudioHardwareNoError; } OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr) { SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr; int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime); double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9; double sampleTime = inOutputTime->mSampleTime; if (def->mStartHostSecs == 0) { def->mStartHostSecs = hostSecs; def->mStartSampleTime = sampleTime; } else { double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs); double smoothSampleRate = def->mSmoothSampleRate; smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate); def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate); def->mSmoothSampleRate = smoothSampleRate; #if 0 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs); double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime); double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs); //if (fabs(jitter) > 0.01) { scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n", avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement); //} #endif } def->mPrevHostSecs = hostSecs; def->mPrevSampleTime = sampleTime; if (!def->UseSeparateIO()) { def->Run(inInputData, outOutputData, oscTime); return kAudioHardwareNoError; } def->Run(def->mInputBufList, outOutputData, oscTime); return kAudioHardwareNoError; } void SC_CoreAudioDriver::Run(const AudioBufferList* inInputData, AudioBufferList* outOutputData, int64 oscTime) { int64 systemTimeBefore = AudioGetCurrentHostTime(); World *world = mWorld; try { int numSamplesPerCallback = NumSamplesPerCallback(); mOSCbuftime = oscTime; #ifdef __APPLE__ // FIXME: aren't denormal flags set per-process? sc_SetDenormalFlags(); #endif mFromEngine.Free(); /*if (mToEngine.HasData()) { scprintf("oscTime %.9f %.9f\n", oscTime*kOSCtoSecs, CoreAudioHostTimeToOSC(AudioGetCurrentHostTime())*kOSCtoSecs); }*/ mToEngine.Perform(); mOscPacketsToEngine.Perform(); int bufFrames = world->mBufLength; int numBufs = numSamplesPerCallback / bufFrames; int numInputBuses = world->mNumInputs; int numOutputBuses = world->mNumOutputs; float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames; float* outputBuses = world->mAudioBus; int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs; int32* outputTouched = world->mAudioBusTouched; int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0; int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0; //static int go = 0; int64 oscInc = mOSCincrement; double oscToSamples = mOSCtoSamples; int bufFramePos = 0; for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) { int32 bufCounter = world->mBufCounter; // de-interleave input if (inInputData) { const AudioBuffer* inInputDataBuffers = inInputData->mBuffers; for (int s = 0, b = 0; bmNumberChannels; if (buf->mData) { float *busdata = inputBuses + b * bufFrames; float *bufdata = (float*)buf->mData + bufFramePos * nchan; if (nchan == 1) { for (int k=0; kmSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1; SC_ScheduledEvent event = mScheduler.Remove(); event.Perform(); } world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; World_Run(world); // interleave output AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers; for (int s = 0, b = 0; bmNumberChannels; if (buf->mData) { float *busdata = outputBuses + b * bufFrames; float *bufdata = (float*)buf->mData + bufFramePos * nchan; if (nchan == 1) { if (outputTouched[b] == bufCounter) { for (int k=0; k mPeakCPU || --mPeakCounter <= 0) { mPeakCPU = cpuUsage; mPeakCounter = mMaxPeakCounter; } mAudioSync.Signal(); } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// // These are not linked in yet, but we'll need to listen for the properties and stop/restart synthesis // if sample-rate, format, or device change. OSStatus hardwareListenerProc ( AudioHardwarePropertyID inPropertyID, void* inClientData) { OSStatus err = noErr; char cStr[255]; UInt32 outSize; Boolean outWritable; AudioDeviceID deviceID; AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; switch(inPropertyID) { case kAudioHardwarePropertyDefaultOutputDevice: scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultOutputDevice\r"); //err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &outWritable); propertyAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize); if (err) break; err = AudioObjectIsPropertySettable(kAudioObjectSystemObject, &propertyAddress, &outWritable); if (err) break; //err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &outSize, &deviceID); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &deviceID); if (err) break; // err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; err = AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &outSize); if (err) break; err = AudioObjectIsPropertySettable(deviceID, &propertyAddress, &outWritable); if (err) break; //err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr); err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &outSize, cStr); if (err) break; // do something break; case kAudioHardwarePropertyDefaultInputDevice: scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultInputDevice\r"); // err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultInputDevice, &outSize, &outWritable); propertyAddress.mSelector = kAudioHardwarePropertyDefaultInputDevice; err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize); if (err) break; err = AudioObjectIsPropertySettable(kAudioObjectSystemObject, &propertyAddress, &outWritable); if (err) break; // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &outSize, &deviceID); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &deviceID); if (err) break; // err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; err = AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &outSize); if (err) break; err = AudioObjectIsPropertySettable(deviceID, &propertyAddress, &outWritable); if (err) break; // err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr); err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &outSize, cStr); if (err) break; // do something break; case kAudioHardwarePropertyDefaultSystemOutputDevice: scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDefaultSystemOutputDevice\r"); //err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &outWritable); propertyAddress.mSelector = kAudioHardwarePropertyDefaultSystemOutputDevice; err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize); if (err) break; err = AudioObjectIsPropertySettable(kAudioObjectSystemObject, &propertyAddress, &outWritable); if (err) break; // err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &outSize, &deviceID); err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &outSize, &deviceID); if (err) break; // err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable); propertyAddress.mSelector = kAudioDevicePropertyDeviceName; err = AudioObjectGetPropertyDataSize(deviceID, &propertyAddress, 0, NULL, &outSize); if (err) break; err = AudioObjectIsPropertySettable(deviceID, &propertyAddress, &outWritable); if (err) break; // err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, cStr); err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, NULL, &outSize, cStr); if (err) break; // do something break; case kAudioHardwarePropertyDevices: { scprintf("%s\n", "***** HARDWARE NOTIFICATION - kAudioHardwarePropertyDevices\r"); } break; default: scprintf("%s\n", "***** HARDWARE NOTIFICATION - %4.4s\r", &inPropertyID); } fflush(stdout); return (noErr); } OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData); bool SC_CoreAudioDriver::DriverStart() { if(mWorld->mVerbosity >= 1){ scprintf("->SC_CoreAudioDriver::DriverStart\n"); } OSStatus err = kAudioHardwareNoError; // AudioTimeStamp now; UInt32 propertySize; Boolean writable; AudioObjectPropertyAddress propertyAddress; propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; if(mWorld->mVerbosity >= 1){ scprintf("start UseSeparateIO?: %d\n", UseSeparateIO()); } try { if (UseSeparateIO()) { // err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup Out device with an IO proc err = AudioDeviceCreateIOProcID(mOutputDevice, appIOProc, (void*) this, &mOutputID); if (err != kAudioHardwareNoError) { scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err); return false; } // err = AudioDeviceAddIOProc(mInputDevice, appIOProcSeparateIn, (void *) this); // setup In device with an IO proc err = AudioDeviceCreateIOProcID(mInputDevice, appIOProcSeparateIn , (void *)this, &mInputID); if (err != kAudioHardwareNoError) { scprintf("AudioDeviceAddIOProc failed %s %d\n", &err, (int)err); return false; } if (mWorld->hw->mInputStreamsEnabled) { propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage; propertyAddress.mScope = kAudioDevicePropertyScopeInput; propertyAddress.mElement = 0; err = AudioObjectGetPropertyDataSize(mInputDevice, &propertyAddress, 0, NULL, &propertySize); err = AudioObjectIsPropertySettable(mInputDevice, &propertyAddress, &writable); AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize); su->mIOProc = (void*)appIOProcSeparateIn; err = AudioObjectGetPropertyData(mInputDevice, &propertyAddress, 0, NULL, &propertySize, su); int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled)); for (int i=0; imStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1'; } err = AudioObjectSetPropertyData(mInputDevice, &propertyAddress, 0, NULL, propertySize, su); } if (mWorld->hw->mOutputStreamsEnabled) { propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; propertyAddress.mElement = 0; err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &propertySize); err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writable); AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize); su->mIOProc = (void*)appIOProc; err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &propertySize, su); int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled)); for (int i=0; imStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1'; } err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, propertySize, su); } err = AudioDeviceStart(mInputDevice, appIOProcSeparateIn); // start playing sound through the device if (err != kAudioHardwareNoError) { scprintf("AudioDeviceStart failed %d\n", (int)err); return false; } err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device if (err != kAudioHardwareNoError) { scprintf("AudioDeviceStart failed %d\n", (int)err); err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn); // stop playing sound through the device return false; } } else { // err = AudioDeviceAddIOProc(mOutputDevice, appIOProc, (void *) this); // setup our device with an IO proc err = AudioDeviceCreateIOProcID(mOutputDevice, appIOProc, (void *) this, &mOutputID); if (err != kAudioHardwareNoError) { scprintf("AudioDeviceAddIOProc failed %d\n", (int)err); return false; } if (mWorld->hw->mInputStreamsEnabled) { propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; propertyAddress.mElement = 0; err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &propertySize); err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writable); AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize); su->mIOProc = (void*)appIOProc; err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &propertySize, su); int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mInputStreamsEnabled)); for (int i=0; imStreamIsOn[i] = mWorld->hw->mInputStreamsEnabled[i] == '1'; } err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, propertySize, su); } if (mWorld->hw->mOutputStreamsEnabled) { propertyAddress.mSelector = kAudioDevicePropertyIOProcStreamUsage; propertyAddress.mScope = kAudioDevicePropertyScopeOutput; propertyAddress.mElement = 0; err = AudioObjectGetPropertyDataSize(mOutputDevice, &propertyAddress, 0, NULL, &propertySize); err = AudioObjectIsPropertySettable(mOutputDevice, &propertyAddress, &writable); AudioHardwareIOProcStreamUsage *su = (AudioHardwareIOProcStreamUsage*)malloc(propertySize); su->mIOProc = (void*)appIOProc; err = AudioObjectGetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, &propertySize, su); int len = std::min(su->mNumberStreams, (UInt32)strlen(mWorld->hw->mOutputStreamsEnabled)); for (int i=0; imStreamIsOn[i] = mWorld->hw->mOutputStreamsEnabled[i] == '1'; } err = AudioObjectSetPropertyData(mOutputDevice, &propertyAddress, 0, NULL, propertySize, su); } err = AudioDeviceStart(mOutputDevice, appIOProc); // start playing sound through the device if (err != kAudioHardwareNoError) { scprintf("AudioDeviceStart failed %d\n", (int)err); return false; } } } catch (...) { scprintf("exception in SC_CoreAudioDriver::DriverStart\n"); } if(mWorld->mVerbosity >= 1){ scprintf("<-SC_CoreAudioDriver::DriverStart\n"); } //http://lists.apple.com/archives/coreaudio-api/2010/Aug/msg00114.html CFRunLoopRef theRunLoop = NULL; AudioObjectPropertyAddress theAddress = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectSetPropertyData(kAudioObjectSystemObject, &theAddress, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop); //for now no spotting of hardware changes, assumption is that ServerOptions inviolate. However, if a device was unplugged, could react to loss of that device //by switching to system default? //note that the number of listeners is stripped down to only one for now, to react to headphone swaps in the case of Built-in Output AddDeviceListeners(mOutputDevice, this); return true; } bool SC_CoreAudioDriver::StopStart() { bool test = DriverStop(); bool test2 = DriverStart(); return test && test2; } bool SC_CoreAudioDriver::DriverStop() { if(mWorld->mVerbosity >= 1){ scprintf("->SC_CoreAudioDriver::DriverStop\n"); } OSStatus err = kAudioHardwareNoError; if (UseSeparateIO()) { err = AudioDeviceStop(mOutputDevice, appIOProc); if (err != kAudioHardwareNoError) { scprintf("Output AudioDeviceStop failed %p\n", err); return false; } err = AudioDeviceDestroyIOProcID(mOutputDevice, mOutputID); if (err != kAudioHardwareNoError) { scprintf("Output AudioDeviceDestroyIOProcID failed %p\n", err); return false; } err = AudioDeviceStop(mInputDevice, appIOProcSeparateIn); if (err != kAudioHardwareNoError) { scprintf("Input AudioDeviceStop failed %p\n", err); return false; } err = AudioDeviceDestroyIOProcID(mInputDevice, mInputID); if (err != kAudioHardwareNoError) { scprintf("Input AudioDeviceDestroyIOProcID failed %p\n", err); return false; } } else { err = AudioDeviceStop(mOutputDevice, appIOProc); if (err != kAudioHardwareNoError) { scprintf("AudioDeviceStop B failed %p\n", err); return false; } err = AudioDeviceDestroyIOProcID(mOutputDevice, mOutputID); if (err != kAudioHardwareNoError) { scprintf("AudioDeviceDestroyIOProcID B failed %p\n", err); return false; } } if(mWorld->mVerbosity >= 1){ scprintf("<-SC_CoreAudioDriver::DriverStop\n"); } return true; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Listen for Device Properties and update interface and globals OSStatus deviceListenerProc (AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress inAddresses[], void* inClientData) { OSStatus err = noErr; SC_CoreAudioDriver* coredriver = (SC_CoreAudioDriver*) inClientData; for (int i=0; iStopStart(); } } return (err); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OSStatus AddDeviceListeners(AudioDeviceID inDevice, void *inClientData) { OSStatus err = noErr; AudioObjectPropertyAddress propertyAddress; // ONLY REACTING TO HEADPHONE SWAPS FOR NOW - see version control history for removed dead code propertyAddress.mSelector = kAudioHardwarePropertyDevices; propertyAddress.mScope = kAudioObjectPropertyScopeGlobal; propertyAddress.mElement = kAudioObjectPropertyElementMaster; err = AudioObjectAddPropertyListener(inDevice, &propertyAddress, deviceListenerProc, inClientData); if (err) return err; return (err); } #endif // SC_AUDIO_API_COREAUDIO // ===================================================================== // Audio driver (CoreAudioIPHONE) #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE SC_iCoreAudioDriver::SC_iCoreAudioDriver(struct World *inWorld) : SC_AudioDriver(inWorld) { receivedIn = 0; } SC_iCoreAudioDriver::~SC_iCoreAudioDriver() { } /* OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr); OSStatus appIOProc2 (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr) { SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr; int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime); AudioTimeStamp readTime; readTime.mSampleTime = inNow->mSampleTime - def->SafetyOffset() - def->NumSamplesPerCallback(); readTime.mFlags = kAudioTimeStampSampleTimeValid; AudioDeviceRead(def->InputDevice(), &readTime, def->GetInputBufferList()); def->Run(def->GetInputBufferList(), outOutputData, oscTime); return kAudioHardwareNoError; } */ OSStatus InputCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon; if (driver->receivedIn) { //printf("exit input with no data \n"); return noErr; } OSStatus ret = AudioUnitRender(driver->inputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, driver->buflist); if (ret) { //printf("no input !\n"); return noErr; } driver->receivedIn = 1; return noErr; } OSStatus RenderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { SC_iCoreAudioDriver *driver = (SC_iCoreAudioDriver *) inRefCon; #ifndef SC_IPHONE if (!driver->receivedIn) { //printf("exit output with no data \n"); return noErr; } #endif //float *fbuffer = (float *) driver->converter_buffer; int i; for (i=0; ibuflist->mBuffers[0].mData)[i]; int k = s + 0x43c00000; float f = *((float *) &k); ((float *)driver->floatInputList->mBuffers[0].mData)[i] = f - 384.0f; } int64 oscTime = GetCurrentOSCTime(); //driver->Run(driver->floatInputList, driver->floatOutputList, oscTime); driver->Run(driver->floatInputList, ioData, oscTime); for (i=0; imBuffers[0].mData)[i]; float f2 = ((float *)ioData->mBuffers[1].mData)[i]; ((int *) ioData->mBuffers[0].mData)[i] = (int) (f1*16777216); ((int *) ioData->mBuffers[1].mData)[i] = (int) (f2*16777216); } /* unsigned long size = 2*1024*sizeof(unsigned long); OSStatus ret = AudioConverterConvertBuffer(driver->converter_in_to_F32, driver->buflist->mBuffers[0].mDataByteSize, driver->buflist->mBuffers[0].mData, &size, driver->converter_buffer); if (ret) { printf("couldn't convert !\n"); return noErr; } int i; for (i=0; imBuffers[0].mData)[i] = ((int *)ioData->mBuffers[1].mData)[i] = driver->converter_buffer[2*i]; } */ driver->receivedIn = 0; return noErr; } void SC_iCoreAudioDriver::Run(const AudioBufferList* inInputData, AudioBufferList* outOutputData, int64 oscTime) { int64 systemTimeBefore = GetMicroseconds(); World *world = mWorld; try { int numSamplesPerCallback = NumSamplesPerCallback(); mOSCbuftime = oscTime; #ifdef __APPLE__ // FIXME: does iOS support x86? sc_SetDenormalFlags(); #endif mFromEngine.Free(); mToEngine.Perform(); mOscPacketsToEngine.Perform(); //printf("mOscPacketsToEngine : %d micros\n", (int) (GetMicroseconds()-systemTimeBefore)); int bufFrames = world->mBufLength; int numBufs = numSamplesPerCallback / bufFrames; int numInputBuses = world->mNumInputs; int numOutputBuses = world->mNumOutputs; float* inputBuses = world->mAudioBus + world->mNumOutputs * bufFrames; float* outputBuses = world->mAudioBus; int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs; int32* outputTouched = world->mAudioBusTouched; int numInputStreams = inInputData ? inInputData->mNumberBuffers : 0; int numOutputStreams = outOutputData ? outOutputData->mNumberBuffers : 0; //static int go = 0; int64 oscInc = mOSCincrement; double oscToSamples = mOSCtoSamples; int bufFramePos = 0; for (int i = 0; i < numBufs; ++i, world->mBufCounter++, bufFramePos += bufFrames) { int32 bufCounter = world->mBufCounter; // de-interleave input if (inInputData) { const AudioBuffer* inInputDataBuffers = inInputData->mBuffers; for (int s = 0, b = 0; bmNumberChannels; if (buf->mData) { float *busdata = inputBuses + b * bufFrames; float *bufdata = (float*)buf->mData + bufFramePos * nchan; if (nchan == 1) { #ifdef IPHONE_VEC vcopy(busdata, bufdata, bufFrames); #else for (int k=0; kmSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1; SC_ScheduledEvent event = mScheduler.Remove(); event.Perform(); } world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; //int64 now = GetMicroseconds(); World_Run(world); //printf("world run : %fms\n", (float) (GetMicroseconds()-now)/1000); // interleave output AudioBuffer* outOutputDataBuffers = outOutputData->mBuffers; for (int s = 0, b = 0; bmNumberChannels; if (buf->mData) { float *busdata = outputBuses + b * bufFrames; float *bufdata = (float*)buf->mData + bufFramePos * nchan; if (nchan == 1) { if (outputTouched[b] == bufCounter) { #ifdef IPHONE_VEC vcopy(bufdata, busdata, bufFrames); #else for (int k=0; k mPeakCPU || --mPeakCounter <= 0) { mPeakCPU = cpuUsage; mPeakCounter = mMaxPeakCounter; } mAudioSync.Signal(); } /* OSStatus appIOProc (AudioDeviceID device, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr) { SC_CoreAudioDriver* def = (SC_CoreAudioDriver*)defptr; int64 oscTime = CoreAudioHostTimeToOSC(inOutputTime->mHostTime); double hostSecs = (double)AudioConvertHostTimeToNanos(inOutputTime->mHostTime) * 1e-9; double sampleTime = inOutputTime->mSampleTime; if (def->mStartHostSecs == 0) { def->mStartHostSecs = hostSecs; def->mStartSampleTime = sampleTime; } else { double instSampleRate = (sampleTime - def->mPrevSampleTime)/(hostSecs - def->mPrevHostSecs); double smoothSampleRate = def->mSmoothSampleRate; smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate); def->mOSCincrement = (int64)(def->mOSCincrementNumerator / smoothSampleRate); def->mSmoothSampleRate = smoothSampleRate; #if 0 double avgSampleRate = (sampleTime - def->mStartSampleTime)/(hostSecs - def->mStartHostSecs); double jitter = (smoothSampleRate * (hostSecs - def->mPrevHostSecs)) - (sampleTime - def->mPrevSampleTime); double drift = (smoothSampleRate - def->mSampleRate) * (hostSecs - def->mStartHostSecs); //if (fabs(jitter) > 0.01) { scprintf("avgSR %.6f smoothSR %.6f instSR %.6f jitter %.6f drift %.6f inc %lld\n", avgSampleRate, smoothSampleRate, instSampleRate, jitter, drift, def->mOSCincrement); //} #endif } def->mPrevHostSecs = hostSecs; def->mPrevSampleTime = sampleTime; if (!def->UseSeparateIO()) { def->Run(inInputData, outOutputData, oscTime); return kAudioHardwareNoError; } def->Run(lastInputData, outOutputData, oscTime); lastInputData = 0; return kAudioHardwareNoError; } */ void AudioSessionInterruptionCbk(void *inClientData, UInt32 inInterruptionState) { } bool SC_iCoreAudioDriver::DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate) { AudioSessionInitialize(0, 0, AudioSessionInterruptionCbk, 0); unsigned long category = kAudioSessionCategory_PlayAndRecord; #ifdef SC_IPHONE UInt32 micInput, micInputSize = sizeof(&micInput); AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable, &micInputSize, &micInput); if(!micInput) { category = kAudioSessionCategory_MediaPlayback; scprintf("SC_IPHONE: WARNING - no audio input available\n"); } #endif AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category); if (mPreferredHardwareBufferFrameSize) { Float32 preferredBufferSize = (float) mPreferredHardwareBufferFrameSize/44100.f; AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize); } AudioSessionSetActive(true); float actualBufferDuration; UInt32 size = sizeof(actualBufferDuration); AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &size, &actualBufferDuration); *outNumSamplesPerCallback = (int) (actualBufferDuration*44100.f+0.5f); *outSampleRate = 44100; AudioComponentDescription desc; desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_RemoteIO; desc.componentManufacturer = kAudioUnitManufacturer_Apple; NewAUGraph(&graph); AUNode node; AudioUnit unit; OSStatus ret = AUGraphAddNode(graph, &desc, &node); //printf("node : %d\n", node); AUGraphOpen(graph); ret = AUGraphNodeInfo(graph, node, &desc, &unit); //printf("%d\n", unit); AudioComponent remoteIOComp = AudioComponentFindNext(0, &desc); if (AudioComponentInstanceNew(remoteIOComp, &inputUnit)!=noErr) { //printf("error instantiating RemoteIO\n"); return false; } //printf("instantiated : %d\n", inputUnit); int enableIO = 1; ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO)); if (ret!=noErr) { //printf("can't set input : %d\n", ret); return false; } enableIO = 0; ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO)); if (ret!=noErr) { //printf("can't set output : %d\n", ret); return false; } AudioUnitInitialize(inputUnit); unsigned long bufferSizeBytes = 1024 * sizeof(unsigned long); buflist = (AudioBufferList *) malloc(sizeof(AudioBufferList)); buflist->mNumberBuffers = 1; buflist->mBuffers[0].mDataByteSize = bufferSizeBytes; buflist->mBuffers[0].mData = malloc(bufferSizeBytes); buflist->mBuffers[0].mNumberChannels = 1; floatInputList = (AudioBufferList *) malloc(sizeof(AudioBufferList)); floatInputList->mNumberBuffers = 1; floatInputList->mBuffers[0].mDataByteSize = bufferSizeBytes; floatInputList->mBuffers[0].mData = malloc(bufferSizeBytes); floatInputList->mBuffers[0].mNumberChannels = 1; /* floatOutputList = (AudioBufferList *) malloc(sizeof(AudioBufferList)+sizeof(AudioBuffer)); floatOutputList->mNumberBuffers = 2; floatOutputList->mBuffers[0].mDataByteSize = bufferSizeBytes; floatOutputList->mBuffers[0].mData = malloc(bufferSizeBytes); floatOutputList->mBuffers[0].mNumberChannels = 1; floatOutputList->mBuffers[1].mDataByteSize = bufferSizeBytes; floatOutputList->mBuffers[1].mData = malloc(bufferSizeBytes); floatOutputList->mBuffers[1].mNumberChannels = 1; */ AURenderCallbackStruct inputStruct; inputStruct.inputProc = InputCallback; inputStruct.inputProcRefCon = this; ret = AudioUnitSetProperty(inputUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Input, 0, &inputStruct, sizeof(inputStruct)); AURenderCallbackStruct renderStruct; renderStruct.inputProc = RenderCallback; renderStruct.inputProcRefCon = this; ret = AudioUnitSetProperty(unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderStruct, sizeof(renderStruct)); AudioStreamBasicDescription streamFormat; streamFormat.mFormatID = kAudioFormatLinearPCM; streamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsNonInterleaved | (24 << kLinearPCMFormatFlagsSampleFractionShift); streamFormat.mSampleRate = 44100; streamFormat.mBitsPerChannel = 32; streamFormat.mChannelsPerFrame = 2; streamFormat.mFramesPerPacket = 1; streamFormat.mBytesPerFrame = ( streamFormat.mBitsPerChannel / 8 ); streamFormat.mBytesPerPacket = streamFormat.mBytesPerFrame * streamFormat.mFramesPerPacket; ret = AudioUnitSetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &streamFormat, sizeof(streamFormat)); AudioStreamBasicDescription audioFormat; audioFormat.mSampleRate = 44100.00; audioFormat.mFormatID = kAudioFormatLinearPCM; audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; audioFormat.mFramesPerPacket = 1; audioFormat.mChannelsPerFrame = 1; audioFormat.mBitsPerChannel = 16; audioFormat.mBytesPerPacket = 2; audioFormat.mBytesPerFrame = 2; ret = AudioUnitSetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &audioFormat, sizeof(audioFormat)); /* AudioStreamBasicDescription d; size = sizeof(d); ret = AudioUnitGetProperty(unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &d, &size); AudioStreamBasicDescription inputFormat; AudioStreamBasicDescription outputFormat; AudioStreamBasicDescription f32Format; size = sizeof(AudioStreamBasicDescription); ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &inputFormat, &size); ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 1, &inputFormat, &size); ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &outputFormat, &size); ret = AudioUnitGetProperty(inputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outputFormat, &size); outputFormat.mChannelsPerFrame = 1; f32Format.mSampleRate = inputFormat.mSampleRate; f32Format.mFormatID = inputFormat.mFormatID; f32Format.mFormatFlags = kAudioFormatFlagsNativeFloatPacked; f32Format.mBytesPerPacket = 4; f32Format.mFramesPerPacket = 1; f32Format.mBytesPerFrame = 4; f32Format.mChannelsPerFrame = 1; f32Format.mBitsPerChannel = 32; f32Format.mReserved = 0; ret = AudioConverterNew(&inputFormat, &f32Format, &converter_in_to_F32); ret = AudioConverterNew(&f32Format, &outputFormat, &converter_F32_to_out); ret = AudioConverterNew(&inputFormat, &outputFormat, &converter_in_to_out); */ AUGraphInitialize(graph); if(mWorld->mVerbosity >= 0){ scprintf("<-SC_CoreAudioDriver::Setup world %p\n", mWorld); } return true; } bool SC_iCoreAudioDriver::DriverStart() { if(mWorld->mVerbosity >= 0){ scprintf("->SC_CoreAudioDriver::DriverStart\n"); } try { OSStatus ret = AUGraphStart(graph); AudioOutputUnitStart(inputUnit); } catch (...) { scprintf("exception in SC_CoreAudioDriver::DriverStart\n"); } if(mWorld->mVerbosity >= 0){ scprintf("<-SC_CoreAudioDriver::DriverStart\n"); } return true; } bool SC_iCoreAudioDriver::DriverStop() { if(mWorld->mVerbosity >= 0){ scprintf("->SC_CoreAudioDriver::DriverStop\n"); } AUGraphStop(graph); AudioOutputUnitStop(inputUnit); if(mWorld->mVerbosity >= 0){ scprintf("<-SC_CoreAudioDriver::DriverStop\n"); } return true; } #endif // SC_AUDIO_API_COREAUDIOIPHONE SuperCollider-Source/server/scsynth/SC_CoreAudio.h000644 000765 000024 00000025227 12756531745 023315 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_CoreAudio_ #define _SC_CoreAudio_ #include "MsgFifo.h" #include "SC_FifoMsg.h" #include "OSC_Packet.h" #include "SC_SyncCondition.h" #include "PriorityQueue.h" #include #include #define SC_AUDIO_API_COREAUDIO 1 #define SC_AUDIO_API_JACK 2 #define SC_AUDIO_API_PORTAUDIO 3 #define SC_AUDIO_API_AUDIOUNITS 4 #define SC_AUDIO_API_COREAUDIOIPHONE 5 #define SC_AUDIO_API_ANDROIDJNI 6 #ifdef SC_ANDROID #define SC_AUDIO_API SC_AUDIO_API_ANDROIDJNI #endif #ifdef SC_IPHONE #define SC_AUDIO_API SC_AUDIO_API_COREAUDIOIPHONE #endif #ifndef SC_AUDIO_API # if defined(_WIN32) # define SC_AUDIO_API SC_AUDIO_API_PORTAUDIO # elif defined(__APPLE__) # define SC_AUDIO_API SC_AUDIO_API_COREAUDIO # else # error SC_AUDIO_API undefined, cannot determine audio backend # endif #endif // SC_AUDIO_API #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS # include # include #endif #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE #include #include #include #include #endif struct SC_ScheduledEvent { /// Callback function responsible for freeing the OSC packet in the correct thread. typedef void (*PacketFreeFunc)(struct World* world, OSC_Packet* packet); /// Frees an OSC packet in the realtime thread (to be used as a PacketFreeFunc). static void FreeInRT(struct World* world, OSC_Packet* packet); /// Frees an OSC packet in the non-realtime thread (to be used as a PacketFreeFunc). static void FreeInNRT(struct World* world, OSC_Packet* packet); SC_ScheduledEvent() : mTime(0), mPacket(0) {} SC_ScheduledEvent(struct World *inWorld, int64 inTime, OSC_Packet *inPacket, PacketFreeFunc freeFunc) : mTime(inTime), mPacket(inPacket), mPacketFreeFunc(freeFunc), mWorld(inWorld) {} int64 Time() { return mTime; } void Perform(); struct key_t { int64 time, stabilityCount; bool operator<(key_t const & rhs) const { if (time < rhs.time) return true; if (time > rhs.time) return false; return stabilityCount < rhs.stabilityCount; } bool operator>(key_t const & rhs) const { if (time > rhs.time) return true; if (time < rhs.time) return false; return stabilityCount > rhs.stabilityCount; } bool operator==(key_t const & rhs) const { return (time == rhs.time) && (stabilityCount == rhs.stabilityCount); } }; key_t key() const { key_t ret; ret.time = mTime; ret.stabilityCount = mStabilityCount; return ret; } int64 mTime; int64 mStabilityCount; OSC_Packet *mPacket; PacketFreeFunc mPacketFreeFunc; struct World *mWorld; }; typedef MsgFifo EngineFifo; // Functions to be implemented by the driver backend extern "C" { int32 server_timeseed(); int64 oscTimeNow(); }; void initializeScheduler(); /** Denotes whether an OSC packet has been performed immediately or has been scheduled for later execution. If the package has been scheduled, memory ownership is transferred from the caller to the scheduler. */ enum PacketStatus { PacketPerformed, PacketScheduled }; /** Perform a completion message in the realtime thread. The return value denotes whether ownership is transferred to the scheduler or not. */ PacketStatus PerformCompletionMsg(World *world, const OSC_Packet& packet); class SC_AudioDriver { protected: int64 mOSCincrement; struct World *mWorld; double mOSCtoSamples; int mSampleTime; // Common members uint32 mHardwareBufferSize; // bufferSize returned by kAudioDevicePropertyBufferSize EngineFifo mFromEngine, mToEngine; EngineFifo mOscPacketsToEngine; SC_SyncCondition mAudioSync; thread mThread; bool mRunThreadFlag; uint32 mSafetyOffset; PriorityQueueT mScheduler; int mNumSamplesPerCallback; uint32 mPreferredHardwareBufferFrameSize; uint32 mPreferredSampleRate; boost::optional mExplicitSampleRate; double mBuffersPerSecond; double mAvgCPU, mPeakCPU; int mPeakCounter, mMaxPeakCounter; double mOSCincrementNumerator; double mStartHostSecs; double mPrevHostSecs; double mStartSampleTime; double mPrevSampleTime; double mSmoothSampleRate; double mSampleRate; // Driver interface methods, implemented by subclasses /** * DriverSetup() should init the driver and write the num of samples per callback * and the sample rate into the two addresses supplied as arguments. * The driver will have access to the "preferred" values of these two args * (mPreferredHardwareBufferFrameSize, mPreferredSampleRate) and ideally should follow them. * This method should open the resources (and return true if successful), but shouldn't * really start the streaming (this is the responsibility of DriverStart()). */ virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate) = 0; /** * Start the audio streaming. Return true iff successful. */ virtual bool DriverStart() = 0; /** * Stop the audio streaming. Return true iff successful. */ virtual bool DriverStop() = 0; public: // Common methods SC_AudioDriver(struct World *inWorld); virtual ~SC_AudioDriver(); int64 mOSCbuftime; bool Setup(); bool Start(); bool Stop(); void ClearSched() { mScheduler.Empty(); } void RunNonRealTime(float *in, float *out, int numSamples, int64 oscTime); void RunThread(); int SafetyOffset() const { return mSafetyOffset; } int NumSamplesPerCallback() const { return mNumSamplesPerCallback; } void SetPreferredHardwareBufferFrameSize(int inSize) { mPreferredHardwareBufferFrameSize = inSize; } void SetPreferredSampleRate(int inRate) { mPreferredSampleRate = inRate; } bool SendMsgToEngine(FifoMsg& inMsg); // called by NRT thread bool SendMsgFromEngine(FifoMsg& inMsg); bool SendOscPacketMsgToEngine(FifoMsg& inMsg); // called by OSC socket listener threads, protected by mWorld->mDriverLock void AddEvent(SC_ScheduledEvent& event) { mScheduler.Add(event); } double GetAvgCPU() const { return mAvgCPU; } double GetPeakCPU() const { return mPeakCPU; } double GetSampleRate() const { return mSampleRate; } double GetActualSampleRate() const { return mSmoothSampleRate; } }; extern SC_AudioDriver* SC_NewAudioDriver(struct World* inWorld); // the following classes should be split out into separate source files. #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIO || SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS class SC_CoreAudioDriver : public SC_AudioDriver { AudioBufferList * mInputBufList; AudioDeviceID mInputDevice; AudioDeviceID mOutputDevice; AudioStreamBasicDescription inputStreamDesc; // info about the default device AudioStreamBasicDescription outputStreamDesc; // info about the default device friend OSStatus appIOProc ( AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr); friend OSStatus appIOProcSeparateIn (AudioDeviceID device, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* defptr); protected: // Driver interface methods virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate); virtual bool DriverStart(); virtual bool DriverStop(); AudioDeviceIOProcID mOutputID; AudioDeviceIOProcID mInputID; public: int builtinoutputflag_; SC_CoreAudioDriver(struct World *inWorld); virtual ~SC_CoreAudioDriver(); bool StopStart(); void Run(const AudioBufferList* inInputData, AudioBufferList* outOutputData, int64 oscTime); bool UseInput() { return mInputDevice != kAudioDeviceUnknown; } bool UseSeparateIO() { return UseInput() && mInputDevice != mOutputDevice; } AudioDeviceID InputDevice() { return mInputDevice; } AudioDeviceID OutputDevice() { return mOutputDevice; } void SetInputBufferList(AudioBufferList * inBufList) { mInputBufList = inBufList; } AudioBufferList* GetInputBufferList() const { return mInputBufList; } }; #endif #if SC_AUDIO_API == SC_AUDIO_API_COREAUDIOIPHONE class SC_iCoreAudioDriver : public SC_AudioDriver { AUGraph graph; AudioStreamBasicDescription inputStreamDesc; // info about the default device AudioStreamBasicDescription outputStreamDesc; // info about the default device protected: // Driver interface methods virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate); virtual bool DriverStart(); virtual bool DriverStop(); public: SC_iCoreAudioDriver(struct World *inWorld); virtual ~SC_iCoreAudioDriver(); void Run(const AudioBufferList* inInputData, AudioBufferList* outOutputData, int64 oscTime); AudioBufferList * buflist; AudioBufferList * floatInputList; AudioBufferList * floatOutputList; AudioConverterRef converter_in_to_F32; AudioConverterRef converter_F32_to_out; AudioConverterRef converter_in_to_out; int *converter_buffer; int receivedIn; AudioUnit inputUnit; }; inline SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld) { return new SC_iCoreAudioDriver(inWorld); } #endif // SC_AUDIO_API_COREAUDIOIPHONE #if SC_AUDIO_API == SC_AUDIO_API_ANDROIDJNI class SC_AndroidJNIAudioDriver : public SC_AudioDriver { protected: // Driver interface methods virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate); virtual bool DriverStart(); virtual bool DriverStop(); public: SC_AndroidJNIAudioDriver(struct World *inWorld); virtual ~SC_AndroidJNIAudioDriver(); void genaudio(short* arri, int numSamples); }; inline SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld) { return new SC_AndroidJNIAudioDriver(inWorld); } #endif // SC_AUDIO_API == SC_AUDIO_API_ANDROIDJNI #endif SuperCollider-Source/server/scsynth/SC_Graph.cpp000644 000765 000024 00000042016 12756531745 023032 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Win32Utils.h" #include "SC_Graph.h" #include "SC_GraphDef.h" #include "SC_Unit.h" #include "SC_UnitSpec.h" #include "SC_UnitDef.h" #include "SC_HiddenWorld.h" #include "SC_WorldOptions.h" #include "SC_Wire.h" #include "SC_WireSpec.h" #include #include #include "SC_Prototypes.h" #include "SC_Errors.h" #include "Unroll.h" void Unit_ChooseMulAddFunc(Unit* unit); //////////////////////////////////////////////////////////////////////////////// void Graph_FirstCalc(Graph *inGraph); void Graph_Dtor(Graph *inGraph) { //scprintf("->Graph_Dtor %d\n", inGraph->mNode.mID); World *world = inGraph->mNode.mWorld; uint32 numUnits = inGraph->mNumUnits; Unit** graphUnits = inGraph->mUnits; if (inGraph->mNode.mCalcFunc != (NodeCalcFunc)Graph_FirstCalc) { // the above test insures that dtors are not called if ctors have not been called. for (uint32 i = 0; imUnitDef->mUnitDtorFunc; if (dtor) (dtor)(unit); } } world->mNumUnits -= numUnits; world->mNumGraphs --; GraphDef* def = GRAPHDEF(inGraph); if (--def->mRefCount <= 0) { if (world->mRealTime) GraphDef_DeleteMsg(world, def); else GraphDef_Free(def); } Node_Dtor(&inGraph->mNode); //scprintf("<-Graph_Dtor\n"); } //////////////////////////////////////////////////////////////////////////////// int Graph_New(struct World *inWorld, struct GraphDef *inGraphDef, int32 inID, struct sc_msg_iter* args, Graph** outGraph,bool argtype)//true for normal args , false for setn type args { Graph* graph; int err = Node_New(inWorld, &inGraphDef->mNodeDef, inID, (Node**)&graph); if (err) return err; Graph_Ctor(inWorld, inGraphDef, graph, args,argtype); *outGraph = graph; return err; } void Graph_Ctor(World *inWorld, GraphDef *inGraphDef, Graph *graph, sc_msg_iter *msg,bool argtype)//true for normal args , false for setn type args { //scprintf("->Graph_Ctor\n"); // hit the memory allocator only once. char *memory = (char*)graph + sizeof(Graph); // allocate space for children uint32 numUnits = inGraphDef->mNumUnitSpecs; graph->mNumUnits = numUnits; inWorld->mNumUnits += numUnits; inWorld->mNumGraphs ++; graph->mUnits = (Unit**)memory; memory += inGraphDef->mUnitsAllocSize; // set calc func graph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_FirstCalc; // allocate wires graph->mNumWires = inGraphDef->mNumWires; graph->mWire = (Wire*)memory; memory += inGraphDef->mWiresAllocSize; graph->mNumCalcUnits = inGraphDef->mNumCalcUnits; graph->mCalcUnits = (Unit**)memory; memory += inGraphDef->mCalcUnitsAllocSize; // initialize controls uint32 numControls = inGraphDef->mNumControls; graph->mNumControls = numControls; graph->mControls = (float*)memory; memory += inGraphDef->mControlAllocSize; graph->mMapControls = (float**)memory; memory += inGraphDef->mMapControlsAllocSize; graph->mControlRates = (int*)memory; memory += inGraphDef->mMapControlRatesAllocSize; { float* graphControls = graph->mControls; float* initialControlValues = inGraphDef->mInitialControlValues; float** graphMapControls = graph->mMapControls; /* add */ int* graphControlRates = graph->mControlRates; for (uint32 i=0; i normal args as always //if argtype == false -> setn type args if(argtype) { while( msg->remain()>=8) { int i = 0; int loop = 0; if (msg->nextTag('i') == 's') { int32* name = msg->gets4(); int32 hash = Hash(name); do { switch (msg->nextTag('f') ) { case 'f' : case 'i' : { float32 value = msg->getf(); Graph_SetControl(graph, hash, name, i, value); break; } case 's' : { const char* string = msg->gets(); if ( *string == 'c') { int bus = sc_atoi(string+1); Graph_MapControl(graph, hash, name, i, bus); } else { if (*string == 'a') { int bus = sc_atoi(string+1); Graph_MapAudioControl(graph, hash, name, i, bus); } } break; } case ']': msg->count++; loop -= 1; break; case '[': msg->count++; loop += 1; i -= 1; break; } ++i; } while (loop); } else { int32 index = msg->geti(); do { switch (msg->nextTag('f') ) { case 'f' : case 'i' : { float32 value = msg->getf(); Graph_SetControl(graph, index + i, value); break; } case 's' : { const char* string = msg->gets(); if ( *string == 'c') { int bus = sc_atoi(string+1); Graph_MapControl(graph, index + i, bus); } else { if (*string == 'a') { int bus = sc_atoi(string+1); Graph_MapAudioControl(graph, index + i, bus); } } break; } case ']': msg->count++; loop -= 1; break; case '[': msg->count++; loop += 1; i -= 1; break; } ++i; } while (loop); } } } //{ // while( msg->remain()>=8) { // int i = 0; // int loop = 0; // if (msg->nextTag('i') == 's') { // int32* name = msg->gets4(); // int32 hash = Hash(name); // if (msg->nextTag('f') == '[' ) { // msg->count++; // loop = 1; // } // do { // if (msg->nextTag('f') == 's' ) { // const char* string = msg->gets(); // if ( *string == 'c') { // int bus = sc_atoi(string+1); // Graph_MapControl(graph, hash, name, i, bus); // } // } else { // if (msg->nextTag('f') == ']' ) { // msg->count++; // loop = 0; // } else { // float32 value = msg->getf(); // Graph_SetControl(graph, hash, name, i, value); // } // } // ++i; // } // while (loop); // } else { // int32 index = msg->geti(); // if (msg->nextTag('f') == '[' ) { // msg->count++; // loop = 1; // } // do { // if (msg->nextTag('f') == 's') { // const char* string = msg->gets(); // if (*string == 'c') { // int bus = sc_atoi(string+1); // Graph_MapControl(graph, index + i, bus); // } // } else { // if (msg->nextTag('f') == ']' ) { // msg->count++; // loop = 0; // } else { // float32 value = msg->getf(); // Graph_SetControl(graph, index + i, value); // } // } // ++i; // } // while (loop); // } // } // // } else{ while (msg->remain()) { if (msg->nextTag('i') == 's') { int32* name = msg->gets4(); int32 hash = Hash(name); int32 n = msg->geti(); for (int i=0; msg->remain() && inextTag('f') == 's') { const char* string = msg->gets(); if (*string == 'c') { int bus = sc_atoi(string+1); Graph_MapControl(graph, hash, name, i, bus); //Node_MapControl(node, hash, name, i, bus); } else { if (*string == 'a') { int bus = sc_atoi(string+1); Graph_MapAudioControl(graph, hash, name, i, bus); } } } else { float32 value = msg->getf(); Graph_SetControl(graph, hash, name, i, value); //Node_SetControl(node, hash, name, i, value); } } } else { int32 index = msg->geti(); int32 n = msg->geti(); for (int i=0; msg->remain() && inextTag('f') == 's') { const char* string = msg->gets(); if (*string == 'c') { int bus = sc_atoi(string+1); Graph_MapControl(graph, index+i, bus); //Node_MapControl(node, index+i, bus); } else { if (*string == 'a') { int bus = sc_atoi(string+1); Graph_MapAudioControl(graph, index + i, bus); } } } else { float32 value = msg->getf(); Graph_SetControl(graph, index+i, value); //Node_SetControl(node, index+i, value); } } } } } // set up scalar values Wire *graphWires = graph->mWire; int numConstants = inGraphDef->mNumConstants; { float *constants = inGraphDef->mConstants; Wire *wire = graphWires; for (int i=0; imFromUnit = 0; wire->mCalcRate = calc_ScalarRate; wire->mBuffer = &wire->mScalarValue; wire->mScalarValue = constants[i]; } } graph->mSampleOffset = inWorld->mSampleOffset; graph->mSubsampleOffset = inWorld->mSubsampleOffset; graph->mRGen = inWorld->mRGen; // defaults to rgen zero. graph->mLocalAudioBusUnit = NULL; graph->mLocalControlBusUnit = NULL; graph->localBufNum = 0; graph->localMaxBufNum = 0; // this is set from synth // initialize units //scprintf("initialize units\n"); Unit** calcUnits = graph->mCalcUnits; Unit** graphUnits = graph->mUnits; int calcCtr=0; float *bufspace = inWorld->hw->mWireBufSpace; uint32 wireCtr = numConstants; // never more than numConstants + numOutputs UnitSpec *unitSpec = inGraphDef->mUnitSpecs; for (uint32 i=0; imParent = graph; unit->mParentIndex = i; graphUnits[i] = unit; { // hook up unit inputs //scprintf("hook up unit inputs\n"); InputSpec *inputSpec = unitSpec->mInputSpec; Wire** unitInput = unit->mInput; float** unitInBuf = unit->mInBuf; uint32 numInputs = unitSpec->mNumInputs; for (uint32 j=0; jmWireIndex; unitInput[j] = wire; unitInBuf[j] = wire->mBuffer; } } { // hook up unit outputs //scprintf("hook up unit outputs\n"); Wire** unitOutput = unit->mOutput; float** unitOutBuf = unit->mOutBuf; uint32 numOutputs = unitSpec->mNumOutputs; Wire *wire = graphWires + wireCtr; wireCtr += numOutputs; int unitCalcRate = unit->mCalcRate; if (unitCalcRate == calc_FullRate) { OutputSpec *outputSpec = unitSpec->mOutputSpec; for (uint32 j=0; jmFromUnit = unit; wire->mCalcRate = calc_FullRate; wire->mBuffer = bufspace + outputSpec->mBufferIndex; unitOutput[j] = wire; unitOutBuf[j] = wire->mBuffer; } calcUnits[calcCtr++] = unit; } else { for (uint32 j=0; jmFromUnit = unit; wire->mCalcRate = unitCalcRate; wire->mBuffer = &wire->mScalarValue; unitOutput[j] = wire; unitOutBuf[j] = wire->mBuffer; } if (unitCalcRate == calc_BufRate) { calcUnits[calcCtr++] = unit; } } } } inGraphDef->mRefCount ++ ; } void Graph_FirstCalc(Graph *inGraph) { //scprintf("->Graph_FirstCalc\n"); uint32 numUnits = inGraph->mNumUnits; Unit **units = inGraph->mUnits; for (uint32 i=0; imUnitDef->mUnitCtorFunc)(unit); } //scprintf("<-Graph_FirstCalc\n"); inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_Calc; // now do actual graph calculation Graph_Calc(inGraph); } void Node_NullCalc(struct Node* /*inNode*/); void Graph_NullFirstCalc(Graph *inGraph) { //scprintf("->Graph_FirstCalc\n"); uint32 numUnits = inGraph->mNumUnits; Unit **units = inGraph->mUnits; for (uint32 i=0; imUnitDef->mUnitCtorFunc)(unit); } //scprintf("<-Graph_FirstCalc\n"); inGraph->mNode.mCalcFunc = &Node_NullCalc; } inline void Graph_Calc_unit(Unit * unit) { (unit->mCalcFunc)(unit, unit->mBufLength); } void Graph_Calc(Graph *inGraph) { //scprintf("->Graph_Calc\n"); uint32 numCalcUnits = inGraph->mNumCalcUnits; Unit **calcUnits = inGraph->mCalcUnits; int unroll8 = numCalcUnits / 8; int remain8 = numCalcUnits % 8; int i = 0; for (int j = 0; j!=unroll8; i += 8, ++j) { Graph_Calc_unit(calcUnits[i]); Graph_Calc_unit(calcUnits[i+1]); Graph_Calc_unit(calcUnits[i+2]); Graph_Calc_unit(calcUnits[i+3]); Graph_Calc_unit(calcUnits[i+4]); Graph_Calc_unit(calcUnits[i+5]); Graph_Calc_unit(calcUnits[i+6]); Graph_Calc_unit(calcUnits[i+7]); } int unroll4 = remain8 / 4; int remain4 = remain8 % 4; if (unroll4) { Graph_Calc_unit(calcUnits[i]); Graph_Calc_unit(calcUnits[i+1]); Graph_Calc_unit(calcUnits[i+2]); Graph_Calc_unit(calcUnits[i+3]); i+=4; } int unroll2 = remain4 / 2; int remain2 = remain4 % 2; if (unroll2) { Graph_Calc_unit(calcUnits[i]); Graph_Calc_unit(calcUnits[i+1]); i += 2; } if (remain2) Graph_Calc_unit(calcUnits[i]); //scprintf("<-Graph_Calc\n"); } void Graph_CalcTrace(Graph *inGraph); void Graph_CalcTrace(Graph *inGraph) { uint32 numCalcUnits = inGraph->mNumCalcUnits; Unit **calcUnits = inGraph->mCalcUnits; scprintf("\nTRACE %d %s #units: %d\n", inGraph->mNode.mID, inGraph->mNode.mDef->mName, numCalcUnits); for (uint32 i=0; imUnitDef->mUnitDefName); for (uint32 j=0; jmNumInputs; ++j) { scprintf(" %g", ZIN0(j)); } scprintf("\n"); (unit->mCalcFunc)(unit, unit->mBufLength); scprintf(" out"); for (uint32 j=0; jmNumOutputs; ++j) { scprintf(" %g", ZOUT0(j)); } scprintf("\n"); } inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_Calc; } void Graph_Trace(Graph *inGraph) { if (inGraph->mNode.mCalcFunc == (NodeCalcFunc)&Graph_Calc) { inGraph->mNode.mCalcFunc = (NodeCalcFunc)&Graph_CalcTrace; } } int Graph_GetControl(Graph* inGraph, uint32 inIndex, float& outValue) { if (inIndex >= GRAPHDEF(inGraph)->mNumControls) return kSCErr_IndexOutOfRange; outValue = inGraph->mControls[inIndex]; return kSCErr_None; } int Graph_GetControl(Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, float& outValue) { ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph); ParamSpec *spec = table->Get(inHash, inName); if (!spec || inIndex >= spec->mNumChannels) return kSCErr_IndexOutOfRange; return Graph_GetControl(inGraph, spec->mIndex + inIndex, outValue); } void Graph_SetControl(Graph* inGraph, uint32 inIndex, float inValue) { if (inIndex >= GRAPHDEF(inGraph)->mNumControls) return; inGraph->mControlRates[inIndex] = 0; float *ptr = inGraph->mControls + inIndex; inGraph->mMapControls[inIndex] = ptr; // unmap the control *ptr = inValue; } void Graph_SetControl(Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, float inValue) { ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph); ParamSpec *spec = table->Get(inHash, inName); if (!spec || inIndex >= spec->mNumChannels) return; //printf("setting: %s: to value %f\n", spec->mName, inValue); Graph_SetControl(inGraph, spec->mIndex + inIndex, inValue); } void Graph_MapControl(Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus) { ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph); ParamSpec *spec = table->Get(inHash, inName); if (!spec || inIndex >= spec->mNumChannels) return; //printf("mapping: %s: to bus index %i\n", spec->mName, inBus); Graph_MapControl(inGraph, spec->mIndex + inIndex, inBus); } void Graph_MapControl(Graph* inGraph, uint32 inIndex, uint32 inBus) { if (inIndex >= GRAPHDEF(inGraph)->mNumControls) return; World *world = inGraph->mNode.mWorld; if (inBus >= 0x80000000) { inGraph->mControlRates[inIndex] = 0; inGraph->mMapControls[inIndex] = inGraph->mControls + inIndex; } else if (inBus < world->mNumControlBusChannels) { inGraph->mControlRates[inIndex] = 1; inGraph->mMapControls[inIndex] = world->mControlBus + inBus; } } void Graph_MapAudioControl(Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus) { ParamSpecTable* table = GRAPH_PARAM_TABLE(inGraph); ParamSpec *spec = table->Get(inHash, inName); if (!spec || inIndex >= spec->mNumChannels) return; //printf("mapping: %s: to bus index %i\n", spec->mName, inBus); if (spec) Graph_MapAudioControl(inGraph, spec->mIndex + inIndex, inBus); } void Graph_MapAudioControl(Graph* inGraph, uint32 inIndex, uint32 inBus) { if (inIndex >= GRAPHDEF(inGraph)->mNumControls) return; World *world = inGraph->mNode.mWorld; /* what is the below doing??? it is unmapping by looking for negative ints */ if (inBus >= 0x80000000) { inGraph->mControlRates[inIndex] = 0; inGraph->mMapControls[inIndex] = inGraph->mControls + inIndex; } else if (inBus < world->mNumAudioBusChannels) { inGraph->mControlRates[inIndex] = 2; inGraph->mMapControls[inIndex] = world->mAudioBus + (inBus * world->mBufLength); } } SuperCollider-Source/server/scsynth/SC_GraphDef.cpp000644 000765 000024 00000070705 12756531745 023457 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef _WIN32 #include "SC_Win32Utils.h" #endif #include "clz.h" #include "SC_Graph.h" #include "SC_GraphDef.h" #include "SC_Wire.h" #include "SC_WireSpec.h" #include "SC_UnitSpec.h" #include "SC_UnitDef.h" #include "SC_HiddenWorld.h" #include "SC_WorldOptions.h" #include "ReadWriteMacros.h" #include "SC_Prototypes.h" #include "SC_CoreAudio.h" #include "SC_DirUtils.h" #include #include #include #include #include extern Malloc gMalloc; int32 GetHash(ParamSpec* inParamSpec) { return inParamSpec->mHash; } int32* GetKey(ParamSpec* inParamSpec) { return inParamSpec->mName; } void ReadName(char*& buffer, int32* name); void ReadName(char*& buffer, int32* name) { uint32 namelen = readUInt8(buffer); if (namelen >= kSCNameByteLen) { std::ostringstream os; os << "name too long (> " << kSCNameByteLen - 1 << " chars): " << std::string(buffer, namelen); throw std::runtime_error(os.str()); } memset(name, 0, kSCNameByteLen); readData(buffer, (char*)name, namelen); } void ReadNodeDefName(char*& buffer, int32* name); void ReadNodeDefName(char*& buffer, int32* name) { uint32 namelen = readUInt8(buffer); if (namelen >= kSCNodeDefNameByteLen) { std::ostringstream os; os << "node definition name too long (> " << kSCNodeDefNameByteLen - 1 << " chars): " << std::string(buffer, namelen); throw std::runtime_error(os.str()); } memset(name, 0, kSCNodeDefNameByteLen); readData(buffer, (char*)name, namelen); } void ParamSpec_Read(ParamSpec* inParamSpec, char*& buffer); void ParamSpec_Read(ParamSpec* inParamSpec, char*& buffer) { ReadName(buffer, inParamSpec->mName); inParamSpec->mIndex = readInt32_be(buffer); inParamSpec->mHash = Hash(inParamSpec->mName); } void ParamSpec_ReadVer1(ParamSpec* inParamSpec, char*& buffer); void ParamSpec_ReadVer1(ParamSpec* inParamSpec, char*& buffer) { ReadName(buffer, inParamSpec->mName); inParamSpec->mIndex = readInt16_be(buffer); inParamSpec->mHash = Hash(inParamSpec->mName); } void InputSpec_Read(InputSpec* inInputSpec, char*& buffer); void InputSpec_Read(InputSpec* inInputSpec, char*& buffer) { inInputSpec->mFromUnitIndex = readInt32_be(buffer); inInputSpec->mFromOutputIndex = readInt32_be(buffer); inInputSpec->mWireIndex = -1; } void InputSpec_ReadVer1(InputSpec* inInputSpec, char*& buffer); void InputSpec_ReadVer1(InputSpec* inInputSpec, char*& buffer) { inInputSpec->mFromUnitIndex = (int16)readInt16_be(buffer); inInputSpec->mFromOutputIndex = (int16)readInt16_be(buffer); inInputSpec->mWireIndex = -1; } void OutputSpec_Read(OutputSpec* inOutputSpec, char*& buffer); void OutputSpec_Read(OutputSpec* inOutputSpec, char*& buffer) { inOutputSpec->mCalcRate = readInt8(buffer); inOutputSpec->mWireIndex = -1; inOutputSpec->mBufferIndex = -1; inOutputSpec->mNumConsumers = 0; } void UnitSpec_Read(UnitSpec* inUnitSpec, char*& buffer); void UnitSpec_Read(UnitSpec* inUnitSpec, char*& buffer) { int32 name[kSCNameLen]; ReadName(buffer, name); inUnitSpec->mUnitDef = GetUnitDef(name); if (!inUnitSpec->mUnitDef) { char str[256]; sprintf(str, "UGen '%s' not installed.", (char*)name); throw std::runtime_error(str); return; } inUnitSpec->mCalcRate = readInt8(buffer); inUnitSpec->mNumInputs = readInt32_be(buffer); inUnitSpec->mNumOutputs = readInt32_be(buffer); inUnitSpec->mSpecialIndex = readInt16_be(buffer); inUnitSpec->mInputSpec = (InputSpec*)malloc(sizeof(InputSpec) * inUnitSpec->mNumInputs); inUnitSpec->mOutputSpec = (OutputSpec*)malloc(sizeof(OutputSpec) * inUnitSpec->mNumOutputs); for (uint32 i=0; imNumInputs; ++i) { InputSpec_Read(inUnitSpec->mInputSpec + i, buffer); } for (uint32 i=0; imNumOutputs; ++i) { OutputSpec_Read(inUnitSpec->mOutputSpec + i, buffer); } uint64 numPorts = inUnitSpec->mNumInputs + inUnitSpec->mNumOutputs; inUnitSpec->mAllocSize = inUnitSpec->mUnitDef->mAllocSize + numPorts * (sizeof(Wire*) + sizeof(float*)); } void UnitSpec_ReadVer1(UnitSpec* inUnitSpec, char*& buffer); void UnitSpec_ReadVer1(UnitSpec* inUnitSpec, char*& buffer) { int32 name[kSCNameLen]; ReadName(buffer, name); inUnitSpec->mUnitDef = GetUnitDef(name); if (!inUnitSpec->mUnitDef) { char str[256]; sprintf(str, "UGen '%s' not installed.", (char*)name); throw std::runtime_error(str); return; } inUnitSpec->mCalcRate = readInt8(buffer); inUnitSpec->mNumInputs = readInt16_be(buffer); inUnitSpec->mNumOutputs = readInt16_be(buffer); inUnitSpec->mSpecialIndex = readInt16_be(buffer); inUnitSpec->mInputSpec = (InputSpec*)malloc(sizeof(InputSpec) * inUnitSpec->mNumInputs); inUnitSpec->mOutputSpec = (OutputSpec*)malloc(sizeof(OutputSpec) * inUnitSpec->mNumOutputs); for (uint32 i=0; imNumInputs; ++i) { InputSpec_ReadVer1(inUnitSpec->mInputSpec + i, buffer); } for (uint32 i=0; imNumOutputs; ++i) { OutputSpec_Read(inUnitSpec->mOutputSpec + i, buffer); } uint64 numPorts = inUnitSpec->mNumInputs + inUnitSpec->mNumOutputs; inUnitSpec->mAllocSize = inUnitSpec->mUnitDef->mAllocSize + numPorts * (sizeof(Wire*) + sizeof(float*)); } GraphDef* GraphDef_Read(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion); GraphDef* GraphDef_ReadVer1(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion); GraphDef* GraphDefLib_Read(World *inWorld, char* buffer, GraphDef* inList); GraphDef* GraphDefLib_Read(World *inWorld, char* buffer, GraphDef* inList) { int32 magic = readInt32_be(buffer); if (magic != (('S'<<24)|('C'<<16)|('g'<<8)|'f') /*'SCgf'*/) return inList; int32 version = readInt32_be(buffer); uint32 numDefs, i; switch (version) { case 2: numDefs = readInt16_be(buffer); for (i=0; imNumVariants = 0; inVariant->mVariants = 0; ReadName(buffer, inVariant->mNodeDef.mName); inVariant->mNodeDef.mHash = Hash(inVariant->mNodeDef.mName); inVariant->mInitialControlValues = (float32*)malloc(sizeof(float32) * inGraphDef->mNumControls); for (uint32 i=0; imNumControls; ++i) { inVariant->mInitialControlValues[i] = readFloat_be(buffer); } } typedef struct IndexMap { uint32 index; uint32 paramSpecIndex; } IndexMap; static inline bool sortIndexMaps(IndexMap map1, IndexMap map2) { return map1.paramSpecIndex < map2.paramSpecIndex; } // ver 2 inline static void calcParamSpecs(GraphDef* graphDef, char*& buffer) { if (graphDef->mNumParamSpecs) { int hashTableSize = NEXTPOWEROFTWO(graphDef->mNumParamSpecs); graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, hashTableSize, false); uint32 nSpecs = graphDef->mNumParamSpecs; graphDef->mParamSpecs = (ParamSpec*)malloc(nSpecs * sizeof(ParamSpec)); IndexMap *tempMaps = (IndexMap*)malloc(nSpecs * sizeof(IndexMap)); for (uint32 i=0; imParamSpecs + i; ParamSpec_Read(paramSpec, buffer); graphDef->mParamSpecTable->Add(paramSpec); IndexMap *tempMap = tempMaps + i; tempMap->index = i; tempMap->paramSpecIndex = paramSpec->mIndex; } // calculate numChannels for each spec // printf("\n\n**************\n"); std::sort(tempMaps, tempMaps + nSpecs, sortIndexMaps); for (uint32 i=0; i<(nSpecs - 1); ++i) { IndexMap *tempMap = tempMaps + i; IndexMap *nextTempMap = tempMap + 1; ParamSpec *paramSpec = graphDef->mParamSpecs + tempMap->index; paramSpec->mNumChannels = nextTempMap->paramSpecIndex - tempMap->paramSpecIndex; // printf("%s: numChannels = %i\n", paramSpec->mName, paramSpec->mNumChannels); } IndexMap *tempMap = tempMaps + nSpecs - 1; ParamSpec *paramSpec = graphDef->mParamSpecs + tempMap->index; paramSpec->mNumChannels = graphDef->mNumControls - tempMap->paramSpecIndex; // printf("%s: numChannels = %i\n", paramSpec->mName, paramSpec->mNumChannels, paramSpec->mIndex); free(tempMaps); } else { // empty table to eliminate test in Graph_SetControl graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, 4, false); graphDef->mParamSpecs = 0; } } // ver 1 inline static void calcParamSpecs1(GraphDef* graphDef, char*& buffer) { if (graphDef->mNumParamSpecs) { int hashTableSize = NEXTPOWEROFTWO(graphDef->mNumParamSpecs); graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, hashTableSize, false); uint32 nSpecs = graphDef->mNumParamSpecs; graphDef->mParamSpecs = (ParamSpec*)malloc(nSpecs * sizeof(ParamSpec)); IndexMap *tempMaps = (IndexMap*)malloc(nSpecs * sizeof(IndexMap)); for (uint32 i=0; imParamSpecs + i; ParamSpec_ReadVer1(paramSpec, buffer); // read version 1 (the only difference to ver 2). graphDef->mParamSpecTable->Add(paramSpec); IndexMap *tempMap = tempMaps + i; tempMap->index = i; tempMap->paramSpecIndex = paramSpec->mIndex; } // calculate numChannels for each spec // printf("\n\n**************\n"); std::sort(tempMaps, tempMaps + nSpecs, sortIndexMaps); for (uint32 i=0; i<(nSpecs - 1); ++i) { IndexMap *tempMap = tempMaps + i; IndexMap *nextTempMap = tempMap + 1; ParamSpec *paramSpec = graphDef->mParamSpecs + tempMap->index; paramSpec->mNumChannels = nextTempMap->paramSpecIndex - tempMap->paramSpecIndex; // printf("%s: numChannels = %i\n", paramSpec->mName, paramSpec->mNumChannels); } IndexMap *tempMap = tempMaps + nSpecs - 1; ParamSpec *paramSpec = graphDef->mParamSpecs + tempMap->index; paramSpec->mNumChannels = graphDef->mNumControls - tempMap->paramSpecIndex; // printf("%s: numChannels = %i\n", paramSpec->mName, paramSpec->mNumChannels, paramSpec->mIndex); free(tempMaps); } else { // empty table to eliminate test in Graph_SetControl graphDef->mParamSpecTable = new ParamSpecTable(&gMalloc, 4, false); graphDef->mParamSpecs = 0; } } // ver 2 GraphDef* GraphDef_Read(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion) { int32 name[kSCNodeDefNameLen]; ReadNodeDefName(buffer, name); GraphDef* graphDef = (GraphDef*)calloc(1, sizeof(GraphDef)); graphDef->mOriginal = graphDef; graphDef->mNodeDef.mAllocSize = sizeof(Graph); memcpy((char*)graphDef->mNodeDef.mName, (char*)name, kSCNodeDefNameByteLen); graphDef->mNodeDef.mHash = Hash(graphDef->mNodeDef.mName); graphDef->mNumConstants = readInt32_be(buffer); graphDef->mConstants = (float*)malloc(graphDef->mNumConstants * sizeof(float)); for (uint32 i=0; imNumConstants; ++i) { graphDef->mConstants[i] = readFloat_be(buffer); } graphDef->mNumControls = readInt32_be(buffer); graphDef->mInitialControlValues = (float32*)malloc(sizeof(float32) * graphDef->mNumControls); for (uint32 i=0; imNumControls; ++i) { graphDef->mInitialControlValues[i] = readFloat_be(buffer); } graphDef->mNumParamSpecs = readInt32_be(buffer); calcParamSpecs(graphDef, buffer); graphDef->mNumWires = graphDef->mNumConstants; graphDef->mNumUnitSpecs = readInt32_be(buffer); graphDef->mUnitSpecs = (UnitSpec*)malloc(sizeof(UnitSpec) * graphDef->mNumUnitSpecs); graphDef->mNumCalcUnits = 0; for (uint32 i=0; imNumUnitSpecs; ++i) { UnitSpec *unitSpec = graphDef->mUnitSpecs + i; UnitSpec_Read(unitSpec, buffer); switch (unitSpec->mCalcRate) { case calc_ScalarRate : unitSpec->mRateInfo = &inWorld->mBufRate; break; case calc_BufRate : graphDef->mNumCalcUnits++; unitSpec->mRateInfo = &inWorld->mBufRate; break; case calc_FullRate : graphDef->mNumCalcUnits++; unitSpec->mRateInfo = &inWorld->mFullRate; break; case calc_DemandRate : unitSpec->mRateInfo = &inWorld->mBufRate; break; } graphDef->mNodeDef.mAllocSize += unitSpec->mAllocSize; graphDef->mNumWires += unitSpec->mNumOutputs; } DoBufferColoring(inWorld, graphDef); graphDef->mWiresAllocSize = graphDef->mNumWires * sizeof(Wire); graphDef->mUnitsAllocSize = graphDef->mNumUnitSpecs * sizeof(Unit*); graphDef->mCalcUnitsAllocSize = graphDef->mNumCalcUnits * sizeof(Unit*); graphDef->mNodeDef.mAllocSize += graphDef->mWiresAllocSize; graphDef->mNodeDef.mAllocSize += graphDef->mUnitsAllocSize; graphDef->mNodeDef.mAllocSize += graphDef->mCalcUnitsAllocSize; graphDef->mControlAllocSize = graphDef->mNumControls * sizeof(float); graphDef->mNodeDef.mAllocSize += graphDef->mControlAllocSize; graphDef->mMapControlsAllocSize = graphDef->mNumControls * sizeof(float*); graphDef->mNodeDef.mAllocSize += graphDef->mMapControlsAllocSize; graphDef->mMapControlRatesAllocSize = graphDef->mNumControls * sizeof(int*); graphDef->mNodeDef.mAllocSize += graphDef->mMapControlRatesAllocSize; graphDef->mNext = inList; graphDef->mRefCount = 1; graphDef->mNumVariants = readInt16_be(buffer); if (graphDef->mNumVariants) { graphDef->mVariants = (GraphDef*)calloc(graphDef->mNumVariants, sizeof(GraphDef)); for (uint32 i=0; imNumVariants; ++i) { GraphDef_ReadVariant(inWorld, buffer, graphDef, graphDef->mVariants + i); } } return graphDef; } // ver 0 or 1 GraphDef* GraphDef_ReadVer1(World *inWorld, char*& buffer, GraphDef* inList, int32 inVersion) { int32 name[kSCNodeDefNameLen]; ReadNodeDefName(buffer, name); GraphDef* graphDef = (GraphDef*)calloc(1, sizeof(GraphDef)); graphDef->mOriginal = graphDef; graphDef->mNodeDef.mAllocSize = sizeof(Graph); memcpy((char*)graphDef->mNodeDef.mName, (char*)name, kSCNodeDefNameByteLen); graphDef->mNodeDef.mHash = Hash(graphDef->mNodeDef.mName); graphDef->mNumConstants = readInt16_be(buffer); graphDef->mConstants = (float*)malloc(graphDef->mNumConstants * sizeof(float)); for (uint32 i=0; imNumConstants; ++i) { graphDef->mConstants[i] = readFloat_be(buffer); } graphDef->mNumControls = readInt16_be(buffer); graphDef->mInitialControlValues = (float32*)malloc(sizeof(float32) * graphDef->mNumControls); for (uint32 i=0; imNumControls; ++i) { graphDef->mInitialControlValues[i] = readFloat_be(buffer); } graphDef->mNumParamSpecs = readInt16_be(buffer); calcParamSpecs1(graphDef, buffer); graphDef->mNumWires = graphDef->mNumConstants; graphDef->mNumUnitSpecs = readInt16_be(buffer); graphDef->mUnitSpecs = (UnitSpec*)malloc(sizeof(UnitSpec) * graphDef->mNumUnitSpecs); graphDef->mNumCalcUnits = 0; for (uint32 i=0; imNumUnitSpecs; ++i) { UnitSpec *unitSpec = graphDef->mUnitSpecs + i; UnitSpec_ReadVer1(unitSpec, buffer); switch (unitSpec->mCalcRate) { case calc_ScalarRate : unitSpec->mRateInfo = &inWorld->mBufRate; break; case calc_BufRate : graphDef->mNumCalcUnits++; unitSpec->mRateInfo = &inWorld->mBufRate; break; case calc_FullRate : graphDef->mNumCalcUnits++; unitSpec->mRateInfo = &inWorld->mFullRate; break; case calc_DemandRate : unitSpec->mRateInfo = &inWorld->mBufRate; break; } graphDef->mNodeDef.mAllocSize += unitSpec->mAllocSize; graphDef->mNumWires += unitSpec->mNumOutputs; } DoBufferColoring(inWorld, graphDef); graphDef->mWiresAllocSize = graphDef->mNumWires * sizeof(Wire); graphDef->mUnitsAllocSize = graphDef->mNumUnitSpecs * sizeof(Unit*); graphDef->mCalcUnitsAllocSize = graphDef->mNumCalcUnits * sizeof(Unit*); graphDef->mNodeDef.mAllocSize += graphDef->mWiresAllocSize; graphDef->mNodeDef.mAllocSize += graphDef->mUnitsAllocSize; graphDef->mNodeDef.mAllocSize += graphDef->mCalcUnitsAllocSize; graphDef->mControlAllocSize = graphDef->mNumControls * sizeof(float); graphDef->mNodeDef.mAllocSize += graphDef->mControlAllocSize; graphDef->mMapControlsAllocSize = graphDef->mNumControls * sizeof(float*); graphDef->mNodeDef.mAllocSize += graphDef->mMapControlsAllocSize; graphDef->mMapControlRatesAllocSize = graphDef->mNumControls * sizeof(int*); graphDef->mNodeDef.mAllocSize += graphDef->mMapControlRatesAllocSize; graphDef->mNext = inList; graphDef->mRefCount = 1; if (inVersion >= 1) { graphDef->mNumVariants = readInt16_be(buffer); if (graphDef->mNumVariants) { graphDef->mVariants = (GraphDef*)calloc(graphDef->mNumVariants, sizeof(GraphDef)); for (uint32 i=0; imNumVariants; ++i) { GraphDef_ReadVariant(inWorld, buffer, graphDef, graphDef->mVariants + i); } } } return graphDef; } void GraphDef_Define(World *inWorld, GraphDef *inList) { GraphDef *graphDef = inList; while (graphDef) { GraphDef *next = graphDef->mNext; GraphDef* previousDef = World_GetGraphDef(inWorld, graphDef->mNodeDef.mName); if (previousDef) { World_RemoveGraphDef(inWorld, previousDef); if (--previousDef->mRefCount == 0) { GraphDef_DeleteMsg(inWorld, previousDef); } } World_AddGraphDef(inWorld, graphDef); graphDef->mNext = 0; graphDef = next; } } #include "SC_SequencedCommand.h" #include "SC_Errors.h" SCErr GraphDef_Remove(World *inWorld, int32 *inName) { GraphDef* graphDef = World_GetGraphDef(inWorld, inName); if (graphDef) { World_RemoveGraphDef(inWorld, graphDef); if (--graphDef->mRefCount == 0) { return GraphDef_DeleteMsg(inWorld, graphDef); } } return kSCErr_None; } SCErr SendReplyCmd_d_removed(World * inWorld,int inSize,char* inData, ReplyAddress *inReply) { void* space = World_Alloc(inWorld, sizeof(SendReplyCmd)); SendReplyCmd *cmd = new (space) SendReplyCmd(inWorld, inReply); if (!cmd) return kSCErr_Failed; int err = cmd->Init(inData, inSize); if (err) { cmd->~SendReplyCmd(); World_Free(inWorld, space); return err; } if (inWorld->mRealTime) cmd->CallNextStage(); else cmd->CallEveryStage(); return kSCErr_None; } SCErr GraphDef_DeleteMsg(World *inWorld, GraphDef *inDef) { DeleteGraphDefMsg msg; msg.mDef = inDef; inWorld->hw->mDeleteGraphDefs.Write(msg); small_scpacket packet; packet.adds("/d_removed"); packet.maketags(2); packet.addtag(','); packet.addtag('s'); packet.adds((char*)inDef->mNodeDef.mName); ReplyAddress *users = inWorld->hw->mUsers; int numUsers = inWorld->hw->mNumUsers; for (int i=0; i GraphDef_Load(inWorld, filename, inList); } sc_GlobFree(glob); return inList; } GraphDef* GraphDef_Load(World *inWorld, const char *filename, GraphDef *inList) { FILE *file = fopen(filename, "rb"); if (!file) { scprintf("*** ERROR: can't fopen '%s'\n", filename); return inList; } fseek(file, 0, SEEK_END); int size = ftell(file); char *buffer = (char*)malloc(size); if (!buffer) { scprintf("*** ERROR: can't malloc buffer size %d\n", size); fclose(file); return inList; } fseek(file, 0, SEEK_SET); size_t readSize = fread(buffer, 1, size, file); fclose(file); if (readSize!= size) { scprintf("*** ERROR: invalid fread\n", size); free(buffer); return inList; } try { inList = GraphDefLib_Read(inWorld, buffer, inList); } catch (std::exception& exc) { scprintf("exception in GrafDef_Load: %s\n", exc.what()); scprintf("while reading file '%s'\n", filename); } catch (...) { scprintf("unknown exception in GrafDef_Load\n"); scprintf("while reading file '%s'\n", filename); } free(buffer); return inList; } GraphDef* GraphDef_LoadDir(World *inWorld, char *dirname, GraphDef *inList) { SC_DirHandle *dir = sc_OpenDir(dirname); if (!dir) { scprintf("*** ERROR: open directory failed '%s'\n", dirname); return inList; } for (;;) { char diritem[MAXPATHLEN]; bool skipItem = false; bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem); if (!validItem) break; if (skipItem) continue; if (sc_DirectoryExists(diritem)) { inList = GraphDef_LoadDir(inWorld, diritem, inList); } else { int dnamelen = strlen(diritem); if (strncmp(diritem+dnamelen-9, ".scsyndef", 9) == 0) { inList = GraphDef_Load(inWorld, diritem, inList); } } } sc_CloseDir(dir); return inList; } void UnitSpec_Free(UnitSpec *inUnitSpec); void UnitSpec_Free(UnitSpec *inUnitSpec) { free(inUnitSpec->mInputSpec); free(inUnitSpec->mOutputSpec); } void GraphDef_Free(GraphDef *inGraphDef) { if (inGraphDef != inGraphDef->mOriginal) return; for (uint32 i=0; imNumUnitSpecs; ++i) { UnitSpec_Free(inGraphDef->mUnitSpecs + i); } for (uint32 i=0; imNumVariants; ++i) { free(inGraphDef->mVariants[i].mInitialControlValues); } delete inGraphDef->mParamSpecTable; free(inGraphDef->mParamSpecs); free(inGraphDef->mInitialControlValues); free(inGraphDef->mConstants); free(inGraphDef->mUnitSpecs); free(inGraphDef->mVariants); free(inGraphDef); } void NodeDef_Dump(NodeDef *inNodeDef) { scprintf("mName '%s'\n", (char*)inNodeDef->mName); scprintf("mHash %d\n", inNodeDef->mHash); scprintf("mAllocSize %lu\n", inNodeDef->mAllocSize); } void GraphDef_Dump(GraphDef *inGraphDef) { NodeDef_Dump(&inGraphDef->mNodeDef); scprintf("mNumControls %d\n", inGraphDef->mNumControls); scprintf("mNumWires %d\n", inGraphDef->mNumWires); scprintf("mNumUnitSpecs %d\n", inGraphDef->mNumUnitSpecs); scprintf("mNumWireBufs %d\n", inGraphDef->mNumWireBufs); for (uint32 i=0; imNumControls; ++i) { scprintf(" %d mInitialControlValues %g\n", i, inGraphDef->mInitialControlValues[i]); } for (uint32 i=0; imNumWires; ++i) { //WireSpec_Dump(inGraphDef->mWireSpec + i); } for (uint32 i=0; imNumUnitSpecs; ++i) { //UnitSpec_Dump(inGraphDef->mUnitSpecs + i); } } /* SynthBufferAllocator { var nextBufIndex = 0; var stack; var refs; *new { ^super.new.init } init { refs = Bag.new; } alloc { arg count; var bufNumber; if (stack.size > 0, { bufNumber = stack.pop },{ bufNumber = nextBufIndex; nextBufIndex = nextBufIndex + 1; }); refs.add(bufNumber, count); ^bufNumber } release { arg bufNumber; refs.remove(bufNumber); if (refs.includes(bufNumber).not, { stack = stack.add(bufNumber) }); } numBufs { ^nextBufIndex } } */ struct BufColorAllocator { int16 *refs; int16 *stack; int16 stackPtr; int16 nextIndex; int16 refsMaxSize; int16 stackMaxSize; BufColorAllocator(); ~BufColorAllocator(); uint32 alloc(uint32 count); bool release(int inIndex); int NumBufs() { return nextIndex; } }; inline BufColorAllocator::BufColorAllocator() { refsMaxSize = 32; stackMaxSize = 32; refs = (int16*)calloc(refsMaxSize, sizeof(int16)); stack = (int16*)calloc(stackMaxSize, sizeof(int16)); stackPtr = 0; nextIndex = 0; } inline BufColorAllocator::~BufColorAllocator() { free(refs); free(stack); } inline uint32 BufColorAllocator::alloc(uint32 count) { uint32 outIndex; if (stackPtr) { outIndex = stack[--stackPtr]; } else { outIndex = nextIndex++; } if (outIndex >= refsMaxSize) { refs = (int16*)realloc(refs, refsMaxSize*2*sizeof(int16)); memset(refs + refsMaxSize, 0, refsMaxSize*sizeof(int16)); refsMaxSize *= 2; } refs[outIndex] = count; return outIndex; } inline bool BufColorAllocator::release(int inIndex) { if (refs[inIndex] == 0) return false; if (--refs[inIndex] == 0) { if (stackPtr >= stackMaxSize) { stack = (int16*)realloc(stack, stackMaxSize*2*sizeof(int16)); memset(stack + stackMaxSize, 0, stackMaxSize*sizeof(int16)); stackMaxSize *= 2; } stack[stackPtr++] = inIndex; } return true; } static void ReleaseInputBuffers(GraphDef *inGraphDef, UnitSpec *unitSpec, BufColorAllocator& bufColor) { for (int64 i=(int64)(unitSpec->mNumInputs)-1; i>=0; --i) { InputSpec *inputSpec = unitSpec->mInputSpec + i; if (inputSpec->mFromUnitIndex >= 0) { UnitSpec *outUnit = inGraphDef->mUnitSpecs + inputSpec->mFromUnitIndex; OutputSpec *outputSpec = outUnit->mOutputSpec + inputSpec->mFromOutputIndex; inputSpec->mWireIndex = outputSpec->mWireIndex; if (outputSpec->mCalcRate == calc_FullRate) { if (unitSpec->mCalcRate == calc_DemandRate) // we never release any input buffers of demand-rate ugens continue; if (!bufColor.release(outputSpec->mBufferIndex)) { scprintf("buffer coloring error: tried to release output with zero count\n"); scprintf("output: %d %s %d\n", inputSpec->mFromUnitIndex, outUnit->mUnitDef->mUnitDefName, inputSpec->mFromOutputIndex); scprintf("input: %s %d\n", unitSpec->mUnitDef->mUnitDefName, i); throw std::runtime_error("buffer coloring error."); } } } else { inputSpec->mWireIndex = inputSpec->mFromOutputIndex; } } } static void AllocOutputBuffers(UnitSpec *unitSpec, BufColorAllocator& bufColor, int32& wireIndexCtr) { //scprintf("AllocOutputBuffers %s numoutputs %d\n", unitSpec->mUnitDef->mUnitDefName, unitSpec->mNumOutputs); for (uint32 i=0; imNumOutputs; ++i) { OutputSpec *outputSpec = unitSpec->mOutputSpec + i; outputSpec->mWireIndex = wireIndexCtr++; if (outputSpec->mCalcRate == calc_FullRate) { uint32 bufIndex = bufColor.alloc(outputSpec->mNumConsumers); outputSpec->mBufferIndex = bufIndex; } } } void DoBufferColoring(World *inWorld, GraphDef *inGraphDef) { // count consumers of outputs for (uint32 j=0; jmNumUnitSpecs; ++j) { UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j; for (uint32 i=0; imNumInputs; ++i) { InputSpec *inputSpec = unitSpec->mInputSpec + i; if (inputSpec->mFromUnitIndex >= 0) { UnitSpec *outUnit = inGraphDef->mUnitSpecs + inputSpec->mFromUnitIndex; OutputSpec *outputSpec = outUnit->mOutputSpec + inputSpec->mFromOutputIndex; outputSpec->mNumConsumers ++; } } } // buffer coloring { BufColorAllocator bufColor; int32 wireIndexCtr = inGraphDef->mNumConstants; // mNumConstants is a uint32, but limited to int32 in OSC for (uint32 j=0; jmNumUnitSpecs; ++j) { UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j; if (unitSpec->mUnitDef->mFlags & kUnitDef_CantAliasInputsToOutputs) { // set wire index, alloc outputs AllocOutputBuffers(unitSpec, bufColor, wireIndexCtr); // set wire index, release inputs ReleaseInputBuffers(inGraphDef, unitSpec, bufColor); } else { // set wire index, release inputs ReleaseInputBuffers(inGraphDef, unitSpec, bufColor); // set wire index, alloc outputs AllocOutputBuffers(unitSpec, bufColor, wireIndexCtr); } } inGraphDef->mNumWireBufs = bufColor.NumBufs(); if (inWorld->mRunning) { // cannot reallocate interconnect buffers while running audio. if (inGraphDef->mNumWireBufs > inWorld->hw->mMaxWireBufs) { throw std::runtime_error("exceeded number of interconnect buffers."); } } else { inWorld->hw->mMaxWireBufs = sc_max(inWorld->hw->mMaxWireBufs, inGraphDef->mNumWireBufs); } } // multiply buf indices by buf length for proper offset int bufLength = inWorld->mBufLength; for (uint32 j=0; jmNumUnitSpecs; ++j) { UnitSpec *unitSpec = inGraphDef->mUnitSpecs + j; for (uint32 i=0; imNumOutputs; ++i) { OutputSpec *outputSpec = unitSpec->mOutputSpec + i; if (outputSpec->mCalcRate == calc_FullRate) { outputSpec->mBufferIndex *= bufLength; } } } } SuperCollider-Source/server/scsynth/SC_GraphDef.h000644 000765 000024 00000004475 12756531745 023125 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_GraphDef_ #define _SC_GraphDef_ #include "SC_SynthDef.h" #include "HashTable.h" struct ParamSpec { int32 mName[kSCNameLen]; int32 mIndex; int32 mHash; int32 mNumChannels; }; typedef HashTable ParamSpecTable; struct GraphDef { NodeDef mNodeDef; uint32 mNumControls; uint32 mNumAudioControls; uint32 mNumWires; uint32 mNumConstants; uint32 mNumUnitSpecs; uint32 mNumWireBufs; uint32 mNumCalcUnits; float32 *mInitialControlValues; float32 *mConstants; struct UnitSpec *mUnitSpecs; size_t mWiresAllocSize, mUnitsAllocSize, mCalcUnitsAllocSize; size_t mControlAllocSize, mMapControlsAllocSize, mMapControlRatesAllocSize; uint32 mNumParamSpecs; ParamSpec *mParamSpecs; ParamSpecTable *mParamSpecTable; int mRefCount; struct GraphDef* mNext; struct GraphDef *mOriginal; uint32 mNumVariants; struct GraphDef* mVariants; }; typedef struct GraphDef GraphDef; GraphDef* GraphDef_Recv(World *inWorld, char *buffer, GraphDef *inList); GraphDef* GraphDef_Load(struct World *inWorld, const char *filename, GraphDef* inList); GraphDef* GraphDef_LoadDir(struct World *inWorld, char *dirname, GraphDef* inList); GraphDef* GraphDef_LoadGlob(World *inWorld, const char *pattern, GraphDef *inList); SCErr GraphDef_Remove(World *inWorld, int32 *inName); SCErr GraphDef_DeleteMsg(struct World *inWorld, GraphDef *inDef); void GraphDef_Dump(GraphDef *inGraphDef); int32 GetHash(ParamSpec* inParamSpec); int32* GetKey(ParamSpec* inParamSpec); #endif SuperCollider-Source/server/scsynth/SC_Group.cpp000644 000765 000024 00000030577 12756531745 023076 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Group.h" #include "SC_GraphDef.h" #include "Hash.h" #include "sc_msg_iter.h" #include #include #include "SC_Prototypes.h" #include "SC_Str4.h" #include "SC_World.h" #include "SC_WorldOptions.h" #include "SC_Errors.h" #include "scsynthsend.h" NodeDef gGroupNodeDef; void Group_Dtor(Group *inGroup) { Group_DeleteAll(inGroup); inGroup->mNode.mWorld->mNumGroups--; Node_Dtor(&inGroup->mNode); } void GroupNodeDef_Init() { str4cpy(gGroupNodeDef.mName, "group"); gGroupNodeDef.mHash = Hash(gGroupNodeDef.mName); gGroupNodeDef.mAllocSize = sizeof(Group); } int Group_New(World *inWorld, int32 inID, Group** outGroup) { Group *group; int err = Node_New(inWorld, &gGroupNodeDef, inID, (Node**)&group); if (err) return err; group->mNode.mCalcFunc = (NodeCalcFunc)&Group_Calc; group->mNode.mIsGroup = true; group->mHead = 0; group->mTail = 0; inWorld->mNumGroups++; *outGroup = group; return kSCErr_None; } void Group_Calc(Group *inGroup) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; (*child->mCalcFunc)(child); child = next; } } void Group_CalcTrace(Group *inGroup) { scprintf("TRACE Group %d\n", inGroup->mNode.mID); Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; scprintf(" %d %s\n", child->mID, (char*)child->mDef->mName); (*child->mCalcFunc)(child); child = next; } inGroup->mNode.mCalcFunc = (NodeCalcFunc)&Group_Calc; } void Group_Trace(Group *inGroup) { if (inGroup->mNode.mCalcFunc == (NodeCalcFunc)&Group_Calc) { inGroup->mNode.mCalcFunc = (NodeCalcFunc)&Group_CalcTrace; } } void Group_DumpNodeTree(Group *inGroup) { static int tabCount = 0; if(tabCount == 0) scprintf("NODE TREE Group %d\n", inGroup->mNode.mID); tabCount++; Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; for(int i = 0; i < tabCount; i ++) scprintf(" "); // small 'tabs' scprintf("%d %s\n", child->mID, (char*)child->mDef->mName); if (child->mIsGroup) { Group_DumpTree((Group*)child); } (*child->mCalcFunc)(child); child = next; } tabCount--; } void Group_DumpNodeTreeAndControls(Group *inGroup) { static int tabCount = 0; if(tabCount == 0) scprintf("NODE TREE Group %d\n", inGroup->mNode.mID); tabCount++; Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; int i; for(i = 0; i < tabCount; i ++) scprintf(" "); // small 'tabs' scprintf("%d %s", child->mID, (char*)child->mDef->mName); // def will be 'group' if it's a group if (child->mIsGroup) { Group_DumpTreeAndControls((Group*)child); } else { Graph* childGraph = (Graph*)child; int numControls = childGraph->mNumControls; if(numControls > 0) { scprintf("\n "); for(i = 0; i < tabCount; i ++) scprintf(" "); char **names; names = new char*[numControls]; for(i = 0; i < numControls; i++){ names[i] = NULL; } // check the number of named controls and stash their names at the correct index GraphDef* def = (GraphDef*)(child->mDef); int numNamedControls = def->mNumParamSpecs; for(i = 0; i < numNamedControls; i++){ ParamSpec *paramSpec = def->mParamSpecs + i; names[paramSpec->mIndex] = (char*)paramSpec->mName; } // now print the names and values in index order, checking for mappings for(i=0; i < numControls; i++){ float *ptr = childGraph->mControls + i; if(names[i]){ scprintf(" %s: ", names[i]); } else { scprintf(" ", names[i]); } // the ptr in nMapControls should be the same as the control itself, if not, it's mapped. if((childGraph->mMapControls[i]) != ptr){ int bus; if(childGraph->mControlRates[i] == 2){ bus = (childGraph->mMapControls[i]) - (child->mWorld->mAudioBus); bus = (int)((float)bus / child->mWorld->mBufLength); scprintf("a%d", bus); } else { bus = (childGraph->mMapControls[i]) - (child->mWorld->mControlBus); scprintf("c%d", bus); } //scprintf("bus: %d\n", bus); } else { scprintf("%.14g", *ptr); } } } } scprintf("\n"); (*child->mCalcFunc)(child); child = next; } tabCount--; } void Group_CalcDumpTree(Group *inGroup) { Group_DumpNodeTree(inGroup); inGroup->mNode.mCalcFunc = (NodeCalcFunc)&Group_Calc; } void Group_DumpTree(Group* inGroup) { if (inGroup->mNode.mCalcFunc == (NodeCalcFunc)&Group_Calc) { inGroup->mNode.mCalcFunc = (NodeCalcFunc)&Group_CalcDumpTree; } } void Group_CalcDumpTreeAndControls(Group *inGroup) { Group_DumpNodeTreeAndControls(inGroup); inGroup->mNode.mCalcFunc = (NodeCalcFunc)&Group_Calc; } void Group_DumpTreeAndControls(Group* inGroup) { if (inGroup->mNode.mCalcFunc == (NodeCalcFunc)&Group_Calc) { inGroup->mNode.mCalcFunc = (NodeCalcFunc)&Group_CalcDumpTreeAndControls; } } // count the children for this group (deep) void Group_CountNodeTags(Group* inGroup, int* count) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; (*count)+= 2; if (child->mIsGroup) { Group_CountNodeTags((Group*)child, count); } else { (*count)++; } // for the defname child = next; } } // count the children for this group (deep) void Group_CountNodeAndControlTags(Group* inGroup, int* count, int* controlAndDefCount) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; (*count)++; if (child->mIsGroup) { Group_CountNodeAndControlTags((Group*)child, count, controlAndDefCount); } else { //(*controlCount) += ((Graph*)child)->mNumControls + ((GraphDef*)(child->mDef))->mNumParamSpecs + 1; (*controlAndDefCount) += ((Graph*)child)->mNumControls * 2 + 2; // def, numControls, name or index and value for each } child = next; } } void Group_QueryTree(Group* inGroup, big_scpacket *packet) { packet->addtag('i'); packet->addi(inGroup->mNode.mID); // count the children for this group, but not their children (shallow) int count = 0; Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; count++; child = next; } packet->addtag('i'); packet->addi(count); // numChildren; for a Group >= 0 // now iterate over the children // id, numChildren, defname child = inGroup->mHead; while (child) { Node *next = child->mNext; if (child->mIsGroup) { Group_QueryTree((Group*)child, packet); } else { packet->addtag('i'); // nodeID packet->addtag('i'); // numChildren packet->addtag('s'); // defname packet->addi(child->mID); packet->addi(-1); packet->adds((char*)child->mDef->mName); } child = next; } } void Group_QueryTreeAndControls(Group* inGroup, big_scpacket *packet) { packet->addtag('i'); packet->addi(inGroup->mNode.mID); // count the children for this group, but not their children (shallow) int count = 0; Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; count++; child = next; } packet->addtag('i'); packet->addi(count); // now iterate over the children // id, numChildren, defname child = inGroup->mHead; while (child) { Node *next = child->mNext; if (child->mIsGroup) { Group_QueryTreeAndControls((Group*)child, packet); } else { packet->addtag('i'); packet->addtag('i'); packet->addtag('s'); packet->addi(child->mID); // nodeID packet->addi(-1); // numChildren packet->adds((char*)child->mDef->mName); // defName Graph* childGraph = (Graph*)child; int numControls = childGraph->mNumControls; packet->addtag('i'); packet->addi(numControls); char **names; names = new char*[numControls]; int i; for(i = 0; i < numControls; i++){ names[i] = NULL; } // check the number of named controls and stash their names GraphDef* def = (GraphDef*)(child->mDef); int numNamedControls = def->mNumParamSpecs; for(i = 0; i < numNamedControls; i++){ ParamSpec *paramSpec = def->mParamSpecs + i; names[paramSpec->mIndex] = (char*)paramSpec->mName; } // now add the names and values in index order, checking for mappings for(i=0; i < numControls; i++){ float *ptr = childGraph->mControls + i; if(names[i]){ packet->addtag('s'); packet->adds(names[i]); } else { packet->addtag('i'); packet->addi(i); } // the ptr in nMapControls should be the same as the control itself, if not, it's mapped. if((childGraph->mMapControls[i]) != ptr){ // it's mapped int bus; char buf[10]; //should be long enough if (childGraph->mControlRates[i] == 2) { bus = (childGraph->mMapControls[i]) - (child->mWorld->mAudioBus); bus = (int)((float)bus / child->mWorld->mBufLength); sprintf(buf, "%c%d", 'a', bus); } else { bus = (childGraph->mMapControls[i]) - (child->mWorld->mControlBus); sprintf(buf, "%c%d", 'c', bus); } //scprintf("bus: %d\n", bus); packet->addtag('s'); packet->adds(buf); } else { packet->addtag('f'); packet->addf(*ptr); } } } child = next; } } void Group_DeleteAll(Group *inGroup) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; child->mPrev = child->mNext = 0; child->mParent = 0; Node_Delete(child); child = next; } inGroup->mHead = inGroup->mTail = 0; } void Group_DeepFreeGraphs(Group *inGroup) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; if (child->mIsGroup) { Group_DeepFreeGraphs((Group*)child); } else { Node_Remove(child); Node_Delete(child); } child = next; } } void Group_AddHead (Group *s, Node *child) { if (child->mID == 0) return; // failed child->mPrev = 0; child->mNext = s->mHead; if (s->mHead) { s->mHead->mPrev = child; s->mHead = child; } else s->mHead = s->mTail = child; child->mParent = s; } void Group_AddTail (Group *s, Node *child) { if (child->mID == 0) return; // failed child->mPrev = s->mTail; child->mNext = 0; if (s->mTail) { s->mTail->mNext = child; s->mTail = child; } else s->mHead = s->mTail = child; child->mParent = s; } void Group_Insert(Group *s, Node *child, int index) { if (child->mID == 0) return; // failed if (index <= 0) Group_AddHead(s, child); else { Node *before = s->mHead; for (int i=0; imNext; if (!before) { Group_AddTail(s, child); return; } } Node_AddBefore(child, before); } } void Group_MapControl(Group *inGroup, uint32 inIndex, uint32 inBus) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; Node_MapControl(child, inIndex, inBus); child = next; } } void Group_MapControl(Group *inGroup, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; Node_MapControl(child, inHash, inName, inIndex, inBus); child = next; } } void Group_MapAudioControl(Group *inGroup, uint32 inIndex, uint32 inBus) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; Node_MapAudioControl(child, inIndex, inBus); child = next; } } void Group_MapAudioControl(Group *inGroup, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; Node_MapAudioControl(child, inHash, inName, inIndex, inBus); child = next; } } void Group_SetControl(Group *inGroup, uint32 inIndex, float inValue) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; Node_SetControl(child, inIndex, inValue); child = next; } } void Group_SetControl(Group *inGroup, int32 inHash, int32 *inName, uint32 inIndex, float inValue) { Node *child = inGroup->mHead; while (child) { Node *next = child->mNext; Node_SetControl(child, inHash, inName, inIndex, inValue); child = next; } } SuperCollider-Source/server/scsynth/SC_Group.h000644 000765 000024 00000001775 12321461511 022516 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Group_ #define _SC_Group_ #include "SC_Graph.h" struct Group { Node mNode; Node *mHead, *mTail; }; typedef struct Group Group; #endif SuperCollider-Source/server/scsynth/SC_HiddenWorld.h000644 000765 000024 00000006131 12524671173 023630 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_HiddenWorld_ #define _SC_HiddenWorld_ #include "SC_Types.h" #include "SC_Rate.h" #include "SC_SndBuf.h" #include "SC_RGen.h" #include "HashTable.h" #include "SC_World.h" #include "SC_Reply.h" #include "MsgFifo.h" #include #include "boost/sync/semaphore.hpp" #include "../../common/server_shm.hpp" extern HashTable *gUnitDefLib; struct TriggerMsg { World *mWorld; int32 mNodeID; int32 mTriggerID; float mValue; void Perform(); }; struct NodeReplyMsg { World *mWorld; int32 mNodeID; int32 mID; int32 mNumArgs; float *mValues; int32 mCmdNameSize; char *mCmdName; void *mRTMemory; void Perform(); }; struct NodeEndMsg { World *mWorld; int32 mNodeID; int32 mGroupID; int32 mPrevNodeID; int32 mNextNodeID; int32 mIsGroup; int32 mHeadID; int32 mTailID; int32 mState; void Perform(); }; struct DeleteGraphDefMsg { struct GraphDef* mDef; void Perform(); }; typedef MsgFifoNoFree TriggersFifo; typedef MsgFifoNoFree NodeReplyFifo; typedef MsgFifoNoFree NodeEndsFifo; typedef MsgFifoNoFree DeleteGraphDefsFifo; typedef HashTable GrafDefTable; typedef std::map ClientIDDict; struct HiddenWorld { class AllocPool *mAllocPool; IntHashTable *mNodeLib; GrafDefTable *mGraphDefLib; uint32 mNumUsers, mMaxUsers; ReplyAddress *mUsers; uint32 *mClientIDs, mClientIDTop; ClientIDDict *mClientIDdict; class SC_AudioDriver *mAudioDriver; char mPassword[32]; uint32 mMaxWireBufs; float *mWireBufSpace; TriggersFifo mTriggers; NodeReplyFifo mNodeMsgs; NodeEndsFifo mNodeEnds; DeleteGraphDefsFifo mDeleteGraphDefs; boost::sync::semaphore * mQuitProgram; bool mTerminating; #ifndef NO_LIBSNDFILE SNDFILE *mNRTInputFile; SNDFILE *mNRTOutputFile; FILE *mNRTCmdFile; #endif int32 mHiddenID; int32 mRecentID; #ifdef __APPLE__ const char* mInputStreamsEnabled; const char* mOutputStreamsEnabled; #endif const char *mInDeviceName; const char *mOutDeviceName; class server_shared_memory_creator * mShmem; }; typedef struct HiddenWorld HiddenWorld; inline SC_AudioDriver *AudioDriver(World *inWorld) { return inWorld->hw->mAudioDriver; } #endif SuperCollider-Source/server/scsynth/SC_Jack.cpp000644 000765 000024 00000041233 12766171707 022640 0ustar00crucialstaff000000 000000 /* Jack audio driver interface. Copyright (c) 2003-2006 stefan kersten. ==================================================================== SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_CoreAudio.h" #include "SC_HiddenWorld.h" #include "SC_Prototypes.h" #include "SC_StringParser.h" #include "SC_WorldOptions.h" #include "SC_TimeDLL.hpp" #include "SC_Time.hpp" #include #ifdef SC_JACK_USE_METADATA_API # include # include # include #endif #include #include #include #include #include #include // ===================================================================== // Constants static const char* kJackDriverIdent = "JackDriver"; static const char* kJackDefaultClientName = "SuperCollider"; int32 server_timeseed() { return timeSeed(); } int64 oscTimeNow() { return OSCTime(getTime()); } void initializeScheduler() { } // ===================================================================== // Audio driver static int sc_jack_process_cb(jack_nframes_t numFrames, void *arg); static int sc_jack_bufsize_cb(jack_nframes_t numSamples, void *arg); static int sc_jack_srate_cb(jack_nframes_t sampleRate, void *arg); static int sc_jack_graph_order_cb(void *arg); static void sc_jack_shutdown_cb(void *arg); typedef jack_default_audio_sample_t sc_jack_sample_t; struct SC_JackPortList { int mSize; jack_port_t** mPorts; sc_jack_sample_t** mBuffers; SC_JackPortList(jack_client_t *client, int orderOffset, int numPorts, int type); ~SC_JackPortList(); }; class SC_JackDriver : public SC_AudioDriver { jack_client_t *mClient; SC_JackPortList *mInputList; SC_JackPortList *mOutputList; double mMaxOutputLatency; SC_TimeDLL mDLL; protected: // driver interface methods virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate); virtual bool DriverStart(); virtual bool DriverStop(); public: SC_JackDriver(struct World *inWorld); virtual ~SC_JackDriver(); // process loop void Run(); // reset state void Reset(double sampleRate, int bufferSize); // notifications bool BufferSizeChanged(int numSamples); bool SampleRateChanged(double sampleRate); bool GraphOrderChanged(); bool XRun(); private: void ConnectPorts(const char * src, const char * dst) { int err = jack_connect(mClient, src, dst); scprintf("%s: %s %s to %s\n", kJackDriverIdent, err ? "couldn't connect " : "connected ", src, dst); } void ConnectClientInputs(const char * pattern); void ConnectClientOutputs(const char * pattern); }; SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld) { return new SC_JackDriver(inWorld); } // ===================================================================== // SC_JackPortList SC_JackPortList::SC_JackPortList(jack_client_t *client, int orderOffset, int numPorts, int type) : mSize(numPorts), mPorts(0), mBuffers(0) { const char *fmt = (type == JackPortIsInput ? "in_%d" : "out_%d"); #ifdef SC_JACK_USE_METADATA_API const char *prettyFmt= (type == JackPortIsInput ? "Input %d" : "Output %d"); #endif char tempStr[32]; mPorts = new jack_port_t*[mSize]; mBuffers = new float*[mSize]; for (int i = 0; i < mSize; i++) { snprintf(tempStr, 32, fmt, i+1); mPorts[i] = jack_port_register( client, tempStr, JACK_DEFAULT_AUDIO_TYPE, type, 0); mBuffers[i] = 0; #ifdef SC_JACK_USE_METADATA_API jack_uuid_t uuid = jack_port_uuid(mPorts[i]); if(!jack_uuid_empty(uuid)) { snprintf(tempStr, 32, prettyFmt, i+1); jack_set_property(client, uuid, JACK_METADATA_PRETTY_NAME, tempStr, "text/plain"); snprintf(tempStr, 32, "%d", orderOffset + i); jack_set_property(client, uuid, JACKEY_ORDER, tempStr, "http://www.w3.org/2001/XMLSchema#integer"); } #endif } } SC_JackPortList::~SC_JackPortList() { delete [] mPorts; delete [] mBuffers; } // ===================================================================== // JACK callbacks int sc_jack_process_cb(jack_nframes_t numFrames, void *arg) { ((SC_JackDriver*)arg)->Run(); return 0; } int sc_jack_bufsize_cb(jack_nframes_t numSamples, void *arg) { return !((SC_JackDriver*)arg)->BufferSizeChanged((int)numSamples); } int sc_jack_srate_cb(jack_nframes_t sampleRate, void *arg) { return !((SC_JackDriver*)arg)->SampleRateChanged((double)sampleRate); } int sc_jack_graph_order_cb(void* arg) { return !((SC_JackDriver*)arg)->GraphOrderChanged(); } int sc_jack_xrun_cb(void* arg) { return !((SC_JackDriver*)arg)->XRun(); } void sc_jack_shutdown_cb(void* arg) { scprintf("%s: killed by jack\n", kJackDriverIdent); World * world = (World*)arg; world->hw->mTerminating = true; world->hw->mQuitProgram->post(); } // ===================================================================== // SC_JackDriver (JACK) SC_JackDriver::SC_JackDriver(struct World *inWorld) : SC_AudioDriver(inWorld), mClient(0), mInputList(0), mOutputList(0), mMaxOutputLatency(0.) { } SC_JackDriver::~SC_JackDriver() { if (mClient) { jack_client_close(mClient); } delete mInputList; delete mOutputList; } // ==================================================================== // NOTE: for now, in lieu of a mechanism that passes generic options to // the platform driver, we rely on environment variables: // // SC_JACK_DEFAULT_INPUTS: which outports to connect to // SC_JACK_DEFAULT_OUTPUTS: which inports to connect to // ==================================================================== bool SC_JackDriver::DriverSetup(int* outNumSamples, double* outSampleRate) { char* clientName = 0; char* serverName = 0; if (mWorld->hw->mInDeviceName && (strlen(mWorld->hw->mInDeviceName) > 0)) { // parse string : SC_StringParser sp(mWorld->hw->mInDeviceName, ':'); if (!sp.AtEnd()) serverName = strdup(sp.NextToken()); if (!sp.AtEnd()) clientName = strdup(sp.NextToken()); if (clientName == 0) { // no semicolon found clientName = serverName; serverName = 0; } else if (strlen(clientName) == 0) { free(clientName); clientName = 0; } } mClient = jack_client_open( clientName ? clientName : kJackDefaultClientName, serverName ? JackServerName : JackNullOption, NULL, serverName); if (serverName) free(serverName); if (clientName) free(clientName); if (mClient == 0) return false; scprintf("%s: client name is '%s'\n", kJackDriverIdent, jack_get_client_name(mClient)); // create jack I/O ports mInputList = new SC_JackPortList(mClient, 0, mWorld->mNumInputs, JackPortIsInput); mOutputList = new SC_JackPortList(mClient, mWorld->mNumInputs, mWorld->mNumOutputs, JackPortIsOutput); // register callbacks jack_set_process_callback(mClient, sc_jack_process_cb, this); jack_set_buffer_size_callback(mClient, sc_jack_bufsize_cb, this); jack_set_sample_rate_callback(mClient, sc_jack_srate_cb, this); jack_set_graph_order_callback(mClient, sc_jack_graph_order_cb, this); jack_set_xrun_callback(mClient, sc_jack_xrun_cb, this); jack_on_shutdown(mClient, sc_jack_shutdown_cb, mWorld); *outNumSamples = (int)jack_get_buffer_size(mClient); *outSampleRate = (double)jack_get_sample_rate(mClient); return true; } void SC_JackDriver::ConnectClientInputs(const char * pattern) { const char **ports = jack_get_ports (mClient, pattern, NULL, JackPortIsOutput); jack_port_t ** ourports = mInputList->mPorts; if (!ports) return; int i = 0; while (ports[i]) { if (i == mInputList->mSize) break; const char * src = ports[i]; const char * dst = jack_port_name(ourports[i]); ConnectPorts(src, dst); ++i; } free(ports); } void SC_JackDriver::ConnectClientOutputs(const char * pattern) { const char **ports = jack_get_ports (mClient, pattern, NULL, JackPortIsInput); jack_port_t ** ourports = mOutputList->mPorts; if (!ports) return; int i = 0; while (ports[i]) { if (i == mOutputList->mSize) break; const char * src = jack_port_name(ourports[i]); const char * dst = ports[i]; ConnectPorts(src, dst); ++i; } free(ports); } bool SC_JackDriver::DriverStart() { if (!mClient) return false; int err; SC_StringParser sp; jack_port_t **ports; int numPorts; // activate client err = jack_activate(mClient); if (err) { scprintf("%s: couldn't activate jack client\n", kJackDriverIdent); return false; } // connect default inputs sp = SC_StringParser(getenv("SC_JACK_DEFAULT_INPUTS"), ','); ports = mInputList->mPorts; numPorts = mInputList->mSize; for (int i = 0; !sp.AtEnd() && (i < numPorts); i++) { const char *thatPortName = sp.NextToken(); if (i == 0 && sp.AtEnd() && (strchr(thatPortName, ':') == 0)) { ConnectClientInputs(thatPortName); break; } const char *thisPortName = jack_port_name(ports[i]); if (thisPortName && thatPortName) ConnectPorts(thatPortName, thisPortName); } // connect default outputs sp = SC_StringParser(getenv("SC_JACK_DEFAULT_OUTPUTS"), ','); ports = mOutputList->mPorts; numPorts = mOutputList->mSize; for (int i = 0; !sp.AtEnd() && (i < numPorts); i++) { const char *thatPortName = sp.NextToken(); if (i == 0 && sp.AtEnd() && (strchr(thatPortName, ':') == 0)) { ConnectClientOutputs(thatPortName); break; } const char *thisPortName = jack_port_name(ports[i]); if (thisPortName && thatPortName) ConnectPorts(thisPortName, thatPortName); } return true; } bool SC_JackDriver::DriverStop() { int err = 0; if (mClient) err = jack_deactivate(mClient); return err == 0; } void sc_SetDenormalFlags(); void SC_JackDriver::Run() { sc_SetDenormalFlags(); jack_client_t* client = mClient; World* world = mWorld; #ifdef SC_JACK_USE_DLL mDLL.Update(secondsSinceEpoch(getTime())); #if SC_JACK_DEBUG_DLL static int tick = 0; if (++tick >= 10) { tick = 0; scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n", mDLL.PeriodTime(), mDLL.Period(), mDLL.SampleRate(), mDLL.Error(), mDLL.AvgError(), mOSCincrement * kOSCtoSecs); } #endif #else HostTime hostTime = getTime(); double hostSecs = secondsSinceEpoch(hostTime); double sampleTime = (double)(jack_frame_time(client) + jack_frames_since_cycle_start(client)); if (mStartHostSecs == 0) { mStartHostSecs = hostSecs; mStartSampleTime = sampleTime; } else { double instSampleRate = (sampleTime - mPrevSampleTime) / (hostSecs - mPrevHostSecs); double smoothSampleRate = mSmoothSampleRate; smoothSampleRate = smoothSampleRate + 0.002 * (instSampleRate - smoothSampleRate); if (fabs(smoothSampleRate - mSampleRate) > 10.) { smoothSampleRate = mSampleRate; } mOSCincrement = (int64)(mOSCincrementNumerator / smoothSampleRate); mSmoothSampleRate = smoothSampleRate; #if 0 double avgSampleRate = (sampleTime - mStartSampleTime)/(hostSecs - mStartHostSecs); double jitter = (smoothSampleRate * (hostSecs - mPrevHostSecs)) - (sampleTime - mPrevSampleTime); double drift = (smoothSampleRate - mSampleRate) * (hostSecs - mStartHostSecs); #endif } mPrevHostSecs = hostSecs; mPrevSampleTime = sampleTime; #endif try { mFromEngine.Free(); mToEngine.Perform(); mOscPacketsToEngine.Perform(); int numInputs = mInputList->mSize; int numOutputs = mOutputList->mSize; jack_port_t **inPorts = mInputList->mPorts; jack_port_t **outPorts = mOutputList->mPorts; sc_jack_sample_t **inBuffers = mInputList->mBuffers; sc_jack_sample_t **outBuffers = mOutputList->mBuffers; int numSamples = NumSamplesPerCallback(); int bufFrames = mWorld->mBufLength; int numBufs = numSamples / bufFrames; float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames; float *outBuses = mWorld->mAudioBus; int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs; int32 *outTouched = mWorld->mAudioBusTouched; int minInputs = sc_min(numInputs, (int)mWorld->mNumInputs); int minOutputs = sc_min(numOutputs, (int)mWorld->mNumOutputs); int bufFramePos = 0; // cache I/O buffers for (int i = 0; i < minInputs; ++i) { inBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(inPorts[i], numSamples); } for (int i = 0; i < minOutputs; ++i) { outBuffers[i] = (sc_jack_sample_t*)jack_port_get_buffer(outPorts[i], numSamples); } // main loop #ifdef SC_JACK_USE_DLL int64 oscTime = mOSCbuftime = (int64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5); // int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate()); int64 oscInc = mOSCincrement = (int64)((mDLL.Period() / numBufs) * kSecondsToOSCunits + .5); mSmoothSampleRate = mDLL.SampleRate(); double oscToSamples = mOSCtoSamples = mSmoothSampleRate * kOSCtoSecs /* 1/pow(2,32) */; #else int64 oscTime = mOSCbuftime = OSCTime(hostTime) - (int64)(mMaxOutputLatency * kSecondsToOSCunits + .5); int64 oscInc = mOSCincrement; double oscToSamples = mOSCtoSamples; #endif for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) { int32 bufCounter = mWorld->mBufCounter; int32 *tch; // copy+touch inputs tch = inTouched; for (int k = 0; k < minInputs; ++k) { sc_jack_sample_t *src = inBuffers[k] + bufFramePos; float *dst = inBuses + k * bufFrames; for (int n = 0; n < bufFrames; ++n) { *dst++ = *src++; } *tch++ = bufCounter; } // run engine int64 schedTime; int64 nextTime = oscTime + oscInc; while ((schedTime = mScheduler.NextTime()) <= nextTime) { float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5; float diffTimeFloor = floor(diffTime); world->mSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1; SC_ScheduledEvent event = mScheduler.Remove(); event.Perform(); } world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; World_Run(world); // copy touched outputs tch = outTouched; for (int k = 0; k < minOutputs; ++k) { sc_jack_sample_t *dst = outBuffers[k] + bufFramePos; if (*tch++ == bufCounter) { float *src = outBuses + k * bufFrames; for (int n = 0; n < bufFrames; ++n) { *dst++ = *src++; } } else { for (int n = 0; n < bufFrames; ++n) { *dst++ = 0.0f; } } } // advance OSC time mOSCbuftime = oscTime = nextTime; } } catch (std::exception& exc) { scprintf("%s: exception in real time: %s\n", kJackDriverIdent, exc.what()); } catch (...) { scprintf("%s: unknown exception in real time\n", kJackDriverIdent); } double cpuUsage = (double)jack_cpu_load(mClient); mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU); if (cpuUsage > mPeakCPU || --mPeakCounter <= 0) { mPeakCPU = cpuUsage; mPeakCounter = mMaxPeakCounter; } mAudioSync.Signal(); } void SC_JackDriver::Reset(double sampleRate, int bufferSize) { mSampleRate = mSmoothSampleRate = sampleRate; mNumSamplesPerCallback = bufferSize; World_SetSampleRate(mWorld, mSampleRate); mBuffersPerSecond = mSampleRate / mNumSamplesPerCallback; mMaxPeakCounter = (int)mBuffersPerSecond; mOSCincrement = (int64)(mOSCincrementNumerator / mSampleRate); #ifdef SC_JACK_USE_DLL mDLL.Reset( mSampleRate, mNumSamplesPerCallback, SC_TIME_DLL_BW, secondsSinceEpoch(getTime())); #endif } bool SC_JackDriver::BufferSizeChanged(int numSamples) { Reset(jack_get_sample_rate(mClient), numSamples); return true; } bool SC_JackDriver::SampleRateChanged(double sampleRate) { Reset(sampleRate, jack_get_buffer_size(mClient)); return true; } bool SC_JackDriver::GraphOrderChanged() { SC_JackPortList* outputs = mOutputList; jack_nframes_t lat = 0; for (int i=0; i < outputs->mSize; ++i) { jack_latency_range_t range; jack_port_get_latency_range( outputs->mPorts[i], JackPlaybackLatency, &range ); jack_nframes_t portLat = range.max; if (portLat > lat) lat = portLat; } double maxLat = (double)lat / mSampleRate; if (maxLat != mMaxOutputLatency) { mMaxOutputLatency = maxLat; scprintf("%s: max output latency %.1f ms\n", kJackDriverIdent, maxLat * 1e3); } return true; } bool SC_JackDriver::XRun() { Reset(mSampleRate, mNumSamplesPerCallback); return true; } // EOF SuperCollider-Source/server/scsynth/SC_Lib.cpp000644 000765 000024 00000010466 12321461511 022460 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Lib.h" #include "SC_Lib_Cintf.h" #include "SC_SequencedCommand.h" #include "scsynthsend.h" #include #include #include "SC_Prototypes.h" #include "SC_Str4.h" #include "SC_WorldOptions.h" void SendDone(ReplyAddress *inReply, const char *inCommandName) { small_scpacket packet; packet.adds("/done"); packet.maketags(2); packet.addtag(','); packet.addtag('s'); packet.adds(inCommandName); SendReply(inReply, packet.data(), packet.size()); } void SendDoneWithIntValue(ReplyAddress *inReply, const char *inCommandName, int value) { small_scpacket packet; packet.adds("/done"); packet.maketags(3); packet.addtag(','); packet.addtag('s'); packet.adds(inCommandName); packet.addtag('i'); packet.addi(value); SendReply(inReply, packet.data(), packet.size()); } void SendFailure(ReplyAddress *inReply, const char *inCommandName, const char *errString) { small_scpacket packet; packet.adds("/fail"); packet.maketags(3); packet.addtag(','); packet.addtag('s'); packet.addtag('s'); packet.adds(inCommandName); packet.adds(errString); SendReply(inReply, packet.data(), packet.size()); } void SendFailureWithIntValue(ReplyAddress *inReply, const char *inCommandName, const char *errString, uint32 index) { small_scpacket packet; packet.adds("/fail"); packet.maketags(4); packet.addtag(','); packet.addtag('s'); packet.addtag('s'); packet.adds(inCommandName); packet.adds(errString); packet.addtag('i'); packet.addi((int)index); SendReply(inReply, packet.data(), packet.size()); } void ReportLateness(ReplyAddress *inReply, float32 seconds) { small_scpacket packet; packet.adds("/late"); packet.maketags(2); packet.addtag(','); packet.addtag('f'); packet.addf(seconds); SendReply(inReply, packet.data(), packet.size()); } SC_NamedObj::SC_NamedObj() { SetName("?"); } SC_NamedObj::~SC_NamedObj() {} void SC_NamedObj::SetName(const int32 *inName) { if (str4len(inName) > (int)kSCNameLen) return; str4cpy(mName, inName); mHash = Hash(mName); } void SC_NamedObj::SetName(const char *inName) { if (str4len(inName) > (int)kSCNameLen) return; str4cpy(mName, inName); mHash = Hash(mName); } SC_LibCmd::SC_LibCmd(SC_CommandFunc inFunc) : mFunc(inFunc) {} SCErr SC_LibCmd::Perform(struct World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { SCErr err; // int kSendError = 1; // i.e., 0x01 | 0x02; try { err = (mFunc)(inWorld, inSize, inData, inReply); } catch (int iexc) { err = iexc; } catch (std::exception& exc) { if(inWorld->mLocalErrorNotification <= 0 && inWorld->mErrorNotification) { CallSendFailureCommand(inWorld, (char*)Name(), exc.what(), inReply); scprintf("FAILURE IN SERVER %s %s\n", (char*)Name(), exc.what()); } return kSCErr_Failed; } catch (...) { err = kSCErr_Failed; } if (err && (inWorld->mLocalErrorNotification <= 0 && inWorld->mErrorNotification)) { char errstr[128]; SC_ErrorString(err, errstr); CallSendFailureCommand(inWorld, (char*)Name(), errstr, inReply); scprintf("FAILURE IN SERVER %s %s\n", (char*)Name(), errstr); } return err; } SCErr NewCommand(const char *inPath, uint32 inCommandNumber, SC_CommandFunc inFunc) { char path[256]; sprintf(path, "/%s", inPath); SC_LibCmd *cmd = new SC_LibCmd(inFunc); cmd->SetName(path); gCmdLib->Add(cmd); // support OSC commands without the leading slash SC_LibCmd *cmd2 = new SC_LibCmd(inFunc); cmd2->SetName(inPath); gCmdLib->Add(cmd2); // support integer OSC commands gCmdArray[inCommandNumber] = cmd; return kSCErr_None; } SuperCollider-Source/server/scsynth/SC_Lib.h000644 000765 000024 00000003002 12321461511 022111 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Lib_ #define _SC_Lib_ #include "SC_Errors.h" #include "SC_Types.h" #include "Hash.h" #include "HashTable.h" #include #include class SC_NamedObj { public: SC_NamedObj(); virtual ~SC_NamedObj(); const int32* Name() const { return mName; } void SetName(const char *inName); void SetName(const int32 *inName); private: friend int32 GetHash(const SC_NamedObj *inObj); friend const int32* GetKey(const SC_NamedObj *inObj); int32 mName[kSCNameLen]; int32 mHash; }; inline int32 GetHash(const SC_NamedObj *inObj) { return inObj->mHash; } inline const int32 *GetKey(const SC_NamedObj *inObj) { return inObj->mName; } #endif SuperCollider-Source/server/scsynth/SC_Lib_Cintf.cpp000644 000765 000024 00000026573 12756531745 023634 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Lib_Cintf.h" #include "SC_CoreAudio.h" #include "SC_UnitDef.h" #include "SC_BufGen.h" #include "SC_World.h" #include "SC_WorldOptions.h" #include "SC_StringParser.h" #include "SC_InterfaceTable.h" #include "SC_DirUtils.h" #include #ifndef _MSC_VER #include #endif //_MSC_VER #ifndef _WIN32 #include #endif #ifdef _WIN32 #include "SC_Win32Utils.h" #else #include #endif // Plugin directory in resource directory # define SC_PLUGIN_DIR_NAME "plugins" // Extension for binary plugins #ifndef SC_PLUGIN_EXT # define SC_PLUGIN_EXT ".scx" #endif #ifndef _WIN32 # include #endif #ifdef __APPLE__ extern "C" { #include #include } char gTempVal; #endif Malloc gMalloc; HashTable *gCmdLib; HashTable *gUnitDefLib = 0; HashTable *gBufGenLib = 0; HashTable *gPlugInCmds = 0; extern struct InterfaceTable gInterfaceTable; SC_LibCmd* gCmdArray[NUMBER_OF_COMMANDS]; void initMiscCommands(); static bool PlugIn_LoadDir(const char *dirname, bool reportError); std::vector open_handles; #ifdef __APPLE__ void read_section(const struct mach_header *mhp, unsigned long slide, const char *segname, const char *sectname) { u_int32_t size; char *sect = getsectdatafromheader(mhp, segname, sectname, &size); if(!sect) return; char *start = sect + slide; char *end = start + size; while(start != end) { gTempVal += *(char *)start; start++; } } #endif extern void IO_Load(InterfaceTable *table); extern void Osc_Load(InterfaceTable *table); extern void Delay_Load(InterfaceTable *table); extern void BinaryOp_Load(InterfaceTable *table); extern void Filter_Load(InterfaceTable *table); extern void Gendyn_Load(InterfaceTable *table); extern void LF_Load(InterfaceTable *table); extern void Noise_Load(InterfaceTable *table); extern void MulAdd_Load(InterfaceTable *table); extern void Grain_Load(InterfaceTable *table); extern void Pan_Load(InterfaceTable *table); extern void Reverb_Load(InterfaceTable *table); extern void Trigger_Load(InterfaceTable *table); extern void UnaryOp_Load(InterfaceTable *table); extern void DiskIO_Load(InterfaceTable *table); extern void Test_Load(InterfaceTable *table); extern void PhysicalModeling_Load(InterfaceTable *table); extern void Demand_Load(InterfaceTable *table); extern void DynNoise_Load(InterfaceTable *table); extern void FFT_UGens_Load(InterfaceTable *table); extern void iPhone_Load(InterfaceTable *table); void deinitialize_library() { #ifdef _WIN32 for(void * ptrhinstance : open_handles){ HINSTANCE hinstance = (HINSTANCE)ptrhinstance; void *ptr = (void *)GetProcAddress( hinstance, "unload" ); if(ptr){ UnLoadPlugInFunc unloadFunc = (UnLoadPlugInFunc)ptr; (*unloadFunc)(); } } //FreeLibrary dlclose(handle); #else for(void * handle : open_handles){ void *ptr = dlsym(handle, "unload"); if(ptr){ UnLoadPlugInFunc unloadFunc = (UnLoadPlugInFunc)ptr; (*unloadFunc)(); } } #endif open_handles.clear(); } void initialize_library(const char *uGensPluginPath) { gCmdLib = new HashTable(&gMalloc, 64, true); gUnitDefLib = new HashTable(&gMalloc, 512, true); gBufGenLib = new HashTable(&gMalloc, 512, true); gPlugInCmds = new HashTable(&gMalloc, 64, true); initMiscCommands(); #ifdef STATIC_PLUGINS IO_Load(&gInterfaceTable); Osc_Load(&gInterfaceTable); Delay_Load(&gInterfaceTable); BinaryOp_Load(&gInterfaceTable); Filter_Load(&gInterfaceTable); Gendyn_Load(&gInterfaceTable); LF_Load(&gInterfaceTable); Noise_Load(&gInterfaceTable); MulAdd_Load(&gInterfaceTable); Grain_Load(&gInterfaceTable); Pan_Load(&gInterfaceTable); Reverb_Load(&gInterfaceTable); Trigger_Load(&gInterfaceTable); UnaryOp_Load(&gInterfaceTable); DiskIO_Load(&gInterfaceTable); PhysicalModeling_Load(&gInterfaceTable); Test_Load(&gInterfaceTable); Demand_Load(&gInterfaceTable); DynNoise_Load(&gInterfaceTable); #if defined(SC_IPHONE) && !TARGET_IPHONE_SIMULATOR iPhone_Load(&gInterfaceTable); #endif FFT_UGens_Load(&gInterfaceTable); return; #endif // If uGensPluginPath is supplied, it is exclusive. bool loadUGensExtDirs = true; if(uGensPluginPath){ loadUGensExtDirs = false; SC_StringParser sp(uGensPluginPath, SC_STRPARSE_PATHDELIMITER); while (!sp.AtEnd()) { PlugIn_LoadDir(const_cast(sp.NextToken()), true); } } if(loadUGensExtDirs) { #ifdef SC_PLUGIN_DIR // load globally installed plugins if (sc_DirectoryExists(SC_PLUGIN_DIR)) { PlugIn_LoadDir(SC_PLUGIN_DIR, true); } #endif // load default plugin directory char pluginDir[MAXPATHLEN]; sc_GetResourceDirectory(pluginDir, MAXPATHLEN); sc_AppendToPath(pluginDir, MAXPATHLEN, SC_PLUGIN_DIR_NAME); if (sc_DirectoryExists(pluginDir)) { PlugIn_LoadDir(pluginDir, true); } } // get extension directories char extensionDir[MAXPATHLEN]; if (!sc_IsStandAlone() && loadUGensExtDirs) { // load system extension plugins sc_GetSystemExtensionDirectory(extensionDir, MAXPATHLEN); PlugIn_LoadDir(extensionDir, false); // load user extension plugins sc_GetUserExtensionDirectory(extensionDir, MAXPATHLEN); PlugIn_LoadDir(extensionDir, false); // load user plugin directories SC_StringParser sp(getenv("SC_PLUGIN_PATH"), SC_STRPARSE_PATHDELIMITER); while (!sp.AtEnd()) { PlugIn_LoadDir(const_cast(sp.NextToken()), true); } } #ifdef __APPLE__ /* on darwin plugins are lazily loaded (dlopen uses mmap internally), which can produce audible glitches when UGens have to be paged-in. to work around this we preload all the plugins by iterating through their memory space. */ #ifndef __x86_64__ /* seems to cause a stack corruption on llvm-gcc-4.2, sdk 10.5 on 10.6 */ unsigned long images = _dyld_image_count(); for(unsigned long i = 0; i < images; i++) { const mach_header *hdr = _dyld_get_image_header(i); unsigned long slide = _dyld_get_image_vmaddr_slide(i); const char *name = _dyld_get_image_name(i); uint32_t size; char *sect; if(!strcmp(name + (strlen(name) - 4), ".scx")) { read_section(hdr, slide, "__TEXT", "__text"); read_section(hdr, slide, "__TEXT", "__const"); read_section(hdr, slide, "__TEXT", "__cstring"); read_section(hdr, slide, "__TEXT", "__picsymbol_stub"); read_section(hdr, slide, "__TEXT", "__symbol_stub"); read_section(hdr, slide, "__TEXT", "__const"); read_section(hdr, slide, "__TEXT", "__literal4"); read_section(hdr, slide, "__TEXT", "__literal8"); read_section(hdr, slide, "__DATA", "__data"); read_section(hdr, slide, "__DATA", "__la_symbol_ptr"); read_section(hdr, slide, "__DATA", "__nl_symbol_ptr"); read_section(hdr, slide, "__DATA", "__dyld"); read_section(hdr, slide, "__DATA", "__const"); read_section(hdr, slide, "__DATA", "__mod_init_func"); read_section(hdr, slide, "__DATA", "__bss"); read_section(hdr, slide, "__DATA", "__common"); read_section(hdr, slide, "__IMPORT", "__jump_table"); read_section(hdr, slide, "__IMPORT", "__pointers"); } } #endif #endif } typedef int (*InfoFunction)(); bool checkAPIVersion(void * f, const char * filename) { if (f) { InfoFunction fn = (InfoFunction)f; if ((*fn)() == sc_api_version) return true; } scprintf("*** ERROR: API Version Mismatch: %s\n", filename); return false; } bool checkServerVersion(void * f, const char * filename) { if (f) { InfoFunction fn = (InfoFunction)f; if ((*fn)() == 1) return false; } return true; } static bool PlugIn_Load(const char *filename) { #ifdef _WIN32 HINSTANCE hinstance = LoadLibrary( filename ); if (!hinstance) { char *s; DWORD lastErr = GetLastError(); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, lastErr , MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&s, 0, NULL ); scprintf("*** ERROR: LoadLibrary '%s' err '%s'\n", filename, s); LocalFree( s ); return false; } void *apiVersionPtr = (void *)GetProcAddress( hinstance, "api_version" ); if (!checkAPIVersion(apiVersionPtr, filename)) { FreeLibrary(hinstance); return false; } void *serverCheckPtr = (void *)GetProcAddress( hinstance, "server_type" ); if (!checkServerVersion(serverCheckPtr , filename)) { FreeLibrary(hinstance); return false; } void *ptr = (void *)GetProcAddress( hinstance, "load" ); if (!ptr) { char *s; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError() , MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&s, 0, NULL ); scprintf("*** ERROR: GetProcAddress err '%s'\n", s); LocalFree( s ); FreeLibrary(hinstance); return false; } LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr; (*loadFunc)(&gInterfaceTable); // FIXME: at the moment we never call FreeLibrary() on a loaded plugin open_handles.push_back(hinstance); return true; #else void* handle = dlopen(filename, RTLD_NOW); if (!handle) { scprintf("*** ERROR: dlopen '%s' err '%s'\n", filename, dlerror()); dlclose(handle); return false; } void *apiVersionPtr = (void *)dlsym( handle, "api_version" ); if (!checkAPIVersion(apiVersionPtr, filename)) { dlclose(handle); return false; } void *serverCheckPtr = (void *)dlsym( handle, "server_type" ); if (!checkServerVersion(serverCheckPtr , filename)) { dlclose(handle); return false; } void *ptr = dlsym(handle, "load"); if (!ptr) { scprintf("*** ERROR: dlsym load err '%s'\n", dlerror()); dlclose(handle); return false; } LoadPlugInFunc loadFunc = (LoadPlugInFunc)ptr; (*loadFunc)(&gInterfaceTable); open_handles.push_back(handle); return true; #endif } static bool PlugIn_LoadDir(const char *dirname, bool reportError) { bool success = true; SC_DirHandle *dir = sc_OpenDir(dirname); if (!dir) { if (reportError) { scprintf("*** ERROR: open directory failed '%s'\n", dirname); fflush(stdout); } return false; } int firstCharOffset = strlen(dirname)+1; for (;;) { char diritem[MAXPATHLEN]; bool skipItem = true; bool validItem = sc_ReadDir(dir, dirname, diritem, skipItem); if (!validItem) break; if (skipItem || (*(diritem+firstCharOffset) == '.')) continue; // skip files+folders whose first char is a dot if (sc_DirectoryExists(diritem)) { success = PlugIn_LoadDir(diritem, reportError); } else { int dnamelen = strlen(diritem); int extlen = strlen(SC_PLUGIN_EXT); char *extptr = diritem+dnamelen-extlen; if (strncmp(extptr, SC_PLUGIN_EXT, extlen) == 0) { success = PlugIn_Load(diritem); } } if (!success) continue; } sc_CloseDir(dir); return success; } SuperCollider-Source/server/scsynth/SC_Lib_Cintf.h000644 000765 000024 00000003110 12756531745 023257 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Lib_Cintf_ #define _SC_Lib_Cintf_ #include "SC_Lib.h" #include "SC_Reply.h" #include "SC_OSC_Commands.h" typedef SCErr (*SC_CommandFunc)(struct World *inWorld, int inSize, char *inData, ReplyAddress *inReply); class SC_LibCmd : public SC_NamedObj { public: SC_LibCmd(SC_CommandFunc inFunc); SCErr Perform(struct World *inWorld, int inSize, char *inData, ReplyAddress *inReply); private: SC_CommandFunc mFunc; }; extern Malloc gMalloc; extern HashTable *gCmdLib; void initialize_library(const char *mUGensPluginPath); void deinitialize_library(); SCErr NewCommand(const char *inPath, uint32 inCommandNumber, SC_CommandFunc inFunc); extern SC_LibCmd* gCmdArray[NUMBER_OF_COMMANDS]; #endif SuperCollider-Source/server/scsynth/SC_MiscCmds.cpp000644 000765 000024 00000143415 12756531745 023500 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Lib.h" #include "SC_CoreAudio.h" #include "SC_HiddenWorld.h" #include "SC_Graph.h" #include "SC_GraphDef.h" #include "SC_Group.h" #include "SC_UnitDef.h" #include #include "SC_Lib_Cintf.h" #include "SC_SequencedCommand.h" #include #include "SC_Prototypes.h" #include "scsynthsend.h" #include "SC_WorldOptions.h" extern int gMissingNodeID; // returns number of bytes in an OSC string. int OSCstrlen(char *strin); Node* Msg_GetNode(World *inWorld, sc_msg_iter& msg) { Node *node; if (msg.nextTag('i') == 's') { const char* loc = msg.gets(); int32 nodeID = msg.geti(); gMissingNodeID = nodeID; node = World_GetNode(inWorld, nodeID); while (*loc) { if (!node) return 0; switch (*loc) { case 'h' : if (!node->mIsGroup) return 0; node = ((Group*)node)->mHead; break; case 't' : if (!node->mIsGroup) return 0; node = ((Group*)node)->mTail; break; case 'u' : node = &node->mParent->mNode; break; case 'p' : node = node->mPrev; break; case 'n' : node = node->mNext; break; } loc++; } } else { int32 nodeID = msg.geti(); gMissingNodeID = nodeID; node = World_GetNode(inWorld, nodeID); } return node; } Group* Msg_GetGroup(World *inWorld, sc_msg_iter& msg) { Node* node = Msg_GetNode(inWorld, msg); return node && node->mIsGroup ? (Group*)node : 0; } Graph* Msg_GetGraph(World *inWorld, sc_msg_iter& msg) { Node* node = Msg_GetNode(inWorld, msg); return !node || node->mIsGroup ? 0 : (Graph*)node; } SCErr meth_none(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_none(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { return kSCErr_None; } SCErr meth_sync(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_sync(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(SyncCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_alloc(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_alloc(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufAllocCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_free(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_free(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufFreeCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_close(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_close(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufCloseCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_allocRead(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_allocRead(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufAllocReadCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_read(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_read(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufReadCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_allocReadChannel(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_allocReadChannel(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufAllocReadChannelCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_readChannel(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_readChannel(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufReadChannelCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_write(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_write(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufWriteCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_b_zero(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_zero(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufZeroCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_u_cmd(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_u_cmd(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { return Unit_DoCmd(inWorld, inSize, inData); }; SCErr meth_cmd(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_cmd(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { return PlugIn_DoCmd(inWorld, inSize, inData, inReply); }; /* SCErr meth_n_cmd(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_cmd(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { sc_msg_iter msg(inSize, inData); Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; char *args = msg.rdpos; int arglen = msg.remain(); //!! (node->mDef->fNodeCmd)(node, arglen, args); return kSCErr_None; } */ SCErr meth_n_trace(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_trace(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; Node_Trace(node); } return kSCErr_None; } SCErr meth_g_dumpTree(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_dumpTree(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; int32 flag = msg.geti(); if(flag) { Group_DumpTreeAndControls(group); } else { Group_DumpTree(group); } } return kSCErr_None; } //SCErr meth_g_queryTree(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); //SCErr meth_g_queryTree(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) //{ // sc_msg_iter msg(inSize, inData); // while (msg.remain()) { // Group *group = Msg_GetGroup(inWorld, msg); // if (!group) return kSCErr_GroupNotFound; // // // first count the total number of nodes to know how many tags the packet should have // int numNodes = 1; // include this one // // Group_CountNodes(group, &numNodes); // // big_scpacket packet; // packet.adds("/g_queryTree.reply"); // packet.maketags(numNodes * 3 + 1); // packet.addtag(','); // // Group_QueryTree(group, &packet); // // if (packet.size()) { // CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); // } // } // return kSCErr_None; //} SCErr meth_g_queryTree(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_queryTree(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; big_scpacket packet; packet.adds("/g_queryTree.reply"); int32 flag = msg.geti(); if(flag) { // first count the total number of nodes to know how many tags the packet should have int numNodes = 1; // include this one int numControlsAndDefs = 0; Group_CountNodeAndControlTags(group, &numNodes, &numControlsAndDefs); // nodeID and numChildren + numControlsAndDefs + controlFlag packet.maketags(numNodes * 2 + numControlsAndDefs + 2); packet.addtag(','); packet.addtag('i'); packet.addi(1); // include controls flag Group_QueryTreeAndControls(group, &packet); } else { // first count the total number of nodes to know how many tags the packet should have int numNodeTags = 2; // include this one Group_CountNodeTags(group, &numNodeTags); packet.maketags(numNodeTags + 2); // nodeID and numChildren packet.addtag(','); packet.addtag('i'); packet.addi(0); // include controls flag Group_QueryTree(group, &packet); } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } } return kSCErr_None; } SCErr meth_n_run(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_run(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; int32 run = msg.geti(); Node_SetRun(node, run); } return kSCErr_None; } SCErr meth_n_map(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_map(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; while (msg.remain() >= 8) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int bus = msg.geti(); Node_MapControl(node, Hash(name), name, 0, bus); } else { int32 index = msg.geti(); int32 bus = msg.geti(); Node_MapControl(node, index, bus); } } return kSCErr_None; } SCErr meth_n_mapn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_mapn(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; while (msg.remain() >= 12) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); int bus = msg.geti(); int n = msg.geti(); for (int i=0; i= 8) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int bus = msg.geti(); Node_MapAudioControl(node, Hash(name), name, 0, bus); } else { int32 index = msg.geti(); int32 bus = msg.geti(); Node_MapAudioControl(node, index, bus); } } return kSCErr_None; } SCErr meth_n_mapan(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_mapan(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; while (msg.remain() >= 12) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); int bus = msg.geti(); int n = msg.geti(); for (int i=0; i=8) { int i = 0; int loop = 0; if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); do { switch (msg.nextTag('f') ) { case 'f' : case 'i' : { float32 value = msg.getf(); Node_SetControl(node, hash, name, i, value); ++i; break; } case 's' : { const char* string = msg.gets(); if ( *string == 'c') { int bus = sc_atoi(string+1); Node_MapControl(node, hash, name, i, bus); ++i; } if ( *string == 'a') { int bus = sc_atoi(string+1); Node_MapAudioControl(node, hash, name, i, bus); ++i; } break; } case ']': msg.count++; loop--; break; case '[': msg.count++; loop++; break; } } while (loop); } else { int32 index = msg.geti(); do { switch (msg.nextTag('f') ) { case 'f' : case 'i' : { float32 value = msg.getf(); Node_SetControl(node, index + i, value); ++i; break; } case 's' : { const char* string = msg.gets(); if ( *string == 'c') { int bus = sc_atoi(string+1); Node_MapControl(node, index + i, bus); ++i; } if ( *string == 'a') { int bus = sc_atoi(string+1); Node_MapAudioControl(node, index + i, bus); ++i; } break; } case ']': msg.count++; loop--; break; case '[': msg.count++; loop++; break; } } while (loop); } } //{ // int i = 0; // int loop = 0; // if (msg.nextTag('i') == 's') { // int32* name = msg.gets4(); // int32 hash = Hash(name); // if (msg.nextTag('f') == '[' ) { // msg.count++; // loop = 1; // } // do { // if (msg.nextTag('f') == 's' ) { // const char* string = msg.gets(); // if ( *string == 'c') { // int bus = sc_atoi(string+1); // Node_MapControl(node, hash, name, i, bus); // } // } else { // if (msg.nextTag('f') == ']' ) { // msg.count++; // loop = 0; // } else { // float32 value = msg.getf(); // Node_SetControl(node, hash, name, i, value); // } // } // ++i; // } // while (loop); // } else { // int32 index = msg.geti(); // if (msg.nextTag('f') == '[' ) { // msg.count++; // loop = 1; // } // do { // if (msg.nextTag('f') == 's') { // const char* string = msg.gets(); // if (*string == 'c') { // int bus = sc_atoi(string+1); // Node_MapControl(node, index + i, bus); // } // } else { // if (msg.nextTag('f') == ']' ) { // msg.count++; // loop = 0; // } else { // float32 value = msg.getf(); // Node_SetControl(node, index + i, value); // } // } // ++i; // } // while (loop); // } // } return kSCErr_None; } SCErr meth_n_setn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_setn(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; while (msg.remain()) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); int32 n = msg.geti(); for (int i=0; msg.remain() && i= 12) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); int32 n = msg.geti(); float32 value = msg.getf(); for (int i=0; i> 2; packet.adds("/b_info"); packet.maketags(numbufs * 4 + 1); packet.addtag(','); while (msg.remain()) { int bufindex = msg.geti(); SndBuf* buf = World_GetBuf(inWorld, bufindex); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('f'); packet.addi(bufindex); packet.addi(buf->frames); packet.addi(buf->channels); packet.addf(buf->samplerate); } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } return kSCErr_None; } SCErr meth_d_load(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_d_load(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(LoadSynthDefCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_d_recv(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_d_recv(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(RecvSynthDefCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_d_loadDir(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_d_loadDir(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(LoadSynthDefDirCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_d_freeAll(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_d_freeAll(World *inWorld, int /*inSize*/, char * /*inData*/, ReplyAddress* /*inReply*/) { World_FreeAllGraphDefs(inWorld); return kSCErr_None; } SCErr meth_d_free(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_d_free(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { int32* defname = msg.gets4(); if (!defname) return kSCErr_SynthDefNotFound; SCErr err = GraphDef_Remove(inWorld, defname); if(err != kSCErr_None) return err; } return kSCErr_None; } SCErr meth_s_new(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_s_new(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { SCErr err; sc_msg_iter msg(inSize, inData); int32 *defname = msg.gets4(); if (!defname) return kSCErr_WrongArgType; int32 nodeID = msg.geti(); int32 addAction = msg.geti(); GraphDef *def = World_GetGraphDef(inWorld, defname); if (!def) { scprintf("*** ERROR: SynthDef %s not found\n", (char*)defname); return kSCErr_SynthDefNotFound; } Graph *graph = 0; switch (addAction) { case 0 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,true);//true for normal args if (err) return err; if (!graph) return kSCErr_Failed; Group_AddHead(group, &graph->mNode); } break; case 1 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,true); if (err) return err; Group_AddTail(group, &graph->mNode); } break; case 2 : { Node *beforeThisNode = Msg_GetNode(inWorld, msg); if (!beforeThisNode) return kSCErr_NodeNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,true); if (err) return err; Node_AddBefore(&graph->mNode, beforeThisNode); } break; case 3 : { Node *afterThisNode = Msg_GetNode(inWorld, msg); if (!afterThisNode) return kSCErr_NodeNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,true); if (err) return err; Node_AddAfter(&graph->mNode, afterThisNode); } break; case 4 : { Node *replaceThisNode = Msg_GetNode(inWorld, msg); if (!replaceThisNode) return kSCErr_NodeNotFound; Node_RemoveID(replaceThisNode); err = Graph_New(inWorld, def, nodeID, &msg, &graph,true); if (err) return err; Node_Replace(&graph->mNode, replaceThisNode); } break; default: return kSCErr_Failed; } Node_StateMsg(&graph->mNode, kNode_Go); return kSCErr_None; } SCErr meth_s_newargs(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_s_newargs(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { SCErr err; sc_msg_iter msg(inSize, inData); int32 *defname = msg.gets4(); if (!defname) return kSCErr_WrongArgType; int32 nodeID = msg.geti(); int32 addAction = msg.geti(); GraphDef *def = World_GetGraphDef(inWorld, defname); if (!def) { scprintf("*** ERROR: SynthDef %s not found\n", (char*)defname); return kSCErr_SynthDefNotFound; } Graph *graph = 0; switch (addAction) { case 0 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,false);//false for setn type args if (err) return err; if (!graph) return kSCErr_Failed; Group_AddHead(group, &graph->mNode); } break; case 1 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,false); if (err) return err; Group_AddTail(group, &graph->mNode); } break; case 2 : { Node *beforeThisNode = Msg_GetNode(inWorld, msg); if (!beforeThisNode) return kSCErr_NodeNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,false); if (err) return err; Node_AddBefore(&graph->mNode, beforeThisNode); } break; case 3 : { Node *afterThisNode = Msg_GetNode(inWorld, msg); if (!afterThisNode) return kSCErr_NodeNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,false); if (err) return err; Node_AddAfter(&graph->mNode, afterThisNode); } break; case 4 : { Node *replaceThisNode = Msg_GetNode(inWorld, msg); if (!replaceThisNode) return kSCErr_NodeNotFound; err = Graph_New(inWorld, def, nodeID, &msg, &graph,false); if (err) return err; Node_Replace(&graph->mNode, replaceThisNode); } break; default: return kSCErr_Failed; } Node_StateMsg(&graph->mNode, kNode_Go); return kSCErr_None; } SCErr meth_g_new(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_new(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { SCErr err; sc_msg_iter msg(inSize, inData); while (msg.remain()) { int32 newGroupID = msg.geti(); int32 addAction = msg.geti(); Group *newGroup = 0; switch (addAction) { case 0 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; err = Group_New(inWorld, newGroupID, &newGroup); if (err) { if (err == kSCErr_DuplicateNodeID) { newGroup = World_GetGroup(inWorld, newGroupID); if (!newGroup || !newGroup->mNode.mParent || newGroup->mNode.mParent != group) return err; } else return err; } else { Group_AddHead(group, &newGroup->mNode); } } break; case 1 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; err = Group_New(inWorld, newGroupID, &newGroup); if (err) { if (err == kSCErr_DuplicateNodeID) { newGroup = World_GetGroup(inWorld, newGroupID); if (!newGroup || !newGroup->mNode.mParent || newGroup->mNode.mParent != group) return err; } else return err; } else { Group_AddTail(group, &newGroup->mNode); } } break; case 2 : { Node *beforeThisNode = Msg_GetNode(inWorld, msg); if (!beforeThisNode) return kSCErr_TargetNodeNotFound; err = Group_New(inWorld, newGroupID, &newGroup); if (err) { if (err == kSCErr_DuplicateNodeID) { newGroup = World_GetGroup(inWorld, newGroupID); if (!newGroup || !newGroup->mNode.mParent || newGroup->mNode.mParent->mNode.mID != beforeThisNode->mParent->mNode.mID) return err; } else return err; } else { Node_AddBefore(&newGroup->mNode, beforeThisNode); } } break; case 3 : { Node *afterThisNode = Msg_GetNode(inWorld, msg); if (!afterThisNode) return kSCErr_TargetNodeNotFound; err = Group_New(inWorld, newGroupID, &newGroup); if (err) { if (err == kSCErr_DuplicateNodeID) { newGroup = World_GetGroup(inWorld, newGroupID); if (!newGroup || !newGroup->mNode.mParent || newGroup->mNode.mParent->mNode.mID != afterThisNode->mParent->mNode.mID) return err; } else return err; } else { Node_AddAfter(&newGroup->mNode, afterThisNode); } } break; case 4 : { Node *replaceThisNode = Msg_GetNode(inWorld, msg); if (!replaceThisNode) return kSCErr_TargetNodeNotFound; if (replaceThisNode->mID == 0) return kSCErr_ReplaceRootGroup; Node_RemoveID(replaceThisNode); err = Group_New(inWorld, newGroupID, &newGroup); if (err) return err; Node_Replace(&newGroup->mNode, replaceThisNode); } break; default: return kSCErr_Failed; } Node_StateMsg(&newGroup->mNode, kNode_Go); } return kSCErr_None; } SCErr meth_p_new(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_p_new(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { /* we emulate the concept of parallel groups by using sequential groups */ return meth_g_new(inWorld, inSize, inData, inReply); } SCErr meth_n_free(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_free(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; Node_Delete(node); } return kSCErr_None; } SCErr meth_n_before(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_before(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); Node *prevNode = 0; Node *prevTarget = 0; while (msg.remain()) { Node *node = Msg_GetNode(inWorld, msg); Node *target = Msg_GetNode(inWorld, msg); if (!node || !target) continue; // tolerate failure if (prevNode && prevNode != node) { // move the last pair that succeeded Node_Remove(prevNode); Node_AddBefore(prevNode, prevTarget); Node_StateMsg(prevNode, kNode_Move); } prevNode = node; prevTarget = target; } if (prevNode && prevNode != prevTarget) { // move the last pair that succeeded Node_Remove(prevNode); Node_AddBefore(prevNode, prevTarget); Node_StateMsg(prevNode, kNode_Move); } return kSCErr_None; } SCErr meth_n_after(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_after(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); Node *prevNode = 0; Node *prevTarget = 0; while (msg.remain()) { Node *node = Msg_GetNode(inWorld, msg); Node *target = Msg_GetNode(inWorld, msg); if (!node || !target) continue; // tolerate failure if (prevNode && prevNode != node) { // move the last pair that succeeded Node_Remove(prevNode); Node_AddAfter(prevNode, prevTarget); Node_StateMsg(prevNode, kNode_Move); } prevNode = node; prevTarget = target; } if (prevNode) { // move the last pair that succeeded Node_Remove(prevNode); Node_AddAfter(prevNode, prevTarget); Node_StateMsg(prevNode, kNode_Move); } return kSCErr_None; } SCErr meth_n_order(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_n_order(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { Node *prevNode = 0; Node *node = 0; sc_msg_iter msg(inSize, inData); int32 addAction = msg.geti(); // place the first node in the list based on target and addAction switch (addAction) { case 0 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; while(!node && msg.remain()) { node = Msg_GetNode(inWorld, msg); if(!node) scprintf("Warning Node not found\n"); } if (!node) return kSCErr_NodeNotFound; Group *prevGroup = node->mParent; Node_Remove(node); Group_AddHead(group, node); if (group != prevGroup) { Node_StateMsg(node, kNode_Move); } prevNode = node; } break; case 1 : { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; while(!node && msg.remain()) { node = Msg_GetNode(inWorld, msg); if(!node) scprintf("Warning Node not found\n"); } if (!node) return kSCErr_NodeNotFound; Group *prevGroup = node->mParent; Node_Remove(node); Group_AddTail(group, node); if (group != prevGroup) { Node_StateMsg(node, kNode_Move); } prevNode = node; } break; case 2 : { Node *beforeNode = Msg_GetNode(inWorld, msg); if (!beforeNode) return kSCErr_TargetNodeNotFound; while(!node && msg.remain()) { node = Msg_GetNode(inWorld, msg); if(!node) scprintf("Warning Node not found\n"); } if (!node) return kSCErr_NodeNotFound; Node_Remove(node); Node_AddBefore(node, beforeNode); Node_StateMsg(node, kNode_Move); prevNode = node; } break; case 3 : { Node *afterNode = Msg_GetNode(inWorld, msg); if (!afterNode) return kSCErr_TargetNodeNotFound; while(!node && msg.remain()) { node = Msg_GetNode(inWorld, msg); if(!node) scprintf("Warning Node not found\n"); } if (!node) return kSCErr_NodeNotFound; Node_Remove(node); Node_AddAfter(node, afterNode); Node_StateMsg(node, kNode_Move); prevNode = node; } break; default: return kSCErr_Failed; } // now iterate through in order while (msg.remain()) { node = Msg_GetNode(inWorld, msg); if(!node) { scprintf("Warning Node not found\n"); continue; } Node_Remove(node); Node_AddAfter(node, prevNode); Node_StateMsg(node, kNode_Move); prevNode = node; } return kSCErr_None; } SCErr meth_g_head(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_head(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; Group *prevGroup = node->mParent; Node_Remove(node); Group_AddHead(group, node); if (group != prevGroup) { Node_StateMsg(node, kNode_Move); } } return kSCErr_None; } SCErr meth_g_tail(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_tail(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; //Group *prevGroup = node->mParent; Node_Remove(node); Group_AddTail(group, node); //if (group != prevGroup) { Node_StateMsg(node, kNode_Move); //} } return kSCErr_None; } SCErr meth_g_insert(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_insert(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; Node *node = Msg_GetNode(inWorld, msg); if (!node) return kSCErr_NodeNotFound; Group *prevGroup = node->mParent; int index = msg.geti(); Node_Remove(node); Group_Insert(group, node, index); if (group != prevGroup) { Node_StateMsg(node, kNode_Move); } } return kSCErr_None; } SCErr meth_g_freeAll(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_freeAll(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; Group_DeleteAll(group); } return kSCErr_None; } SCErr meth_g_deepFree(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_g_deepFree(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); while (msg.remain()) { Group *group = Msg_GetGroup(inWorld, msg); if (!group) return kSCErr_GroupNotFound; Group_DeepFreeGraphs(group); } return kSCErr_None; } SCErr meth_status(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_status(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(AudioStatusCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_quit(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_quit(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(AudioQuitCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_clearSched(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_clearSched(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { if(inWorld->mRealTime){ inWorld->hw->mAudioDriver->ClearSched(); } return kSCErr_None; } SCErr meth_dumpOSC(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_dumpOSC(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { sc_msg_iter msg(inSize, inData); inWorld->mDumpOSC = msg.geti(); return kSCErr_None; } SCErr meth_b_set(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_set(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); int bufindex = msg.geti(); SndBuf* buf = World_GetBuf(inWorld, bufindex); if (!buf) return kSCErr_Failed; float *data = buf->data; uint32 numSamples = buf->samples; while (msg.remain() >= 8) { uint32 sampleIndex = msg.geti(); float32 value = msg.getf(); if (sampleIndex < numSamples) { data[sampleIndex] = value; } else return kSCErr_IndexOutOfRange; } return kSCErr_None; } SCErr meth_b_setn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_setn(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); int bufindex = msg.geti(); SndBuf* buf = World_GetBuf(inWorld, bufindex); if (!buf) return kSCErr_Failed; float *data = buf->data; int numSamples = buf->samples; while (msg.remain()) { int32 start = msg.geti(); int32 n = msg.geti(); int32 end = start+n-1; if (end < 0 || start >= numSamples) continue; start = sc_clip(start, 0, numSamples-1); end = sc_clip(end, 0, numSamples-1); for (int i=start; msg.remain() && i<=end; ++i) { float32 value = msg.getf(); data[i] = value; } } return kSCErr_None; } SCErr meth_b_fill(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_fill(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); int bufindex = msg.geti(); SndBuf* buf = World_GetBuf(inWorld, bufindex); if (!buf) return kSCErr_Failed; float *data = buf->data; int numSamples = buf->samples; while (msg.remain() >= 12) { int32 start = msg.geti(); int32 n = msg.geti(); float32 value = msg.getf(); int32 end = start+n-1; if (end < 0 || start >= numSamples) continue; start = sc_clip(start, 0, numSamples-1); end = sc_clip(end, 0, numSamples-1); for (int i=start; i<=end; ++i) data[i] = value; } return kSCErr_None; } SCErr meth_b_gen(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_gen(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(BufGenCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_c_set(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_c_set(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); float *data = inWorld->mControlBus; int32 *touched = inWorld->mControlBusTouched; int32 bufCounter = inWorld->mBufCounter; uint32 maxIndex = inWorld->mNumControlBusChannels; while (msg.remain() >= 8) { uint32 index = msg.geti(); float32 value = msg.getf(); if (index < maxIndex) { data[index] = value; touched[index] = bufCounter; } else return kSCErr_IndexOutOfRange; } return kSCErr_None; } SCErr meth_c_setn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_c_setn(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); float *data = inWorld->mControlBus; int32 *touched = inWorld->mControlBusTouched; int32 bufCounter = inWorld->mBufCounter; int maxIndex = inWorld->mNumControlBusChannels; while (msg.remain()) { int32 start = msg.geti(); int32 n = msg.geti(); int32 end = start+n-1; if (start < 0 || end >= maxIndex || start > end) return kSCErr_IndexOutOfRange; for (int i=start; msg.remain() && i<=end; ++i) { float32 value = msg.getf(); data[i] = value; touched[i] = bufCounter; } } return kSCErr_None; } SCErr meth_c_get(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_c_get(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); float *data = inWorld->mControlBus; uint32 maxIndex = inWorld->mNumControlBusChannels; int numheads = msg.remain() >> 2; big_scpacket packet; packet.adds("/c_set"); packet.maketags(numheads * 2 + 1); packet.addtag(','); while (msg.remain() >= 4) { uint32 index = msg.geti(); if (index >= maxIndex) return kSCErr_IndexOutOfRange; packet.addtag('i'); packet.addtag('f'); packet.addi(index); packet.addf(data[index]); } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } return kSCErr_None; } SCErr meth_c_getn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_c_getn(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); float *data = inWorld->mControlBus; int maxIndex = inWorld->mNumControlBusChannels; // figure out how many tags to allocate int numcontrols = 0; int numheads = msg.remain() >> 3; while (msg.remain()) { msg.geti(); // skip start int32 n = msg.geti(); numcontrols += n; } big_scpacket packet; packet.adds("/c_setn"); packet.maketags(numheads * 2 + numcontrols + 1); packet.addtag(','); // start over at beginning of message msg.init(inSize, inData); while (msg.remain()) { int32 start = msg.geti(); int32 n = msg.geti(); int32 end = start+n-1; if (start < 0 || end >= maxIndex || start > end) return kSCErr_IndexOutOfRange; packet.addtag('i'); packet.addtag('i'); packet.addi(start); packet.addi(n); for (int i=start; i<=end; ++i) { packet.addtag('f'); packet.addf(data[i]); } } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } return kSCErr_None; } SCErr meth_c_fill(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_c_fill(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); float *data = inWorld->mControlBus; int32 *touched = inWorld->mControlBusTouched; int32 bufCounter = inWorld->mBufCounter; int maxIndex = inWorld->mNumControlBusChannels; while (msg.remain() >= 12) { int32 start = msg.geti(); int32 n = msg.geti(); float32 value = msg.getf(); int32 end = start+n-1; if (end < 0 || start >= maxIndex) continue; start = sc_clip(start, 0, maxIndex-1); end = sc_clip(end, 0, maxIndex-1); for (int i=start; i<=end; ++i) { data[i] = value; touched[i] = bufCounter; } } return kSCErr_None; } SCErr meth_b_get(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_get(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); int bufindex = msg.geti(); SndBuf* buf = World_GetBuf(inWorld, bufindex); if (!buf) return kSCErr_Failed; float *data = buf->data; uint32 maxIndex = buf->samples; int numheads = msg.remain() >> 2; big_scpacket packet; packet.adds("/b_set"); packet.maketags(numheads * 2 + 2); packet.addtag(','); packet.addtag('i'); packet.addi(bufindex); while (msg.remain() >= 4) { uint32 index = msg.geti(); if (index >= maxIndex) return kSCErr_IndexOutOfRange; packet.addtag('i'); packet.addtag('f'); packet.addi(index); packet.addf(data[index]); } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } return kSCErr_None; } SCErr meth_b_getn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_b_getn(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); int bufindex = msg.geti(); SndBuf* buf = World_GetBuf(inWorld, bufindex); if (!buf) return kSCErr_Failed; float *data = buf->data; int32 maxIndex = buf->samples; // figure out how many tags to allocate int numcontrols = 0; int numheads = msg.remain() >> 3; while (msg.remain()) { msg.geti(); // skip start int32 n = msg.geti(); numcontrols += n; } big_scpacket packet; packet.adds("/b_setn"); packet.maketags(numheads * 2 + numcontrols + 2); packet.addtag(','); // start over at beginning of message msg.init(inSize, inData); msg.geti(); // skip buf index packet.addtag('i'); packet.addi(bufindex); while (msg.remain()) { int32 start = msg.geti(); int32 n = msg.geti(); int32 end = start+n-1; if (start < 0 || end >= maxIndex || start > end) return kSCErr_IndexOutOfRange; packet.addtag('i'); packet.addtag('i'); packet.addi(start); packet.addi(n); for (int i=start; i<=end; ++i) { packet.addtag('f'); packet.addf(data[i]); } } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } return kSCErr_None; } SCErr meth_s_get(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_s_get(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); Graph *graph = Msg_GetGraph(inWorld, msg); if (!graph) return kSCErr_NodeNotFound; int numheads = msg.tags ? strlen(msg.tags) - 1 : msg.remain() >> 2; big_scpacket packet; packet.adds("/n_set"); packet.maketags(numheads * 2 + 2); packet.addtag(','); packet.addtag('i'); packet.addi(graph->mNode.mID); while (msg.remain() >= 4) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); float32 value = 0.f; Graph_GetControl(graph, hash, name, 0, value); packet.addtag('s'); packet.addtag('f'); packet.adds((char*)name); packet.addf(value); } else { int32 index = msg.geti(); float32 value = 0.f; Graph_GetControl(graph, index, value); packet.addtag('i'); packet.addtag('f'); packet.addi(index); packet.addf(value); } } if (packet.size()) { CallSequencedCommand(SendReplyCmd, inWorld, packet.size(), packet.data(), inReply); } return kSCErr_None; } SCErr meth_s_getn(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_s_getn(World *inWorld, int inSize, char *inData, ReplyAddress* inReply) { sc_msg_iter msg(inSize, inData); Graph *graph = Msg_GetGraph(inWorld, msg); if (!graph) return kSCErr_NodeNotFound; // figure out how many tags to allocate int numcontrols = 0; int numheads = msg.tags ? (strlen(msg.tags) - 1) >> 1 : msg.remain() >> 3; while (msg.remain()) { msg.geti(); // skip start int32 n = msg.geti(); numcontrols += n; } big_scpacket packet; packet.adds("/n_setn"); packet.maketags(numheads * 2 + numcontrols + 2); packet.addtag(','); // start over at beginning of message msg.init(inSize, inData); msg.geti(); // skip buf index packet.addtag('i'); packet.addi(graph->mNode.mID); while (msg.remain()) { if (msg.nextTag('i') == 's') { int32* name = msg.gets4(); int32 hash = Hash(name); int32 n = msg.geti(); packet.addtag('s'); packet.addtag('i'); packet.adds((char*)name); packet.addi(n); for (int i=0; imNode); } return kSCErr_None; } SCErr meth_notify(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_notify(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { CallSequencedCommand(NotifyCmd, inWorld, inSize, inData, inReply); return kSCErr_None; } SCErr meth_error(World *inWorld, int inSize, char *inData, ReplyAddress *inReply); SCErr meth_error(World *inWorld, int inSize, char *inData, ReplyAddress* /*inReply*/) { sc_msg_iter msg(inSize, inData); int mode = msg.geti(); // inWorld->mLocalErrorNotification = mode; // // if non-zero, new state should be saved permanently // if(mode) { inWorld->mErrorNotification = mode; }; // -1 = bundle off, -2 = bundle on, 0 = permanent off, 1 = permanent on switch(mode) { case -1: inWorld->mLocalErrorNotification += 1; break; case -2: inWorld->mLocalErrorNotification -= 1; break; case 0: inWorld->mErrorNotification = 0; break; case 1: inWorld->mErrorNotification = 1; }; return kSCErr_None; } #define NEW_COMMAND(name) NewCommand(#name, cmd_##name, meth_##name) void initMiscCommands(); void initMiscCommands() { // nrt NEW_COMMAND(none); NEW_COMMAND(notify); NEW_COMMAND(status); NEW_COMMAND(quit); NEW_COMMAND(clearSched); NEW_COMMAND(d_recv); NEW_COMMAND(d_load); NEW_COMMAND(d_loadDir); NEW_COMMAND(d_freeAll); NEW_COMMAND(d_free); NEW_COMMAND(s_new); NEW_COMMAND(s_newargs); NEW_COMMAND(n_trace); NEW_COMMAND(n_free); NEW_COMMAND(n_run); NEW_COMMAND(u_cmd); NEW_COMMAND(cmd); //NEW_COMMAND(n_cmd); NEW_COMMAND(n_map); NEW_COMMAND(n_mapn); NEW_COMMAND(n_mapa); NEW_COMMAND(n_mapan); NEW_COMMAND(n_set); NEW_COMMAND(n_setn); NEW_COMMAND(n_fill); NEW_COMMAND(n_before); NEW_COMMAND(n_after); NEW_COMMAND(n_order); NEW_COMMAND(g_new); NEW_COMMAND(g_head); NEW_COMMAND(g_tail); NEW_COMMAND(g_freeAll); NEW_COMMAND(g_deepFree); NEW_COMMAND(p_new); NEW_COMMAND(b_alloc); NEW_COMMAND(b_allocRead); NEW_COMMAND(b_allocReadChannel); NEW_COMMAND(b_read); NEW_COMMAND(b_readChannel); NEW_COMMAND(b_write); NEW_COMMAND(b_free); NEW_COMMAND(b_close); NEW_COMMAND(b_zero); NEW_COMMAND(b_set); NEW_COMMAND(b_setn); NEW_COMMAND(b_fill); NEW_COMMAND(b_gen); NEW_COMMAND(c_set); NEW_COMMAND(c_setn); NEW_COMMAND(c_fill); NEW_COMMAND(dumpOSC); NEW_COMMAND(c_get); NEW_COMMAND(c_getn); NEW_COMMAND(b_get); NEW_COMMAND(b_getn); NEW_COMMAND(s_get); NEW_COMMAND(s_getn); NEW_COMMAND(n_query); NEW_COMMAND(b_query); NEW_COMMAND(s_noid); NEW_COMMAND(sync); NEW_COMMAND(g_dumpTree); NEW_COMMAND(g_queryTree); NEW_COMMAND(error); } SuperCollider-Source/server/scsynth/SC_Node.cpp000644 000765 000024 00000027722 12756531745 022665 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Group.h" #include "SC_SynthDef.h" #include "SC_World.h" #include "SC_WorldOptions.h" #include "SC_Errors.h" #include #include #include #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include "Unroll.h" void Node_StateMsg(Node* inNode, int inState); // create a new node int Node_New(World *inWorld, NodeDef *def, int32 inID, Node** outNode) { if (inID < 0) { if (inID == -1) { // -1 means generate an id for the event HiddenWorld* hw = inWorld->hw; inID = hw->mHiddenID = (hw->mHiddenID - 8) | 0x80000000; } else { return kSCErr_ReservedNodeID; } } if (World_GetNode(inWorld, inID)) { return kSCErr_DuplicateNodeID; } Node* node = (Node*)World_Alloc(inWorld, def->mAllocSize); node->mWorld = inWorld; node->mDef = def; node->mParent = 0; node->mPrev = 0; node->mNext = 0; node->mIsGroup = false; node->mID = inID; node->mHash = Hash(inID); if (!World_AddNode(inWorld, node)) { World_Free(inWorld, node); return kSCErr_TooManyNodes; } inWorld->hw->mRecentID = inID; *outNode = node; return kSCErr_None; } // node destructor void Node_Dtor(Node *inNode) { Node_StateMsg(inNode, kNode_End); Node_Remove(inNode); World *world = inNode->mWorld; world->hw->mNodeLib->Remove(inNode); World_Free(world, inNode); } // remove a node from a group void Node_Remove(Node* s) { Group *group = s->mParent; if (s->mPrev) s->mPrev->mNext = s->mNext; else if (group) group->mHead = s->mNext; if (s->mNext) s->mNext->mPrev = s->mPrev; else if (group) group->mTail = s->mPrev; s->mPrev = s->mNext = 0; s->mParent = 0; } void Node_RemoveID(Node *inNode) { if (inNode->mID == 0) return; // failed World* world = inNode->mWorld; if (!World_RemoveNode(world, inNode)) { int err = kSCErr_Failed; // shouldn't happen.. throw err; } HiddenWorld* hw = world->hw; int id = hw->mHiddenID = (hw->mHiddenID - 8) | 0x80000000; inNode->mID = id; inNode->mHash = Hash(id); if (!World_AddNode(world, inNode)) { scprintf("mysterious failure in Node_RemoveID\n"); Node_Delete(inNode); // enums are uncatchable. must throw an int. int err = kSCErr_Failed; // shouldn't happen.. throw err; } //inWorld->hw->mRecentID = id; } // delete a node void Node_Delete(Node* inNode) { if (inNode->mID == 0) return; // failed if (inNode->mIsGroup) Group_Dtor((Group*)inNode); else Graph_Dtor((Graph*)inNode); } // add a node after another one void Node_AddAfter(Node* s, Node *afterThisOne) { if (!afterThisOne->mParent || s->mID == 0) return; // failed s->mParent = afterThisOne->mParent; s->mPrev = afterThisOne; s->mNext = afterThisOne->mNext; if (afterThisOne->mNext) afterThisOne->mNext->mPrev = s; else s->mParent->mTail = s; afterThisOne->mNext = s; } // add a node before another one void Node_AddBefore(Node* s, Node *beforeThisOne) { if (!beforeThisOne->mParent || s->mID == 0) return; // failed s->mParent = beforeThisOne->mParent; s->mPrev = beforeThisOne->mPrev; s->mNext = beforeThisOne; if (beforeThisOne->mPrev) beforeThisOne->mPrev->mNext = s; else s->mParent->mHead = s; beforeThisOne->mPrev = s; } void Node_Replace(Node* s, Node *replaceThisOne) { //scprintf("->Node_Replace\n"); Group *group = replaceThisOne->mParent; if (!group) return; // failed if (s->mID == 0) return; s->mParent = group; s->mPrev = replaceThisOne->mPrev; s->mNext = replaceThisOne->mNext; if (s->mPrev) s->mPrev->mNext = s; else group->mHead = s; if (s->mNext) s->mNext->mPrev = s; else group->mTail = s; replaceThisOne->mPrev = replaceThisOne->mNext = 0; replaceThisOne->mParent = 0; Node_Delete(replaceThisOne); //scprintf("<-Node_Replace\n"); } // set a node's control so that it reads from a control bus - index argument void Node_MapControl(Node* inNode, int inIndex, int inBus) { if (inNode->mIsGroup) { Group_MapControl((Group*)inNode, inIndex, inBus); } else { Graph_MapControl((Graph*)inNode, inIndex, inBus); } } // set a node's control so that it reads from a control bus - name argument void Node_MapControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, int inBus) { if (inNode->mIsGroup) { Group_MapControl((Group*)inNode, inHash, inName, inIndex, inBus); } else { Graph_MapControl((Graph*)inNode, inHash, inName, inIndex, inBus); } } // set a node's control so that it reads from a control bus - index argument void Node_MapAudioControl(Node* inNode, int inIndex, int inBus) { if (inNode->mIsGroup) { Group_MapAudioControl((Group*)inNode, inIndex, inBus); } else { Graph_MapAudioControl((Graph*)inNode, inIndex, inBus); } } // set a node's control so that it reads from a control bus - name argument void Node_MapAudioControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, int inBus) { if (inNode->mIsGroup) { Group_MapAudioControl((Group*)inNode, inHash, inName, inIndex, inBus); } else { Graph_MapAudioControl((Graph*)inNode, inHash, inName, inIndex, inBus); } } // set a node's control value - index argument void Node_SetControl(Node* inNode, int inIndex, float inValue) { if (inNode->mIsGroup) { Group_SetControl((Group*)inNode, inIndex, inValue); } else { Graph_SetControl((Graph*)inNode, inIndex, inValue); } } // set a node's control value - name argument void Node_SetControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, float inValue) { if (inNode->mIsGroup) { Group_SetControl((Group*)inNode, inHash, inName, inIndex, inValue); } else { Graph_SetControl((Graph*)inNode, inHash, inName, inIndex, inValue); } } // this function can be installed using Node_SetRun to cause a node to do nothing // during its execution time. void Node_NullCalc(struct Node* /*inNode*/) { } void Graph_FirstCalc(Graph *inGraph); void Graph_NullFirstCalc(Graph *inGraph); // if inRun is zero then the node's calc function is set to Node_NullCalc, // otherwise its normal calc function is installed. void Node_SetRun(Node* inNode, int inRun) { if (inRun) { if (inNode->mCalcFunc == &Node_NullCalc) { if (inNode->mIsGroup) { inNode->mCalcFunc = (NodeCalcFunc)&Group_Calc; } else { inNode->mCalcFunc = (NodeCalcFunc)&Graph_Calc; } Node_StateMsg(inNode, kNode_On); } } else { if (inNode->mCalcFunc != &Node_NullCalc) { if (!inNode->mIsGroup && inNode->mCalcFunc == (NodeCalcFunc)&Graph_FirstCalc) { inNode->mCalcFunc = (NodeCalcFunc)&Graph_NullFirstCalc; } else { inNode->mCalcFunc = (NodeCalcFunc)&Node_NullCalc; } Node_StateMsg(inNode, kNode_Off); } } } void Node_Trace(Node *inNode) { if (inNode->mIsGroup) { Group_Trace((Group*)inNode); } else { Graph_Trace((Graph*)inNode); } } void Node_End(Node* inNode) { inNode->mCalcFunc = (NodeCalcFunc)&Node_Delete; } // send a trigger from a node to a client program. // this function puts the trigger on a FIFO which is harvested by another thread that // actually does the sending. void Node_SendTrigger(Node* inNode, int triggerID, float value) { World *world = inNode->mWorld; if (!world->mRealTime) return; TriggerMsg msg; msg.mWorld = world; msg.mNodeID = inNode->mID; msg.mTriggerID = triggerID; msg.mValue = value; world->hw->mTriggers.Write(msg); } // Send a reply from a node to a client program. // // This function puts the reply on a FIFO which is harvested by another thread that // actually does the sending. // // NOTE: Only to be called from the realtime thread. void Node_SendReply(Node* inNode, int replyID, const char* cmdName, int numArgs, const float* values) { World *world = inNode->mWorld; if (!world->mRealTime) return; const int cmdNameSize = strlen(cmdName); void* mem = World_Alloc(world, cmdNameSize + numArgs*sizeof(float)); if (mem == 0) return; NodeReplyMsg msg; msg.mWorld = world; msg.mNodeID = inNode->mID; msg.mID = replyID; msg.mValues = (float*)((char*)mem + cmdNameSize); memcpy(msg.mValues, values, numArgs*sizeof(float)); msg.mNumArgs = numArgs; msg.mCmdName = (char*)mem; memcpy(msg.mCmdName, cmdName, cmdNameSize); msg.mCmdNameSize = cmdNameSize; msg.mRTMemory = mem; world->hw->mNodeMsgs.Write(msg); } void Node_SendReply(Node* inNode, int replyID, const char* cmdName, float value) { Node_SendReply(inNode, replyID, cmdName, 1, &value); } // notify a client program of a node's state change. // this function puts the message on a FIFO which is harvested by another thread that // actually does the sending. void Node_StateMsg(Node* inNode, int inState) { if (inNode->mID < 0 && inState != kNode_Info) return; // no notification for negative IDs World *world = inNode->mWorld; if (!world->mRealTime) return; NodeEndMsg msg; msg.mWorld = world; msg.mNodeID = inNode->mID; msg.mGroupID = inNode->mParent ? inNode->mParent->mNode.mID : -1 ; msg.mPrevNodeID = inNode->mPrev ? inNode->mPrev->mID : -1 ; msg.mNextNodeID = inNode->mNext ? inNode->mNext->mID : -1 ; if (inNode->mIsGroup) { Group *group = (Group*)inNode; msg.mIsGroup = 1; msg.mHeadID = group->mHead ? group->mHead->mID : -1; msg.mTailID = group->mTail ? group->mTail->mID : -1; } else { msg.mIsGroup = 0; msg.mHeadID = -1; msg.mTailID = -1; } msg.mState = inState; world->hw->mNodeEnds.Write(msg); } #include "SC_Unit.h" void Unit_DoneAction(int doneAction, Unit *unit) { switch (doneAction) { case 1 : Node_SetRun(&unit->mParent->mNode, 0); break; case 2 : Node_End(&unit->mParent->mNode); break; case 3 : { Node_End(&unit->mParent->mNode); Node* prev = unit->mParent->mNode.mPrev; if (prev) Node_End(prev); } break; case 4 : { Node_End(&unit->mParent->mNode); Node* next = unit->mParent->mNode.mNext; if (next) Node_End(next); } break; case 5 : { Node_End(&unit->mParent->mNode); Node* prev = unit->mParent->mNode.mPrev; if (!prev) break; if (prev && prev->mIsGroup) Group_DeleteAll((Group*)prev); else Node_End(prev); } break; case 6 : { Node_End(&unit->mParent->mNode); Node* next = unit->mParent->mNode.mNext; if (!next) break; if (next->mIsGroup) Group_DeleteAll((Group*)next); else Node_End(next); } break; case 7 : { Node* node = &unit->mParent->mNode; while (node) { Node *prev = node->mPrev; Node_End(node); node = prev; } } break; case 8 : { Node* node = &unit->mParent->mNode; while (node) { Node *next = node->mNext; Node_End(node); node = next; } } break; case 9 : { Node_End(&unit->mParent->mNode); Node* prev = unit->mParent->mNode.mPrev; if (prev) Node_SetRun(prev, 0); } break; case 10 : { Node_End(&unit->mParent->mNode); Node* next = unit->mParent->mNode.mNext; if (next) Node_SetRun(next, 0); } break; case 11 : { Node_End(&unit->mParent->mNode); Node* prev = unit->mParent->mNode.mPrev; if (!prev) break; if (prev->mIsGroup) Group_DeepFreeGraphs((Group*)prev); else Node_End(prev); } break; case 12 : { Node_End(&unit->mParent->mNode); Node* next = unit->mParent->mNode.mNext; if (!next) break; if (next->mIsGroup) Group_DeepFreeGraphs((Group*)next); else Node_End(next); } break; case 13 : { Node* node = unit->mParent->mNode.mParent->mHead; while (node) { Node *next = node->mNext; Node_End(node); node = next; } } break; case 14 : Node_End(&unit->mParent->mNode.mParent->mNode); break; } } SuperCollider-Source/server/scsynth/SC_PortAudio.cpp000644 000765 000024 00000035013 12756531745 023676 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_CoreAudio.h" #include #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include "SC_WorldOptions.h" #include "SC_Time.hpp" #include #include #include "portaudio.h" #define SC_PA_USE_DLL int32 server_timeseed() { return timeSeed(); } #ifdef SC_PA_USE_DLL #include "SC_TimeDLL.hpp" // ===================================================================== // Timing static inline int64 sc_PAOSCTime() { return OSCTime(getTime()); } static inline double sc_PAOSCTimeSeconds() { return (uint64)sc_PAOSCTime() * kOSCtoSecs; } int64 oscTimeNow() { return sc_PAOSCTime(); } void initializeScheduler() { } #else //SC_PA_USE_DLL int64 gOSCoffset = 0; static inline int64 GetCurrentOSCTime() { return OSCTime(getTime()); } int64 oscTimeNow() { return GetCurrentOSCTime(); } int64 PaStreamTimeToOSC(PaTime pa_time) { uint64 s, f; s = (uint64)pa_time; f = (uint64)((pa_time - s) * 1000000 * kMicrosToOSCunits); return (s << 32) + f; } void initializeScheduler() { gOSCoffset = GetCurrentOSCTime(); } #endif //SC_PA_USE_DLL class SC_PortAudioDriver : public SC_AudioDriver { int mInputChannelCount, mOutputChannelCount; PaStream *mStream; PaTime mPaStreamStartupTime; int64 mPaStreamStartupTimeOSC; #ifdef SC_PA_USE_DLL double mMaxOutputLatency; SC_TimeDLL mDLL; #endif protected: // Driver interface methods virtual bool DriverSetup(int* outNumSamplesPerCallback, double* outSampleRate); virtual bool DriverStart(); virtual bool DriverStop(); public: SC_PortAudioDriver(struct World *inWorld); virtual ~SC_PortAudioDriver(); int PortAudioCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags ); private: void GetPaDeviceFromName(const char* device, int* mInOut); }; SC_AudioDriver* SC_NewAudioDriver(struct World *inWorld) { return new SC_PortAudioDriver(inWorld); } #define PRINT_PORTAUDIO_ERROR( function, errorcode )\ scprintf( "SC_PortAudioDriver: PortAudio failed at %s with error: '%s'\n",\ #function, Pa_GetErrorText( errorcode ) ) SC_PortAudioDriver::SC_PortAudioDriver(struct World *inWorld) : SC_AudioDriver(inWorld) , mStream(0) #ifdef SC_PA_USE_DLL ,mMaxOutputLatency(0.) #endif { PaError paerror = Pa_Initialize(); if( paerror != paNoError ) PRINT_PORTAUDIO_ERROR( Pa_Initialize, paerror ); } SC_PortAudioDriver::~SC_PortAudioDriver() { if( mStream ){ PaError paerror = Pa_CloseStream( mStream ); if( paerror != paNoError ) PRINT_PORTAUDIO_ERROR( Pa_CloseStream, paerror ); } Pa_Terminate(); } static int SC_PortAudioStreamCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { SC_PortAudioDriver *driver = (SC_PortAudioDriver*)userData; return driver->PortAudioCallback( input, output, frameCount, timeInfo, statusFlags ); } void sc_SetDenormalFlags(); int SC_PortAudioDriver::PortAudioCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags ) { sc_SetDenormalFlags(); World *world = mWorld; (void) frameCount, timeInfo, statusFlags; // suppress unused parameter warnings #ifdef SC_PA_USE_DLL mDLL.Update(sc_PAOSCTimeSeconds()); #if SC_PA_DEBUG_DLL static int tick = 0; if (++tick >= 10) { tick = 0; scprintf("DLL: t %.6f p %.9f sr %.6f e %.9f avg(e) %.9f inc %.9f\n", mDLL.PeriodTime(), mDLL.Period(), mDLL.SampleRate(), mDLL.Error(), mDLL.AvgError(), mOSCincrement * kOSCtoSecs); //scprintf("mOSCbuftime1 %llu \t %llu \t %f \n",GetCurrentOSCTime(),(uint64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5),((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5)); } #endif #endif try { #if !defined(SC_PA_USE_DLL) // synchronise against the output buffer - timeInfo->currentTime is 0.0 bug in PA? if (mPaStreamStartupTime==0 && mPaStreamStartupTimeOSC==0) { mPaStreamStartupTimeOSC = GetCurrentOSCTime(); mPaStreamStartupTime = timeInfo->outputBufferDacTime; } mOSCbuftime = PaStreamTimeToOSC(timeInfo->outputBufferDacTime - mPaStreamStartupTime) + mPaStreamStartupTimeOSC; #endif mFromEngine.Free(); mToEngine.Perform(); mOscPacketsToEngine.Perform(); const float **inBuffers = (const float**)input; float **outBuffers = (float**)output; int numSamples = NumSamplesPerCallback(); int bufFrames = mWorld->mBufLength; int numBufs = numSamples / bufFrames; float *inBuses = mWorld->mAudioBus + mWorld->mNumOutputs * bufFrames; float *outBuses = mWorld->mAudioBus; int32 *inTouched = mWorld->mAudioBusTouched + mWorld->mNumOutputs; int32 *outTouched = mWorld->mAudioBusTouched; int bufFramePos = 0; #ifdef SC_PA_USE_DLL int64 oscTime = mOSCbuftime = (uint64)((mDLL.PeriodTime() - mMaxOutputLatency) * kSecondsToOSCunits + .5); // int64 oscInc = mOSCincrement = (int64)(mOSCincrementNumerator / mDLL.SampleRate()); int64 oscInc = mOSCincrement = (uint64)((mDLL.Period() / numBufs) * kSecondsToOSCunits + .5); mSmoothSampleRate = mDLL.SampleRate(); double oscToSamples = mOSCtoSamples = mSmoothSampleRate * kOSCtoSecs /* 1/pow(2,32) */; #else int64 oscTime = mOSCbuftime; int64 oscInc = mOSCincrement; double oscToSamples = mOSCtoSamples; #endif // main loop for (int i = 0; i < numBufs; ++i, mWorld->mBufCounter++, bufFramePos += bufFrames) { int32 bufCounter = mWorld->mBufCounter; int32 *tch; // copy+touch inputs tch = inTouched; for (int k = 0; k < mInputChannelCount; ++k) { const float *src = inBuffers[k] + bufFramePos; float *dst = inBuses + k * bufFrames; memcpy(dst, src, bufFrames * sizeof(float)); *tch++ = bufCounter; } // run engine int64 schedTime; int64 nextTime = oscTime + oscInc; // DEBUG /* if (mScheduler.Ready(nextTime)) { double diff = (mScheduler.NextTime() - mOSCbuftime)*kOSCtoSecs; scprintf("rdy %.6f %.6f %.6f %.6f \n", (mScheduler.NextTime()-gStartupOSCTime) * kOSCtoSecs, (mOSCbuftime-gStartupOSCTime)*kOSCtoSecs, diff, (nextTime-gStartupOSCTime)*kOSCtoSecs); } */ while ((schedTime = mScheduler.NextTime()) <= nextTime) { float diffTime = (float)(schedTime - oscTime) * oscToSamples + 0.5; float diffTimeFloor = floor(diffTime); world->mSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= world->mBufLength) world->mSampleOffset = world->mBufLength-1; SC_ScheduledEvent event = mScheduler.Remove(); event.Perform(); } world->mSampleOffset = 0; world->mSubsampleOffset = 0.0f; World_Run(world); // copy touched outputs tch = outTouched; for (int k = 0; k < mOutputChannelCount; ++k) { float *dst = outBuffers[k] + bufFramePos; if (*tch++ == bufCounter) { const float *src = outBuses + k * bufFrames; memcpy(dst, src, bufFrames * sizeof(float)); } else { memset(dst, 0, bufFrames * sizeof(float)); } } // update buffer time oscTime = mOSCbuftime = nextTime; } } catch (std::exception& exc) { scprintf("SC_PortAudioDriver: exception in real time: %s\n", exc.what()); } catch (...) { scprintf("SC_PortAudioDriver: unknown exception in real time\n"); } double cpuUsage = Pa_GetStreamCpuLoad(mStream) * 100.0; mAvgCPU = mAvgCPU + 0.1 * (cpuUsage - mAvgCPU); if (cpuUsage > mPeakCPU || --mPeakCounter <= 0) { mPeakCPU = cpuUsage; mPeakCounter = mMaxPeakCounter; } mAudioSync.Signal(); return paContinue; } void SC_PortAudioDriver::GetPaDeviceFromName(const char* device, int* mInOut) { const PaDeviceInfo *pdi; const PaHostApiInfo *apiInfo; char devString[256]; PaDeviceIndex numDevices = Pa_GetDeviceCount(); mInOut[0] = paNoDevice; mInOut[1] = paNoDevice; // This tries to find one or two devices that match the given name (substring) // might cause problems for some names... for( int i=0; ihostApi); strcpy(devString, apiInfo->name); strcat(devString, " : "); strcat(devString, pdi->name); if (strstr(devString, device)) { if (pdi->maxInputChannels > 0) mInOut[0] = i; if (pdi->maxOutputChannels > 0) mInOut[1] = i; } } } // ==================================================================== // // bool SC_PortAudioDriver::DriverSetup(int* outNumSamples, double* outSampleRate) { int mDeviceInOut[2]; PaError paerror; const PaDeviceInfo *pdi; const PaHostApiInfo *apiInfo; const PaStreamInfo *psi; PaTime suggestedLatencyIn, suggestedLatencyOut; PaDeviceIndex numDevices = Pa_GetDeviceCount(); // print out all options: fprintf(stdout, "\nDevice options:\n"); for( int i=0; ihostApi); fprintf(stdout, " - %s : %s (device #%d with %d ins %d outs)\n", apiInfo->name,pdi->name, i, pdi->maxInputChannels, pdi->maxOutputChannels); } mDeviceInOut[0] = paNoDevice; mDeviceInOut[1] = paNoDevice; if (mWorld->hw->mInDeviceName) GetPaDeviceFromName(mWorld->hw->mInDeviceName, mDeviceInOut); if (mDeviceInOut[0] == paNoDevice) mDeviceInOut[0] = Pa_GetDefaultInputDevice(); if (mDeviceInOut[1] == paNoDevice) mDeviceInOut[1] = Pa_GetDefaultOutputDevice(); *outNumSamples = mWorld->mBufLength; if (mPreferredSampleRate) *outSampleRate = mPreferredSampleRate; else *outSampleRate = 44100.; if (mDeviceInOut[0]!=paNoDevice || mDeviceInOut[1]!=paNoDevice) { if (mPreferredHardwareBufferFrameSize) // controls the suggested latency by hardwareBufferSize switch -Z suggestedLatencyIn = suggestedLatencyOut = mPreferredHardwareBufferFrameSize / (*outSampleRate); else { if (mDeviceInOut[0]!=paNoDevice) suggestedLatencyIn = Pa_GetDeviceInfo( mDeviceInOut[0] )->defaultLowInputLatency; if (mDeviceInOut[1]!=paNoDevice) suggestedLatencyOut = Pa_GetDeviceInfo( mDeviceInOut[1] )->defaultLowOutputLatency; } fprintf(stdout, "\nBooting with:\n"); PaSampleFormat fmt = paFloat32 | paNonInterleaved; if (mDeviceInOut[0]!=paNoDevice){ // avoid to allocate the 128 virtual channels reported by the portaudio library for ALSA "default" mInputChannelCount = std::min(mWorld->mNumInputs, Pa_GetDeviceInfo( mDeviceInOut[0] )->maxInputChannels); fprintf(stdout, " In: %s : %s\n", Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[0] )->hostApi)->name, Pa_GetDeviceInfo( mDeviceInOut[0] )->name); }else{ mInputChannelCount = 0; } if (mDeviceInOut[1]!=paNoDevice){ // avoid to allocate the 128 virtual channels reported by the portaudio library for ALSA "default" mOutputChannelCount = std::min(mWorld->mNumOutputs, Pa_GetDeviceInfo( mDeviceInOut[1] )->maxOutputChannels); fprintf(stdout, " Out: %s : %s\n", Pa_GetHostApiInfo(Pa_GetDeviceInfo( mDeviceInOut[1] )->hostApi)->name, Pa_GetDeviceInfo( mDeviceInOut[1] )->name); }else{ mOutputChannelCount = 0; } PaStreamParameters *inStreamParams_p; PaStreamParameters inStreamParams; if (mDeviceInOut[0]!=paNoDevice){ inStreamParams.device = mDeviceInOut[0]; inStreamParams.channelCount = mInputChannelCount; inStreamParams.sampleFormat = fmt; inStreamParams.suggestedLatency = suggestedLatencyIn; inStreamParams.hostApiSpecificStreamInfo = NULL; inStreamParams_p = &inStreamParams; }else{ inStreamParams_p = NULL; } PaStreamParameters *outStreamParams_p; PaStreamParameters outStreamParams; if (mDeviceInOut[1]!=paNoDevice){ outStreamParams.device = mDeviceInOut[1]; outStreamParams.channelCount = mOutputChannelCount; outStreamParams.sampleFormat = fmt; outStreamParams.suggestedLatency = suggestedLatencyOut; outStreamParams.hostApiSpecificStreamInfo = NULL; outStreamParams_p = &outStreamParams; }else{ outStreamParams_p = NULL; } paerror = Pa_OpenStream(&mStream, inStreamParams_p, outStreamParams_p, *outSampleRate, *outNumSamples, paNoFlag, SC_PortAudioStreamCallback, this ); if( paerror != paNoError ) PRINT_PORTAUDIO_ERROR( Pa_OpenStream, paerror ); else { psi = Pa_GetStreamInfo(mStream); if (!psi) fprintf(stdout," Could not obtain further info from portaudio stream\n"); else { fprintf(stdout," Sample rate: %.3f\n", psi->sampleRate); fprintf(stdout," Latency (in/out): %.3f / %.3f sec\n", psi->inputLatency, psi->outputLatency); #ifdef SC_PA_USE_DLL mMaxOutputLatency = psi->outputLatency; #endif } } return paerror == paNoError; } // should not be necessary, but a last try with OpenDefaultStream... paerror = Pa_OpenDefaultStream( &mStream, mWorld->mNumInputs, mWorld->mNumOutputs, paFloat32 | paNonInterleaved, *outSampleRate, *outNumSamples, SC_PortAudioStreamCallback, this ); mInputChannelCount = mWorld->mNumInputs; mOutputChannelCount = mWorld->mNumOutputs; if( paerror != paNoError ) PRINT_PORTAUDIO_ERROR( Pa_OpenDefaultStream, paerror ); return paerror == paNoError; } bool SC_PortAudioDriver::DriverStart() { if (!mStream) return false; PaError paerror = Pa_StartStream( mStream ); if( paerror != paNoError ) PRINT_PORTAUDIO_ERROR( Pa_StartStream, paerror ); // sync times mPaStreamStartupTimeOSC = 0; mPaStreamStartupTime = 0; // it would be better to do the sync here, but the timeInfo in the callback is incomplete //mPaStreamStartupTimeOSC = GetCurrentOSCTime(); //mPaStreamStartupTime = Pa_GetStreamTime(mStream); #ifdef SC_PA_USE_DLL mDLL.Reset( mSampleRate, mNumSamplesPerCallback, SC_TIME_DLL_BW, sc_PAOSCTimeSeconds()); #endif return paerror == paNoError; } bool SC_PortAudioDriver::DriverStop() { if (!mStream) return false; PaError paerror = Pa_StopStream(mStream); if( paerror != paNoError ) PRINT_PORTAUDIO_ERROR( Pa_StopStream, paerror ); return paerror == paNoError; } SuperCollider-Source/server/scsynth/SC_Prototypes.h000644 000765 000024 00000023034 12450771573 023621 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_Prototypes_ #define _SC_Prototypes_ #include // for size_t #include #include #include "SC_Types.h" #include "scsynthsend.h" //////////////////////////////////////////////////////////////////////// // replacement for calloc. // calloc lazily zeroes memory on first touch. This is good for most purposes, but bad for realtime audio. void* zalloc(size_t n, size_t size); void zfree(void* ptr); //////////////////////////////////////////////////////////////////////// void World_Run(struct World *inWorld); void World_Start(World *inWorld); void World_SetSampleRate(struct World *inWorld, double inSampleRate); extern "C" { void* World_Alloc(struct World *inWorld, size_t inByteSize); void* World_Realloc(struct World *inWorld, void *inPtr, size_t inByteSize); void World_Free(struct World *inWorld, void *inPtr); void World_NRTLock(World *world); void World_NRTUnlock(World *world); } size_t World_TotalFree(struct World *inWorld); size_t World_LargestFreeChunk(struct World *inWorld); int32 GetKey(struct Node *inNode); int32 GetHash(struct Node *inNode); bool World_AddNode(struct World *inWorld, struct Node* inNode); bool World_RemoveNode(struct World *inWorld, struct Node* inNode); extern "C" { struct Node* World_GetNode(struct World *inWorld, int32 inID); struct Graph* World_GetGraph(struct World *inWorld, int32 inID); } struct Group* World_GetGroup(struct World *inWorld, int32 inID); int32 *GetKey(struct UnitDef *inUnitDef); int32 GetHash(struct UnitDef *inUnitDef); bool AddUnitDef(struct UnitDef* inUnitDef); bool RemoveUnitDef(struct UnitDef* inUnitDef); struct UnitDef* GetUnitDef(int32* inKey); int32 *GetKey(struct BufGen *inBufGen); int32 GetHash(struct BufGen *inBufGen); bool AddBufGen(struct BufGen* inBufGen); bool RemoveBufGen(struct BufGen* inBufGen); struct BufGen* GetBufGen(int32* inKey); int32 *GetKey(struct PlugInCmd *inPlugInCmd); int32 GetHash(struct PlugInCmd *inPlugInCmd); bool AddPlugInCmd(struct PlugInCmd* inPlugInCmd); bool RemovePlugInCmd(struct PlugInCmd* inPlugInCmd); struct PlugInCmd* GetPlugInCmd(int32* inKey); int PlugIn_DoCmd(struct World *inWorld, int inSize, char *inArgs, struct ReplyAddress *inReply); int32 *GetKey(struct GraphDef *inGraphDef); int32 GetHash(struct GraphDef *inGraphDef); void World_AddGraphDef(struct World *inWorld, struct GraphDef* inGraphDef); void World_RemoveGraphDef(struct World *inWorld, struct GraphDef* inGraphDef); struct GraphDef* World_GetGraphDef(struct World *inWorld, int32* inKey); void World_FreeAllGraphDefs(World *inWorld); void GraphDef_Free(GraphDef *inGraphDef); void GraphDef_Define(World *inWorld, GraphDef *inList); void GraphDef_FreeOverwritten(World *inWorld); SCErr bufAlloc(struct SndBuf* buf, int numChannels, int numFrames, double sampleRate); //////////////////////////////////////////////////////////////////////// void Rate_Init(struct Rate *inRate, double inSampleRate, int inBufLength); //////////////////////////////////////////////////////////////////////// #define GRAPHDEF(inGraph) ((GraphDef*)((inGraph)->mNode.mDef)) #define GRAPH_PARAM_TABLE(inGraph) (GRAPHDEF(inGraph)->mParamSpecTable) int Graph_New(struct World *inWorld, struct GraphDef *def, int32 inID, struct sc_msg_iter* args, struct Graph** outGraph,bool argtype=true); void Graph_Ctor(struct World *inWorld, struct GraphDef *inGraphDef, struct Graph *graph, struct sc_msg_iter *msg,bool argtype); void Graph_Dtor(struct Graph *inGraph); int Graph_GetControl(struct Graph* inGraph, uint32 inIndex, float& outValue); int Graph_GetControl(struct Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, float& outValue); void Graph_SetControl(struct Graph* inGraph, uint32 inIndex, float inValue); void Graph_SetControl(struct Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, float inValue); void Graph_MapControl(Graph* inGraph, uint32 inIndex, uint32 inBus); void Graph_MapControl(Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus); void Graph_MapAudioControl(Graph* inGraph, uint32 inIndex, uint32 inBus); void Graph_MapAudioControl(Graph* inGraph, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus); void Graph_Trace(Graph *inGraph); //////////////////////////////////////////////////////////////////////// int Node_New(struct World *inWorld, struct NodeDef *def, int32 inID, struct Node **outNode); void Node_Dtor(struct Node *inNode); void Node_Remove(struct Node* s); void Node_RemoveID(Node *inNode); void Node_Delete(struct Node* inNode); void Node_AddAfter(struct Node* s, struct Node *afterThisOne); void Node_AddBefore(struct Node* s, struct Node *beforeThisOne); void Node_Replace(struct Node* s, struct Node *replaceThisOne); void Node_SetControl(Node* inNode, int inIndex, float inValue); void Node_SetControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, float inValue); void Node_MapControl(Node* inNode, int inIndex, int inBus); void Node_MapControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, int inBus); void Node_MapAudioControl(Node* inNode, int inIndex, int inBus); void Node_MapAudioControl(Node* inNode, int32 inHash, int32 *inName, int inIndex, int inBus); void Node_StateMsg(Node* inNode, int inState); void Node_Trace(Node* inNode); void Node_SendReply(Node* inNode, int replyID, const char* cmdName, int numArgs, const float* values); void Node_SendReply(Node* inNode, int replyID, const char* cmdName, float value); extern "C" { void Node_SetRun(Node* inNode, int inRun); void Node_SendTrigger(Node* inNode, int triggerID, float value); void Node_End(struct Node* inNode); void Node_NullCalc(struct Node* inNode); void Unit_DoneAction(int doneAction, struct Unit* unit); } //////////////////////////////////////////////////////////////////////// extern "C" { void Group_Calc(Group *inGroup); void Graph_Calc(struct Graph *inGraph); } int Group_New(World *inWorld, int32 inID, Group** outGroup); void Group_Dtor(Group *inGroup); void Group_DeleteAll(Group *inGroup); void Group_DeepFreeGraphs(Group *inGroup); void Group_AddHead (Group *s, Node *child); void Group_AddTail (Group *s, Node *child); void Group_Insert(Group *s, Node *child, int inIndex); void Group_SetControl(struct Group* inGroup, uint32 inIndex, float inValue); void Group_SetControl(struct Group *inGroup, int32 inHash, int32 *inName, uint32 inIndex, float inValue); void Group_MapControl(Group* inGroup, uint32 inIndex, uint32 inBus); void Group_MapControl(Group* inGroup, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus); void Group_MapAudioControl(Group* inGroup, uint32 inIndex, uint32 inBus); void Group_MapAudioControl(Group* inGroup, int32 inHash, int32 *inName, uint32 inIndex, uint32 inBus); void Group_Trace(Group* inGroup); void Group_DumpTree(Group* inGroup); void Group_DumpTreeAndControls(Group* inGroup); void Group_CountNodeTags(Group* inGroup, int* count); void Group_CountNodeAndControlTags(Group* inGroup, int* count, int* controlAndDefCount); void Group_QueryTree(Group* inGroup, big_scpacket* packet); void Group_QueryTreeAndControls(Group* inGroup, big_scpacket *packet); //////////////////////////////////////////////////////////////////////// struct Unit* Unit_New(struct World *inWorld, struct UnitSpec *inUnitSpec, char*& memory); void Unit_EndCalc(struct Unit *inUnit, int inNumSamples); void Unit_End(struct Unit *inUnit); void Unit_Dtor(struct Unit *inUnit); extern "C" { void Unit_ZeroOutputs(struct Unit *inUnit, int inNumSamples); } //////////////////////////////////////////////////////////////////////// void SendDone(struct ReplyAddress *inReply, const char *inCommandName); void SendDoneWithIntValue(struct ReplyAddress *inReply, const char *inCommandName, int value); void SendFailure(struct ReplyAddress *inReply, const char *inCommandName, const char *errString); void SendFailureWithIntValue(struct ReplyAddress *inReply, const char *inCommandName, const char *errString, uint32 index); void ReportLateness(struct ReplyAddress *inReply, float32 seconds); int32 Hash(struct ReplyAddress *inReplyAddress); //////////////////////////////////////////////////////////////////////// extern "C" { int32 server_timeseed(); } //////////////////////////////////////////////////////////////////////// typedef bool (*AsyncStageFn)(World *inWorld, void* cmdData); typedef void (*AsyncFreeFn)(World *inWorld, void* cmdData); int PerformAsynchronousCommand ( World *inWorld, void* replyAddr, const char* cmdName, void *cmdData, AsyncStageFn stage2, // stage2 is non real time AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData ); //////////////////////////////////////////////////////////////////////// #endif SuperCollider-Source/server/scsynth/SC_Rate.cpp000644 000765 000024 00000003046 12756531745 022664 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Rate.h" #include "SC_Constants.h" #include "SC_Prototypes.h" void Rate_Init(Rate *inRate, double inSampleRate, int inBufLength) { inRate->mSampleRate = inSampleRate; inRate->mSampleDur = 1. / inRate->mSampleRate; inRate->mRadiansPerSample = twopi / inRate->mSampleRate; inRate->mBufLength = inBufLength; inRate->mBufDuration = inRate->mBufLength / inRate->mSampleRate; inRate->mBufRate = 1. / inRate->mBufDuration; inRate->mSlopeFactor = 1. / inRate->mBufLength; inRate->mFilterLoops = inRate->mBufLength / 3; inRate->mFilterRemain = inRate->mBufLength % 3; if( inRate->mFilterLoops == 0. ) inRate->mFilterSlope = 0.; else inRate->mFilterSlope = 1. / inRate->mFilterLoops; } SuperCollider-Source/server/scsynth/SC_SequencedCommand.cpp000644 000765 000024 00000112175 12756531745 025210 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_SequencedCommand.h" #include "SC_CoreAudio.h" #include "SC_Errors.h" #include "scsynthsend.h" #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include "SC_DirUtils.h" #include "SC_StringParser.h" #include "../../common/SC_SndFileHelpers.hpp" #include "SC_WorldOptions.h" #define GET_COMPLETION_MSG(msg) \ mMsgSize = msg.getbsize(); \ if (mMsgSize) { \ mMsgData = (char*)World_Alloc(mWorld, mMsgSize); \ msg.getb(mMsgData, mMsgSize); \ } void PerformCompletionMsg(World *inWorld, OSC_Packet *inPacket); #define SEND_COMPLETION_MSG \ if (mMsgSize) { \ OSC_Packet packet; \ packet.mData = mMsgData; \ packet.mSize = mMsgSize; \ packet.mReplyAddr = mReplyAddress; \ PacketStatus status = PerformCompletionMsg(mWorld, packet); \ if (status == PacketScheduled) { \ mMsgSize = 0; \ mMsgData = 0; \ } \ } void SndBuf_Init(SndBuf *buf); void SndBuf_Init(SndBuf *buf) { buf->data = 0; buf->channels = 0; buf->samples = 0; buf->frames = 0; buf->mask = 0; buf->mask1 = 0; buf->coord = 0; buf->sndfile = 0; } char* allocAndRestrictPath(World *mWorld, const char* inPath, const char* restrictBase); char* allocAndRestrictPath(World *mWorld, const char* inPath, const char* restrictBase){ char strbuf[PATH_MAX]; int offset = 0; int remain = PATH_MAX; // Ensure begins with the base if(strncmp(inPath, restrictBase, strlen(restrictBase)) != 0){ strcpy(strbuf, restrictBase); offset = strlen(restrictBase); remain -= offset; if(inPath[0]!='/' && strbuf[strlen(strbuf)-1]!='/'){ strbuf[offset] = '/'; ++offset; --remain; } } // Now copy string, but discard any ".." (which could be benign, but easy to abuse) SC_StringParser sp(inPath, '/'); size_t tokenlen; while (!sp.AtEnd()) { const char *token = const_cast(sp.NextToken()); tokenlen = strlen(token); // now add the new token, then a slash, as long as token is neither dodgy nor overflows if(strcmp(token, "..")!=0 && remain > tokenlen){ strcpy(strbuf+offset, token); offset += tokenlen; remain -= tokenlen; if(!sp.AtEnd()) { strbuf[offset] = '/'; ++offset; --remain; } } } // Now we can make a long-term home for the string and return it char* saferPath = (char*)World_Alloc(mWorld, strlen(strbuf)+1); strcpy(saferPath, strbuf); return saferPath; } SC_SequencedCommand::SC_SequencedCommand(World *inWorld, ReplyAddress *inReplyAddress) : mNextStage(1), mWorld(inWorld), mMsgSize(0), mMsgData(0) { if (inReplyAddress) mReplyAddress = *inReplyAddress; else mReplyAddress.mReplyFunc = null_reply_func; } SC_SequencedCommand::~SC_SequencedCommand() { if (mMsgData) World_Free(mWorld, mMsgData); } int SC_SequencedCommand::Init(char* /*inData*/, int /*inSize*/) { return kSCErr_None; } void SC_SequencedCommand::SendDone(const char *inCommandName) { ::SendDone(&mReplyAddress, inCommandName); }; void SC_SequencedCommand::SendDoneWithIntValue(const char *inCommandName, int value) { ::SendDoneWithIntValue(&mReplyAddress, inCommandName, value); }; void SC_SequencedCommand::CallEveryStage() { switch (mNextStage) { case 1 : if (!Stage1()) break; mNextStage++; case 2 : if (!Stage2()) break; mNextStage++; case 3 : if (!Stage3()) break; mNextStage++; case 4 : Stage4(); break; } Delete(); } void DoSequencedCommand(FifoMsg *inMsg); void DoSequencedCommand(FifoMsg *inMsg) { SC_SequencedCommand *cmd = (SC_SequencedCommand*)inMsg->mData; cmd->CallNextStage(); } void FreeSequencedCommand(FifoMsg *inMsg); void FreeSequencedCommand(FifoMsg *inMsg) { SC_SequencedCommand *cmd = (SC_SequencedCommand*)inMsg->mData; cmd->Delete(); } void SC_SequencedCommand::CallNextStage() { bool sendAgain = false; FifoMsg msg; int isRealTime = mNextStage & 1; switch (mNextStage) { case 1 : sendAgain = Stage1(); // RT break; case 2 : sendAgain = Stage2(); // NRT break; case 3 : sendAgain = Stage3(); // RT break; case 4 : Stage4(); // NRT break; } mNextStage++; SC_AudioDriver *driver = AudioDriver(mWorld); if (sendAgain) { msg.Set(mWorld, DoSequencedCommand, 0, (void*)this); // send this to next time. if (isRealTime) { // send to NRT driver->SendMsgFromEngine(msg); } else { // send to RT driver->SendMsgToEngine(msg); } } else { if (isRealTime) { Delete(); } else { // can only be freed from RT. msg.Set(mWorld, FreeSequencedCommand, 0, (void*)this); driver->SendMsgToEngine(msg); } } } void SC_SequencedCommand::Delete() { CallDestructor(); World_Free(mWorld, this); } bool SC_SequencedCommand::Stage1() { return true; } bool SC_SequencedCommand::Stage2() { return false; } bool SC_SequencedCommand::Stage3() { return false; } void SC_SequencedCommand::Stage4() { } /////////////////////////////////////////////////////////////////////////// #include "sc_msg_iter.h" #include SyncCmd::SyncCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int SyncCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mID = msg.geti(); return kSCErr_None; } void SyncCmd::CallDestructor() { this->~SyncCmd(); } bool SyncCmd::Stage2() { return true; } bool SyncCmd::Stage3() { return true; } void SyncCmd::Stage4() { small_scpacket packet; packet.adds("/synced"); packet.maketags(2); packet.addtag(','); packet.addtag('i'); packet.addi(mID); SendReply(&mReplyAddress, packet.data(), packet.size()); } /////////////////////////////////////////////////////////////////////////// BufAllocCmd::BufAllocCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int BufAllocCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); mNumFrames = msg.geti(); mNumChannels = msg.geti(1); GET_COMPLETION_MSG(msg); return kSCErr_None; } void BufAllocCmd::CallDestructor() { this->~BufAllocCmd(); } bool BufAllocCmd::Stage2() { SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); mFreeData = buf->data; bufAlloc(buf, mNumChannels, mNumFrames, mWorld->mFullRate.mSampleRate); mSndBuf = *buf; return true; } bool BufAllocCmd::Stage3() { SndBuf* buf = World_GetBuf(mWorld, mBufIndex); *buf = mSndBuf; mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufAllocCmd::Stage4() { zfree(mFreeData); SendDoneWithIntValue("/b_alloc", mBufIndex); } /////////////////////////////////////////////////////////////////////////// #include "sc_msg_iter.h" #include BufGenCmd::BufGenCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mData(0) { } BufGenCmd::~BufGenCmd() { World_Free(mWorld, mData); } int BufGenCmd::Init(char *inData, int inSize) { mSize = inSize; mData = (char*)World_Alloc(mWorld, mSize); memcpy(mData, inData, mSize); sc_msg_iter msg(mSize, mData); mBufIndex = msg.geti(); int32 *genName = msg.gets4(); if (!genName) return kSCErr_WrongArgType; mBufGen = GetBufGen(genName); if (!mBufGen) return kSCErr_BufGenNotFound; mMsg = msg; return kSCErr_None; } void BufGenCmd::CallDestructor() { this->~BufGenCmd(); } bool BufGenCmd::Stage2() { SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); mFreeData = buf->data; (*mBufGen->mBufGenFunc)(mWorld, buf, &mMsg); if (buf->data == mFreeData) mFreeData = NULL; mSndBuf = *buf; return true; } bool BufGenCmd::Stage3() { SndBuf* buf = World_GetBuf(mWorld, mBufIndex); *buf = mSndBuf; mWorld->mSndBufUpdates[mBufIndex].writes ++ ; return true; } void BufGenCmd::Stage4() { zfree(mFreeData); SendDoneWithIntValue("/b_gen", mBufIndex); } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// BufFreeCmd::BufFreeCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int BufFreeCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); GET_COMPLETION_MSG(msg); return kSCErr_None; } void BufFreeCmd::CallDestructor() { this->~BufFreeCmd(); } bool BufFreeCmd::Stage2() { SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); mFreeData = buf->data; #ifndef NO_LIBSNDFILE if (buf->sndfile) sf_close(buf->sndfile); #endif SndBuf_Init(buf); return true; } bool BufFreeCmd::Stage3() { SndBuf *buf = World_GetBuf(mWorld, mBufIndex); SndBuf_Init(buf); mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufFreeCmd::Stage4() { zfree(mFreeData); SendDoneWithIntValue("/b_free", mBufIndex); } /////////////////////////////////////////////////////////////////////////// BufZeroCmd::BufZeroCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int BufZeroCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); GET_COMPLETION_MSG(msg); return kSCErr_None; } void BufZeroCmd::CallDestructor() { this->~BufZeroCmd(); } bool BufZeroCmd::Stage2() { SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); memset(buf->data, 0, buf->samples * sizeof(float)); return true; } bool BufZeroCmd::Stage3() { mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufZeroCmd::Stage4() { SendDoneWithIntValue("/b_zero", mBufIndex); } /////////////////////////////////////////////////////////////////////////// BufAllocReadCmd::BufAllocReadCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mFreeData(0), mFilename(0) { } int BufAllocReadCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } mFileOffset = msg.geti(); mNumFrames = msg.geti(); GET_COMPLETION_MSG(msg); return kSCErr_None; } BufAllocReadCmd::~BufAllocReadCmd() { World_Free(mWorld, mFilename); } void BufAllocReadCmd::CallDestructor() { this->~BufAllocReadCmd(); } bool BufAllocReadCmd::Stage2() { #ifdef NO_LIBSNDFILE SendFailure(&mReplyAddress, "/b_allocRead", "scsynth compiled without libsndfile\n"); scprintf("scsynth compiled without libsndfile\n"); return false; #else SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); SF_INFO fileinfo; memset(&fileinfo, 0, sizeof(fileinfo)); SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo); if (!sf) { char str[512]; sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL)); SendFailureWithIntValue(&mReplyAddress, "/b_allocRead", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str); scprintf(str); return false; } if (mFileOffset < 0) mFileOffset = 0; else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames; if (mNumFrames <= 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset; // alloc data size mFreeData = buf->data; SCErr err = bufAlloc(buf, fileinfo.channels, mNumFrames, fileinfo.samplerate); if (err) goto leave; sf_seek(sf, mFileOffset, SEEK_SET); sf_readf_float(sf, buf->data, mNumFrames); leave: mSndBuf = *buf; sf_close(sf); return true; #endif } bool BufAllocReadCmd::Stage3() { SndBuf* buf = World_GetBuf(mWorld, mBufIndex); *buf = mSndBuf; mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufAllocReadCmd::Stage4() { zfree(mFreeData); SendDoneWithIntValue("/b_allocRead", mBufIndex); } /////////////////////////////////////////////////////////////////////////// BufReadCmd::BufReadCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0) { } int BufReadCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } mFileOffset = msg.geti(); mNumFrames = msg.geti(-1); mBufOffset = msg.geti(); mLeaveFileOpen = msg.geti(); GET_COMPLETION_MSG(msg); return kSCErr_None; } BufReadCmd::~BufReadCmd() { World_Free(mWorld, mFilename); } void BufReadCmd::CallDestructor() { this->~BufReadCmd(); } bool BufReadCmd::Stage2() { #ifdef NO_LIBSNDFILE SendFailure(&mReplyAddress, "/b_read", "scsynth compiled without libsndfile\n"); scprintf("scsynth compiled without libsndfile\n"); return false; #else SF_INFO fileinfo; SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); int framesToEnd = buf->frames - mBufOffset; if (framesToEnd <= 0) return true; SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo); if (!sf) { char str[512]; sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL)); SendFailureWithIntValue(&mReplyAddress, "/b_read", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str); scprintf(str); return false; } if (fileinfo.channels != buf->channels) { char str[512]; sf_close(sf); sprintf(str, "Channel mismatch. File '%s' has %d channels. Buffer has %d channels.\n", mFilename, fileinfo.channels, buf->channels); SendFailureWithIntValue(&mReplyAddress, "/b_read", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str); scprintf(str); return false; } if (mFileOffset < 0) mFileOffset = 0; else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames; if (mNumFrames < 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset; if (mNumFrames > framesToEnd) mNumFrames = framesToEnd; sf_seek(sf, mFileOffset, SEEK_SET); if (mNumFrames > 0) { sf_readf_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames); } if(buf->sndfile) sf_close(buf->sndfile); if (mLeaveFileOpen) { buf->sndfile = sf; } else { sf_close(sf); buf->sndfile = 0; } mSampleRate = (double)fileinfo.samplerate; return true; #endif } bool BufReadCmd::Stage3() { SndBuf* buf = World_GetBuf(mWorld, mBufIndex); buf->samplerate = mSampleRate; if (mLeaveFileOpen) buf->mask = buf->mask1 = -1; mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufReadCmd::Stage4() { SendDoneWithIntValue("/b_read", mBufIndex); } /////////////////////////////////////////////////////////////////////////// SC_BufReadCommand::SC_BufReadCommand(World* inWorld, ReplyAddress* inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mNumChannels(0) { } SC_BufReadCommand::~SC_BufReadCommand() { } void SC_BufReadCommand::InitChannels(sc_msg_iter& msg) { mNumChannels = 0; while (msg.nextTag(0) == 'i') { int c = msg.geti(); if (mNumChannels <= kMaxNumChannels) { mChannels[mNumChannels++] = c; } } } bool SC_BufReadCommand::CheckChannels(int inNumChannels) { for (int i=0; i < mNumChannels; ++i) { if (mChannels[i] >= inNumChannels) { return false; } } return true; } void SC_BufReadCommand::CopyChannels(float* dst, float* src, size_t srcChannels, size_t numFrames) { for (int ci=0; ci < mNumChannels; ++ci) { int c = mChannels[ci]; if (c >= 0 && c < srcChannels) { for (size_t fi=0; fi < numFrames; ++fi) { dst[fi*mNumChannels+ci] = src[fi*srcChannels+c]; } } else { for (size_t fi=0; fi < numFrames; ++fi) { dst[fi*mNumChannels+ci] = 0.f; } } } } /////////////////////////////////////////////////////////////////////////// BufAllocReadChannelCmd::BufAllocReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_BufReadCommand(inWorld, inReplyAddress), mFreeData(0), mFilename(0) { } int BufAllocReadChannelCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } mFileOffset = msg.geti(); mNumFrames = msg.geti(); InitChannels(msg); GET_COMPLETION_MSG(msg); return kSCErr_None; } BufAllocReadChannelCmd::~BufAllocReadChannelCmd() { World_Free(mWorld, mFilename); } void BufAllocReadChannelCmd::CallDestructor() { this->~BufAllocReadChannelCmd(); } bool BufAllocReadChannelCmd::Stage2() { #ifdef NO_LIBSNDFILE SendFailure(&mReplyAddress, "/b_allocReadChannel", "scsynth compiled without libsndfile\n"); scprintf("scsynth compiled without libsndfile\n"); return false; #else SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); SF_INFO fileinfo; memset(&fileinfo, 0, sizeof(fileinfo)); SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo); if (!sf) { char str[512]; sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL)); SendFailureWithIntValue(&mReplyAddress, "/b_allocReadChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str); scprintf(str); return false; } if (mFileOffset < 0) mFileOffset = 0; else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames; if (mNumFrames <= 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset; if (mNumChannels == 0) { // alloc data size mFreeData = buf->data; SCErr err = bufAlloc(buf, fileinfo.channels, mNumFrames, fileinfo.samplerate); if (err) goto leave; // read all channels sf_seek(sf, mFileOffset, SEEK_SET); sf_readf_float(sf, buf->data, mNumFrames); } else { // verify channel indexes if (!CheckChannels(fileinfo.channels)) { const char* str = "Channel index out of range.\n"; SendFailureWithIntValue(&mReplyAddress, "/b_allocReadChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str); scprintf(str); sf_close(sf); return false; } // alloc data size mFreeData = buf->data; SCErr err = bufAlloc(buf, mNumChannels, mNumFrames, fileinfo.samplerate); if (err) goto leave; // alloc temp buffer float* data = (float*)malloc(mNumFrames*fileinfo.channels*sizeof(float)); if (data == 0) goto leave; // read some channels sf_seek(sf, mFileOffset, SEEK_SET); sf_readf_float(sf, data, mNumFrames); CopyChannels(buf->data, data, fileinfo.channels, mNumFrames); // free temp buffer free(data); } leave: mSndBuf = *buf; sf_close(sf); return true; #endif } bool BufAllocReadChannelCmd::Stage3() { SndBuf* buf = World_GetBuf(mWorld, mBufIndex); *buf = mSndBuf; mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufAllocReadChannelCmd::Stage4() { zfree(mFreeData); SendDoneWithIntValue("/b_allocReadChannel", mBufIndex); } /////////////////////////////////////////////////////////////////////////// BufReadChannelCmd::BufReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_BufReadCommand(inWorld, inReplyAddress), mFilename(0) { } int BufReadChannelCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } mFileOffset = msg.geti(); mNumFrames = msg.geti(-1); mBufOffset = msg.geti(); mLeaveFileOpen = msg.geti(); InitChannels(msg); GET_COMPLETION_MSG(msg); return kSCErr_None; } BufReadChannelCmd::~BufReadChannelCmd() { World_Free(mWorld, mFilename); } void BufReadChannelCmd::CallDestructor() { this->~BufReadChannelCmd(); } bool BufReadChannelCmd::Stage2() { #ifdef NO_LIBSNDFILE SendFailure(&mReplyAddress, "/b_readChannel", "scsynth compiled without libsndfile\n"); scprintf("scsynth compiled without libsndfile\n"); return false; #else SF_INFO fileinfo; SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); int framesToEnd = buf->frames - mBufOffset; if (framesToEnd <= 0) return true; SNDFILE* sf = sf_open(mFilename, SFM_READ, &fileinfo); if (!sf) { char str[512]; sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL)); SendFailureWithIntValue(&mReplyAddress, "/b_readChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_read", str); scprintf(str); return false; } if (mNumChannels > 0) { // verify channel indexes if (!( CheckChannels(fileinfo.channels)) ) { // nescivi: && CheckChannels(buf->channels) (should not check here for buf->channels) const char* str = "Channel index out of range.\n"; SendFailureWithIntValue(&mReplyAddress, "/b_readChannel", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_allocRead", str); scprintf(str); sf_close(sf); return false; } // nescivi: this also seems out of place: we want to read from a file with more channels than are in the buffer // } else if (fileinfo.channels != buf->channels) { // char str[256]; // sf_close(sf); // sprintf(str, "Channel mismatch. File '%s' has %d channels. Buffer has %d channels.\n", // mFilename, fileinfo.channels, buf->channels); // SendFailure(&mReplyAddress, "/b_read", str); // scprintf(str); // return false; } if (mFileOffset < 0) mFileOffset = 0; else if (mFileOffset > fileinfo.frames) mFileOffset = fileinfo.frames; if (mNumFrames < 0 || mNumFrames + mFileOffset > fileinfo.frames) mNumFrames = fileinfo.frames - mFileOffset; if (mNumFrames > framesToEnd) mNumFrames = framesToEnd; sf_seek(sf, mFileOffset, SEEK_SET); if (mNumFrames > 0) { if (mNumChannels == 0) { // read all channels sf_readf_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames); } else { // alloc temp buffer float* data = (float*)malloc(mNumFrames*fileinfo.channels*sizeof(float)); if (data == 0) goto leave; // read some channels sf_seek(sf, mFileOffset, SEEK_SET); sf_readf_float(sf, data, mNumFrames); CopyChannels(buf->data + (mBufOffset * mNumChannels), data, fileinfo.channels, mNumFrames); // free temp buffer free(data); } } leave: if(buf->sndfile) sf_close(buf->sndfile); if (mLeaveFileOpen) { buf->sndfile = sf; } else { sf_close(sf); buf->sndfile = 0; } mSampleRate = (double)fileinfo.samplerate; return true; #endif } bool BufReadChannelCmd::Stage3() { SndBuf* buf = World_GetBuf(mWorld, mBufIndex); buf->samplerate = mSampleRate; if (mLeaveFileOpen) buf->mask = buf->mask1 = -1; mWorld->mSndBufUpdates[mBufIndex].writes ++ ; SEND_COMPLETION_MSG; return true; } void BufReadChannelCmd::Stage4() { SendDoneWithIntValue("/b_readChannel", mBufIndex); } /////////////////////////////////////////////////////////////////////////// BufWriteCmd::BufWriteCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0) { } #ifdef NO_LIBSNDFILE struct SF_INFO {}; #endif int BufWriteCmd::Init(char *inData, int inSize) { #ifdef NO_LIBSNDFILE SendFailure(&mReplyAddress, "/b_write", "scsynth compiled without libsndfile\n"); scprintf("scsynth compiled without libsndfile\n"); return false; #else sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } const char *headerFormatString = msg.gets("aiff"); const char *sampleFormatString = msg.gets("int16"); mNumFrames = msg.geti(-1); mBufOffset = msg.geti(); mLeaveFileOpen = msg.geti(); GET_COMPLETION_MSG(msg); memset(&mFileInfo, 0, sizeof(mFileInfo)); return sndfileFormatInfoFromStrings(&mFileInfo, headerFormatString, sampleFormatString); #endif } BufWriteCmd::~BufWriteCmd() { World_Free(mWorld, mFilename); } void BufWriteCmd::CallDestructor() { this->~BufWriteCmd(); } bool BufWriteCmd::Stage2() { #ifdef NO_LIBSNDFILE return false; #else SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); int framesToEnd = buf->frames - mBufOffset; if (framesToEnd < 0) framesToEnd = 0; mFileInfo.samplerate = (int)buf->samplerate; mFileInfo.channels = buf->channels; SNDFILE* sf = sf_open(mFilename, SFM_WRITE, &mFileInfo); if (!sf) { char str[512]; sprintf(str, "File '%s' could not be opened: %s\n", mFilename, sf_strerror(NULL)); SendFailureWithIntValue(&mReplyAddress, "/b_write", str, mBufIndex); //SendFailure(&mReplyAddress, "/b_write", str); scprintf(str); return false; } if (mNumFrames < 0 || mNumFrames > buf->frames) mNumFrames = buf->frames; if (mNumFrames > framesToEnd) mNumFrames = framesToEnd; sf_command(sf, SFC_SET_CLIPPING, NULL, SF_TRUE); // choose clipping rather than wraparound for integer-format files if (mNumFrames > 0) { sf_writef_float(sf, buf->data + (mBufOffset * buf->channels), mNumFrames); } if(buf->sndfile) sf_close(buf->sndfile); if (mLeaveFileOpen) { buf->sndfile = sf; } else { sf_close(sf); buf->sndfile = 0; } return true; #endif } bool BufWriteCmd::Stage3() { SEND_COMPLETION_MSG; return true; } void BufWriteCmd::Stage4() { SendDoneWithIntValue("/b_write", mBufIndex); } /////////////////////////////////////////////////////////////////////////// BufCloseCmd::BufCloseCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int BufCloseCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mBufIndex = msg.geti(); GET_COMPLETION_MSG(msg); return kSCErr_None; } void BufCloseCmd::CallDestructor() { this->~BufCloseCmd(); } bool BufCloseCmd::Stage2() { #ifdef NO_LIBSNDFILE SendFailure(&mReplyAddress, "/b_close", "scsynth compiled without libsndfile\n"); scprintf("scsynth compiled without libsndfile\n"); return false; #else SndBuf *buf = World_GetNRTBuf(mWorld, mBufIndex); if (buf->sndfile) { sf_close(buf->sndfile); buf->sndfile = 0; } return true; #endif } bool BufCloseCmd::Stage3() { SEND_COMPLETION_MSG; return true; } void BufCloseCmd::Stage4() { SendDoneWithIntValue("/b_close", mBufIndex); } /////////////////////////////////////////////////////////////////////////// AudioQuitCmd::AudioQuitCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } void AudioQuitCmd::CallDestructor() { this->~AudioQuitCmd(); } bool AudioQuitCmd::Stage2() { mWorld->hw->mTerminating = true; return true; } bool AudioQuitCmd::Stage3() { #if SC_AUDIO_API == SC_AUDIO_API_AUDIOUNITS SendFailure(&mReplyAddress, "/quit", "not allowed in AU host\n"); scprintf("/quit : quit not allowed in AU host\n"); return false; #else if (mWorld->hw->mShmem) mWorld->hw->mShmem->disconnect(); return true; #endif } void AudioQuitCmd::Stage4() { SendDone("/quit"); mWorld->hw->mQuitProgram->post(); } /////////////////////////////////////////////////////////////////////////// AudioStatusCmd::AudioStatusCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } void AudioStatusCmd::CallDestructor() { this->~AudioStatusCmd(); } bool AudioStatusCmd::Stage2() { // we stop replying to status requests after receiving /quit if (mWorld->hw->mTerminating == true) return false; small_scpacket packet; packet.adds("/status.reply"); packet.maketags(10); packet.addtag(','); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('f'); packet.addtag('f'); packet.addtag('d'); packet.addtag('d'); packet.addi(1); // audio is always active now. packet.addi(mWorld->mNumUnits); packet.addi(mWorld->mNumGraphs); packet.addi(mWorld->mNumGroups); packet.addi(mWorld->hw->mGraphDefLib->NumItems()); SC_AudioDriver *driver = mWorld->hw->mAudioDriver; packet.addf(driver->GetAvgCPU()); packet.addf(driver->GetPeakCPU()); packet.addd(driver->GetSampleRate()); packet.addd(driver->GetActualSampleRate()); SendReply(&mReplyAddress, packet.data(), packet.size()); return false; } /////////////////////////////////////////////////////////////////////////// NotifyCmd::NotifyCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int NotifyCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); mOnOff = msg.geti(); return kSCErr_None; } void NotifyCmd::CallDestructor() { this->~NotifyCmd(); } bool NotifyCmd::Stage2() { HiddenWorld *hw = mWorld->hw; if (mOnOff) { for (uint32 i=0; imNumUsers; ++i) { if (mReplyAddress == hw->mUsers[i]) { // already in table - don't fail though.. SendFailureWithIntValue(&mReplyAddress, "/notify", "notify: already registered\n", hw->mClientIDdict->at(mReplyAddress)); scprintf("/notify : already registered\n"); return false; } } // add reply address to user table if (hw->mNumUsers >= hw->mMaxUsers) { SendFailure(&mReplyAddress, "/notify", "too many users\n"); scprintf("too many users\n"); return false; } uint32 clientID = hw->mClientIDs[hw->mClientIDTop++]; // pop an ID hw->mClientIDdict->insert(std::pair(mReplyAddress,clientID)); hw->mUsers[hw->mNumUsers++] = mReplyAddress; SendDoneWithIntValue("/notify", clientID); } else { for (uint32 i=0; imNumUsers; ++i) { if (mReplyAddress == hw->mUsers[i]) { // remove from list hw->mClientIDs[--hw->mClientIDTop] = hw->mClientIDdict->at(mReplyAddress); // push the freed ID hw->mClientIDdict->erase(mReplyAddress); hw->mUsers[i] = hw->mUsers[--hw->mNumUsers]; SendDone("/notify"); return false; } } SendFailure(&mReplyAddress, "/notify", "not registered\n"); scprintf("not registered\n"); } return false; } /////////////////////////////////////////////////////////////////////////// SendFailureCmd::SendFailureCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mCmdName(0), mErrString(0) { } SendFailureCmd::~SendFailureCmd() { World_Free(mWorld, mCmdName); World_Free(mWorld, mErrString); } void SendFailureCmd::InitSendFailureCmd(const char *inCmdName, const char* inErrString) { mCmdName = (char*)World_Alloc(mWorld, strlen(inCmdName)+1); strcpy(mCmdName, inCmdName); mErrString = (char*)World_Alloc(mWorld, strlen(inErrString)+1); strcpy(mErrString, inErrString); } void SendFailureCmd::CallDestructor() { this->~SendFailureCmd(); } bool SendFailureCmd::Stage2() { SendFailure(&mReplyAddress, mCmdName, mErrString); return false; } /////////////////////////////////////////////////////////////////////////// RecvSynthDefCmd::RecvSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mBuffer(0) { } int RecvSynthDefCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); int size = msg.getbsize(); if (!size) throw kSCErr_WrongArgType; mBuffer = (char*)World_Alloc(mWorld, size); msg.getb(mBuffer, size); GET_COMPLETION_MSG(msg); mDefs = 0; return kSCErr_None; } RecvSynthDefCmd::~RecvSynthDefCmd() { World_Free(mWorld, mBuffer); } void RecvSynthDefCmd::CallDestructor() { this->~RecvSynthDefCmd(); } bool RecvSynthDefCmd::Stage2() { mDefs = GraphDef_Recv(mWorld, mBuffer, mDefs); return true; } bool RecvSynthDefCmd::Stage3() { GraphDef_Define(mWorld, mDefs); SEND_COMPLETION_MSG; return true; } void RecvSynthDefCmd::Stage4() { SendDone("/d_recv"); } /////////////////////////////////////////////////////////////////////////// LoadSynthDefCmd::LoadSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0) { } int LoadSynthDefCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } GET_COMPLETION_MSG(msg); mDefs = 0; return kSCErr_None; } LoadSynthDefCmd::~LoadSynthDefCmd() { World_Free(mWorld, mFilename); } void LoadSynthDefCmd::CallDestructor() { this->~LoadSynthDefCmd(); } bool LoadSynthDefCmd::Stage2() { char* fname = mFilename; mDefs = GraphDef_LoadGlob(mWorld, fname, mDefs); return true; } bool LoadSynthDefCmd::Stage3() { GraphDef_Define(mWorld, mDefs); SEND_COMPLETION_MSG; return true; } void LoadSynthDefCmd::Stage4() { SendDone("/d_load"); } /////////////////////////////////////////////////////////////////////////// LoadSynthDefDirCmd::LoadSynthDefDirCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress), mFilename(0) { } int LoadSynthDefDirCmd::Init(char *inData, int inSize) { sc_msg_iter msg(inSize, inData); const char *filename = msg.gets(); if (!filename) return kSCErr_WrongArgType; if(mWorld->mRestrictedPath){ mFilename = allocAndRestrictPath(mWorld, filename, mWorld->mRestrictedPath); }else{ mFilename = (char*)World_Alloc(mWorld, strlen(filename)+1); strcpy(mFilename, filename); } GET_COMPLETION_MSG(msg); mDefs = 0; return kSCErr_None; } LoadSynthDefDirCmd::~LoadSynthDefDirCmd() { World_Free(mWorld, mFilename); } void LoadSynthDefDirCmd::CallDestructor() { this->~LoadSynthDefDirCmd(); } bool LoadSynthDefDirCmd::Stage2() { mDefs = GraphDef_LoadDir(mWorld, mFilename, mDefs); return true; } bool LoadSynthDefDirCmd::Stage3() { GraphDef_Define(mWorld, mDefs); SEND_COMPLETION_MSG; return true; } void LoadSynthDefDirCmd::Stage4() { SendDone("/d_loadDir"); } /////////////////////////////////////////////////////////////////////////// SendReplyCmd::SendReplyCmd(World *inWorld, ReplyAddress *inReplyAddress) : SC_SequencedCommand(inWorld, inReplyAddress) { } int SendReplyCmd::Init(char *inData, int inSize) { mMsgSize = inSize; mMsgData = (char*)World_Alloc(mWorld, mMsgSize); memcpy(mMsgData, inData, inSize); return kSCErr_None; } void SendReplyCmd::CallDestructor() { this->~SendReplyCmd(); } bool SendReplyCmd::Stage2() { SendReply(&mReplyAddress, mMsgData, mMsgSize); return false; } /////////////////////////////////////////////////////////////////////////// int PerformAsynchronousCommand( World *inWorld, void* replyAddr, const char* cmdName, void *cmdData, AsyncStageFn stage2, // stage2 is non real time AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData ) { void* space = World_Alloc(inWorld, sizeof(AsyncPlugInCmd)); AsyncPlugInCmd *cmd = new (space) AsyncPlugInCmd(inWorld, (ReplyAddress*)replyAddr, cmdName, cmdData, stage2, stage3, stage4, cleanup, completionMsgSize, completionMsgData); if (!cmd) return kSCErr_Failed; if (inWorld->mRealTime) cmd->CallNextStage(); else cmd->CallEveryStage(); return kSCErr_None; } /////////////////////////////////////////////////////////////////////////// AsyncPlugInCmd::AsyncPlugInCmd(World *inWorld, ReplyAddress *inReplyAddress, const char* cmdName, void *cmdData, AsyncStageFn stage2, // stage2 is non real time AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true AsyncFreeFn cleanup, // cleanup is called in real time int completionMsgSize, void* completionMsgData) : SC_SequencedCommand(inWorld, inReplyAddress), mCmdName(cmdName), mCmdData(cmdData), mStage2(stage2), mStage3(stage3), mStage4(stage4), mCleanup(cleanup) { if (completionMsgSize && completionMsgData) { mMsgSize = completionMsgSize; mMsgData = (char*)World_Alloc(mWorld, mMsgSize); memcpy(mMsgData, completionMsgData, mMsgSize); } } AsyncPlugInCmd::~AsyncPlugInCmd() { (mCleanup)(mWorld, mCmdData); if (mMsgData) World_Free(mWorld, mMsgData); } void AsyncPlugInCmd::CallDestructor() { this->~AsyncPlugInCmd(); } bool AsyncPlugInCmd::Stage2() { bool result = !mStage2 || (mStage2)(mWorld, mCmdData); return result; } bool AsyncPlugInCmd::Stage3() { bool result = !mStage3 || (mStage3)(mWorld, mCmdData); if (result) SEND_COMPLETION_MSG; return result; } void AsyncPlugInCmd::Stage4() { bool result = !mStage4 || (mStage4)(mWorld, mCmdData); if (result && mCmdName && mReplyAddress.mReplyFunc != null_reply_func) SendDone((char*)mCmdName); } SuperCollider-Source/server/scsynth/SC_SequencedCommand.h000644 000765 000024 00000032052 12321461511 024625 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Having SequencedCommands allows performing actions that might otherwise require * taking a mutex, which is undesirable in a real time thread. * Some commands require several stages of processing at both the real time * and non real time levels. This class does the messaging between levels for you * so that you only need to write the functions. */ #ifndef _SC_SequencedCommand_ #define _SC_SequencedCommand_ #include "OSC_Packet.h" #include "SC_World.h" #include "SC_BufGen.h" #include "sc_msg_iter.h" #ifndef NO_LIBSNDFILE #include #endif #include #define CallSequencedCommand(T, inWorld, inSize, inData, inReply) \ void* space = World_Alloc(inWorld, sizeof(T)); \ T *cmd = new (space) T(inWorld, inReply); \ if (!cmd) return kSCErr_Failed; \ int err = cmd->Init(inData, inSize); \ if (err) { \ cmd->~T(); \ World_Free(inWorld, space); \ return err; \ } \ if (inWorld->mRealTime) cmd->CallNextStage(); \ else cmd->CallEveryStage(); class SC_SequencedCommand { public: SC_SequencedCommand(World *inWorld, ReplyAddress *inReplyAddress); virtual ~SC_SequencedCommand(); void Delete(); void CallEveryStage(); void CallNextStage(); virtual int Init(char *inData, int inSize); virtual bool Stage1(); // real time virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time void SendDone(const char *inCommandName); void SendDoneWithIntValue(const char *inCommandName, int value); protected: int mNextStage; ReplyAddress mReplyAddress; World *mWorld; int mMsgSize; char *mMsgData; virtual void CallDestructor()=0; }; /////////////////////////////////////////////////////////////////////////// class SyncCmd : public SC_SequencedCommand { public: SyncCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: virtual void CallDestructor(); int mID; }; /////////////////////////////////////////////////////////////////////////// class BufGenCmd : public SC_SequencedCommand { public: BufGenCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~BufGenCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; BufGen *mBufGen; sc_msg_iter mMsg; char *mData; int mSize; SndBuf mSndBuf; float *mFreeData; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufAllocCmd : public SC_SequencedCommand { public: BufAllocCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; SndBuf mSndBuf; int mNumChannels, mNumFrames; float *mFreeData; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufFreeCmd : public SC_SequencedCommand { public: BufFreeCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; float *mFreeData; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufCloseCmd : public SC_SequencedCommand { public: BufCloseCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufZeroCmd : public SC_SequencedCommand { public: BufZeroCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufAllocReadCmd : public SC_SequencedCommand { public: BufAllocReadCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~BufAllocReadCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; float *mFreeData; SndBuf mSndBuf; char *mFilename; int mFileOffset, mNumFrames; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufReadCmd : public SC_SequencedCommand { public: BufReadCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~BufReadCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; char *mFilename; int mFileOffset, mNumFrames, mBufOffset; bool mLeaveFileOpen; double mSampleRate; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class SC_BufReadCommand : public SC_SequencedCommand { public: enum { kMaxNumChannels = 32 }; SC_BufReadCommand(World* inWorld, ReplyAddress* inReplyAddress); virtual ~SC_BufReadCommand(); protected: void InitChannels(sc_msg_iter& msg); bool CheckChannels(int inNumChannels); void CopyChannels(float* dst, float* src, size_t srcChannels, size_t numFrames); protected: int mNumChannels; int mChannels[kMaxNumChannels]; }; /////////////////////////////////////////////////////////////////////////// class BufAllocReadChannelCmd : public SC_BufReadCommand { public: BufAllocReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~BufAllocReadChannelCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; float *mFreeData; SndBuf mSndBuf; char *mFilename; int mFileOffset, mNumFrames; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufReadChannelCmd : public SC_BufReadCommand { public: BufReadChannelCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~BufReadChannelCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; char *mFilename; int mFileOffset, mNumFrames, mBufOffset; bool mLeaveFileOpen; double mSampleRate; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class BufWriteCmd : public SC_SequencedCommand { public: BufWriteCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~BufWriteCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: int mBufIndex; char *mFilename; #ifndef NO_LIBSNDFILE SF_INFO mFileInfo; #endif int mNumFrames, mBufOffset; bool mLeaveFileOpen; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class AudioQuitCmd : public SC_SequencedCommand { public: AudioQuitCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class AudioStatusCmd : public SC_SequencedCommand { public: AudioStatusCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual bool Stage2(); // non real time protected: virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class NotifyCmd : public SC_SequencedCommand { public: NotifyCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time protected: virtual void CallDestructor(); int mOnOff; int mID; }; /////////////////////////////////////////////////////////////////////////// #define CallSendFailureCommand(inWorld, inCmdName, inErrString, inReply) \ void* space = World_Alloc(inWorld, sizeof(SendFailureCmd)); \ SendFailureCmd *cmd = new (space) SendFailureCmd(inWorld, inReply); \ if (!cmd) return kSCErr_Failed; \ cmd->InitSendFailureCmd(inCmdName, inErrString); \ if (inWorld->mRealTime) cmd->CallNextStage(); \ else cmd->CallEveryStage(); \ class SendFailureCmd : public SC_SequencedCommand { public: SendFailureCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~SendFailureCmd(); virtual void InitSendFailureCmd(const char *inCmdName, const char* inErrString); virtual bool Stage2(); // non real time protected: char *mCmdName, *mErrString; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// #include "SC_GraphDef.h" class LoadSynthDefCmd : public SC_SequencedCommand { public: LoadSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~LoadSynthDefCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: char *mFilename; GraphDef *mDefs; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// #include "SC_GraphDef.h" class RecvSynthDefCmd : public SC_SequencedCommand { public: RecvSynthDefCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~RecvSynthDefCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: char *mBuffer; GraphDef *mDefs; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class LoadSynthDefDirCmd : public SC_SequencedCommand { public: LoadSynthDefDirCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual ~LoadSynthDefDirCmd(); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: char *mFilename; GraphDef *mDefs; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// class SendReplyCmd : public SC_SequencedCommand { public: SendReplyCmd(World *inWorld, ReplyAddress *inReplyAddress); virtual int Init(char *inData, int inSize); virtual bool Stage2(); // non real time protected: virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// typedef bool (*AsyncStageFn)(World *inWorld, void* cmdData); typedef void (*AsyncFreeFn)(World *inWorld, void* cmdData); class AsyncPlugInCmd : public SC_SequencedCommand { public: AsyncPlugInCmd(World *inWorld, ReplyAddress *inReplyAddress, const char* cmdName, void *cmdData, AsyncStageFn stage2, // stage2 is non real time AsyncStageFn stage3, // stage3 is real time - completion msg performed if stage3 returns true AsyncStageFn stage4, // stage4 is non real time - sends done if stage4 returns true AsyncFreeFn cleanup, int completionMsgSize, void* completionMsgData); virtual ~AsyncPlugInCmd(); virtual bool Stage2(); // non real time virtual bool Stage3(); // real time virtual void Stage4(); // non real time protected: const char *mCmdName; void *mCmdData; AsyncStageFn mStage2, mStage3, mStage4; AsyncFreeFn mCleanup; virtual void CallDestructor(); }; /////////////////////////////////////////////////////////////////////////// #endif SuperCollider-Source/server/scsynth/SC_Str4.cpp000644 000765 000024 00000002464 12321461511 022605 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_Str4.h" void str4cpy(int32 *dst, const char *src) { char *cdst0 = (char*)(dst); char *cdst = cdst0; while (*src) { *cdst++ = *src++; } int charlen = cdst - cdst0; int pad = 4 - (charlen & 3); for (int i = 0; i < pad; ++i) { *cdst++ = 0; } } void mem4cpy(int32 *dst, const char *src, int charlen) { dst[str4len(charlen)-1] = 0; char *cdst0 = (char*)(dst); char *cdst = cdst0; for (int i=0; i #include #ifndef _LASTCHAR_ #define _LASTCHAR_ #if BYTE_ORDER == LITTLE_ENDIAN const int32 kLASTCHAR = 0xFF000000; #else const int32 kLASTCHAR = 0x000000FF; #endif #endif void str4cpy(int32 *dst, const char *src); void mem4cpy(int32 *dst, const char *src, int charlen); // returns the number of pad bytes to add to a string of a given length inline int str4padbytes(int charlen) { return 4 - (charlen & 3); } // converts length in bytes to length in words inline int str4len(int charlen) { return (charlen + 4) >> 2; } // returns length in words of a char * inline int str4len(const char *src) { const char *src0 = src; while (*src) { src++; } return str4len(src - src0); } // returns length in words of a int32 * inline int str4len(const int32 *src) { const int32 *src0 = src; while (*src++ & kLASTCHAR) {} int wordlen = src - src0; return wordlen; } // returns length in words of a int32 * inline bool str4eq(const int32 *a, const int32 *b) { while(true) { if (*a != *b) return false; if ((*a & kLASTCHAR) == 0) return true; a++; b++; } } // copy an int32 * inline void str4cpy(int32 *dst, const int32 *src) { int32 c; do { *dst++ = c = *src++; } while (c & kLASTCHAR); } inline int sc_atoi(const char *string) { int value = 0; if (*string == 0) return -1; uint32 c; while ((c = *string++ - '0') <= 9) { value = value * 10 + c; } return value; } #endif SuperCollider-Source/server/scsynth/SC_SynthDef.h000644 000765 000024 00000002560 12321461511 023137 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SynthDef_ #define _SynthDef_ #include "SC_Types.h" #include "sc_msg_iter.h" typedef void (*NodeDtorFunc)(struct Node* inNode); // Node definition names can be 255 characters long. const unsigned int kSCNodeDefNameLen = 64; const unsigned int kSCNodeDefNameByteLen = 64 * sizeof(int32); struct NodeDef { int32 mName[kSCNodeDefNameLen]; int32 mHash; size_t mAllocSize; }; typedef struct NodeDef NodeDef; extern NodeDef gGroupNodeDef; void GroupNodeDef_Init(); void NodeDef_Dump(NodeDef *inNodeDef); #endif SuperCollider-Source/server/scsynth/SC_Time.hpp000644 000765 000024 00000004752 12756531745 022701 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. Copyright (c) 2013 Tim Blechmann http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SC_TIME_HPP #define SC_TIME_HPP #include "../../common/SC_Lock.h" // for chrono #include "SC_Types.h" const int32 kSECONDS_FROM_1900_to_1970 = (int32)2208988800UL; /* 17 leap years */ const double kOSCtoSecs = 2.328306436538696e-10; const double kSecondsToOSCunits = 4294967296.; // pow(2,32) const double kMicrosToOSCunits = 4294.967296; // pow(2,32)/1e6 const double kNanosToOSCunits = 4.294967296; // pow(2,32)/1e9 typedef std::chrono::system_clock::time_point HostTime; static inline std::chrono::system_clock::time_point getTime() { return std::chrono::system_clock::now(); } template static inline double secondsSinceEpoch(TimePoint const & tp) { return std::chrono::duration_cast(tp.time_since_epoch()).count() * 1e-9; } template static inline int64 OSCTime(TimePoint const & tp) { using namespace std::chrono; typedef typename TimePoint::duration Duration; Duration sinceEpoch = tp.time_since_epoch(); seconds secs = duration_cast(sinceEpoch); nanoseconds nsecs = sinceEpoch - secs; return ((int64)(secs.count() + kSECONDS_FROM_1900_to_1970) << 32) + (int64)(nsecs.count() * kNanosToOSCunits); } static inline int32 timeSeed() { using namespace std::chrono; static int32 count = 0; typedef high_resolution_clock::time_point TimePoint; typedef TimePoint::duration Duration; TimePoint now = high_resolution_clock::now(); Duration sinceEpoch = now.time_since_epoch(); seconds secs = duration_cast(sinceEpoch); nanoseconds nsecs = sinceEpoch - secs; return (int32)secs.count() ^ (int32)nsecs.count() ^ count--; } #endif // SC_TIME_HPP SuperCollider-Source/server/scsynth/SC_TimeDLL.hpp000644 000765 000024 00000004536 12321461511 023212 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* #include "SC_CoreAudio.h" #include #include "SC_Prototypes.h" #include "SC_HiddenWorld.h" #include "SC_WorldOptions.h" #include #ifdef _WIN32 #include "SC_Win32Utils.h" #else #include #endif */ // ===================================================================== // SC_TimeDLL // // Delay-Locked-Loop after // Fons Adriaensen, "Using a DLL to filter time" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define SC_TIME_DLL_BW 0.012 class SC_TimeDLL { public: SC_TimeDLL() : m_b(0.), m_c(0.), m_t0(0.), m_t1(0.), m_e2(0.), m_np(0), m_ei(0.), m_ec(0) { } void Reset(double sampleRate, uint32_t periodFrames, double bandWidth, double t) { // compute coefficients m_np = periodFrames; m_b = 2*M_PI*bandWidth*m_np/sampleRate; m_c = m_b*m_b/2.; // initialize filter double tp = m_np/sampleRate; m_e2 = tp; m_t0 = t; m_t1 = t + tp; // initialize statistics m_ei = 0.; m_ec = 0; } void Update(double t) { // compute error double e = m_e = t - m_t1; // update filter m_t0 = m_t1; m_t1 += m_b * e + m_e2; m_e2 += m_c * e; // collect statistics m_ei += e; m_ec++; } double PeriodTime() const { return m_t0; } double NextPeriodTime() const { return m_t1; } double Period() const { return m_t1 - m_t0; } double SampleRate() const { return m_np/Period(); } double Error() const { return m_e; } double AvgError() const { return m_ec > 0 ? m_ei/m_ec : 0; } private: double m_b, m_c; double m_t0, m_t1, m_e, m_e2; int m_np; double m_ei; int m_ec; }; SuperCollider-Source/server/scsynth/SC_Unit.cpp000644 000765 000024 00000004550 12321461511 022666 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "SC_Endian.h" #include "SC_Unit.h" #include "SC_UnitSpec.h" #include "SC_UnitDef.h" #include "SC_World.h" #include "SC_Wire.h" #include "Unroll.h" #include "SC_Prototypes.h" void Unit_ChooseMulAddFunc(Unit* unit); Unit* Unit_New(World *inWorld, UnitSpec *inUnitSpec, char*& memory) { UnitDef *def = inUnitSpec->mUnitDef; Unit *unit = (Unit*)memory; memory += def->mAllocSize; unit->mWorld = inWorld; unit->mUnitDef = def; uint32 numInputs = inUnitSpec->mNumInputs; uint32 numOutputs = inUnitSpec->mNumOutputs; unit->mNumInputs = numInputs; unit->mNumOutputs = numOutputs; uint64 numPorts = numInputs + numOutputs; unit->mInput = (Wire**)memory; memory += numPorts * sizeof(Wire*); unit->mOutput = unit->mInput + numInputs; unit->mInBuf = (float**)memory; memory += numPorts * sizeof(float*); unit->mOutBuf = unit->mInBuf + numInputs; unit->mCalcRate = inUnitSpec->mCalcRate; unit->mSpecialIndex = inUnitSpec->mSpecialIndex; Rate* rateInfo = unit->mRate = inUnitSpec->mRateInfo; unit->mBufLength = rateInfo->mBufLength; unit->mDone = false; return unit; } void Unit_Dtor(Unit *inUnit) { } void Unit_ZeroOutputs(Unit *unit, int inNumSamples) { uint32 numOuts = unit->mNumOutputs; for (uint32 i=0; imDone = true; Unit_ZeroOutputs(inUnit, inNumSamples); } void Unit_End(Unit *inUnit) { inUnit->mCalcFunc = (UnitCalcFunc)&Unit_EndCalc; } SuperCollider-Source/server/scsynth/SC_UnitDef.cpp000644 000765 000024 00000007367 12321461511 023316 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "SC_Endian.h" // first to avoid win32 IN clash #include "SC_Graph.h" #include "SC_InterfaceTable.h" #include "SC_Lib_Cintf.h" #include "SC_Prototypes.h" #include "SC_Str4.h" #include "SC_Unit.h" #include "SC_UnitDef.h" #include "SC_World.h" #include "sc_msg_iter.h" bool UnitDef_Create(const char *inName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags) { if (strlen(inName) >= kSCNameByteLen) return false; UnitDef *unitDef = (UnitDef*)malloc(sizeof(UnitDef)); if (!unitDef) return false; str4cpy(unitDef->mUnitDefName, inName); unitDef->mHash = Hash(unitDef->mUnitDefName); unitDef->mAllocSize = inAllocSize; unitDef->mUnitCtorFunc = inCtor; unitDef->mUnitDtorFunc = inDtor; unitDef->mCmds = 0; unitDef->mFlags = inFlags; if (!AddUnitDef(unitDef)) { free(unitDef); return false; } return true; } bool UnitDef_AddCmd(const char *inUnitDefName, const char *inCmdName, UnitCmdFunc inFunc) { if (strlen(inUnitDefName) >= kSCNameByteLen) return false; int32 unitDefName[kSCNameLen]; memset(unitDefName, 0, kSCNameByteLen); strcpy((char*)unitDefName, inUnitDefName); if (strlen(inCmdName) >= kSCNameByteLen) return false; UnitDef* unitDef = GetUnitDef(unitDefName); if (!unitDef) return false; if (!unitDef->mCmds) unitDef->mCmds = new HashTable(&gMalloc, 4, true); UnitCmd *cmd = new UnitCmd(); memset(cmd->mCmdName, 0, kSCNameByteLen); strcpy((char*)cmd->mCmdName, inCmdName); cmd->mFunc = inFunc; cmd->mHash = Hash(cmd->mCmdName); unitDef->mCmds->Add(cmd); return true; } bool PlugIn_DefineCmd(const char *inCmdName, PlugInCmdFunc inFunc, void *inUserData) { if (strlen(inCmdName) >= kSCNameByteLen) return false; PlugInCmd *cmd = new PlugInCmd(); memset(cmd->mCmdName, 0, kSCNameByteLen); strcpy((char*)cmd->mCmdName, inCmdName); cmd->mFunc = inFunc; cmd->mHash = Hash(cmd->mCmdName); cmd->mUserData = inUserData; AddPlugInCmd(cmd); return true; } int Unit_DoCmd(World *inWorld, int inSize, char *inData) { sc_msg_iter msg(inSize, inData); int nodeID = msg.geti(); Graph* graph = World_GetGraph(inWorld, nodeID); if (!graph) return kSCErr_NodeNotFound; uint32 unitID = msg.geti(); if (unitID >= graph->mNumUnits) return kSCErr_IndexOutOfRange; Unit *unit = graph->mUnits[unitID]; UnitDef* unitDef = unit->mUnitDef; int32 *cmdName = msg.gets4(); if (!cmdName) return kSCErr_Failed; if (!unitDef->mCmds) return kSCErr_Failed; UnitCmd *cmd = unitDef->mCmds->Get(cmdName); if (!cmd) return kSCErr_Failed; (cmd->mFunc)(unit, &msg); return kSCErr_None; } int PlugIn_DoCmd(World *inWorld, int inSize, char *inData, ReplyAddress *inReply) { sc_msg_iter msg(inSize, inData); int32 *cmdName = msg.gets4(); if (!cmdName) return kSCErr_Failed; PlugInCmd *cmd = GetPlugInCmd(cmdName); if (!cmd) return kSCErr_Failed; (cmd->mFunc)(inWorld, cmd->mUserData, &msg, (void*)inReply); return kSCErr_None; } SuperCollider-Source/server/scsynth/SC_UnitDef.h000644 000765 000024 00000003516 12321461511 022753 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _UnitDef_ #define _UnitDef_ #include "SC_Types.h" #include "SC_Unit.h" #include "HashTable.h" struct PlugInCmd { int32 mCmdName[kSCNameLen]; int32 mHash; PlugInCmdFunc mFunc; void *mUserData; }; struct UnitCmd { int32 mCmdName[kSCNameLen]; int32 mHash; UnitCmdFunc mFunc; }; struct UnitDef { int32 mUnitDefName[kSCNameLen]; int32 mHash; size_t mAllocSize; UnitCtorFunc mUnitCtorFunc; UnitDtorFunc mUnitDtorFunc; HashTable* mCmds; uint32 mFlags; }; extern "C" { bool UnitDef_Create(const char *inName, size_t inAllocSize, UnitCtorFunc inCtor, UnitDtorFunc inDtor, uint32 inFlags); bool UnitDef_AddCmd(const char *inUnitDefName, const char *inCmdName, UnitCmdFunc inFunc); bool PlugIn_DefineCmd(const char *inCmdName, PlugInCmdFunc inFunc, void *inUserData); } int Unit_DoCmd(World *inWorld, int inSize, char *inData); inline int32* GetKey(UnitCmd *inCmd) { return inCmd->mCmdName; } inline int32 GetHash(UnitCmd *inCmd) { return inCmd->mHash; } #endif SuperCollider-Source/server/scsynth/SC_UnitSpec.h000644 000765 000024 00000002367 12321461511 023152 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_UnitSpec_ #define _SC_UnitSpec_ #include // for size_t #include "SC_Unit.h" struct UnitSpec { struct UnitDef* mUnitDef; int16 mCalcRate; uint32 mNumInputs, mNumOutputs; // changed from uint16, ver 2 int16 mSpecialIndex; struct InputSpec* mInputSpec; struct OutputSpec* mOutputSpec; struct Rate* mRateInfo; size_t mAllocSize; }; typedef struct UnitSpec UnitSpec; #endif SuperCollider-Source/server/scsynth/SC_WireSpec.h000644 000765 000024 00000002565 12321461511 023141 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SC_WireSpec_ #define _SC_WireSpec_ #include "SC_Types.h" struct InputSpec { // read from file: int32 mFromUnitIndex; // changed from int16, ver 2 int32 mFromOutputIndex; // changed from int16, ver 2 // computed: int32 mWireIndex; // changed from int16, ver 2 }; typedef struct InputSpec InputSpec; struct OutputSpec { // read from file: int16 mCalcRate; // computed: int32 mWireIndex; // changed from uint16, ver 2 int64 mBufferIndex; uint32 mNumConsumers; }; typedef struct OutputSpec OutputSpec; #endif SuperCollider-Source/server/scsynth/SC_World.cpp000644 000765 000024 00000102331 12756531745 023055 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef _WIN32 #include "SC_Win32Utils.h" #endif #ifdef __APPLE__ #include "../../common/SC_Apple.hpp" #endif #include "SC_World.h" #include "SC_WorldOptions.h" #include "SC_HiddenWorld.h" #include "SC_InterfaceTable.h" #include "SC_AllocPool.h" #include "SC_GraphDef.h" #include "SC_UnitDef.h" #include "SC_BufGen.h" #include "SC_Node.h" #include "SC_CoreAudio.h" #include "SC_Group.h" #include "SC_Errors.h" #include #include "SC_Prototypes.h" #include "SC_DirUtils.h" #include "SC_Lock.h" #include "SC_Lib_Cintf.h" #include "../../common/SC_SndFileHelpers.hpp" #include "../../common/Samp.hpp" #include "SC_StringParser.h" #ifdef _WIN32 # include #else # include #endif #include "../supernova/utilities/malloc_aligned.hpp" // undefine the shadowed scfft functions #undef scfft_create #undef scfft_dofft #undef scfft_doifft #undef scfft_destroy #if (_POSIX_MEMLOCK - 0) >= 200112L # include # include #endif #include "server_shm.hpp" InterfaceTable gInterfaceTable; PrintFunc gPrint = 0; extern HashTable *gUnitDefLib; extern HashTable *gBufGenLib; extern HashTable *gPlugInCmds; extern "C" { #ifdef NO_LIBSNDFILE struct SF_INFO {}; #endif bool SendMsgToEngine(World *inWorld, FifoMsg& inMsg); bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg); } //////////////////////////////////////////////////////////////////////////////// inline void* sc_malloc(size_t size) { return nova::malloc_aligned(size); } void* sc_dbg_malloc(size_t size, const char* tag, int line) { void* ptr = sc_malloc(size); fprintf(stderr, "sc_dbg_malloc [%s:%d] %p %zu\n", tag, line, ptr, size); #if SC_MEMORY_ALIGNMENT > 1 if (((intptr_t)ptr % SC_MEMORY_ALIGNMENT) != 0) { fprintf(stderr, "sc_dbg_malloc [%s:%d] %p %zu: memory alignment error\n", tag, line, ptr, size); abort(); } #endif return ptr; } inline void sc_free(void* ptr) { return nova::free_aligned(ptr); } void sc_dbg_free(void* ptr, const char* tag, int line) { fprintf(stderr, "sc_dbg_free [%s:%d]: %p\n", tag, line, ptr); sc_free(ptr); } inline void* sc_zalloc(size_t n, size_t size) { size *= n; if (size) { void* ptr = sc_malloc(size); if (ptr) { memset(ptr, 0, size); return ptr; } } return 0; } void* sc_dbg_zalloc(size_t n, size_t size, const char* tag, int line) { void* ptr = sc_zalloc(n, size); fprintf(stderr, "sc_dbg_zalloc [%s:%d]: %p %zu %zu\n", tag, line, ptr, n, size); return ptr; } # if SC_DEBUG_MEMORY # define malloc_alig(size) sc_dbg_malloc((size), __FUNCTION__, __LINE__) # define free_alig(ptr) sc_dbg_free((ptr), __FUNCTION__, __LINE__) # define zalloc_(n, size) sc_dbg_zalloc((n), (size), __FUNCTION__, __LINE__) # else # define malloc_alig(size) sc_malloc((size)) # define free_alig(ptr) sc_free((ptr)) # define zalloc_(n, size) sc_zalloc((n), (size)) # endif // SC_DEBUG_MEMORY void* zalloc(size_t n, size_t size) { return zalloc_(n, size); } void zfree(void * ptr) { return free_alig(ptr); } //////////////////////////////////////////////////////////////////////////////// // Set denormal FTZ mode on CPUs that need/support it. void sc_SetDenormalFlags(); #ifdef __SSE2__ #include void sc_SetDenormalFlags() { _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); _mm_setcsr(_mm_getcsr() | 0x40); // DAZ } #elif defined(__SSE__) #include void sc_SetDenormalFlags() { _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); } #else void sc_SetDenormalFlags() { } #endif //////////////////////////////////////////////////////////////////////////////// static bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd); static void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames); static void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd); void InterfaceTable_Init() { InterfaceTable *ft = &gInterfaceTable; ft->mSine = gSine; ft->mCosecant = gInvSine; ft->mSineSize = kSineSize; ft->mSineWavetable = gSineWavetable; ft->fPrint = &scprintf; ft->fRanSeed = &server_timeseed; ft->fNodeEnd = &Node_End; ft->fDefineUnit = &UnitDef_Create; ft->fDefineBufGen = &BufGen_Create; ft->fClearUnitOutputs = &Unit_ZeroOutputs; ft->fNRTAlloc = &malloc; ft->fNRTRealloc = &realloc; ft->fNRTFree = &free; ft->fRTAlloc = &World_Alloc; ft->fRTRealloc = &World_Realloc; ft->fRTFree = &World_Free; ft->fNodeRun = &Node_SetRun; ft->fSendTrigger = &Node_SendTrigger; ft->fSendNodeReply = &Node_SendReply; ft->fDefineUnitCmd = &UnitDef_AddCmd; ft->fDefinePlugInCmd = &PlugIn_DefineCmd; ft->fSendMsgFromRT = &SendMsgFromEngine; ft->fSendMsgToRT = &SendMsgToEngine; #ifdef NO_LIBSNDFILE ft->fSndFileFormatInfoFromStrings = NULL; #else ft->fSndFileFormatInfoFromStrings = &sndfileFormatInfoFromStrings; #endif ft->fGetNode = &World_GetNode; ft->fGetGraph = &World_GetGraph; ft->fNRTLock = &World_NRTLock; ft->fNRTUnlock = &World_NRTUnlock; ft->mUnused0 = false; ft->fGroup_DeleteAll = &Group_DeleteAll; ft->fDoneAction = &Unit_DoneAction; ft->fDoAsynchronousCommand = &PerformAsynchronousCommand; ft->fBufAlloc = &bufAlloc; ft->fSCfftCreate = &scfft_create; ft->fSCfftDestroy = &scfft_destroy; ft->fSCfftDoFFT = &scfft_dofft; ft->fSCfftDoIFFT = &scfft_doifft; ft->fGetScopeBuffer = &getScopeBuffer; ft->fPushScopeBuffer = &pushScopeBuffer; ft->fReleaseScopeBuffer = &releaseScopeBuffer; } void initialize_library(const char *mUGensPluginPath); void initializeScheduler(); static void World_LoadGraphDefs(World* world); void World_LoadGraphDefs(World* world) { GraphDef *list = 0; if(getenv("SC_SYNTHDEF_PATH")){ if(world->mVerbosity > 0) scprintf("Loading synthdefs from path: %s\n", getenv("SC_SYNTHDEF_PATH")); SC_StringParser sp(getenv("SC_SYNTHDEF_PATH"), SC_STRPARSE_PATHDELIMITER); while (!sp.AtEnd()) { GraphDef *list = 0; char *path = const_cast(sp.NextToken()); list = GraphDef_LoadDir(world, path, list); GraphDef_Define(world, list); } }else{ char resourceDir[MAXPATHLEN]; if(sc_IsStandAlone()) sc_GetResourceDirectory(resourceDir, MAXPATHLEN); else sc_GetUserAppSupportDirectory(resourceDir, MAXPATHLEN); sc_AppendToPath(resourceDir, MAXPATHLEN, "synthdefs"); if(world->mVerbosity > 0) scprintf("Loading synthdefs from default path: %s\n", resourceDir); list = GraphDef_LoadDir(world, resourceDir, list); GraphDef_Define(world, list); } } namespace scsynth { void startAsioThread(); void stopAsioThread(); } World* World_New(WorldOptions *inOptions) { #if (_POSIX_MEMLOCK - 0) >= 200112L if (inOptions->mMemoryLocking && inOptions->mRealTime) { bool lock_memory = false; rlimit limit; int failure = getrlimit(RLIMIT_MEMLOCK, &limit); if (failure) scprintf("getrlimit failure\n"); else { if (limit.rlim_cur == RLIM_INFINITY and limit.rlim_max == RLIM_INFINITY) lock_memory = true; else scprintf("memory locking disabled due to resource limiting\n"); if (lock_memory) { if (mlockall(MCL_FUTURE) != -1) scprintf("memory locking enabled.\n"); } } } #endif World *world = 0; try { static bool gLibInitted = false; if (!gLibInitted) { InterfaceTable_Init(); initialize_library(inOptions->mUGensPluginPath); initializeScheduler(); gLibInitted = true; } world = (World*)zalloc(1, sizeof(World)); world->hw = (HiddenWorld*)zalloc(1, sizeof(HiddenWorld)); world->hw->mAllocPool = new AllocPool(malloc, free, inOptions->mRealTimeMemorySize * 1024, 0); world->hw->mQuitProgram = new boost::sync::semaphore(0); world->hw->mTerminating = false; HiddenWorld *hw = world->hw; hw->mGraphDefLib = new HashTable(&gMalloc, inOptions->mMaxGraphDefs, false); hw->mNodeLib = new IntHashTable(hw->mAllocPool, inOptions->mMaxNodes, false); hw->mUsers = (ReplyAddress*)zalloc(inOptions->mMaxLogins, sizeof(ReplyAddress)); hw->mNumUsers = 0; hw->mMaxUsers = inOptions->mMaxLogins; hw->mClientIDs = (uint32*)zalloc(inOptions->mMaxLogins, sizeof(uint32)); for (int i = 0; imMaxUsers; i++) { hw->mClientIDs[i] = i; } hw->mClientIDTop = 0; hw->mClientIDdict = new ClientIDDict(); hw->mHiddenID = -8; hw->mRecentID = -8; world->mNumUnits = 0; world->mNumGraphs = 0; world->mNumGroups = 0; world->mBufCounter = 0; world->mBufLength = inOptions->mBufLength; world->mSampleOffset = 0; world->mSubsampleOffset = 0.f; world->mNumAudioBusChannels = inOptions->mNumAudioBusChannels; world->mNumControlBusChannels = inOptions->mNumControlBusChannels; world->mNumInputs = inOptions->mNumInputBusChannels; world->mNumOutputs = inOptions->mNumOutputBusChannels; world->mVerbosity = inOptions->mVerbosity; world->mErrorNotification = 1; // i.e., 0x01 | 0x02 world->mLocalErrorNotification = 0; if (inOptions->mSharedMemoryID) { server_shared_memory_creator::cleanup(inOptions->mSharedMemoryID); hw->mShmem = new server_shared_memory_creator(inOptions->mSharedMemoryID, inOptions->mNumControlBusChannels); world->mControlBus = hw->mShmem->get_control_busses(); } else { hw->mShmem = 0; world->mControlBus = (float*)zalloc(world->mNumControlBusChannels, sizeof(float)); } world->mNumSharedControls = 0; world->mSharedControls = inOptions->mSharedControls; int numsamples = world->mBufLength * world->mNumAudioBusChannels; world->mAudioBus = (float*)zalloc(numsamples, sizeof(float)); world->mAudioBusTouched = (int32*)zalloc(inOptions->mNumAudioBusChannels, sizeof(int32)); world->mControlBusTouched = (int32*)zalloc(inOptions->mNumControlBusChannels, sizeof(int32)); world->mNumSndBufs = inOptions->mNumBuffers; world->mSndBufs = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf)); world->mSndBufsNonRealTimeMirror = (SndBuf*)zalloc(world->mNumSndBufs, sizeof(SndBuf)); world->mSndBufUpdates = (SndBufUpdates*)zalloc(world->mNumSndBufs, sizeof(SndBufUpdates)); GroupNodeDef_Init(); int err = Group_New(world, 0, &world->mTopGroup); if (err) throw err; world->mRealTime = inOptions->mRealTime; world->ft = &gInterfaceTable; world->mNumRGens = inOptions->mNumRGens; world->mRGen = new RGen[world->mNumRGens]; for (uint32 i=0; imNumRGens; ++i) { world->mRGen[i].init(server_timeseed()); } world->mNRTLock = new SC_Lock(); world->mDriverLock = new SC_Lock(); if (inOptions->mPassword) { strncpy(world->hw->mPassword, inOptions->mPassword, 31); world->hw->mPassword[31] = 0; } else { world->hw->mPassword[0] = 0; } #ifdef __APPLE__ world->hw->mInputStreamsEnabled = inOptions->mInputStreamsEnabled; world->hw->mOutputStreamsEnabled = inOptions->mOutputStreamsEnabled; #endif world->hw->mInDeviceName = inOptions->mInDeviceName; world->hw->mOutDeviceName = inOptions->mOutDeviceName; hw->mMaxWireBufs = inOptions->mMaxWireBufs; hw->mWireBufSpace = 0; world->mRendezvous = inOptions->mRendezvous; world->mRestrictedPath = inOptions->mRestrictedPath; sc_SetDenormalFlags(); if (world->mRealTime) { hw->mAudioDriver = SC_NewAudioDriver(world); hw->mAudioDriver->SetPreferredHardwareBufferFrameSize( inOptions->mPreferredHardwareBufferFrameSize ); hw->mAudioDriver->SetPreferredSampleRate( inOptions->mPreferredSampleRate ); if (inOptions->mLoadGraphDefs) { World_LoadGraphDefs(world); } if (!hw->mAudioDriver->Setup()) { scprintf("could not initialize audio.\n"); return 0; } if (!hw->mAudioDriver->Start()) { scprintf("start audio failed.\n"); return 0; } #ifdef __APPLE__ SC::Apple::disableAppNap(); #endif } else { hw->mAudioDriver = 0; } scsynth::startAsioThread(); } catch (std::exception& exc) { scprintf("Exception in World_New: %s\n", exc.what()); World_Cleanup(world,true); return 0; } catch (...) { } return world; } int World_CopySndBuf(World *world, uint32 index, SndBuf *outBuf, bool onlyIfChanged, bool *outDidChange) { if (index > world->mNumSndBufs) return kSCErr_IndexOutOfRange; SndBufUpdates *updates = world->mSndBufUpdates + index; bool didChange = updates->reads != updates->writes; if (!onlyIfChanged || didChange) { reinterpret_cast(world->mNRTLock)->lock(); SndBuf *buf = world->mSndBufsNonRealTimeMirror + index; if (buf->data && buf->samples) { uint32 bufSize = buf->samples * sizeof(float); if (buf->samples != outBuf->samples) { free_alig(outBuf->data); outBuf->data = (float*)malloc_alig(bufSize); } memcpy(outBuf->data, buf->data, bufSize); outBuf->channels = buf->channels; outBuf->samples = buf->samples; outBuf->frames = buf->frames; outBuf->mask = buf->mask; outBuf->mask1 = buf->mask1; } else { free_alig(outBuf->data); outBuf->data = 0; outBuf->channels = 0; outBuf->samples = 0; outBuf->frames = 0; outBuf->mask = 0; outBuf->mask1 = 0; } outBuf->samplerate = buf->samplerate; outBuf->sampledur = buf->sampledur; outBuf->coord = buf->coord; outBuf->sndfile = 0; updates->reads = updates->writes; reinterpret_cast(world->mNRTLock)->unlock(); } if (outDidChange) *outDidChange = didChange; return kSCErr_None; } bool nextOSCPacket(FILE *file, OSC_Packet *packet, int64& outTime) { int32 msglen; if (fread(&msglen, 1, sizeof(int32), file) != sizeof(int32)) return true; // msglen is in network byte order msglen = OSCint((char*)&msglen); if (msglen > 1073741824){ throw std::runtime_error("OSC packet too long. > 2^30 bytes\n"); } packet->mData = (char *)realloc((void *)packet->mData, (size_t)msglen); if(!packet->mData) throw std::runtime_error("nextOSCPacket: realloc failed...\n"); size_t read = fread(packet->mData, 1, msglen, file); if (read != msglen) throw std::runtime_error("nextOSCPacket: invalid read of OSC packet\n"); if (strcmp(packet->mData, "#bundle")!=0) throw std::runtime_error("OSC packet not a bundle\n"); packet->mSize = msglen; outTime = OSCtime(packet->mData+8); return false; } void PerformOSCBundle(World *inWorld, OSC_Packet *inPacket); #ifndef NO_LIBSNDFILE void World_NonRealTimeSynthesis(struct World *world, WorldOptions *inOptions) { if (inOptions->mLoadGraphDefs) { World_LoadGraphDefs(world); } int bufLength = world->mBufLength; int fileBufFrames = inOptions->mPreferredHardwareBufferFrameSize; if (fileBufFrames <= 0) fileBufFrames = 8192; int bufMultiple = (fileBufFrames + bufLength - 1) / bufLength; fileBufFrames = bufMultiple * bufLength; // batch process non real time audio if (!inOptions->mNonRealTimeOutputFilename) throw std::runtime_error("Non real time output filename is NULL.\n"); SF_INFO inputFileInfo, outputFileInfo; float *inputFileBuf = 0; float *outputFileBuf = 0; int numInputChannels = 0; int numOutputChannels; outputFileInfo.samplerate = inOptions->mPreferredSampleRate; numOutputChannels = outputFileInfo.channels = world->mNumOutputs; sndfileFormatInfoFromStrings(&outputFileInfo, inOptions->mNonRealTimeOutputHeaderFormat, inOptions->mNonRealTimeOutputSampleFormat); world->hw->mNRTOutputFile = sf_open(inOptions->mNonRealTimeOutputFilename, SFM_WRITE, &outputFileInfo); sf_command(world->hw->mNRTOutputFile, SFC_SET_CLIPPING, NULL, SF_TRUE); if (!world->hw->mNRTOutputFile) throw std::runtime_error("Couldn't open non real time output file.\n"); outputFileBuf = (float*)calloc(1, world->mNumOutputs * fileBufFrames * sizeof(float)); if (inOptions->mNonRealTimeInputFilename) { world->hw->mNRTInputFile = sf_open(inOptions->mNonRealTimeInputFilename, SFM_READ, &inputFileInfo); if (!world->hw->mNRTInputFile) throw std::runtime_error("Couldn't open non real time input file.\n"); inputFileBuf = (float*)calloc(1, inputFileInfo.channels * fileBufFrames * sizeof(float)); if (world->mNumInputs != (uint32)inputFileInfo.channels) scprintf("WARNING: input file channels didn't match number of inputs specified in options.\n"); numInputChannels = world->mNumInputs = inputFileInfo.channels; // force it. if (inputFileInfo.samplerate != (int)inOptions->mPreferredSampleRate) scprintf("WARNING: input file sample rate does not equal output sample rate.\n"); } else { world->hw->mNRTInputFile = 0; } FILE *cmdFile; if (inOptions->mNonRealTimeCmdFilename) { #ifdef _WIN32 cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "rb"); #else cmdFile = fopen(inOptions->mNonRealTimeCmdFilename, "r"); #endif } else cmdFile = stdin; if (!cmdFile) throw std::runtime_error("Couldn't open non real time command file.\n"); OSC_Packet packet; memset(&packet, 0, sizeof(packet)); packet.mData = (char *)malloc(8192); packet.mIsBundle = true; packet.mReplyAddr.mReplyFunc = null_reply_func; int64 schedTime; if (nextOSCPacket(cmdFile, &packet, schedTime)) throw std::runtime_error("command file empty.\n"); int64 prevTime = schedTime; World_SetSampleRate(world, inOptions->mPreferredSampleRate); World_Start(world); int64 oscTime = 0; double oscToSeconds = 1. / pow(2.,32.); double oscToSamples = inOptions->mPreferredSampleRate * oscToSeconds; int64 oscInc = (int64)((double)bufLength / oscToSamples); if(inOptions->mVerbosity >= 0) { printf("start time %g\n", schedTime * oscToSeconds); } bool run = true; int inBufStep = numInputChannels * bufLength; int outBufStep = numOutputChannels * bufLength; float* inputBuses = world->mAudioBus + world->mNumOutputs * bufLength; float* outputBuses = world->mAudioBus; int32* inputTouched = world->mAudioBusTouched + world->mNumOutputs; int32* outputTouched = world->mAudioBusTouched; for (; run;) { int bufFramesCalculated = 0; float* inBufPos = inputFileBuf; float* outBufPos = outputFileBuf; if (world->hw->mNRTInputFile) { int framesRead = sf_readf_float(world->hw->mNRTInputFile, inputFileBuf, fileBufFrames); if (framesRead < fileBufFrames) { memset(inputFileBuf + framesRead * numInputChannels, 0, (fileBufFrames - framesRead) * numInputChannels * sizeof(float)); } } for (int i=0; imBufCounter; // deinterleave input to input buses if (inputFileBuf) { float *inBus = inputBuses; for (int j=0; jmSampleOffset = (int)diffTimeFloor; world->mSubsampleOffset = diffTime - diffTimeFloor; if (world->mSampleOffset < 0) world->mSampleOffset = 0; else if (world->mSampleOffset >= bufLength) world->mSampleOffset = bufLength-1; PerformOSCBundle(world, &packet); if (nextOSCPacket(cmdFile, &packet, schedTime)) { run = false; break; } if(inOptions->mVerbosity >= 0) { printf("nextOSCPacket %g\n", schedTime * oscToSeconds); } if (schedTime < prevTime) { scprintf("ERROR: Packet time stamps out-of-order.\n"); run = false; goto Bail; } prevTime = schedTime; } World_Run(world); // interleave output to output buffer float *outBus = outputBuses; for (int j=0; jmBufCounter++; oscTime = nextTime; } Bail: // write output sf_writef_float(world->hw->mNRTOutputFile, outputFileBuf, bufFramesCalculated); } if (cmdFile != stdin) fclose(cmdFile); sf_close(world->hw->mNRTOutputFile); world->hw->mNRTOutputFile = 0; if (world->hw->mNRTInputFile) { sf_close(world->hw->mNRTInputFile); world->hw->mNRTInputFile = 0; } free(packet.mData); World_Cleanup(world,true); } #endif // !NO_LIBSNDFILE void World_WaitForQuit(struct World *inWorld, bool unload_plugins) { try { inWorld->hw->mQuitProgram->wait(); World_Cleanup(inWorld, unload_plugins); } catch (std::exception& exc) { scprintf("Exception in World_WaitForQuit: %s\n", exc.what()); } catch (...) { } } void World_SetSampleRate(World *inWorld, double inSampleRate) { inWorld->mSampleRate = inSampleRate; Rate_Init(&inWorld->mFullRate, inSampleRate, inWorld->mBufLength); Rate_Init(&inWorld->mBufRate, inSampleRate / inWorld->mBufLength, 1); } //////////////////////////////////////////////////////////////////////////////// void* World_Alloc(World *inWorld, size_t inByteSize) { return inWorld->hw->mAllocPool->Alloc(inByteSize); } void* World_Realloc(World *inWorld, void *inPtr, size_t inByteSize) { return inWorld->hw->mAllocPool->Realloc(inPtr, inByteSize); } size_t World_TotalFree(World *inWorld) { return inWorld->hw->mAllocPool->TotalFree(); } size_t World_LargestFreeChunk(World *inWorld) { return inWorld->hw->mAllocPool->LargestFreeChunk(); } void World_Free(World *inWorld, void *inPtr) { inWorld->hw->mAllocPool->Free(inPtr); } //////////////////////////////////////////////////////////////////////////////// int32 *GetKey(GraphDef *inGraphDef) { return inGraphDef->mNodeDef.mName; } int32 GetHash(GraphDef *inGraphDef) { return inGraphDef->mNodeDef.mHash; } void World_AddGraphDef(World *inWorld, GraphDef* inGraphDef) { bool added = inWorld->hw->mGraphDefLib->Add(inGraphDef); if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)inGraphDef->mNodeDef.mName); for (uint32 i=0; imNumVariants; ++i) { GraphDef* var = inGraphDef->mVariants + i; added = inWorld->hw->mGraphDefLib->Add(var); if(!added) scprintf("ERROR: Could not add SynthDef %s.\nTry adjusting ServerOptions:maxSynthDefs or the -d cmdline flag.\n", (char*)var->mNodeDef.mName); } } void World_RemoveGraphDef(World *inWorld, GraphDef* inGraphDef) { for (uint32 i=0; imNumVariants; ++i) { GraphDef* var = inGraphDef->mVariants + i; inWorld->hw->mGraphDefLib->Remove(var); } inWorld->hw->mGraphDefLib->Remove(inGraphDef); } void World_FreeAllGraphDefs(World *inWorld) { GrafDefTable* lib = inWorld->hw->mGraphDefLib; int size = lib->TableSize(); for (int i=0; iAtIndex(i); if (def) GraphDef_Free(def); } lib->MakeEmpty(); } GraphDef* World_GetGraphDef(World *inWorld, int32* inKey) { return inWorld->hw->mGraphDefLib->Get(inKey); } //////////////////////////////////////////////////////////////////////////////// int32 *GetKey(UnitDef *inUnitDef) { return inUnitDef->mUnitDefName; } int32 GetHash(UnitDef *inUnitDef) { return inUnitDef->mHash; } bool AddUnitDef(UnitDef* inUnitDef) { return gUnitDefLib->Add(inUnitDef); } bool RemoveUnitDef(UnitDef* inUnitDef) { return gUnitDefLib->Remove(inUnitDef); } UnitDef* GetUnitDef(int32* inKey) { return gUnitDefLib->Get(inKey); } //////////////////////////////////////////////////////////////////////////////// int32 *GetKey(BufGen *inBufGen) { return inBufGen->mBufGenName; } int32 GetHash(BufGen *inBufGen) { return inBufGen->mHash; } bool AddBufGen(BufGen* inBufGen) { return gBufGenLib->Add(inBufGen); } bool RemoveBufGen(BufGen* inBufGen) { return gBufGenLib->Remove(inBufGen); } BufGen* GetBufGen(int32* inKey) { return gBufGenLib->Get(inKey); } //////////////////////////////////////////////////////////////////////////////// int32 *GetKey(PlugInCmd *inPlugInCmd) { return inPlugInCmd->mCmdName; } int32 GetHash(PlugInCmd *inPlugInCmd) { return inPlugInCmd->mHash; } bool AddPlugInCmd(PlugInCmd* inPlugInCmd) { return gPlugInCmds->Add(inPlugInCmd); } bool RemovePlugInCmd(PlugInCmd* inPlugInCmd) { return gPlugInCmds->Remove(inPlugInCmd); } PlugInCmd* GetPlugInCmd(int32* inKey) { return gPlugInCmds->Get(inKey); } //////////////////////////////////////////////////////////////////////////////// int32 GetKey(Node *inNode) { return inNode->mID; } int32 GetHash(Node *inNode) { return inNode->mHash; } bool World_AddNode(World *inWorld, Node* inNode) { return inWorld->hw->mNodeLib->Add(inNode); } bool World_RemoveNode(World *inWorld, Node* inNode) { return inWorld->hw->mNodeLib->Remove(inNode); } Node* World_GetNode(World *inWorld, int32 inID) { if (inID == -1) inID = inWorld->hw->mRecentID; return inWorld->hw->mNodeLib->Get(inID); } Graph* World_GetGraph(World *inWorld, int32 inID) { if (inID == -1) inID = inWorld->hw->mRecentID; Node *node = World_GetNode(inWorld, inID); if (!node) return 0; return node->mIsGroup ? 0 : (Graph*)node; } Group* World_GetGroup(World *inWorld, int32 inID) { Node *node = World_GetNode(inWorld, inID); if (!node) return 0; return node->mIsGroup ? (Group*)node : 0; } //////////////////////////////////////////////////////////////////////////////// void World_Run(World *inWorld) { // run top group Node *node = (Node*)inWorld->mTopGroup; (*node->mCalcFunc)(node); } void World_Start(World *inWorld) { inWorld->mBufCounter = 0; for (uint32 i=0; imNumAudioBusChannels; ++i) inWorld->mAudioBusTouched[i] = -1; for (uint32 i=0; imNumControlBusChannels; ++i) inWorld->mControlBusTouched[i] = -1; inWorld->hw->mWireBufSpace = (float*)malloc_alig(inWorld->hw->mMaxWireBufs * inWorld->mBufLength * sizeof(float)); inWorld->hw->mTriggers.MakeEmpty(); inWorld->hw->mNodeMsgs.MakeEmpty(); inWorld->hw->mNodeEnds.MakeEmpty(); inWorld->mRunning = true; } void World_Cleanup(World *world, bool unload_plugins) { if (!world) return; scsynth::stopAsioThread(); if(unload_plugins) deinitialize_library(); HiddenWorld *hw = world->hw; if (hw && world->mRealTime) hw->mAudioDriver->Stop(); world->mRunning = false; if (world->mTopGroup) Group_DeleteAll(world->mTopGroup); reinterpret_cast(world->mDriverLock)->lock(); if (hw) { sc_free(hw->mWireBufSpace); delete hw->mAudioDriver; hw->mAudioDriver = 0; } delete reinterpret_cast(world->mNRTLock); reinterpret_cast(world->mDriverLock)->unlock(); delete reinterpret_cast(world->mDriverLock); World_Free(world, world->mTopGroup); for (uint32 i=0; imNumSndBufs; ++i) { SndBuf *nrtbuf = world->mSndBufsNonRealTimeMirror + i; SndBuf * rtbuf = world->mSndBufs + i; if (nrtbuf->data) free_alig(nrtbuf->data); if (rtbuf->data && rtbuf->data != nrtbuf->data) free_alig(rtbuf->data); #ifndef NO_LIBSNDFILE if (nrtbuf->sndfile) sf_close(nrtbuf->sndfile); if (rtbuf->sndfile && rtbuf->sndfile != nrtbuf->sndfile) sf_close(rtbuf->sndfile); #endif } free_alig(world->mSndBufsNonRealTimeMirror); free_alig(world->mSndBufs); free_alig(world->mControlBusTouched); free_alig(world->mAudioBusTouched); if (hw->mShmem) { delete hw->mShmem; } else free_alig(world->mControlBus); free_alig(world->mAudioBus); delete [] world->mRGen; if (hw) { #ifndef NO_LIBSNDFILE if (hw->mNRTInputFile) sf_close(hw->mNRTInputFile); if (hw->mNRTOutputFile) sf_close(hw->mNRTOutputFile); if (hw->mNRTCmdFile) fclose(hw->mNRTCmdFile); #endif free_alig(hw->mUsers); free_alig(hw->mClientIDs); delete hw->mClientIDdict; delete hw->mNodeLib; delete hw->mGraphDefLib; delete hw->mQuitProgram; delete hw->mAllocPool; free_alig(hw); } free_alig(world); } void World_NRTLock(World *world) { reinterpret_cast(world->mNRTLock)->lock(); } void World_NRTUnlock(World *world) { reinterpret_cast(world->mNRTLock)->unlock(); } //////////////////////////////////////////////////////////////////////////////// bool getScopeBuffer(World *inWorld, int index, int channels, int maxFrames, ScopeBufferHnd &hnd) { server_shared_memory_creator * shm = inWorld->hw->mShmem; scope_buffer_writer writer = shm->get_scope_buffer_writer( index, channels, maxFrames ); if( writer.valid() ) { hnd.internalData = writer.buffer; hnd.data = writer.data(); hnd.channels = channels; hnd.maxFrames = maxFrames; return true; } else { hnd.internalData = 0; return false; } } void pushScopeBuffer(World *inWorld, ScopeBufferHnd &hnd, int frames) { scope_buffer_writer writer(reinterpret_cast(hnd.internalData)); writer.push(frames); hnd.data = writer.data(); } void releaseScopeBuffer(World *inWorld, ScopeBufferHnd &hnd) { scope_buffer_writer writer(reinterpret_cast(hnd.internalData)); server_shared_memory_creator * shm = inWorld->hw->mShmem; shm->release_scope_buffer_writer( writer ); } //////////////////////////////////////////////////////////////////////////////// inline int32 BUFMASK(int32 x) { return (1 << (31 - CLZ(x))) - 1; } SCErr bufAlloc(SndBuf* buf, int numChannels, int numFrames, double sampleRate) { long numSamples = numFrames * numChannels; if(numSamples < 1) return kSCErr_Failed; buf->data = (float*)zalloc(numSamples, sizeof(float)); if (!buf->data) return kSCErr_Failed; buf->channels = numChannels; buf->frames = numFrames; buf->samples = numSamples; buf->mask = BUFMASK(numSamples); // for delay lines buf->mask1 = buf->mask - 1; // for oscillators buf->samplerate = sampleRate; buf->sampledur = 1. / sampleRate; return kSCErr_None; } #include "scsynthsend.h" void TriggerMsg::Perform() { small_scpacket packet; packet.adds("/tr"); packet.maketags(4); packet.addtag(','); packet.addtag('i'); packet.addtag('i'); packet.addtag('f'); packet.addi(mNodeID); packet.addi(mTriggerID); packet.addf(mValue); ReplyAddress *users = mWorld->hw->mUsers; int numUsers = mWorld->hw->mNumUsers; for (int i=0; imWorld, msg->mData); } void NodeReplyMsg::Perform() { small_scpacket packet; packet.adds(mCmdName, mCmdNameSize); packet.maketags(3 + mNumArgs); packet.addtag(','); packet.addtag('i'); packet.addi(mNodeID); packet.addtag('i'); packet.addi(mID); for(int i=0; ihw->mUsers; int numUsers = mWorld->hw->mNumUsers; for (int i=0; iSendMsgToEngine(msg); } void NodeEndMsg::Perform() { small_scpacket packet; switch (mState) { case kNode_Go : packet.adds("/n_go"); break; case kNode_End : packet.adds("/n_end"); break; case kNode_On : packet.adds("/n_on"); break; case kNode_Off : packet.adds("/n_off"); break; case kNode_Move : packet.adds("/n_move"); break; case kNode_Info : packet.adds("/n_info"); break; } if (mIsGroup) { packet.maketags(8); packet.addtag(','); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addi(mNodeID); packet.addi(mGroupID); packet.addi(mPrevNodeID); packet.addi(mNextNodeID); packet.addi(mIsGroup); packet.addi(mHeadID); packet.addi(mTailID); } else { packet.maketags(6); packet.addtag(','); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addtag('i'); packet.addi(mNodeID); packet.addi(mGroupID); packet.addi(mPrevNodeID); packet.addi(mNextNodeID); packet.addi(mIsGroup); } ReplyAddress *users = mWorld->hw->mUsers; int numUsers = mWorld->hw->mNumUsers; for (int i=0; ihw->mUsers; int numUsers = inWorld->hw->mNumUsers; for (int i=0; ihw->mAudioDriver->SendMsgToEngine(inMsg); } bool SendMsgFromEngine(World *inWorld, FifoMsg& inMsg) { return inWorld->hw->mAudioDriver->SendMsgFromEngine(inMsg); } void SetPrintFunc(PrintFunc func) { gPrint = func; } int scprintf(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); if (gPrint) return (*gPrint)(fmt, vargs); else return vprintf(fmt, vargs); } SuperCollider-Source/server/scsynth/scsynth_main.cpp000644 000765 000024 00000025060 12766171707 024102 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_WorldOptions.h" #include "SC_Version.hpp" #include #include #include #include #include #include "clz.h" #include #ifdef _WIN32 # include #else # include #endif #ifdef _WIN32 // according to this page: http://www.mkssoftware.com/docs/man3/setlinebuf.3.asp // setlinebuf is equivalent to the setvbuf call below. inline int setlinebuf(FILE *stream) { return setvbuf( stream, (char*)0, _IONBF, 0 ); } #endif void Usage(); void Usage() { scprintf( "supercollider_synth options:\n" " -v print the supercollider version and exit\n" " -u a port number 0-65535\n" " -t a port number 0-65535\n" " -B an IP address\n" " -c (default %d)\n" " -a (default %d)\n" " -i (default %d)\n" " -o (default %d)\n" " -z (default %d)\n" " -Z (default %d)\n" " -S (default %d)\n" " -b (default %d)\n" " -n (default %d)\n" " -d (default %d)\n" " -m (default %d)\n" " -w (default %d)\n" " -r (default %d)\n" " -D (default %d)\n" " -R (default %d)\n" " -l (default %d)\n" " maximum number of named return addresses stored\n" " also maximum number of tcp connections accepted\n" " -p \n" " When using TCP, the session password must be the first command sent.\n" " The default is no password.\n" " UDP ports never require passwords, so for security use TCP.\n" " -N \n" #ifdef __APPLE__ " -I \n" " -O \n" #endif #if (_POSIX_MEMLOCK - 0) >= 200112L " -L enable memory locking\n" #endif " -H \n" " -V \n" " 0 is normal behaviour\n" " -1 suppresses informational messages\n" " -2 suppresses informational and many error messages\n" " -U a colon-separated list of paths\n" " if -U is specified, the standard paths are NOT searched for plugins.\n" " -P \n" " if specified, prevents file-accessing OSC commands from\n" " accessing files outside .\n" "\nTo quit, send a 'quit' command via UDP or TCP, or press ctrl-C.\n\n", kDefaultWorldOptions.mNumControlBusChannels, kDefaultWorldOptions.mNumAudioBusChannels, kDefaultWorldOptions.mNumInputBusChannels, kDefaultWorldOptions.mNumOutputBusChannels, kDefaultWorldOptions.mBufLength, kDefaultWorldOptions.mPreferredHardwareBufferFrameSize, kDefaultWorldOptions.mPreferredSampleRate, kDefaultWorldOptions.mNumBuffers, kDefaultWorldOptions.mMaxNodes, kDefaultWorldOptions.mMaxGraphDefs, kDefaultWorldOptions.mRealTimeMemorySize, kDefaultWorldOptions.mMaxWireBufs, kDefaultWorldOptions.mNumRGens, kDefaultWorldOptions.mRendezvous, kDefaultWorldOptions.mLoadGraphDefs, kDefaultWorldOptions.mMaxLogins ); exit(1); } #define checkNumArgs(n) \ if (i+n > argc) { \ if (n == 2) scprintf("ERROR: Argument expected after option %s\n", argv[j]); \ else scprintf("ERROR: More arguments expected after option %s\n", argv[j]); \ Usage(); \ } \ i += n; int main(int argc, char* argv[]); int main(int argc, char* argv[]) { setlinebuf(stdout); #ifdef _WIN32 // initialize winsock WSAData wsaData; int nCode; if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) { scprintf( "WSAStartup() failed with error code %d.\n", nCode ); return 1; } #endif int udpPortNum = -1; int tcpPortNum = -1; std::string bindTo("0.0.0.0"); WorldOptions options = kDefaultWorldOptions; for (int i=1; iargc || argv[j+2][0]=='-') { options.mOutDeviceName = options.mInDeviceName; } else { // If there's a second argument then the user wants separate I/O devices options.mOutDeviceName = argv[j+2]; ++i; } #else options.mOutDeviceName = options.mInDeviceName; // Non-Mac platforms always use same device #endif break; case 'L' : checkNumArgs(1); #if (_POSIX_MEMLOCK - 0) >= 200112L options.mMemoryLocking = true; #else options.mMemoryLocking = false; #endif break; case 'V' : checkNumArgs(2); options.mVerbosity = atoi(argv[j+1]); break; case 'v' : scprintf("scsynth %s (%s)\n", SC_VersionString().c_str(), SC_BuildString().c_str()); exit(0); break; case 'R' : checkNumArgs(2); options.mRendezvous = atoi(argv[j+1]) > 0; break; case 'U' : checkNumArgs(2); options.mUGensPluginPath = argv[j+1]; break; case 'P' : checkNumArgs(2); options.mRestrictedPath = argv[j+1]; break; case 'C' : checkNumArgs(2); break; case 'h': default: Usage(); } } if (udpPortNum == -1 && tcpPortNum == -1 && options.mRealTime) { scprintf("ERROR: There must be a -u and/or a -t options, or -N for nonrealtime.\n"); Usage(); } if (options.mNumInputBusChannels + options.mNumOutputBusChannels > options.mNumAudioBusChannels) { scprintf("ERROR: number of audio bus channels < inputs + outputs.\n"); Usage(); } if (options.mRealTime) { int port = (udpPortNum > 0) ? udpPortNum : tcpPortNum; options.mSharedMemoryID = port; } else options.mSharedMemoryID = 0; struct World *world = World_New(&options); if (!world) return 1; if (!options.mRealTime) { #ifdef NO_LIBSNDFILE return 1; #else int exitCode = 0; try { World_NonRealTimeSynthesis(world, &options); } catch (std::exception& exc) { scprintf("%s\n", exc.what()); exitCode = 1; } return exitCode; #endif } if (udpPortNum >= 0) { if (!World_OpenUDP(world, bindTo.c_str(), udpPortNum)) { World_Cleanup(world,true); return 1; } } if (tcpPortNum >= 0) { if (!World_OpenTCP(world, bindTo.c_str(), tcpPortNum, options.mMaxLogins, 8)) { World_Cleanup(world,true); return 1; } } if(options.mVerbosity >=0){ #ifdef NDEBUG scprintf("SuperCollider 3 server ready.\n"); #else scprintf("SuperCollider 3 server ready (debug build).\n"); #endif } fflush(stdout); World_WaitForQuit(world,true); #ifdef _WIN32 // clean up winsock WSACleanup(); #endif // _WIN32 return 0; } SuperCollider-Source/server/plugins/BeatTrack.cpp000644 000765 000024 00000057325 12321461511 023220 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //BeatTrack UGen implemented by Nick Collins (http://www.informatics.sussex.ac.uk/users/nc81/) //post FFT UGen version 1 Nov 2007 //conversion of Matthew Davies autocorrelation beat tracking model, adapted for real-time use //currently using QMUL complex domain onset detection function model //#include "SC_PlugIn.h" //#include //#include //#include //#include //#include #include "ML.h" //FFT data //#define N 1024 //FFT size //FFT size over 2 #define NOVER2 512 //#define NOVER4 256 //FFT size //#define OVERLAP 512 //#define OVERLAPINDEX 512 //#define HOPSIZE 512 //#define FS 44100 //assumes fixed sampling rate //#define FRAMESR 86.1328 //converted for different sampling rates #define FRAMEPERIOD 0.01161 #define SKIP 128 //#define TIMEELAPSED 1.48608 //this data assumes LAGS is 128 static float g_m[128]= {0.00054069,0.00108050,0.00161855,0.00215399,0.00268594,0.00321356,0.00373600,0.00425243,0.00476204,0.00526404,0.00575765,0.00624213,0.00671675,0.00718080,0.00763362,0.00807455,0.00850299,0.00891836,0.00932010,0.00970771,0.01008071,0.01043866,0.01078115,0.01110782,0.01141834,0.01171242,0.01198982,0.01225033,0.01249378,0.01272003,0.01292899,0.01312061,0.01329488,0.01345182,0.01359148,0.01371396,0.01381939,0.01390794,0.01397980,0.01403520,0.01407439,0.01409768,0.01410536,0.01409780,0.01407534,0.01403838,0.01398734,0.01392264,0.01384474,0.01375410,0.01365120,0.01353654,0.01341062,0.01327397,0.01312710,0.01297054,0.01280484,0.01263053,0.01244816,0.01225827,0.01206139,0.01185807,0.01164884,0.01143424,0.01121478,0.01099099,0.01076337,0.01053241,0.01029861,0.01006244,0.00982437,0.00958484,0.00934429,0.00910314,0.00886181,0.00862067,0.00838011,0.00814049,0.00790214,0.00766540,0.00743057,0.00719793,0.00696778,0.00674036,0.00651591,0.00629466,0.00607682,0.00586256,0.00565208,0.00544551,0.00524301,0.00504470,0.00485070,0.00466109,0.00447597,0.00429540,0.00411944,0.00394813,0.00378151,0.00361959,0.00346238,0.00330989,0.00316210,0.00301899,0.00288053,0.00274669,0.00261741,0.00249266,0.00237236,0.00225646,0.00214488,0.00203755,0.00193440,0.00183532,0.00174025,0.00164909,0.00156174,0.00147811,0.00139810,0.00132161,0.00124854,0.00117880,0.00111228,0.00104887,0.00098848,0.00093100,0.00087634,0.00082438,}; static float g_mg[257]= {0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000004,0.00000055,0.00000627,0.00005539,0.00037863,0.00200318,0.00820201,0.02599027,0.06373712,0.12096648,0.17767593,0.20196826,0.17767593,0.12096648,0.06373712,0.02599027,0.00820201,0.00200318,0.00037863,0.00005539,0.00000627,0.00000055,0.00000004,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,0.00000000,}; //other functions static void BeatTrack_dofft(BeatTrack *unit, uint32); static void complexdf(BeatTrack *unit); static void finaldecision(BeatTrack *unit); //amortisation static void autocorr(BeatTrack *unit,int j); static void beatperiod(BeatTrack *unit,int j, int whichm); static float findtor(BeatTrack *unit); //as many amortisation steps as tor static void findphase(BeatTrack *unit,int j,int gaussflag,int predicted); static int detectperiodchange(BeatTrack *unit); static void findmeter(BeatTrack *unit); static void setupphaseexpectation(BeatTrack *unit); //create Gaussian focussed matrix for phase void BeatTrack_Ctor(BeatTrack* unit) { /////// //check sampling rate and establish multipliers on estimates and FFT window size //down sampling by factor of two automatic unit->m_srate = unit->mWorld->mFullRate.mSampleRate; //if sample rate is 88200 or 96000, assume taking double size FFT to start with if(unit->m_srate > (44100.0*1.5)) unit->m_srate = unit->m_srate*0.5; unit->m_srateconversion = unit->m_srate/44100.0; //assumes base of 1024 FFT unit->m_frameperiod= (FRAMEPERIOD/unit->m_srateconversion); //in seconds //(int) ((FRAMEPERIOD/unit->m_srateconversion) +0.5); printf("srate %f conversion factor %f frame period %f \n", unit->m_srate, unit->m_srateconversion, unit->m_frameperiod); unit->m_prevmag= (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float)); unit->m_prevphase= (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float)); unit->m_predict= (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float)); ////////time positions////////// unit->m_frame=1; //don't decide immediately, wait for maximum period! /////////df//////// unit->m_dfcounter=DFSTORE-1; //random uncorrelated noise df store for initialisation //RGen& rgen = *unit->mParent->mRGen; //don't want this noise, want consistent starting point! for(int j=0;jm_df[j]=0.0; //(2*rgen.frand() - 1.0); } unit->m_dfmemorycounter=14; Clear(15, unit->m_dfmemory); /////////tempo assess/////////// unit->m_currtempo=2; ////////phase assess/////////// unit->m_currphase=0.0; unit->m_phase=0.0; //default of 2bps unit->m_phaseperblock= ((float)unit->mWorld->mFullRate.mBufLength*2)/((float)unit->mWorld->mSampleRate); unit->m_outputphase= unit->m_phase; unit->m_outputtempo= unit->m_currtempo; unit->m_outputphaseperblock= unit->m_phaseperblock; unit->halftrig=0; unit->q1trig=0; unit->q2trig=0; //amortisation and states unit->m_amortisationstate=0; //off unit->m_stateflag=0; unit->m_timesig=4; unit->m_flagstep=0; unit->mCalcFunc = (UnitCalcFunc)&BeatTrack_next; } void BeatTrack_Dtor(BeatTrack *unit) { RTFree(unit->mWorld, unit->m_prevmag); RTFree(unit->mWorld, unit->m_prevphase); RTFree(unit->mWorld, unit->m_predict); } void BeatTrack_next(BeatTrack *unit, int wrongNumSamples) { //float *in = IN(0); //printf("%d \n",wrongNumSamples); //int numSamples = unit->mWorld->mFullRate.mBufLength; //conditions in reverse order to avoid immediate spillover //printf("state %d \n",unit->m_amortisationstate); //keeps incrementing but will be reset with each calculation run unit->m_amortisationsteps=unit->m_amortisationsteps+1; //if state nonzero do something switch(unit->m_amortisationstate) { case 0: break; //do nothing case case 1: //calculate acf autocorr(unit,unit->m_amortcount); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_amortisationstate=2; unit->m_amortlength=128; unit->m_amortcount=0; unit->m_bestcolumn=0; unit->m_besttorsum= -1000.0; } break; case 2: //periodp beatperiod(unit,unit->m_amortcount,0); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_periodp=findtor(unit); if(unit->m_stateflag==1) { unit->m_amortisationstate=3; unit->m_amortlength=128; unit->m_amortcount=0; unit->m_bestcolumn=0; unit->m_besttorsum= -1000.0; } else { unit->m_periodg= -1000; //will always trigger initially unit->m_amortisationstate=4; } } break; case 3: //periodg beatperiod(unit,unit->m_amortcount,1); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_periodg=findtor(unit); unit->m_amortisationstate=4; } break; case 4: //stepdetect/constdetect if(detectperiodchange(unit)) { unit->m_amortisationstate=5; unit->m_amortlength=128; unit->m_amortcount=0; unit->m_bestcolumn=0; unit->m_besttorsum= -1000.0; unit->m_stateflag=1; findmeter(unit); //set up Gaussian weighting centred on periodp int startindex= 128- ((int)(unit->m_periodp+0.5)); float * mg=unit->m_mg; for (int ii=0; ii<128;++ii){ mg[ii]= g_mg[startindex+ii]; } } else { if(unit->m_stateflag==1) unit->m_tor= unit->m_periodg; else unit->m_tor= unit->m_periodp; unit->m_torround= int(unit->m_tor+0.5); unit->m_amortisationstate=7; unit->m_amortlength=unit->m_torround; unit->m_amortcount=0; } break; case 5: //redo periodg calculation beatperiod(unit,unit->m_amortcount,1); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_periodg=findtor(unit); unit->m_tor= unit->m_periodg; unit->m_torround= int(unit->m_tor+0.5f); unit->m_amortisationstate=6; unit->m_amortlength=unit->m_torround; unit->m_amortcount=0; setupphaseexpectation(unit); //don't need to reset change flag since it isn't stored } break; case 6: //flat phase calc after move to context, avoids bias findphase(unit,unit->m_amortcount,0,0); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_amortisationstate=8; //final state } break; case 7: //phase calc with possible gaussian narrowing of the allowed phases findphase(unit,unit->m_amortcount,unit->m_stateflag,(int)(unit->m_currphase*unit->m_torround+0.5f)); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_amortisationstate=8; //final state } break; case 8: finaldecision(unit); unit->m_amortisationstate=0; break; default: break; } //MUST CHECK IF INCIDENT FFT IS >1, if so update buffer with appropriate coefficients float fbufnum = ZIN0(0); //next FFT bufffer ready, update //assuming at this point that buffer precalculated for any resampling if (!(fbufnum<0)) { unit->m_frame= unit->m_frame+1; BeatTrack_dofft(unit, (uint32)fbufnum); } //test if impulse to output unit->m_phase+=unit->m_phaseperblock; //if not locked, update output phase from model phase, else keep a separate output phase float lock= ZIN0(1); //printf("lock %f \n",lock); if (lock<0.5f) { unit->m_outputphase= unit->m_phase; unit->m_outputtempo= unit->m_currtempo; unit->m_outputphaseperblock= unit->m_phaseperblock; } else unit->m_outputphase+=unit->m_outputphaseperblock; if (unit->m_phase >= 1.f) unit->m_phase-= 1.f; //0 is beat, 1 is quaver, 2 is semiquaver, 3 is actual current tempo in bps //so no audio accuracy with beats, just asap, may as well be control rate ZOUT0(0)=0.0; ZOUT0(1)=0.0; ZOUT0(2)=0.0; ZOUT0(3)=unit->m_outputtempo; //*0.016666667; //output beat if (unit->m_outputphase >= 1.f) { //printf("beat \n"); unit->m_outputphase -= 1.f; ZOUT0(0)=1.0; ZOUT0(1)=1.0; ZOUT0(2)=1.0; unit->halftrig=0; unit->q1trig=0; unit->q2trig=0; } if (unit->m_outputphase>=0.5f && unit->halftrig==0) { ZOUT0(1)=1.0; ZOUT0(2)=1.0; unit->halftrig=1; } if (unit->m_outputphase>=0.25f && unit->q1trig==0) { ZOUT0(2)=1.0; unit->q1trig=1; } if (unit->m_outputphase>=0.75f && unit->q2trig==0) { ZOUT0(2)=1.0; unit->q2trig=1; } } // //calculation function once FFT data ready void BeatTrack_dofft(BeatTrack *unit, uint32 ibufnum) { World *world = unit->mWorld; SndBuf *buf; if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; } } else { buf = world->mSndBufs + ibufnum; } LOCK_SNDBUF(buf); //int numbins = buf->samples - 2 >> 1; unit->m_FFTBuf = buf->data; //just assign it! //transfer data to fftbuf in the format expected by this plugin //ideally, should do this part separate to plug-in as well, so can compare different detection functions; //also, can run multiple in parallel with own autocorrelations; committee? Committee.ar(period1, phase1, period2, phase2, period3, phase3)... //chooses predominant estimate? //feature detection function complexdf(unit); if (unit->m_frame%SKIP==0) { //printf("amortisation time \n"); //amortisation- 8 control periods in a frame //have 2000 calcs to do, split over 100 control periods = 6400 samples, ie one tempo per control period unit->m_bestcolumn=0; unit->m_besttorsum= -1000.0; unit->m_bestphasescore = -1000.0; unit->m_bestphase = 0; //state 0 is do nothing unit->m_amortisationstate=1; unit->m_amortcount=0; unit->m_amortlength=128; unit->m_amortisationsteps=0; //fix time reference for calculations, so it doesn't update during the amortisation- this is the beginning of the df frame unit->m_storedfcounter= unit->m_dfcounter+DFSTORE-DFFRAMELENGTH; //ref for phase calculations unit->m_storedfcounterend= unit->m_dfcounter; //unit->m_fftstoreposhold= unit->m_fftstorepos; unit->m_currphase=unit->m_phase; } } void autocorr(BeatTrack *unit,int j) { int baseframe=unit->m_storedfcounter+DFSTORE; float * df= unit->m_df; float * acf= unit->m_acf; //work out four lags each time for (int k=0;k<4;++k) { int lag=4*j+k; int correction= abs(lag-DFFRAMELENGTH); float sum=0.0; for (int i=lag;im_bestcolumn+1; float * acf= unit->m_acf-1; ind2=0; maxval=-1000; for(int i=2*ind-1;i<=(2*ind+1);++i){ val=acf[i]; if(val>maxval) { maxval=val; ind2=i-(2*ind-1)+1; } } //[val2,ind2] = max(acf(2*ind-1:2*ind+1)); ind2 = ind2 + 2*(ind+1)-2; ind3=0; maxval=-1000; for(int i=3*ind-2;i<=(3*ind+2);++i){ val=acf[i]; if(val>maxval) { maxval=val; ind3=i-(3*ind-2)+1; } } //[val3,ind3] = max(acf(3*ind-2:3*ind+2)); ind3 = ind3 + 3*ind-4; float period; if (unit->m_timesig==4) { ind4=0; maxval=-1000; for(int i=4*ind-3;i<=4*ind+3;++i){ val=acf[i]; if(val>maxval) { maxval=val; ind4=i-(4*ind-3)+1; } } //[val4,ind4] = max(acf(4*ind-3:4*ind+3)); ind4 = ind4 + 4*ind-9; period= (ind+ ind2*0.5+ind3/3.f +ind4*0.25)*0.25; } else period= (ind+ ind2*0.5+ind3/3.f)*0.3333333; //printf("period %f ind %d ind2 %d ind3 %d ind4 %d \n",period, ind,ind2,ind3,ind4); //unit->m_tor=period; //unit->m_torround= int(period+0.5); // return period; } //128 calculation calls for multiplying M and acf, calculates M as it goes apart from precalculated Gaussian or Raleigh distribution void beatperiod(BeatTrack *unit,int j, int whichm) { float * acf = unit->m_acf; //int startindex= 512*j; //int endindex=startindex+512; float sum=0.0; //unit->m_timesig harmonics for (int i=1;i<=(unit->m_timesig); ++i) { int num = 2*i-1; float wt= 1.0/(float)num; for (int k=0;km_mg; //general model even weighting sum=sum*m[j]; if (sum>unit->m_besttorsum) { unit->m_besttorsum=sum; unit->m_bestcolumn=j; } } //j out of unit->m_torround //differs to Davies original in that weight the most recent events more- want minimum reaction time void findphase(BeatTrack *unit,int j,int gaussflag, int predicted) { float * df= unit->m_df; int period= unit->m_torround; int baseframe=unit->m_storedfcounterend+DFSTORE; int numfit= -1; if(period != 0) //round down numfit= (int)(DFFRAMELENGTH/period)-1; //testing backwards from the baseframe, weighting goes down as 1/k float sum=0.0; for (int k=0;km_phaseweights[diff]; } if (sum>unit->m_bestphasescore) { unit->m_bestphasescore = sum; unit->m_bestphase = j; } } //, int predicted void setupphaseexpectation(BeatTrack *unit) //create Gaussian focussed matrix for phase { float * wts= unit->m_phaseweights; float sigma= unit->m_torround * 0.25f; //float mu=period; float mult= 1.0/(2.5066283*sigma); float mult2= 1.0/(2.0*sigma*sigma); //unit->m_torround for (int i=0; i<128;++i) { wts[i]= mult*(exp(-(i*i)*mult2)); } } //why force a countdown each time? Why not keep a continuous buffer of previous periodp, periodg? int detectperiodchange(BeatTrack *unit) { //stepthresh = 3.9017; if(unit->m_flagstep==0) { if(fabs(unit->m_periodg-unit->m_periodp) > 3.9017f) { unit->m_flagstep= 3; } } else { unit->m_flagstep= unit->m_flagstep-1; } if(unit->m_flagstep) { unit->m_prevperiodp[unit->m_flagstep-1]=unit->m_periodp; } if(unit->m_flagstep==1) { unit->m_flagstep= 0; if(fabs(2*unit->m_prevperiodp[0] - unit->m_prevperiodp[1] - unit->m_prevperiodp[2]) < 7.8034f) //(2*3.9017) return 1; } return 0; } //add test void findmeter(BeatTrack *unit) { //int i; //float * acf= unit->m_acf; // float * acf= unit->m_acf-1; // // // int period = ((int)(unit->m_periodp+0.5)); // // float three_energy=0.0; // float four_energy=0.0; // // for(i=(3*period-2);i<(3*period+3);++i) // three_energy += acf[i]; // // for(i=(4*period-2);i<(4*period+3);++i) // four_energy += acf[i]; // // if((6*period+2)<512) { // // for(i=(6*period-2);i<(6*period+3);++i) // three_energy += acf[i]; // // for(i=(2*period-2);i<(2*period+3);++i) // four_energy += acf[i]; // } // // if (three_energy > four_energy) // unit->m_timesig = 3; // else //worked better in evaluation without any 3/4 at all! unit->m_timesig = 4; //printf("time sig %d \n",unit->m_timesig); } //period is unit->m_tor, phase is unit->m_bestphase // float m_tor; int m_torround; void finaldecision(BeatTrack *unit) { //int i,j; unit->m_currtempo= 1.0/(unit->m_tor*unit->m_frameperiod); unit->m_phaseperblock= ((float)unit->mWorld->mFullRate.mBufLength*(unit->m_currtempo))/((float)unit->mWorld->mSampleRate); //printf("SAMPLErate %f %f %f", unit->mWorld->mSampleRate,unit->m_phaseperblock,unit->m_currtempo); //unit->m_amortisationstate control periods worth = 512/64 = 8 //float frameselapsed= 0.125*unit->m_amortisationstate; //float timeelapsed= frameselapsed*unit->m_frameperiod; float timeelapsed= ((float)(unit->m_amortisationsteps)*(unit->mWorld->mFullRate.mBufLength)/((float)unit->mWorld->mSampleRate)); timeelapsed += 7*unit->m_frameperiod; //compensation for detection function being delayed by 7 frames float phaseelapsed= timeelapsed*(unit->m_currtempo); float phasebeforeamort= ((float)unit->m_bestphase/unit->m_torround); //add phase to compensate for ELAPSEDTIME unit->m_currphase= unit->m_phase = fmod(phasebeforeamort+phaseelapsed,(float)1.0); } //Now the format is standardised for the SC FFT UGen as //dc, nyquist and then real/imag pairs for each bin going up successively in frequency void complexdf(BeatTrack *unit) { float * fftbuf= unit->m_FFTBuf; float * prevmag= unit->m_prevmag; float * prevphase= unit->m_prevphase; float * predict= unit->m_predict; float sum=0.0; //printf("complex df time \n"); //sum bins 2 to 256 for (int k=1; km_dfmemorycounter=(unit->m_dfmemorycounter+1)%15; unit->m_dfmemory[unit->m_dfmemorycounter]=sum; //divide by num of bands to get a dB answer float rating=0.0; float * dfmemory=unit->m_dfmemory; int refpos=unit->m_dfmemorycounter+15; int centrepos=(refpos-7)%15; float centreval=dfmemory[centrepos]; for (int k=0;k<15; ++k) { int pos=(refpos-k)%15; float nextval= centreval-dfmemory[pos]; if (nextval<0.0) nextval=nextval*10; rating+=nextval; } if(rating<0.0) rating=0.0; //increment first so this frame is unit->m_loudnesscounterdfcounter unit->m_dfcounter=(unit->m_dfcounter+1)%DFSTORE; unit->m_df[unit->m_dfcounter]=rating*0.1f; //sum //divide by num of bands to get a dB answer } SuperCollider-Source/server/plugins/BeatTrack.h000644 000765 000024 00000005445 12321461511 022661 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define DFFRAMELENGTH 512 #define DFSTORE 700 //store last 700 to avoid problems during amortisation #define LAGS 128 struct BeatTrack : Unit { //corrections for different sampling rates: support 44100 as native, and 48000, 88200, 96000 by frequency domain down sampling //assumes 1024 FFT for first two, 2048 for second two float m_srate; float m_srateconversion; float m_frameperiod; //FFT data //int m_bufWritePos; //float * m_prepareFFTBuf; float * m_FFTBuf; //fftwf_plan planTime2FFT; float * m_prevmag; float * m_prevphase; float * m_predict; //vDSP //unsigned long m_vlog2n; //COMPLEX_SPLIT m_vA; //FFTSetup m_vsetup; //time positions long m_frame; //df float m_df[DFSTORE]; int m_dfcounter; //for peak pick scorer int m_dfmemorycounter; float m_dfmemory[15]; //autocorrelation results on df float m_acf[DFFRAMELENGTH]; //float* m_M; float m_mg[LAGS]; float m_besttorsum; int m_bestcolumn; float m_phaseweights[LAGS]; float m_tor; int m_torround; float m_periodp; float m_periodg; int m_flagstep; float m_prevperiodp[3]; //amortisation search for best phase from 0 to m_torround-1 float m_bestphasescore; int m_bestphase; //tempo float m_currtempo; //phase float m_currphase; //phasor, trigger beat and modulo when >1.0 float m_phase, m_phaseperblock; //phasor output separate so can have it lock and keep going when don't want to track float m_outputphase, m_outputtempo, m_outputphaseperblock; int halftrig; int q1trig; int q2trig; //amortization - more complex structure to support different rates of work int m_amortisationstate; int m_amortcount; int m_amortlength; int m_amortisationsteps; //model states int m_stateflag; int m_timesig; int m_storedfcounter; int m_storedfcounterend; }; extern "C" { //required interface functions void BeatTrack_next(BeatTrack *unit, int wrongNumSamples); void BeatTrack_Ctor(BeatTrack *unit); void BeatTrack_Dtor(BeatTrack *unit); } SuperCollider-Source/server/plugins/BeatTrack2.cpp000644 000765 000024 00000050424 12321461511 023273 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //BeatTrack2 UGen implemented by Nick Collins (http://www.informatics.sussex.ac.uk/users/nc81/) //6 Nov 2007 #include "ML.h" //need to add bestgroove option to store groove, else remove output which is currently always straight 16ths static const int g_numtempi= 120; static float g_periods[g_numtempi]= { 1, 0.98360655737705, 0.96774193548387, 0.95238095238095, 0.9375, 0.92307692307692, 0.90909090909091, 0.8955223880597, 0.88235294117647, 0.8695652173913, 0.85714285714286, 0.84507042253521, 0.83333333333333, 0.82191780821918, 0.81081081081081, 0.8, 0.78947368421053, 0.77922077922078, 0.76923076923077, 0.75949367088608, 0.75, 0.74074074074074, 0.73170731707317, 0.72289156626506, 0.71428571428571, 0.70588235294118, 0.69767441860465, 0.68965517241379, 0.68181818181818, 0.67415730337079, 0.66666666666667, 0.65934065934066, 0.65217391304348, 0.64516129032258, 0.63829787234043, 0.63157894736842, 0.625, 0.61855670103093, 0.61224489795918, 0.60606060606061, 0.6, 0.59405940594059, 0.58823529411765, 0.58252427184466, 0.57692307692308, 0.57142857142857, 0.56603773584906, 0.5607476635514, 0.55555555555556, 0.55045871559633, 0.54545454545455, 0.54054054054054, 0.53571428571429, 0.53097345132743, 0.52631578947368, 0.52173913043478, 0.51724137931034, 0.51282051282051, 0.50847457627119, 0.50420168067227, 0.5, 0.49586776859504, 0.49180327868852, 0.48780487804878, 0.48387096774194, 0.48, 0.47619047619048, 0.47244094488189, 0.46875, 0.46511627906977, 0.46153846153846, 0.45801526717557, 0.45454545454545, 0.45112781954887, 0.44776119402985, 0.44444444444444, 0.44117647058824, 0.43795620437956, 0.43478260869565, 0.43165467625899, 0.42857142857143, 0.42553191489362, 0.42253521126761, 0.41958041958042, 0.41666666666667, 0.41379310344828, 0.41095890410959, 0.40816326530612, 0.40540540540541, 0.40268456375839, 0.4, 0.39735099337748, 0.39473684210526, 0.3921568627451, 0.38961038961039, 0.38709677419355, 0.38461538461538, 0.38216560509554, 0.37974683544304, 0.37735849056604, 0.375, 0.37267080745342, 0.37037037037037, 0.3680981595092, 0.36585365853659, 0.36363636363636, 0.36144578313253, 0.35928143712575, 0.35714285714286, 0.35502958579882, 0.35294117647059, 0.35087719298246, 0.34883720930233, 0.34682080924855, 0.3448275862069, 0.34285714285714, 0.34090909090909, 0.33898305084746, 0.33707865168539, 0.33519553072626 }; //float g_tempoweight[g_numtempi]= { 0.8, 0.82581988897472, 0.83651483716701, 0.84472135955, 0.85163977794943, 0.85773502691896, 0.86324555320337, 0.8683130051064, 0.87302967433402, 0.87745966692415, 0.88164965809277, 0.88563488385777, 0.88944271909999, 0.89309493362513, 0.89660917830793, 0.9, 0.90327955589886, 0.90645812948448, 0.90954451150103, 0.91254628677423, 0.91547005383793, 0.91832159566199, 0.9211060141639, 0.92382783747338, 0.92649110640674, 0.92909944487358, 0.93165611772088, 0.93416407864999, 0.93662601021279, 0.93904435743076, 0.94142135623731, 0.94375905768565, 0.94605934866804, 0.94832396974191, 0.95055453054182, 0.95275252316519, 0.9549193338483, 0.95705625319186, 0.95916448515084, 0.96124515496597, 0.96329931618555, 0.96532795690183, 0.96733200530682, 0.969312334656, 0.97126976771554, 0.97320508075689, 0.97511900715418, 0.97701224063136, 0.97888543819998, 0.98073922282301, 0.98257418583506, 0.98439088914586, 0.98618986725025, 0.98797162906496, 0.9897366596101, 0.99148542155127, 0.99321835661586, 0.99493588689618, 0.99663841605004, 0.99832633040858, 1, 0.99832633040858, 0.99663841605004, 0.99493588689618, 0.99321835661586, 0.99148542155127, 0.9897366596101, 0.98797162906496, 0.98618986725025, 0.98439088914586, 0.98257418583506, 0.98073922282301, 0.97888543819998, 0.97701224063136, 0.97511900715418, 0.97320508075689, 0.97126976771554, 0.969312334656, 0.96733200530682, 0.96532795690183, 0.96329931618555, 0.96124515496597, 0.95916448515084, 0.95705625319186, 0.9549193338483, 0.95275252316519, 0.95055453054182, 0.94832396974191, 0.94605934866804, 0.94375905768565, 0.94142135623731, 0.93904435743076, 0.93662601021279, 0.93416407864999, 0.93165611772088, 0.92909944487358, 0.92649110640674, 0.92382783747338, 0.9211060141639, 0.91832159566199, 0.91547005383793, 0.91254628677423, 0.90954451150103, 0.90645812948448, 0.90327955589886, 0.9, 0.89660917830793, 0.89309493362513, 0.88944271909999, 0.88563488385777, 0.88164965809277, 0.87745966692415, 0.87302967433402, 0.8683130051064, 0.86324555320337, 0.85773502691896, 0.85163977794943, 0.84472135955, 0.83651483716701, 0.82581988897472 }; //const float g_groove = 0.32; static float g_sep[8]= {0.0, 0.25, 0.5, 0.75, 0.0, 0.32, 0.5, 0.82}; //weight for particular step static float g_weight[4]= {1.0,0.5,0.9,0.6}; //weight for blurring feature envelope locally static float g_weight2[9]= {0.05, 0.1, 0.3,0.7,1.0,0.7,0.3, 0.1, 0.05}; //void BeatTrack2_dofft(BeatTrack2 *unit, uint32); static void calculatetemplate(BeatTrack2 *unit, int which, int j); static void finaldecision(BeatTrack2 *unit); void BeatTrack2_Ctor(BeatTrack2* unit) { //unit->m_srate = unit->mWorld->mFullRate.mSampleRate; float kblocklength= unit->mWorld->mFullRate.mBufDuration; //seconds per control block unit->m_krlength= kblocklength; //N features per block over numphases*2 variants for one of 120 tempi, so need at least 120 blocks to complete unit->m_phaseaccuracy = ZIN0(3); //0.02; //20 msec resolution; could be argument of UGen unit->m_numphases = (int*)RTAlloc(unit->mWorld, g_numtempi * sizeof(int)); //unit->m_phases = (float**)RTAlloc(unit->mWorld, g_numtempi * sizeof(float*)); for (int j=0; jm_phaseaccuracy); //maximum will be 1.0/0.02 = 50 unit->m_numphases[j]=num; // // unit->m_phases[j]= (float*)RTAlloc(unit->mWorld, unit->m_numphases[j] * sizeof(float)); // // float phase=0.0; // // for (i=0; im_phases[j][i] = phase; // phase += unit->m_phaseaccuracy; // } } unit->m_numfeatures = (int)(ZIN0(1)+0.001); //for efficiency unit->m_scores= (float*)RTAlloc(unit->mWorld, (2*unit->m_numfeatures) * sizeof(float)); unit->m_temporalwindowsize= ZIN0(2); //typically small, 2 seconds for fast reactions compared to 6 secs for BeatTrack unit->m_fullwindowsize = unit->m_temporalwindowsize + 1.0 + 0.1; //plus one to cover all phases of the 60bpm based period, and a further 0.1 for indexing safety; ie looking at areas around the point you're interested in unit->m_buffersize = (int)(unit->m_fullwindowsize/unit->m_krlength); //in control blocks //printf("loading test blocklength %f numfeatures %d temporal %f full %f blocks %d \n",unit->m_krlength, unit->m_numfeatures, unit->m_temporalwindowsize, unit->m_fullwindowsize, unit->m_buffersize); //float ** m_pastfeatures; //for each feature, a trail of last m_workingmemorysize values unit->m_pastfeatures = (float**)RTAlloc(unit->mWorld, unit->m_numfeatures * sizeof(float*)); for (int j=0; jm_numfeatures; ++j) { unit->m_pastfeatures[j]= (float*)RTAlloc(unit->mWorld, unit->m_buffersize * sizeof(float)); Clear(unit->m_buffersize, unit->m_pastfeatures[j]); //set all to zero at first //for (i=0; im_buffersize; ++i) { // unit->m_pastfeatures[j][i] = 0.0; // } // } //main counter unit->m_counter= 0; //could avoid allocation by having a hard limit on unit->bestscore= (float*)RTAlloc(unit->mWorld, 4 * unit->m_numfeatures * sizeof(float)); unit->bestphase= (int*)RTAlloc(unit->mWorld, 4 * unit->m_numfeatures * sizeof(int)); unit->besttempo= (int*)RTAlloc(unit->mWorld, 4 * unit->m_numfeatures * sizeof(int)); unit->bestgroove= (int*)RTAlloc(unit->mWorld, 4 * unit->m_numfeatures * sizeof(int)); for (int i=0; i<4; ++i) { int basepos= i*unit->m_numfeatures; for (int j=0; jm_numfeatures; ++j) { unit->bestscore[basepos+j]= -9999.0; unit->bestphase[basepos+j]= 0; unit->besttempo[basepos+j]= 60; unit->bestgroove[basepos+j]= 0; } } unit->m_phase= 0.0; unit->m_period= 0.5; unit->m_groove= 0; unit->m_currtempo=2; unit->m_phaseperblock= unit->m_krlength/unit->m_period; unit->m_predictphase= 0.4f; unit->m_predictperiod = 0.3f; unit->m_outputphase= unit->m_phase; unit->m_outputtempo= unit->m_currtempo; unit->m_outputgroove= unit->m_groove; unit->m_outputphaseperblock= unit->m_phaseperblock; unit->m_calculationperiod= 0.5; //every half second; could also be additional argument to UGen unit->m_calculationschedule= 0.0; //printf("srate %f conversion factor %f frame period %f \n", unit->m_srate, unit->m_srateconversion, unit->m_frameperiod); int bufnum = (int)(ZIN0(5)+0.001f); if (bufnum >= unit->mWorld->mNumSndBufs) bufnum = 0; if (bufnum<0) unit->m_weightingscheme = bufnum<2 ? 0 : 1; else { SndBuf *buf = unit->mWorld->mSndBufs + bufnum; unit->m_tempoweights= buf; unit->m_weightingscheme=2; } //printf("bufnum %d weightingscheme %d check %f %f\n", bufnum, unit->m_weightingscheme, unit->m_tempoweights[0], unit->m_tempoweights[119]); unit->halftrig=0; unit->q1trig=0; unit->q2trig=0; unit->mCalcFunc = (UnitCalcFunc)&BeatTrack2_next; } void BeatTrack2_Dtor(BeatTrack2 *unit) { RTFree(unit->mWorld, unit->m_numphases); RTFree(unit->mWorld, unit->m_scores); RTFree(unit->mWorld, unit->bestscore); RTFree(unit->mWorld, unit->bestphase); RTFree(unit->mWorld, unit->besttempo); for (int j=0; jm_numfeatures; ++j) RTFree(unit->mWorld, unit->m_pastfeatures[j]); RTFree(unit->mWorld, unit->m_pastfeatures); } //over phases and for each groove void calculatetemplate(BeatTrack2 *unit, int which, int j) { int tmpindex; int startcounter= unit->m_startcounter; int numphases= unit->m_numphases[which]; float period= g_periods[which]; float blockconvert= unit->m_krlength; float windowsize = unit->m_temporalwindowsize; int buffersize= unit->m_buffersize; //unit->m_fullwindowsize/unit->m_krlength; //in control blocks float ** pastfeatures= unit->m_pastfeatures; //unit->m_pastfeatures = (float**)RTAlloc(unit->mWorld, unit->m_numfeatures * sizeof(float*)); int beatsfit= (int)(windowsize/period); //complete beats only, or also fit as many as possible? float weight; //compensation for number of events matched; may alter equation later switch (unit->m_weightingscheme) { case 0: weight = 1.0f; //flat break; case 1: weight= 1.0f/(beatsfit*4); //compensate for number of time points tested break; case 2: SndBuf * buf = unit->m_tempoweights; if (buf->data) weight = buf->data[which]; //user defined temmpo biases (usually a mask on allowed tempi) else weight = 1.f; break; } int numfeatures= unit->m_numfeatures; float * scores = unit->m_scores; //[2*numfeatures]; float * bestscore = unit->bestscore; int * bestphase = unit->bestphase; int * besttempo = unit->besttempo; int * bestgroove = unit->bestgroove; for (int i=0; im_phaseaccuracy; //calculation for a particular phase of template //for (j=0; j<2; ++j) { for(int h=0; hbestscore[k]) { tmpindex= numfeatures+k; //shift up to make room bestscore[tmpindex]= bestscore[k]; bestphase[tmpindex]= bestphase[k]; besttempo[tmpindex]= besttempo[k]; bestgroove[tmpindex]=bestgroove[k]; bestscore[k]= scorenow; bestphase[k]= i; besttempo[k]= which; bestgroove[k]=j; //printf("bestscore %f bestphase %d besttempo %d bestgroove %d \n", bestscore[k],bestphase[k],besttempo[k], bestgroove[k]); } else if (scorenow>bestscore[numfeatures+k]) { tmpindex= numfeatures+k; bestscore[tmpindex]= scorenow; bestphase[tmpindex]= i; besttempo[tmpindex]= which; bestgroove[tmpindex]=j; } } //} } } //a winner must appear at least twice, across features, and be superior to the secondbest in those features too by some margins //a consistency check could also run to look at change from last time to this void finaldecision(BeatTrack2 *unit) { int foundgood= 0; int bestcandidate =0; int bestpreviousmatchsum=0; //(-1); //should be 0, but allowing different for now float excess; //, consistency; //int exactmatches, closematches; //can be out by a few indices on period; could match on tempo but not phase etc //combine these four factors in one master score? for (int i=0; im_numfeatures; ++i) { int matchsum=0; float secondbest= unit->bestscore[unit->m_numfeatures+i]; excess= (secondbest!=0) ? (unit->bestscore[i]/ secondbest): unit->bestscore[i]; int tempo = unit->besttempo[i]; //could check consistency too by looking at phase update from last prediction in same feature for (int j=0; jm_numfeatures; ++j) { if(j!=i) { if (abs(unit->besttempo[j]-tempo)<5) matchsum++; } //check over all previous features if (abs(unit->besttempo[2*unit->m_numfeatures+j]- tempo)<5) matchsum++; } //printf("i %d matchsum %d excess %f \n",i, matchsum, excess); if(secondbest!= 0) matchsum += (int)excess; //so must have at least one match //&& (excess>1.03) if ((matchsum>bestpreviousmatchsum)) {bestcandidate = i; bestpreviousmatchsum= matchsum; foundgood=1;} } //consistency: could require it to win twice; have a candidatepending which makes a phase prediction; only let through if prediction fulfilled //unit->m_amortlength will be numtempi *2 = 240 float bestphase = fmod( ((unit->bestphase[bestcandidate] * unit->m_phaseaccuracy) + (unit->m_krlength * (unit->m_amortlength)))/(unit->m_period), (float)1.0); //if(unit->m_prediction) { if ((fabs(bestphase - unit->m_predictphase)< ((2*(unit->m_phaseaccuracy))/unit->m_predictperiod)) && (fabs( (g_periods[unit->besttempo[bestcandidate]]) - unit->m_predictperiod ) <0.04) ) { unit->m_period = unit->m_predictperiod; //time elapsed since a known beat is phase of winner in seconds, to calculation start point, plus time for calculation (120 control blocks) divided by period, modulo 1.0 unit->m_phase= bestphase; unit->m_currtempo = 1.f/unit->m_period; unit->m_phaseperblock = unit->m_krlength/unit->m_period; } //} //unit->m_prediction=false; //if(foundgood) { //if clear winner unit->m_predictperiod = g_periods[unit->besttempo[bestcandidate]]; //time elapsed since a known beat is phase of winner in seconds, to calculation start point, plus time for calculation (120 control blocks) divided by period, modulo 1.0 unit->m_predictphase= fmod( ( (unit->bestphase[bestcandidate] * unit->m_phaseaccuracy) + (unit->m_krlength * (unit->m_amortlength)) + unit->m_calculationperiod)/(unit->m_period),(float)1.0); //if(foundgood) { ////if clear winner // //unit->m_period = g_periods[unit->besttempo[bestcandidate]]; ////time elapsed since a known beat is phase of winner in seconds, to calculation start point, plus time for calculation (120 control blocks) divided by period, modulo 1.0 //unit->m_phase= fmod( ((unit->bestphase[bestcandidate] * unit->m_phaseaccuracy) + (unit->m_krlength * 120))/(unit->m_period), 1.0); // //unit->m_currtempo = 1.0/unit->m_period; //unit->m_phaseperblock = unit->m_krlength/unit->m_period; //} } void BeatTrack2_next(BeatTrack2 *unit, int wrongNumSamples) { //keep updating feature memories unit->m_counter= (unit->m_counter+1)%(unit->m_buffersize); int busnum = (int)(ZIN0(0)+0.001f); //unit->m_features = unit->mWorld->mControlBus + busnum; float * features= unit->mWorld->mControlBus + busnum; //hmm, is this pointer guaranteed to stay the same? may have to update each time... for (int j=0; jm_numfeatures; ++j) { unit->m_pastfeatures[j][unit->m_counter]= features[j]; //unit->m_features[j]; } unit->m_calculationschedule += unit->m_krlength; //check for new calculation round if(unit->m_calculationschedule> unit->m_calculationperiod) { unit->m_calculationschedule -= unit->m_calculationperiod; //reset best scores and move old to previous slots for (int i=0; i<2; ++i) { int pos1= (2+i)*unit->m_numfeatures; int pos2= i*unit->m_numfeatures; for (int j=0; jm_numfeatures; ++j) { unit->bestscore[pos1+j]= unit->bestscore[pos2+j]; unit->bestscore[pos2+j]= -9999.0; unit->bestphase[pos1+j]= unit->bestphase[pos2+j]; unit->bestphase[pos2+j]= 0; unit->besttempo[pos1+j]= unit->besttempo[pos2+j]; unit->besttempo[pos2+j]= 60; } } //state 0 is do nothing unit->m_amortisationstate=1; unit->m_amortcount=0; unit->m_amortlength=g_numtempi*2; // //unit->m_amortisationsteps=0; //store essential data unit->m_startcounter = unit->m_counter; unit->m_currphase=unit->m_phase; } //keeps incrementing but will be reset with each calculation run //unit->m_amortisationsteps=unit->m_amortisationsteps+1; //if state nonzero do something switch(unit->m_amortisationstate) { case 0: break; //do nothing case case 1: //calculate acf calculatetemplate(unit,unit->m_amortcount >> 1, unit->m_amortcount %2); unit->m_amortcount=unit->m_amortcount+1; if(unit->m_amortcount==unit->m_amortlength) { unit->m_amortisationstate=2; //unit->m_amortlength=1; //unit->m_amortcount=0; } break; case 2: //done calculating template matches, now decide whether to follow through finaldecision(unit); unit->m_amortisationstate=0; break; default: break; } //test if impulse to output unit->m_phase+=unit->m_phaseperblock; //if(unit->m_counter%400==0) printf("phase %f period %f\n", unit->m_phase, unit->m_period); //if not locked, update output phase from model phase, else keep a separate output phase float lock= ZIN0(4); //printf("lock %f \n",lock); if(lock<0.5f) { unit->m_outputphase= unit->m_phase; unit->m_outputtempo= unit->m_currtempo; unit->m_outputgroove= unit->m_groove; unit->m_outputphaseperblock= unit->m_phaseperblock; } else { unit->m_outputphase+=unit->m_outputphaseperblock; } if (unit->m_phase >= 1.f) {unit->m_phase-= 1.f;} //0 is beat, 1 is quaver, 2 is semiquaver, 3 is actual current tempo in bps //so no audio accuracy with beats, just asap, may as well be control rate ZOUT0(0)=0.0; ZOUT0(1)=0.0; ZOUT0(2)=0.0; ZOUT0(3)=unit->m_outputtempo; //*0.016666667; ZOUT0(4)=unit->m_outputphase; ZOUT0(5)=unit->m_outputgroove; //output beat if (unit->m_outputphase >= 1.f) { //printf("beat \n"); unit->m_outputphase -= 1.f; ZOUT0(0)=1.0; ZOUT0(1)=1.0; ZOUT0(2)=1.0; unit->halftrig=0; unit->q1trig=0; unit->q2trig=0; } if (unit->m_outputphase>=0.5 && unit->halftrig==0) { ZOUT0(1)=1.0; ZOUT0(2)=1.0; unit->halftrig=1; } float groove= unit->m_outputgroove *0.07; if (unit->m_outputphase>=(0.25+groove) && unit->q1trig==0) { ZOUT0(2)=1.0; unit->q1trig=1; } if (unit->m_outputphase>=(0.75+groove) && unit->q2trig==0) { ZOUT0(2)=1.0; unit->q2trig=1; } } SuperCollider-Source/server/plugins/BeatTrack2.h000644 000765 000024 00000006343 12321461511 022741 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //N feature stream inputs, cross correlation with template on each channel //templates- search 120 tempi * 2 groove types (really just /2 and /3 subdivision) and no metrical discernment * a different numbers of phases depending on tempo //assume 4 features * 120 tempi * 2 groove * 20 phase = 19200 per calculation time; say you calculate each 0.5 sec, amortise over (44100/64*0.5 >344.5) control blocks; //calculate over 240 blocks #include "SC_PlugIn.h" struct BeatTrack2 : Unit { //adjust for any sampling rate by calculating factors; runs off of k rate inputs float m_srate; float m_phaseaccuracy; //probably 8 control blocks! int m_numtempi; //= 120; //float * m_tempi; int * m_numphases; //float ** m_phases; int m_numfeatures; float * m_features; //pointer to control bus, assumes contiguous busnum for each consecutive feature // float m_temporalwindowsize; //typically small, 2 seconds for fast reactions compared to 6 secs for BeatTrack float m_fullwindowsize; float m_krlength; int m_buffersize; //in control blocks float ** m_pastfeatures; //for each feature, a trail of last m_workingmemorysize values int m_counter, m_startcounter; //time positions float m_calculationschedule; float m_calculationperiod; //tempo float m_period; int m_groove; float m_currtempo; //phase float m_currphase; //phasor, trigger beat and modulo when >1.0 float m_phase, m_phaseperblock; //phasor output separate so can have it lock and keep going when don't want to track float m_outputphase, m_outputtempo, m_outputgroove, m_outputphaseperblock; float m_predictphase, m_predictperiod; //amortization - more complex structure to support different rates of work int m_amortisationstate; int m_amortcount; int m_amortlength; int m_amortisationsteps; //efficiency trick float * m_scores; //tracking best results for each feature //also storing second best and previous best and second best? //thus keep best from previous round too for additional vote/consistency check float * bestscore; int * bestphase; int * besttempo; int * bestgroove; //or store all scores and resolve later? int halftrig; int q1trig; int q2trig; SndBuf * m_tempoweights; int m_weightingscheme; }; extern "C" { //required interface functions void BeatTrack2_next(BeatTrack2 *unit, int wrongNumSamples); void BeatTrack2_Ctor(BeatTrack2 *unit); void BeatTrack2_Dtor(BeatTrack2 *unit); } SuperCollider-Source/server/plugins/BinaryOpUGens.cpp000644 000765 000024 00000517566 12756531745 024100 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include #ifdef _MSC_VER // hypotf is c99, but not c++ #define hypotf _hypotf #endif #ifdef NOVA_SIMD #include "simd_binary_arithmetic.hpp" #include "simd_math.hpp" #include "simd_memory.hpp" #include "function_attributes.h" using nova::slope_argument; #define NOVA_BINARY_WRAPPER(SCNAME, NOVANAME) \ FLATTEN void SCNAME##_aa_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), IN(1), inNumSamples); \ } \ \ FLATTEN void SCNAME##_aa_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd<64>(OUT(0), IN(0), IN(1)); \ } \ \ FLATTEN void SCNAME##_ia_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ float xa = ZIN0(0); \ \ nova::NOVANAME##_vec_simd(OUT(0), xa, IN(1), inNumSamples); \ unit->mPrevA = xa; \ } \ \ FLATTEN void SCNAME##_ia_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ float xa = ZIN0(0); \ \ nova::NOVANAME##_vec_simd<64>(OUT(0), xa, IN(1)); \ unit->mPrevA = xa; \ } \ \ FLATTEN void SCNAME##_ai_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ float xb = ZIN0(1); \ \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), xb, inNumSamples); \ unit->mPrevB = xb; \ } \ \ FLATTEN void SCNAME##_ai_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ float xb = ZIN0(1); \ \ nova::NOVANAME##_vec_simd<64>(OUT(0), IN(0), xb); \ unit->mPrevB = xb; \ } #define NOVA_BINARY_WRAPPER_K(SCNAME, NOVANAME) \ FLATTEN void SCNAME##_aa_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), IN(1), inNumSamples); \ } \ \ FLATTEN void SCNAME##_aa_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd<64>(OUT(0), IN(0), IN(1)); \ } \ \ FLATTEN void SCNAME##_ia_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ float xa = ZIN0(0); \ \ nova::NOVANAME##_vec_simd(OUT(0), xa, IN(1), inNumSamples); \ unit->mPrevA = xa; \ } \ \ FLATTEN void SCNAME##_ia_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ float xa = ZIN0(0); \ \ nova::NOVANAME##_vec_simd<64>(OUT(0), xa, IN(1)); \ unit->mPrevA = xa; \ } \ \ FLATTEN void SCNAME##_ai_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ float xb = ZIN0(1); \ \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), xb, inNumSamples); \ unit->mPrevB = xb; \ } \ \ FLATTEN void SCNAME##_ai_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ float xb = ZIN0(1); \ \ nova::NOVANAME##_vec_simd<64>(OUT(0), IN(0), xb); \ unit->mPrevB = xb; \ } \ \ FLATTEN void SCNAME##_ak_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ float xb = unit->mPrevB; \ float next_b = ZIN0(1); \ \ if (xb == next_b) { \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), xb, inNumSamples); \ } else { \ float slope = CALCSLOPE(next_b, xb); \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); \ unit->mPrevB = next_b; \ } \ } \ \ FLATTEN void SCNAME##_ak_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ float xb = unit->mPrevB; \ float next_b = ZIN0(1); \ \ if (xb == next_b) { \ nova::NOVANAME##_vec_simd<64>(OUT(0), IN(0), xb); \ } else { \ float slope = CALCSLOPE(next_b, xb); \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); \ unit->mPrevB = next_b; \ } \ } \ \ FLATTEN void SCNAME##_ka_nova(BinaryOpUGen *unit, int inNumSamples) \ { \ float xa = unit->mPrevA; \ float next_a = ZIN0(0); \ \ if (xa == next_a) { \ nova::NOVANAME##_vec_simd(OUT(0), xa, IN(1), inNumSamples); \ } else { \ float slope = CALCSLOPE(next_a, xa); \ nova::NOVANAME##_vec_simd(OUT(0), slope_argument(xa, slope), IN(1), inNumSamples); \ unit->mPrevA = next_a; \ } \ } \ FLATTEN void SCNAME##_ka_nova_64(BinaryOpUGen *unit, int inNumSamples) \ { \ float xa = unit->mPrevA; \ float next_a = ZIN0(0); \ \ if (xa == next_a) { \ nova::NOVANAME##_vec_simd<64>(OUT(0), xa, IN(1)); \ } else { \ float slope = CALCSLOPE(next_a, xa); \ nova::NOVANAME##_vec_simd(OUT(0), slope_argument(xa, slope), IN(1), inNumSamples); \ unit->mPrevA = next_a; \ } \ } #define DEFINE_TEMPLATE_FUNCTOR(NAME) \ struct NAME##_functor \ { \ template \ inline FloatType operator()(FloatType a, FloatType b) const \ { \ return NAME(a, b); \ } \ \ template \ inline nova::vec operator()(nova::vec a, \ nova::vec b) const \ { \ return NAME(a, b); \ } \ }; DEFINE_TEMPLATE_FUNCTOR(sc_ring1) DEFINE_TEMPLATE_FUNCTOR(sc_ring2) DEFINE_TEMPLATE_FUNCTOR(sc_ring3) DEFINE_TEMPLATE_FUNCTOR(sc_ring4) DEFINE_TEMPLATE_FUNCTOR(sc_difsqr) DEFINE_TEMPLATE_FUNCTOR(sc_sumsqr) DEFINE_TEMPLATE_FUNCTOR(sc_sqrsum) DEFINE_TEMPLATE_FUNCTOR(sc_sqrdif) namespace nova { NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_ring1, sc_ring1_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_ring2, sc_ring2_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_ring3, sc_ring3_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_ring4, sc_ring4_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_difsqr, sc_difsqr_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_sumsqr, sc_sumsqr_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_sqrsum, sc_sqrsum_functor) NOVA_SIMD_DEFINE_BINARY_WRAPPER (sc_sqrdif, sc_sqrdif_functor) } #endif using namespace std; // for math functions static InterfaceTable *ft; ////////////////////////////////////////////////////////////////////////////////////////////////// /* special binary math operators */ enum { opAdd, opSub, opMul, opIDiv, opFDiv, opMod, opEQ, opNE, opLT, opGT, opLE, opGE, //opIdentical, //opNotIdentical, opMin, opMax, opBitAnd, opBitOr, opBitXor, opLCM, opGCD, opRound, opRoundUp, opTrunc, opAtan2, opHypot, opHypotx, opPow, opShiftLeft, // opShiftRight, // opUnsignedShift, // opFill, // opRing1, // a * (b + 1) == a * b + a opRing2, // a * b + a + b opRing3, // a*a*b opRing4, // a*a*b - a*b*b opDifSqr, // a*a - b*b opSumSqr, // a*a + b*b opSqrSum, // (a + b)^2 opSqrDif, // (a - b)^2 opAbsDif, // |a - b| opThresh, opAMClip, opScaleNeg, opClip2, opExcess, opFold2, opWrap2, opFirstArg, opRandRange, opExpRandRange, opNumBinarySelectors }; inline float sc_andt(float a, float b) { return int(a) & int(b); } inline float sc_ort(float a, float b) { return int(a) | int(b); } inline float sc_xort(float a, float b) { return int(a) ^ int(b); } inline float sc_rst(float a, float b) { return int(a) >> int(b); } inline float sc_lst(float a, float b) { return int(a) << int(b); } struct BinaryOpUGen : public Unit { float mPrevA, mPrevB; }; typedef void (*BinaryOpFunc)(BinaryOpUGen *unit, int inNumSamples); extern "C" { void BinaryOpUGen_Ctor(BinaryOpUGen *unit); //void zero_d(BinaryOpUGen *unit, int inNumSamples); void zero_1(BinaryOpUGen *unit, int inNumSamples); void zero_aa(BinaryOpUGen *unit, int inNumSamples); void firstarg_d(BinaryOpUGen *unit, int inNumSamples); void firstarg_1(BinaryOpUGen *unit, int inNumSamples); void firstarg_aa(BinaryOpUGen *unit, int inNumSamples); void secondarg_d(BinaryOpUGen *unit, int inNumSamples); void secondarg_1(BinaryOpUGen *unit, int inNumSamples); void secondarg_aa(BinaryOpUGen *unit, int inNumSamples); void add_d(BinaryOpUGen *unit, int inNumSamples); void add_1(BinaryOpUGen *unit, int inNumSamples); void add_aa(BinaryOpUGen *unit, int inNumSamples); void add_ak(BinaryOpUGen *unit, int inNumSamples); void add_ka(BinaryOpUGen *unit, int inNumSamples); void add_ai(BinaryOpUGen *unit, int inNumSamples); void add_ia(BinaryOpUGen *unit, int inNumSamples); void sub_d(BinaryOpUGen *unit, int inNumSamples); void sub_1(BinaryOpUGen *unit, int inNumSamples); void sub_aa(BinaryOpUGen *unit, int inNumSamples); void sub_ak(BinaryOpUGen *unit, int inNumSamples); void sub_ka(BinaryOpUGen *unit, int inNumSamples); void sub_ai(BinaryOpUGen *unit, int inNumSamples); void sub_ia(BinaryOpUGen *unit, int inNumSamples); void mul_d(BinaryOpUGen *unit, int inNumSamples); void mul_1(BinaryOpUGen *unit, int inNumSamples); void mul_aa(BinaryOpUGen *unit, int inNumSamples); void mul_ak(BinaryOpUGen *unit, int inNumSamples); void mul_ka(BinaryOpUGen *unit, int inNumSamples); void mul_ai(BinaryOpUGen *unit, int inNumSamples); void mul_ia(BinaryOpUGen *unit, int inNumSamples); void div_d(BinaryOpUGen *unit, int inNumSamples); void div_1(BinaryOpUGen *unit, int inNumSamples); void div_aa(BinaryOpUGen *unit, int inNumSamples); void div_ak(BinaryOpUGen *unit, int inNumSamples); void div_ka(BinaryOpUGen *unit, int inNumSamples); void div_ai(BinaryOpUGen *unit, int inNumSamples); void div_ia(BinaryOpUGen *unit, int inNumSamples); void mod_d(BinaryOpUGen *unit, int inNumSamples); void mod_1(BinaryOpUGen *unit, int inNumSamples); void mod_aa(BinaryOpUGen *unit, int inNumSamples); void mod_ak(BinaryOpUGen *unit, int inNumSamples); void mod_ka(BinaryOpUGen *unit, int inNumSamples); void mod_ai(BinaryOpUGen *unit, int inNumSamples); void mod_ia(BinaryOpUGen *unit, int inNumSamples); void max_d(BinaryOpUGen *unit, int inNumSamples); void max_1(BinaryOpUGen *unit, int inNumSamples); void max_aa(BinaryOpUGen *unit, int inNumSamples); void max_ak(BinaryOpUGen *unit, int inNumSamples); void max_ka(BinaryOpUGen *unit, int inNumSamples); void max_ai(BinaryOpUGen *unit, int inNumSamples); void max_ia(BinaryOpUGen *unit, int inNumSamples); void min_d(BinaryOpUGen *unit, int inNumSamples); void min_1(BinaryOpUGen *unit, int inNumSamples); void min_aa(BinaryOpUGen *unit, int inNumSamples); void min_ak(BinaryOpUGen *unit, int inNumSamples); void min_ka(BinaryOpUGen *unit, int inNumSamples); void min_ai(BinaryOpUGen *unit, int inNumSamples); void min_ia(BinaryOpUGen *unit, int inNumSamples); void and_d(BinaryOpUGen *unit, int inNumSamples); void and_1(BinaryOpUGen *unit, int inNumSamples); void and_aa(BinaryOpUGen *unit, int inNumSamples); void and_ak(BinaryOpUGen *unit, int inNumSamples); void and_ka(BinaryOpUGen *unit, int inNumSamples); void and_ai(BinaryOpUGen *unit, int inNumSamples); void and_ia(BinaryOpUGen *unit, int inNumSamples); void or_d(BinaryOpUGen *unit, int inNumSamples); void or_1(BinaryOpUGen *unit, int inNumSamples); void or_aa(BinaryOpUGen *unit, int inNumSamples); void or_ak(BinaryOpUGen *unit, int inNumSamples); void or_ka(BinaryOpUGen *unit, int inNumSamples); void or_ai(BinaryOpUGen *unit, int inNumSamples); void or_ia(BinaryOpUGen *unit, int inNumSamples); void xor_d(BinaryOpUGen *unit, int inNumSamples); void xor_1(BinaryOpUGen *unit, int inNumSamples); void xor_aa(BinaryOpUGen *unit, int inNumSamples); void xor_ak(BinaryOpUGen *unit, int inNumSamples); void xor_ka(BinaryOpUGen *unit, int inNumSamples); void xor_ai(BinaryOpUGen *unit, int inNumSamples); void xor_ia(BinaryOpUGen *unit, int inNumSamples); void amclip_d(BinaryOpUGen *unit, int inNumSamples); void amclip_1(BinaryOpUGen *unit, int inNumSamples); void amclip_aa(BinaryOpUGen *unit, int inNumSamples); void amclip_ak(BinaryOpUGen *unit, int inNumSamples); void amclip_ka(BinaryOpUGen *unit, int inNumSamples); void amclip_ai(BinaryOpUGen *unit, int inNumSamples); void amclip_ia(BinaryOpUGen *unit, int inNumSamples); void scaleneg_d(BinaryOpUGen *unit, int inNumSamples); void scaleneg_1(BinaryOpUGen *unit, int inNumSamples); void scaleneg_aa(BinaryOpUGen *unit, int inNumSamples); void scaleneg_ak(BinaryOpUGen *unit, int inNumSamples); void scaleneg_ka(BinaryOpUGen *unit, int inNumSamples); void scaleneg_ai(BinaryOpUGen *unit, int inNumSamples); void scaleneg_ia(BinaryOpUGen *unit, int inNumSamples); void pow_d(BinaryOpUGen *unit, int inNumSamples); void pow_1(BinaryOpUGen *unit, int inNumSamples); void pow_aa(BinaryOpUGen *unit, int inNumSamples); void pow_ak(BinaryOpUGen *unit, int inNumSamples); void pow_ka(BinaryOpUGen *unit, int inNumSamples); void pow_ai(BinaryOpUGen *unit, int inNumSamples); void pow_ia(BinaryOpUGen *unit, int inNumSamples); void ring1_d(BinaryOpUGen *unit, int inNumSamples); void ring1_1(BinaryOpUGen *unit, int inNumSamples); void ring1_aa(BinaryOpUGen *unit, int inNumSamples); void ring1_ak(BinaryOpUGen *unit, int inNumSamples); void ring1_ka(BinaryOpUGen *unit, int inNumSamples); void ring1_ai(BinaryOpUGen *unit, int inNumSamples); void ring1_ia(BinaryOpUGen *unit, int inNumSamples); void ring2_d(BinaryOpUGen *unit, int inNumSamples); void ring2_1(BinaryOpUGen *unit, int inNumSamples); void ring2_aa(BinaryOpUGen *unit, int inNumSamples); void ring2_ak(BinaryOpUGen *unit, int inNumSamples); void ring2_ka(BinaryOpUGen *unit, int inNumSamples); void ring2_ai(BinaryOpUGen *unit, int inNumSamples); void ring2_ia(BinaryOpUGen *unit, int inNumSamples); void ring3_d(BinaryOpUGen *unit, int inNumSamples); void ring3_1(BinaryOpUGen *unit, int inNumSamples); void ring3_aa(BinaryOpUGen *unit, int inNumSamples); void ring3_ak(BinaryOpUGen *unit, int inNumSamples); void ring3_ka(BinaryOpUGen *unit, int inNumSamples); void ring3_ai(BinaryOpUGen *unit, int inNumSamples); void ring3_ia(BinaryOpUGen *unit, int inNumSamples); void ring4_d(BinaryOpUGen *unit, int inNumSamples); void ring4_1(BinaryOpUGen *unit, int inNumSamples); void ring4_aa(BinaryOpUGen *unit, int inNumSamples); void ring4_ak(BinaryOpUGen *unit, int inNumSamples); void ring4_ka(BinaryOpUGen *unit, int inNumSamples); void ring4_ai(BinaryOpUGen *unit, int inNumSamples); void ring4_ia(BinaryOpUGen *unit, int inNumSamples); void thresh_d(BinaryOpUGen *unit, int inNumSamples); void thresh_1(BinaryOpUGen *unit, int inNumSamples); void thresh_aa(BinaryOpUGen *unit, int inNumSamples); void thresh_ak(BinaryOpUGen *unit, int inNumSamples); void thresh_ka(BinaryOpUGen *unit, int inNumSamples); void thresh_ai(BinaryOpUGen *unit, int inNumSamples); void thresh_ia(BinaryOpUGen *unit, int inNumSamples); void clip2_d(BinaryOpUGen *unit, int inNumSamples); void clip2_1(BinaryOpUGen *unit, int inNumSamples); void clip2_aa(BinaryOpUGen *unit, int inNumSamples); void clip2_ak(BinaryOpUGen *unit, int inNumSamples); void clip2_ka(BinaryOpUGen *unit, int inNumSamples); void clip2_ai(BinaryOpUGen *unit, int inNumSamples); void clip2_ia(BinaryOpUGen *unit, int inNumSamples); void fold2_d(BinaryOpUGen *unit, int inNumSamples); void fold2_1(BinaryOpUGen *unit, int inNumSamples); void fold2_aa(BinaryOpUGen *unit, int inNumSamples); void fold2_ak(BinaryOpUGen *unit, int inNumSamples); void fold2_ka(BinaryOpUGen *unit, int inNumSamples); void fold2_ai(BinaryOpUGen *unit, int inNumSamples); void fold2_ia(BinaryOpUGen *unit, int inNumSamples); void wrap2_d(BinaryOpUGen *unit, int inNumSamples); void wrap2_1(BinaryOpUGen *unit, int inNumSamples); void wrap2_aa(BinaryOpUGen *unit, int inNumSamples); void wrap2_ak(BinaryOpUGen *unit, int inNumSamples); void wrap2_ka(BinaryOpUGen *unit, int inNumSamples); void wrap2_ai(BinaryOpUGen *unit, int inNumSamples); void wrap2_ia(BinaryOpUGen *unit, int inNumSamples); void excess_d(BinaryOpUGen *unit, int inNumSamples); void excess_1(BinaryOpUGen *unit, int inNumSamples); void excess_aa(BinaryOpUGen *unit, int inNumSamples); void excess_ak(BinaryOpUGen *unit, int inNumSamples); void excess_ka(BinaryOpUGen *unit, int inNumSamples); void excess_ai(BinaryOpUGen *unit, int inNumSamples); void excess_ia(BinaryOpUGen *unit, int inNumSamples); void rrand_d(BinaryOpUGen *unit, int inNumSamples); void rrand_1(BinaryOpUGen *unit, int inNumSamples); void rrand_aa(BinaryOpUGen *unit, int inNumSamples); void rrand_ak(BinaryOpUGen *unit, int inNumSamples); void rrand_ka(BinaryOpUGen *unit, int inNumSamples); void rrand_ai(BinaryOpUGen *unit, int inNumSamples); void rrand_ia(BinaryOpUGen *unit, int inNumSamples); void exprand_d(BinaryOpUGen *unit, int inNumSamples); void exprand_1(BinaryOpUGen *unit, int inNumSamples); void exprand_aa(BinaryOpUGen *unit, int inNumSamples); void exprand_ak(BinaryOpUGen *unit, int inNumSamples); void exprand_ka(BinaryOpUGen *unit, int inNumSamples); void exprand_ai(BinaryOpUGen *unit, int inNumSamples); void exprand_ia(BinaryOpUGen *unit, int inNumSamples); void lt_d(BinaryOpUGen *unit, int inNumSamples); void lt_1(BinaryOpUGen *unit, int inNumSamples); void lt_aa(BinaryOpUGen *unit, int inNumSamples); void lt_ak(BinaryOpUGen *unit, int inNumSamples); void lt_ka(BinaryOpUGen *unit, int inNumSamples); void lt_ai(BinaryOpUGen *unit, int inNumSamples); void lt_ia(BinaryOpUGen *unit, int inNumSamples); void le_d(BinaryOpUGen *unit, int inNumSamples); void le_1(BinaryOpUGen *unit, int inNumSamples); void le_aa(BinaryOpUGen *unit, int inNumSamples); void le_ak(BinaryOpUGen *unit, int inNumSamples); void le_ka(BinaryOpUGen *unit, int inNumSamples); void le_ai(BinaryOpUGen *unit, int inNumSamples); void le_ia(BinaryOpUGen *unit, int inNumSamples); void lcm_d(BinaryOpUGen *unit, int inNumSamples); void lcm_1(BinaryOpUGen *unit, int inNumSamples); void lcm_aa(BinaryOpUGen *unit, int inNumSamples); void lcm_ak(BinaryOpUGen *unit, int inNumSamples); void lcm_ka(BinaryOpUGen *unit, int inNumSamples); void lcm_ai(BinaryOpUGen *unit, int inNumSamples); void lcm_ia(BinaryOpUGen *unit, int inNumSamples); void gcd_d(BinaryOpUGen *unit, int inNumSamples); void gcd_1(BinaryOpUGen *unit, int inNumSamples); void gcd_aa(BinaryOpUGen *unit, int inNumSamples); void gcd_ak(BinaryOpUGen *unit, int inNumSamples); void gcd_ka(BinaryOpUGen *unit, int inNumSamples); void gcd_ai(BinaryOpUGen *unit, int inNumSamples); void gcd_ia(BinaryOpUGen *unit, int inNumSamples); void gt_d(BinaryOpUGen *unit, int inNumSamples); void gt_1(BinaryOpUGen *unit, int inNumSamples); void gt_aa(BinaryOpUGen *unit, int inNumSamples); void gt_ak(BinaryOpUGen *unit, int inNumSamples); void gt_ka(BinaryOpUGen *unit, int inNumSamples); void gt_ai(BinaryOpUGen *unit, int inNumSamples); void gt_ia(BinaryOpUGen *unit, int inNumSamples); void ge_d(BinaryOpUGen *unit, int inNumSamples); void ge_1(BinaryOpUGen *unit, int inNumSamples); void ge_aa(BinaryOpUGen *unit, int inNumSamples); void ge_ak(BinaryOpUGen *unit, int inNumSamples); void ge_ka(BinaryOpUGen *unit, int inNumSamples); void ge_ai(BinaryOpUGen *unit, int inNumSamples); void ge_ia(BinaryOpUGen *unit, int inNumSamples); void eq_d(BinaryOpUGen *unit, int inNumSamples); void eq_1(BinaryOpUGen *unit, int inNumSamples); void eq_aa(BinaryOpUGen *unit, int inNumSamples); void eq_ak(BinaryOpUGen *unit, int inNumSamples); void eq_ka(BinaryOpUGen *unit, int inNumSamples); void eq_ai(BinaryOpUGen *unit, int inNumSamples); void eq_ia(BinaryOpUGen *unit, int inNumSamples); void neq_d(BinaryOpUGen *unit, int inNumSamples); void neq_1(BinaryOpUGen *unit, int inNumSamples); void neq_aa(BinaryOpUGen *unit, int inNumSamples); void neq_ak(BinaryOpUGen *unit, int inNumSamples); void neq_ka(BinaryOpUGen *unit, int inNumSamples); void neq_ai(BinaryOpUGen *unit, int inNumSamples); void neq_ia(BinaryOpUGen *unit, int inNumSamples); void sumsqr_d(BinaryOpUGen *unit, int inNumSamples); void sumsqr_1(BinaryOpUGen *unit, int inNumSamples); void sumsqr_aa(BinaryOpUGen *unit, int inNumSamples); void sumsqr_ak(BinaryOpUGen *unit, int inNumSamples); void sumsqr_ka(BinaryOpUGen *unit, int inNumSamples); void sumsqr_ai(BinaryOpUGen *unit, int inNumSamples); void sumsqr_ia(BinaryOpUGen *unit, int inNumSamples); void difsqr_d(BinaryOpUGen *unit, int inNumSamples); void difsqr_1(BinaryOpUGen *unit, int inNumSamples); void difsqr_aa(BinaryOpUGen *unit, int inNumSamples); void difsqr_ak(BinaryOpUGen *unit, int inNumSamples); void difsqr_ka(BinaryOpUGen *unit, int inNumSamples); void difsqr_ai(BinaryOpUGen *unit, int inNumSamples); void difsqr_ia(BinaryOpUGen *unit, int inNumSamples); void sqrsum_d(BinaryOpUGen *unit, int inNumSamples); void sqrsum_1(BinaryOpUGen *unit, int inNumSamples); void sqrsum_aa(BinaryOpUGen *unit, int inNumSamples); void sqrsum_ak(BinaryOpUGen *unit, int inNumSamples); void sqrsum_ka(BinaryOpUGen *unit, int inNumSamples); void sqrsum_ai(BinaryOpUGen *unit, int inNumSamples); void sqrsum_ia(BinaryOpUGen *unit, int inNumSamples); void sqrdif_d(BinaryOpUGen *unit, int inNumSamples); void sqrdif_1(BinaryOpUGen *unit, int inNumSamples); void sqrdif_aa(BinaryOpUGen *unit, int inNumSamples); void sqrdif_ak(BinaryOpUGen *unit, int inNumSamples); void sqrdif_ka(BinaryOpUGen *unit, int inNumSamples); void sqrdif_ai(BinaryOpUGen *unit, int inNumSamples); void sqrdif_ia(BinaryOpUGen *unit, int inNumSamples); void absdif_d(BinaryOpUGen *unit, int inNumSamples); void absdif_1(BinaryOpUGen *unit, int inNumSamples); void absdif_aa(BinaryOpUGen *unit, int inNumSamples); void absdif_ak(BinaryOpUGen *unit, int inNumSamples); void absdif_ka(BinaryOpUGen *unit, int inNumSamples); void absdif_ai(BinaryOpUGen *unit, int inNumSamples); void absdif_ia(BinaryOpUGen *unit, int inNumSamples); void round_d(BinaryOpUGen *unit, int inNumSamples); void round_1(BinaryOpUGen *unit, int inNumSamples); void round_aa(BinaryOpUGen *unit, int inNumSamples); void round_ak(BinaryOpUGen *unit, int inNumSamples); void round_ka(BinaryOpUGen *unit, int inNumSamples); void round_ai(BinaryOpUGen *unit, int inNumSamples); void round_ia(BinaryOpUGen *unit, int inNumSamples); void roundUp_d(BinaryOpUGen *unit, int inNumSamples); void roundUp_1(BinaryOpUGen *unit, int inNumSamples); void roundUp_aa(BinaryOpUGen *unit, int inNumSamples); void roundUp_ak(BinaryOpUGen *unit, int inNumSamples); void roundUp_ka(BinaryOpUGen *unit, int inNumSamples); void roundUp_ai(BinaryOpUGen *unit, int inNumSamples); void roundUp_ia(BinaryOpUGen *unit, int inNumSamples); void trunc_d(BinaryOpUGen *unit, int inNumSamples); void trunc_1(BinaryOpUGen *unit, int inNumSamples); void trunc_aa(BinaryOpUGen *unit, int inNumSamples); void trunc_ak(BinaryOpUGen *unit, int inNumSamples); void trunc_ka(BinaryOpUGen *unit, int inNumSamples); void trunc_ai(BinaryOpUGen *unit, int inNumSamples); void trunc_ia(BinaryOpUGen *unit, int inNumSamples); void atan2_d(BinaryOpUGen *unit, int inNumSamples); void atan2_1(BinaryOpUGen *unit, int inNumSamples); void atan2_aa(BinaryOpUGen *unit, int inNumSamples); void atan2_ak(BinaryOpUGen *unit, int inNumSamples); void atan2_ka(BinaryOpUGen *unit, int inNumSamples); void atan2_ai(BinaryOpUGen *unit, int inNumSamples); void atan2_ia(BinaryOpUGen *unit, int inNumSamples); void hypot_d(BinaryOpUGen *unit, int inNumSamples); void hypot_1(BinaryOpUGen *unit, int inNumSamples); void hypot_aa(BinaryOpUGen *unit, int inNumSamples); void hypot_ak(BinaryOpUGen *unit, int inNumSamples); void hypot_ka(BinaryOpUGen *unit, int inNumSamples); void hypot_ai(BinaryOpUGen *unit, int inNumSamples); void hypot_ia(BinaryOpUGen *unit, int inNumSamples); void hypotx_d(BinaryOpUGen *unit, int inNumSamples); void hypotx_1(BinaryOpUGen *unit, int inNumSamples); void hypotx_aa(BinaryOpUGen *unit, int inNumSamples); void hypotx_ak(BinaryOpUGen *unit, int inNumSamples); void hypotx_ka(BinaryOpUGen *unit, int inNumSamples); void hypotx_ai(BinaryOpUGen *unit, int inNumSamples); void hypotx_ia(BinaryOpUGen *unit, int inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// static bool ChooseOperatorFunc(BinaryOpUGen *unit); void BinaryOpUGen_Ctor(BinaryOpUGen *unit) { unit->mPrevA = ZIN0(0); unit->mPrevB = ZIN0(1); bool initialized = ChooseOperatorFunc(unit); if (unit->mCalcRate == calc_DemandRate) { OUT0(0) = 0.f; } else { if (!initialized) (unit->mCalcFunc)(unit, 1); } } /* void zero_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : 0.f; } else { RESETINPUT(0); RESETINPUT(1); } } */ void firstarg_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a; } else { RESETINPUT(0); RESETINPUT(1); } } void secondarg_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : b; } else { RESETINPUT(0); RESETINPUT(1); } } void add_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a + b; } else { RESETINPUT(0); RESETINPUT(1); } } void sub_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a - b; } else { RESETINPUT(0); RESETINPUT(1); } } void mul_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * b; } else { RESETINPUT(0); RESETINPUT(1); } } void div_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a / b; } else { RESETINPUT(0); RESETINPUT(1); } } void idiv_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : floor(a / b); } else { RESETINPUT(0); RESETINPUT(1); } } void mod_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_mod(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void max_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_max(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void min_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_min(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void and_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_andt(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void or_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_ort(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void xor_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_xort(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void rightShift_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_rst(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void leftShift_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_lst(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void lcm_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_lcm(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void gcd_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_gcd(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void amclip_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_amclip(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void scaleneg_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_scaleneg(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void pow_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a < 0.f ? -pow(-a, b) : pow(a, b)); } else { RESETINPUT(0); RESETINPUT(1); } } void ring1_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * b + a; } else { RESETINPUT(0); RESETINPUT(1); } } void ring2_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * b + a + b; } else { RESETINPUT(0); RESETINPUT(1); } } void ring3_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * a * b; } else { RESETINPUT(0); RESETINPUT(1); } } void ring4_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * a * b - a * b * b; } else { RESETINPUT(0); RESETINPUT(1); } } void thresh_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_thresh(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void clip2_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_clip2(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void excess_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_excess(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void lt_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a < b ? 1.f : 0.f); } else { RESETINPUT(0); RESETINPUT(1); } } void gt_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a > b ? 1.f : 0.f); } else { RESETINPUT(0); RESETINPUT(1); } } void le_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a <= b ? 1.f : 0.f); } else { RESETINPUT(0); RESETINPUT(1); } } void ge_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a >= b ? 1.f : 0.f); } else { RESETINPUT(0); RESETINPUT(1); } } void eq_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a == b ? 1.f : 0.f); } else { RESETINPUT(0); RESETINPUT(1); } } void neq_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (a != b ? 1.f : 0.f); } else { RESETINPUT(0); RESETINPUT(1); } } void sumsqr_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * a + b * b; } else { RESETINPUT(0); RESETINPUT(1); } } void difsqr_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : a * a - b * b; } else { RESETINPUT(0); RESETINPUT(1); } } void sqrsum_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); float z; OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (z = a + b, z * z); } else { RESETINPUT(0); RESETINPUT(1); } } void sqrdif_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); float z; OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : (z = a - b, z * z); } else { RESETINPUT(0); RESETINPUT(1); } } void absdif_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : fabs(a - b); } else { RESETINPUT(0); RESETINPUT(1); } } void round_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_round(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void roundUp_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_roundUp(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void trunc_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_trunc(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void fold2_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_fold2(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void wrap2_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_wrap2(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void atan2_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : atan2(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void hypot_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : hypot(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void hypotx_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float a = DEMANDINPUT_A(0, inNumSamples); float b = DEMANDINPUT_A(1, inNumSamples); OUT0(0) = sc_isnan(a) || sc_isnan(b) ? NAN : sc_hypotx(a, b); } else { RESETINPUT(0); RESETINPUT(1); } } void rrand_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float xa = DEMANDINPUT_A(0, inNumSamples); float xb = DEMANDINPUT_A(1, inNumSamples); RGen& rgen = *unit->mParent->mRGen; OUT0(0) = sc_isnan(xa) || sc_isnan(xb) ? NAN : xb > xa ? xa + rgen.frand() * (xb - xa) : (xb + rgen.frand() * (xa - xb)); } else { RESETINPUT(0); RESETINPUT(1); } } void exprand_d(BinaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float xa = DEMANDINPUT_A(0, inNumSamples); float xb = DEMANDINPUT_A(1, inNumSamples); RGen& rgen = *unit->mParent->mRGen; OUT0(0) = sc_isnan(xa) || sc_isnan(xb) ? NAN : xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); } else { RESETINPUT(0); RESETINPUT(1); } } void zero_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = 0.f; } void firstarg_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = ZIN0(0); } void secondarg_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = ZIN0(1); } void add_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = ZIN0(0) + ZIN0(1); } void sub_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = ZIN0(0) - ZIN0(1); } void mul_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = ZIN0(0) * ZIN0(1); } void div_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = ZIN0(0) / ZIN0(1); } void idiv_1(BinaryOpUGen *unit, int inNumSamples) { ZOUT0(0) = floor(ZIN0(0) / ZIN0(1)); } void mod_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_mod(xa, xb); } void max_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_max(xa, xb); } void min_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_min(xa, xb); } void and_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_andt(xa, xb); } void or_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_ort(xa, xb); } void xor_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_xort(xa, xb); } void rightShift_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_rst(xa, xb); } void leftShift_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_lst(xa, xb); } void lcm_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_lcm(xa, xb); } void gcd_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_gcd(xa, xb); } void amclip_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_amclip(xa, xb); } void scaleneg_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa >= 0.f ? xa : xa * xb; } void pow_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); } void ring1_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa * xb + xa; } void ring2_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa * xb + xa + xb; } void ring3_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa * xa * xb; } void ring4_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa * xa * xb - xa * xb * xb; } void thresh_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa < xb ? 0.f : xa; } void clip2_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa > xb ? xb : (xa < -xb ? -xb : xa); } void excess_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); } void lt_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa < xb ? 1.f : 0.f; } void le_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa <= xb ? 1.f : 0.f; } void gt_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa > xb ? 1.f : 0.f; } void ge_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa >= xb ? 1.f : 0.f; } void eq_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa == xb ? 1.f : 0.f; } void neq_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa != xb ? 1.f : 0.f; } void sumsqr_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa * xa + xb * xb; } void difsqr_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = xa * xa - xb * xb; } void sqrsum_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); float sum = xa + xb; ZOUT0(0) = sum * sum; } void sqrdif_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); float dif = xa - xb; ZOUT0(0) = dif * dif; } void absdif_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = fabs(xa - xb); } void round_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_round(xa, xb); } void roundUp_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_roundUp(xa, xb); } void trunc_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_trunc(xa, xb); } void fold2_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_fold(xa, -xb, xb); } void wrap2_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_wrap(xa, -xb, xb); } void atan2_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = atan2(xa, xb); } void hypot_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = hypot(xa, xb); } void hypotx_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); ZOUT0(0) = sc_hypotx(xa, xb); } void rrand_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = xb > xa ? xa + rgen.frand() * (xb - xa) : (xb + rgen.frand() * (xa - xb)); } void exprand_1(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); float xb = ZIN0(1); RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); } void zero_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); ZClear(inNumSamples, out); } void firstarg_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); ZCopy(inNumSamples, out, a); } #ifdef NOVA_SIMD FLATTEN void firstarg_aa_nova(BinaryOpUGen *unit, int inNumSamples) { nova::copyvec_simd(OUT(0), IN(0), inNumSamples); } #endif void secondarg_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *b = ZIN(1); ZCopy(inNumSamples, out, b); } #ifdef NOVA_SIMD FLATTEN void secondarg_aa_nova(BinaryOpUGen *unit, int inNumSamples) { nova::copyvec_simd(OUT(0), IN(1), inNumSamples); } #endif void add_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) + ZXP(b); ); } void add_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZCopy(inNumSamples, out, a); } else { float *out = ZOUT(0); float *a = ZIN(0); LOOP1(inNumSamples, ZXP(out) = ZXP(a) + xb; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, ZXP(out) = ZXP(a) + xb; xb += slope; ); unit->mPrevB = xb; } } void add_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZCopy(inNumSamples, out, b); } else { LOOP1(inNumSamples, ZXP(out) = xa + ZXP(b); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, ZXP(out) = xa + ZXP(b); xa += slope; ); unit->mPrevA = xa; } } void add_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = xa + ZXP(b); ); unit->mPrevA = xa; } void add_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) + xb; ); unit->mPrevB = xb; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER(add, plus) FLATTEN void add_ak_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::copyvec_simd(OUT(0), IN(0), inNumSamples); else nova::plus_vec_simd(OUT(0), IN(0), xb, inNumSamples); } else { float slope = CALCSLOPE(next_b, xb); nova::plus_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); unit->mPrevB = next_b; } } FLATTEN void add_ak_nova_64(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::copyvec_simd<64>(OUT(0), IN(0)); else nova::plus_vec_simd<64>(OUT(0), IN(0), xb); } else { float slope = CALCSLOPE(next_b, xb); nova::plus_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); unit->mPrevB = next_b; } } FLATTEN void add_ka_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) nova::copyvec_simd(OUT(0), IN(1), inNumSamples); else nova::plus_vec_simd(OUT(0), IN(1), xa, inNumSamples); } else { float slope = CALCSLOPE(next_a, xa); nova::plus_vec_simd(OUT(0), IN(1), slope_argument(xa, slope), inNumSamples); unit->mPrevA = next_a; } } FLATTEN void add_ka_nova_64(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) nova::copyvec_simd<64>(OUT(0), IN(1)); else nova::plus_vec_simd<64>(OUT(0), IN(1), xa); } else { float slope = CALCSLOPE(next_a, xa); nova::plus_vec_simd(OUT(0), IN(1), slope_argument(xa, slope), inNumSamples); unit->mPrevA = next_a; } } #endif ///////////////////////// void sub_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) - ZXP(b); ); } void sub_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZCopy(inNumSamples, out, a); } else { LOOP1(inNumSamples, ZXP(out) = ZXP(a) - xb; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, ZXP(out) = ZXP(a) - xb; xb += slope; ); unit->mPrevB = xb; } } void sub_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZCopy(inNumSamples, out, b); } else { LOOP1(inNumSamples, ZXP(out) = xa - ZXP(b); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, ZXP(out) = xa - ZXP(b); xa += slope; ); unit->mPrevA = xa; } } void sub_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = xa - ZXP(b); ); unit->mPrevA = xa; } void sub_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) - xb; ); unit->mPrevB = xb; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER(sub, minus) FLATTEN void sub_ak_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::copyvec_simd(OUT(0), IN(0), inNumSamples); else nova::minus_vec_simd(OUT(0), IN(0), xb, inNumSamples); } else { float slope = CALCSLOPE(next_b, xb); nova::minus_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); unit->mPrevB = next_b; } } FLATTEN void sub_ak_nova_64(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::copyvec_aa_simd<64>(OUT(0), IN(0)); else nova::minus_vec_simd<64>(OUT(0), IN(0), xb); } else { float slope = CALCSLOPE(next_b, xb); nova::minus_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); unit->mPrevB = next_b; } } FLATTEN void sub_ka_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { nova::minus_vec_simd(OUT(0), xa, IN(1), inNumSamples); } else { float slope = CALCSLOPE(next_a, xa); nova::minus_vec_simd(OUT(0), slope_argument(xa, slope), IN(1), inNumSamples); unit->mPrevA = next_a; } } FLATTEN void sub_ka_nova_64(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { nova::minus_vec_simd<64>(OUT(0), xa, IN(1)); } else { float slope = CALCSLOPE(next_a, xa); nova::minus_vec_simd(OUT(0), slope_argument(xa, slope), IN(1), inNumSamples); unit->mPrevA = next_a; } } #endif void mul_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) * ZXP(b); ); } void mul_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZClear(inNumSamples, out); } else if (xb == 1.f) { ZCopy(inNumSamples, out, a); } else { LOOP1(inNumSamples, ZXP(out) = ZXP(a) * xb; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, ZXP(out) = ZXP(a) * xb; xb += slope; ); unit->mPrevB = xb; } } void mul_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZClear(inNumSamples, out); } else if (xa == 1.f) { ZCopy(inNumSamples, out, b); } else { LOOP1(inNumSamples, ZXP(out) = xa * ZXP(b); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, ZXP(out) = xa * ZXP(b); xa += slope; ); unit->mPrevA = xa; } } void mul_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) * xb; ); unit->mPrevB = xb; } void mul_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = xa * ZXP(b); ); unit->mPrevA = xa; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER(mul, times) FLATTEN void mul_ka_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) nova::zerovec_simd(OUT(0), inNumSamples); else if (xa == 1.f) nova::copyvec_simd(OUT(0), IN(1), inNumSamples); else nova::times_vec_simd(OUT(0), IN(1), xa, inNumSamples); } else { float slope = CALCSLOPE(next_a, xa); unit->mPrevA = next_a; nova::times_vec_simd(OUT(0), IN(1), slope_argument(xa, slope), inNumSamples); } } FLATTEN void mul_ka_nova_64(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) nova::zerovec_simd<64>(OUT(0)); else if (xa == 1.f) nova::copyvec_simd<64>(OUT(0), IN(1)); else nova::times_vec_simd<64>(OUT(0), IN(1), xa); } else { float slope = CALCSLOPE(next_a, xa); unit->mPrevA = next_a; nova::times_vec_simd(OUT(0), IN(1), slope_argument(xa, slope), inNumSamples); } } FLATTEN void mul_ak_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::zerovec_simd(OUT(0), inNumSamples); else if (xb == 1.f) nova::copyvec_simd(OUT(0), IN(0), inNumSamples); else nova::times_vec_simd(OUT(0), IN(0), xb, inNumSamples); } else { float slope = CALCSLOPE(next_b, xb); unit->mPrevB = next_b; nova::times_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); } } FLATTEN void mul_ak_nova_64(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::zerovec_simd<64>(OUT(0)); else if (xb == 1.f) nova::copyvec_simd<64>(OUT(0), IN(0)); else nova::times_vec_simd<64>(OUT(0), IN(0), xb); } else { float slope = CALCSLOPE(next_b, xb); unit->mPrevB = next_b; nova::times_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); } } #endif void div_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = ZXP(a) / ZXP(b); ); } void div_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZClear(inNumSamples, out); } else if (xb == 1.f) { ZCopy(inNumSamples, out, a); } else { float recip = 1.f/ xb; LOOP1(inNumSamples, ZXP(out) = ZXP(a) * recip; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, ZXP(out) = ZXP(a) / xb; xb += slope; ); unit->mPrevB = xb; } } void div_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZClear(inNumSamples, out); } else { LOOP1(inNumSamples, ZXP(out) = xa / ZXP(b); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, ZXP(out) = xa / ZXP(b); xa += slope; ); unit->mPrevA = xa; } } void div_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = xa / ZXP(b); ); unit->mPrevA = xa; } void div_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); float rxb = 1.f / xb; LOOP1(inNumSamples, ZXP(out) = ZXP(a) * rxb; ); unit->mPrevB = xb; } #ifdef NOVA_SIMD FLATTEN void div_aa_nova(BinaryOpUGen *unit, int inNumSamples) { nova::over_vec_simd(OUT(0), IN(0), IN(1), inNumSamples); } FLATTEN void div_ia_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); nova::over_vec_simd(OUT(0), xa, IN(1), inNumSamples); unit->mPrevA = xa; } FLATTEN void div_ai_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = ZIN0(1); nova::times_vec_simd(OUT(0), IN(0), sc_reciprocal(xb), inNumSamples); unit->mPrevB = xb; } FLATTEN void div_ak_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) nova::zerovec_simd(OUT(0), inNumSamples); else if (xb == 1.f) nova::copyvec_simd(OUT(0), IN(0), inNumSamples); else { float recip = 1.f / xb; nova::times_vec_simd(OUT(0), IN(0), recip, inNumSamples); } } else { float slope = CALCSLOPE(next_b, xb); nova::over_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); unit->mPrevB = next_b; } } FLATTEN void div_ka_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) nova::zerovec_simd(OUT(0), inNumSamples); else nova::over_vec_simd(OUT(0), xa, IN(1), inNumSamples); } else { float slope = CALCSLOPE(next_a, xa); nova::over_vec_simd(OUT(0), slope_argument(xa, slope), IN(1), inNumSamples); unit->mPrevA = next_a; } } #endif void idiv_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = floor(ZXP(a) / ZXP(b)); ); } void idiv_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { ZXP(out) = floor(ZXP(a) / xb); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, ZXP(out) = floor(ZXP(a) / xb); xb += slope; ); unit->mPrevB = xb; } } void idiv_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZClear(inNumSamples, out); } else { LOOP1(inNumSamples, ZXP(out) = floor(xa / ZXP(b)); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, ZXP(out) = floor(xa / ZXP(b)); xa += slope; ); unit->mPrevA = xa; } } void idiv_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = floor(xa / ZXP(b)); ); } void idiv_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, ZXP(out) = floor(ZXP(a) / xb); ); } void mod_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_mod(xa, xb); ); } void mod_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZCopy(inNumSamples, out, a); } else { LOOP1(inNumSamples, ZXP(out) = sc_mod(ZXP(a), xb); ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, ZXP(out) = sc_mod(ZXP(a), xb); xb += slope; ); unit->mPrevB = xb; } } void mod_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZClear(inNumSamples, out); } else { LOOP1(inNumSamples, ZXP(out) = sc_mod(xa, ZXP(b)); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, ZXP(out) = sc_mod(xa, ZXP(b)); xa += slope; ); unit->mPrevA = xa; } } void mod_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, ZXP(out) = sc_mod(xa, ZXP(b)); ); unit->mPrevA = xa; } void mod_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, ZXP(out) = sc_mod(ZXP(a), xb); ); unit->mPrevB = xb; } void max_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_max(xa, xb); ); } void max_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_max(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_max(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void max_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_max(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_max(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void max_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_max(xa, xb); ); unit->mPrevA = xa; } void max_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_max(xa, xb); ); unit->mPrevB = xb; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(max, max) #endif void min_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_min(xa, xb); ); } void min_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_min(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_min(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void min_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_min(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_min(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void min_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_min(xa, xb); ); unit->mPrevA = xa; } void min_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_min(xa, xb); ); unit->mPrevB = xb; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(min, min) #endif void and_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_andt(xa, xb) ; ); } void and_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_andt(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_andt(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void and_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_andt(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_andt(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void and_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_andt(xa, xb); ); unit->mPrevA = xa; } void and_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_andt(xa, xb); ); unit->mPrevB = xb; } void or_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_ort(xa, xb) ; ); } void or_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_ort(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_ort(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void or_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_ort(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_ort(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void or_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_ort(xa, xb); ); unit->mPrevA = xa; } void or_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_ort(xa, xb); ); unit->mPrevB = xb; } void xor_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_xort(xa, xb) ; ); } void xor_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_xort(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_xort(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void xor_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_xort(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_xort(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void xor_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_xort(xa, xb); ); unit->mPrevA = xa; } void xor_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_xort(xa, xb); ); unit->mPrevB = xb; } void rightShift_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_rst(xa, xb) ; ); } void rightShift_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_rst(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_rst(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void rightShift_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_rst(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_rst(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void rightShift_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_rst(xa, xb); ); unit->mPrevA = xa; } void rightShift_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_rst(xa, xb); ); unit->mPrevB = xb; } void leftShift_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_lst(xa, xb) ; ); } void leftShift_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_lst(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_lst(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void leftShift_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_lst(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_lst(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void leftShift_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_lst(xa, xb); ); unit->mPrevA = xa; } void leftShift_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_lst(xa, xb); ); unit->mPrevB = xb; } void lcm_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_lcm(xa, xb); ); } void lcm_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_lcm(xa, xb); ); unit->mPrevB = xb; } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_lcm(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void lcm_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_lcm(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_lcm(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void lcm_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_lcm(xa, xb); ); unit->mPrevA = xa; } void lcm_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_lcm(xa, xb); ); unit->mPrevB = xb; } void gcd_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_gcd(xa, xb); ); } void gcd_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_gcd(xa, xb); ); unit->mPrevB = xb; } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_gcd(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void gcd_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_gcd(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_gcd(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void gcd_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_gcd(xa, xb); ); unit->mPrevA = xa; } void gcd_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_gcd(xa, xb); ); unit->mPrevB = xb; } void amclip_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_amclip(xa, xb); ); } void amclip_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb > 0.f) { LOOP1(inNumSamples, ZXP(out) = ZXP(a) * xb; ); } else { ZClear(inNumSamples, out); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_amclip(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void amclip_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_amclip(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_amclip(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void amclip_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_amclip(xa, xb); ); unit->mPrevA = xa; } void amclip_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_amclip(xa, xb); ); unit->mPrevB = xb; } void scaleneg_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa >= 0.f ? xa : xa * xb; ); } void scaleneg_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= 0.f ? xa : xa * xb; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= 0.f ? xa : xa * xb; xb += slope; ); unit->mPrevB = xb; } } void scaleneg_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa >= 0.f) { LOOP1(inNumSamples, ZXP(out) = xa; ); } else { LOOP1(inNumSamples, ZXP(out) = xa * ZXP(b); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= 0.f ? xa : xa * xb; xa += slope; ); unit->mPrevA = xa; } } void scaleneg_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= 0.f ? xa : xa * xb; ); unit->mPrevA = xa; } void scaleneg_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= 0.f ? xa : xa * xb; ); unit->mPrevB = xb; } void pow_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); ); } void pow_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); xb += slope; ); unit->mPrevB = xb; } } void pow_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa >= 0.f) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = pow(xa, xb); ); } else { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = -pow(-xa, xb); ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); xa += slope; ); unit->mPrevA = xa; } } void pow_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); ); unit->mPrevA = xa; } void pow_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); ); unit->mPrevB = xb; } #ifdef NOVA_SIMD FLATTEN void pow_aa_nova(BinaryOpUGen *unit, int inNumSamples) { nova::spow_vec_simd(OUT(0), IN(0), IN(1), inNumSamples); } FLATTEN void pow_ak_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) nova::spow_vec_simd(OUT(0), IN(0), xb, inNumSamples); else { float slope = CALCSLOPE(next_b, xb); nova::spow_vec_simd(OUT(0), IN(0), slope_argument(xb, slope), inNumSamples); unit->mPrevB = next_b; } } FLATTEN void pow_ka_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = unit->mPrevA; float next_a = ZIN0(0); if (xa == next_a) { if (xa >= 0.f) nova::pow_vec_simd(OUT(0), xa, IN(1), inNumSamples); else nova::spow_vec_simd(OUT(0), xa, IN(1), inNumSamples); } else { float slope = CALCSLOPE(next_a, xa); nova::spow_vec_simd(OUT(0), slope_argument(xa, slope), IN(1), inNumSamples); unit->mPrevA = next_a; } } FLATTEN void pow_ia_nova(BinaryOpUGen *unit, int inNumSamples) { float xa = ZIN0(0); if (xa > 0.f) nova::pow_vec_simd(OUT(0), xa, IN(1), inNumSamples); else nova::spow_vec_simd(OUT(0), xa, IN(1), inNumSamples); unit->mPrevA = xa; } FLATTEN void pow_ai_nova(BinaryOpUGen *unit, int inNumSamples) { float xb = ZIN0(1); nova::spow_vec_simd(OUT(0), IN(0), xb, inNumSamples); } #endif #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER(ring1, sc_ring1) NOVA_BINARY_WRAPPER(ring2, sc_ring2) NOVA_BINARY_WRAPPER(ring3, sc_ring3) NOVA_BINARY_WRAPPER(ring4, sc_ring4) #endif void ring1_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa * xb + xa; ); } void ring1_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZCopy(inNumSamples, out, a); } else if (xb == 1.f) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa + xa; ); } else { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xb + xa; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xb + xa; xb += slope; ); unit->mPrevB = xb; } } void ring1_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { LOOP1(inNumSamples, ZXP(out) = 0.f; ); } else { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xb + xa; ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xb + xa; xa += slope; ); unit->mPrevA = xa; } } void ring1_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xb + xa; ); unit->mPrevA = xa; } void ring1_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xb + xa; ); unit->mPrevB = xb; } void ring2_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa * xb + xa + xb; ); } void ring2_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZCopy(inNumSamples, out, a); } else { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xb + xa + xb; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xb + xa + xb; xb += slope; ); unit->mPrevB = xb; } } void ring2_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZCopy(inNumSamples, out, b); } else { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xb + xa + xb; ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xb + xa + xb; xa += slope; ); unit->mPrevA = xa; } } void ring2_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xb + xa + xb; ); unit->mPrevA = xa; } void ring2_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xb + xa + xb; ); unit->mPrevB = xb; } void ring3_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa * xa * xb; ); } void ring3_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZClear(inNumSamples, out); } else if (xb == 1.f) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa; ); } else { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa * xb; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa * xb; xb += slope; ); unit->mPrevB = xb; } } void ring3_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZClear(inNumSamples, out); } else if (xa == 1.f) { ZCopy(inNumSamples, out, b); } else { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa * xb; ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa * xb; xa += slope; ); unit->mPrevA = xa; } } void ring3_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa * xb; ); unit->mPrevA = xa; } void ring3_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa * xb; ); unit->mPrevB = xb; } void ring4_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa * xa * xb - xa * xb * xb; ); } void ring4_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { if (xb == 0.f) { ZClear(inNumSamples, out); } else if (xb == 1.f) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa - xa; ); } else { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa * xb - xa * xb * xb; ); } } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa * xb - xa * xb * xb; xb += slope; ); unit->mPrevB = xb; } } void ring4_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { if (xa == 0.f) { ZClear(inNumSamples, out); } else if (xa == 1.f) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xb - xb * xb; ); } else { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa * xb - xa * xb * xb; ); } } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa * xb - xa * xb * xb; xa += slope; ); unit->mPrevA = xa; } } void ring4_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa * xb - xa * xb * xb; ); unit->mPrevA = xa; } void ring4_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa * xb - xa * xb * xb; ); unit->mPrevB = xb; } void thresh_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa < xb ? 0.f : xa; ); } void thresh_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa < xb ? 0.f : xa; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa < xb ? 0.f : xa; xb += slope; ); unit->mPrevB = xb; } } void thresh_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa < xb ? 0.f : xa; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa < xb ? 0.f : xa; xa += slope; ); unit->mPrevA = xa; } } void thresh_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa < xb ? 0.f : xa; ); unit->mPrevA = xa; } void thresh_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa < xb ? 0.f : xa; ); unit->mPrevB = xb; } void clip2_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); ); } void clip2_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); xb += slope; ); unit->mPrevB = xb; } } void clip2_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); xa += slope; ); unit->mPrevA = xa; } } void clip2_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); ); unit->mPrevA = xa; } void clip2_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? xb : (xa < -xb ? -xb : xa); ); unit->mPrevB = xb; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(clip2, clip2) #endif void excess_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); ); } void excess_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); xb += slope; ); unit->mPrevB = xb; } } void excess_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); xa += slope; ); unit->mPrevA = xa; } } void excess_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); ); unit->mPrevA = xa; } void excess_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? xa-xb : (xa < -xb ? xa+xb : 0.f); ); unit->mPrevB = xb; } void rrand_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); RGET LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); ); RPUT } void rrand_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); RGET if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); xb += slope; ); unit->mPrevB = xb; } RPUT } void rrand_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); RGET if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); xa += slope; ); unit->mPrevA = xa; } RPUT } void rrand_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); RGET LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); ); unit->mPrevA = xa; RPUT } void rrand_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); RGET LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xb > xa ? xa + frand2(s1, s2, s3) * (xb - xa) : (xb + frand2(s1, s2, s3) * (xa - xb)); ); RPUT unit->mPrevB = xb; } void exprand_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); RGen& rgen = *unit->mParent->mRGen; ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); ); } void exprand_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); RGen& rgen = *unit->mParent->mRGen; if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); xb += slope; ); unit->mPrevB = xb; } } void exprand_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); RGen& rgen = *unit->mParent->mRGen; if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); xa += slope; ); unit->mPrevA = xa; } } void exprand_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); RGen& rgen = *unit->mParent->mRGen; ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); ); unit->mPrevA = xa; } void exprand_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); RGen& rgen = *unit->mParent->mRGen; ZXP(out) = xb > xa ? rgen.exprandrng(xa, xb) : rgen.exprandrng(xb, xa); ); unit->mPrevB = xb; } void lt_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa < xb ? 1.f : 0.f; ); } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(lt, less) #endif void lt_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa < xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa < xb ? 1.f : 0.f; xb += slope; ); unit->mPrevB = xb; } } void lt_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa < xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa < xb ? 1.f : 0.f; xa += slope; ); unit->mPrevA = xa; } } void lt_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa < xb ? 1.f : 0.f; ); unit->mPrevA = xa; } void lt_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa < xb ? 1.f : 0.f; ); unit->mPrevB = xb; } void le_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa <= xb ? 1.f : 0.f; ); } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(le, less_equal) #endif void le_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa <= xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa <= xb ? 1.f : 0.f; xb += slope; ); unit->mPrevB = xb; } } void le_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa <= xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa <= xb ? 1.f : 0.f; xa += slope; ); unit->mPrevA = xa; } } void le_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa <= xb ? 1.f : 0.f; ); unit->mPrevA = xa; } void le_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa <= xb ? 1.f : 0.f; ); unit->mPrevB = xb; } void gt_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa > xb ? 1.f : 0.f; ); } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(gt, greater) #endif void gt_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? 1.f : 0.f; xb += slope; ); unit->mPrevB = xb; } } void gt_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? 1.f : 0.f; xa += slope; ); unit->mPrevA = xa; } } void gt_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa > xb ? 1.f : 0.f; ); unit->mPrevA = xa; } void gt_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa > xb ? 1.f : 0.f; ); unit->mPrevB = xb; } void ge_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa >= xb ? 1.f : 0.f; ); } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(ge, greater_equal) #endif void ge_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= xb ? 1.f : 0.f; xb += slope; ); unit->mPrevB = xb; } } void ge_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= xb ? 1.f : 0.f; xa += slope; ); unit->mPrevA = xa; } } void ge_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa >= xb ? 1.f : 0.f; ); unit->mPrevA = xa; } void ge_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa >= xb ? 1.f : 0.f; ); unit->mPrevB = xb; } void eq_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa == xb ? 1.f : 0.f; ); } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(eq, equal) #endif void eq_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa == xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa == xb ? 1.f : 0.f; xb += slope; ); unit->mPrevB = xb; } } void eq_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa == xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa == xb ? 1.f : 0.f; xa += slope; ); unit->mPrevA = xa; } } void eq_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa == xb ? 1.f : 0.f; ); unit->mPrevA = xa; } void eq_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa == xb ? 1.f : 0.f; ); unit->mPrevB = xb; } void neq_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa != xb ? 1.f : 0.f; ); } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(neq, notequal) #endif void neq_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa != xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa != xb ? 1.f : 0.f; xb += slope; ); unit->mPrevB = xb; } } void neq_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa != xb ? 1.f : 0.f; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa != xb ? 1.f : 0.f; xa += slope; ); unit->mPrevA = xa; } } void neq_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa != xb ? 1.f : 0.f; ); unit->mPrevA = xa; } void neq_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa != xb ? 1.f : 0.f; ); unit->mPrevB = xb; } #ifdef NOVA_SIMD NOVA_BINARY_WRAPPER_K(sumsqr, sc_sumsqr) NOVA_BINARY_WRAPPER_K(difsqr, sc_difsqr) NOVA_BINARY_WRAPPER_K(sqrsum, sc_sqrsum) NOVA_BINARY_WRAPPER_K(sqrdif, sc_sqrdif) #endif void sumsqr_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa * xa + xb * xb; ); } void sumsqr_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa + xb * xb; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa + xb * xb; xb += slope; ); unit->mPrevB = xb; } } void sumsqr_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa + xb * xb; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa + xb * xb; xa += slope; ); unit->mPrevA = xa; } } void sumsqr_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa + xb * xb; ); unit->mPrevA = xa; } void sumsqr_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa + xb * xb; ); unit->mPrevB = xb; } void difsqr_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = xa * xa - xb * xb; ); } void difsqr_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa - xb * xb; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa - xb * xb; xb += slope; ); unit->mPrevB = xb; } } void difsqr_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa - xb * xb; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa - xb * xb; xa += slope; ); unit->mPrevA = xa; } } void difsqr_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = xa * xa - xb * xb; ); unit->mPrevA = xa; } void difsqr_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = xa * xa - xb * xb; ); unit->mPrevB = xb; } void sqrsum_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float sum = ZXP(a) + ZXP(b); ZXP(out) = sum * sum; ); } void sqrsum_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); float sum = xa + xb; ZXP(out) = sum * sum; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); float sum = xa + xb; ZXP(out) = sum * sum; xb += slope; ); unit->mPrevB = xb; } } void sqrsum_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); float sum = xa + xb; ZXP(out) = sum * sum; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); float sum = xa + xb; ZXP(out) = sum * sum; xa += slope; ); unit->mPrevA = xa; } } void sqrsum_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); float sum = xa + xb; ZXP(out) = sum * sum; ); unit->mPrevA = xa; } void sqrsum_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); float sum = xa + xb; ZXP(out) = sum * sum; ); unit->mPrevB = xb; } void sqrdif_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float dif = ZXP(a) - ZXP(b); ZXP(out) = dif * dif; ); } void sqrdif_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); float dif = xa - xb; ZXP(out) = dif * dif; ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); float dif = xa - xb; ZXP(out) = dif * dif; xb += slope; ); unit->mPrevB = xb; } } void sqrdif_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); float dif = xa - xb; ZXP(out) = dif * dif; ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); float dif = xa - xb; ZXP(out) = dif * dif; xa += slope; ); unit->mPrevA = xa; } } void sqrdif_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); float dif = xa - xb; ZXP(out) = dif * dif; ); unit->mPrevA = xa; } void sqrdif_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); float dif = xa - xb; ZXP(out) = dif * dif; ); unit->mPrevB = xb; } void absdif_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float dif = ZXP(a) - ZXP(b); ZXP(out) = fabs(dif); ); } void absdif_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); float dif = xa - xb; ZXP(out) = fabs(dif); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); float dif = xa - xb; ZXP(out) = fabs(dif); xb += slope; ); unit->mPrevB = xb; } } void absdif_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); float dif = xa - xb; ZXP(out) = fabs(dif); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); float dif = xa - xb; ZXP(out) = fabs(dif); xa += slope; ); unit->mPrevA = xa; } } void absdif_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); float dif = xa - xb; ZXP(out) = fabs(dif); ); unit->mPrevA = xa; } void absdif_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); float dif = xa - xb; ZXP(out) = fabs(dif); ); unit->mPrevB = xb; } void round_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_round(xa, xb); ); } void round_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_round(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_round(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void round_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_round(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_round(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void round_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_round(xa, xb); ); unit->mPrevA = xa; } void round_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_round(xa, xb); ); unit->mPrevB = xb; } void roundUp_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_roundUp(xa, xb); ); } void roundUp_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_roundUp(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_roundUp(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void roundUp_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_roundUp(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_roundUp(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void roundUp_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_roundUp(xa, xb); ); unit->mPrevA = xa; } void roundUp_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_roundUp(xa, xb); ); unit->mPrevB = xb; } void trunc_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_trunc(xa, xb); ); } void trunc_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_trunc(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_trunc(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void trunc_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_trunc(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_trunc(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void trunc_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_trunc(xa, xb); ); unit->mPrevA = xa; } void trunc_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_trunc(xa, xb); ); unit->mPrevB = xb; } void fold2_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_fold(xa, -xb, xb); ); } void fold2_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_fold(xa, -xb, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_fold(xa, -xb, xb); xb += slope; ); unit->mPrevB = xb; } } void fold2_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_fold(xa, -xb, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_fold(xa, -xb, xb); xa += slope; ); unit->mPrevA = xa; } } void fold2_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_fold(xa, -xb, xb); ); unit->mPrevA = xa; } void fold2_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_fold(xa, -xb, xb); ); unit->mPrevB = xb; } void wrap2_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_wrap(xa, -xb, xb); ); } void wrap2_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_wrap(xa, -xb, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_wrap(xa, -xb, xb); xb += slope; ); unit->mPrevB = xb; } } void wrap2_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_wrap(xa, -xb, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_wrap(xa, -xb, xb); xa += slope; ); unit->mPrevA = xa; } } void wrap2_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_wrap(xa, -xb, xb); ); unit->mPrevA = xa; } void wrap2_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_wrap(xa, -xb, xb); ); unit->mPrevB = xb; } void atan2_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = atan2(xa, xb); ); } void atan2_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = atan2(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = atan2(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void atan2_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = atan2(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = atan2(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void atan2_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = atan2(xa, xb); ); unit->mPrevA = xa; } void atan2_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = atan2(xa, xb); ); unit->mPrevB = xb; } void hypot_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = hypotf(xa, xb); ); } void hypot_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = hypotf(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = hypotf(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void hypot_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = hypotf(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = hypotf(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void hypot_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = hypotf(xa, xb); ); unit->mPrevA = xa; } void hypot_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = hypotf(xa, xb); ); unit->mPrevB = xb; } void hypotx_aa(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); ZXP(out) = sc_hypotx(xa, xb); ); } void hypotx_ak(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = unit->mPrevB; float next_b = ZIN0(1); if (xb == next_b) { LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_hypotx(xa, xb); ); } else { float slope = CALCSLOPE(next_b, xb); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_hypotx(xa, xb); xb += slope; ); unit->mPrevB = xb; } } void hypotx_ka(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = unit->mPrevA; float *b = ZIN(1); float next_a = ZIN0(0); if (xa == next_a) { LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_hypotx(xa, xb); ); } else { float slope = CALCSLOPE(next_a, xa); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_hypotx(xa, xb); xa += slope; ); unit->mPrevA = xa; } } void hypotx_ia(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); LOOP1(inNumSamples, float xb = ZXP(b); ZXP(out) = sc_hypotx(xa, xb); ); unit->mPrevA = xa; } void hypotx_ai(BinaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); LOOP1(inNumSamples, float xa = ZXP(a); ZXP(out) = sc_hypotx(xa, xb); ); unit->mPrevB = xb; } static BinaryOpFunc ChooseOneSampleFunc(BinaryOpUGen *unit) { BinaryOpFunc func = &zero_1; switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_1; break; case opAdd : func = &add_1; break; case opSub : func = &sub_1; break; case opMul : func = &mul_1; break; case opFDiv : func = &div_1; break; case opIDiv : func = &idiv_1; break; case opMod : func = &mod_1; break; case opEQ : func = &eq_1; break; case opNE : func = &neq_1; break; case opLT : func = <_1; break; case opGT : func = >_1; break; case opLE : func = &le_1; break; case opGE : func = &ge_1; break; case opMin : func = &min_1; break; case opMax : func = &max_1; break; case opBitAnd : func = &and_1; break; case opBitOr : func = &or_1; break; case opBitXor : func = &xor_1; break; case opShiftRight : func = &rightShift_1; break; case opShiftLeft : func = &leftShift_1; break; case opLCM : func = &lcm_1; break; case opGCD : func = &gcd_1; break; case opRound : func = &round_1; break; case opRoundUp : func = &roundUp_1; break; case opTrunc : func = &trunc_1; break; case opAtan2 : func = &atan2_1; break; case opHypot : func = &hypot_1; break; case opHypotx : func = &hypotx_1; break; case opPow : func = &pow_1; break; case opRing1 : func = &ring1_1; break; case opRing2 : func = &ring2_1; break; case opRing3 : func = &ring3_1; break; case opRing4 : func = &ring4_1; break; case opDifSqr : func = &difsqr_1; break; case opSumSqr : func = &sumsqr_1; break; case opSqrSum : func = &sqrsum_1; break; case opSqrDif : func = &sqrdif_1; break; case opAbsDif : func = &absdif_1; break; case opThresh : func = &thresh_1; break; case opAMClip : func = &amclip_1; break; case opScaleNeg : func = &scaleneg_1; break; case opClip2 : func = &clip2_1; break; case opFold2 : func = &fold2_1; break; case opWrap2 : func = &wrap2_1; break; case opExcess : func = &excess_1; break; case opFirstArg : func = &firstarg_1; break; case opRandRange : func = &rrand_1; break; case opExpRandRange : func = &exprand_1; break; //case opSecondArg : func = &secondarg_1; break; default : func = &add_1; break; } return func; } static BinaryOpFunc ChooseDemandFunc(BinaryOpUGen *unit) { BinaryOpFunc func = &zero_1; switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_d; break; case opAdd : func = &add_d; break; case opSub : func = &sub_d; break; case opMul : func = &mul_d; break; case opFDiv : func = &div_d; break; case opIDiv : func = &idiv_d; break; case opMod : func = &mod_d; break; case opEQ : func = &eq_d; break; case opNE : func = &neq_d; break; case opLT : func = <_d; break; case opGT : func = >_d; break; case opLE : func = &le_d; break; case opGE : func = &ge_d; break; case opMin : func = &min_d; break; case opMax : func = &max_d; break; case opBitAnd : func = &and_d; break; case opBitOr : func = &or_d; break; case opBitXor : func = &xor_d; break; case opShiftRight : func = &rightShift_d; break; case opShiftLeft : func = &leftShift_d; break; case opLCM : func = &lcm_d; break; case opGCD : func = &gcd_d; break; case opRound : func = &round_d; break; case opRoundUp : func = &roundUp_d; break; case opTrunc : func = &trunc_d; break; case opAtan2 : func = &atan2_d; break; case opHypot : func = &hypot_d; break; case opHypotx : func = &hypotx_d; break; case opPow : func = &pow_d; break; case opRing1 : func = &ring1_d; break; case opRing2 : func = &ring2_d; break; case opRing3 : func = &ring3_d; break; case opRing4 : func = &ring4_d; break; case opDifSqr : func = &difsqr_d; break; case opSumSqr : func = &sumsqr_d; break; case opSqrSum : func = &sqrsum_d; break; case opSqrDif : func = &sqrdif_d; break; case opAbsDif : func = &absdif_d; break; case opThresh : func = &thresh_d; break; case opAMClip : func = &amclip_d; break; case opScaleNeg : func = &scaleneg_d; break; case opClip2 : func = &clip2_d; break; case opFold2 : func = &fold2_d; break; case opWrap2 : func = &wrap2_d; break; case opExcess : func = &excess_d; break; case opFirstArg : func = &firstarg_d; break; case opRandRange : func = &rrand_d; break; case opExpRandRange : func = &exprand_d; break; //case opSecondArg : func = &secondarg_d; break; default : func = &add_d; break; } return func; } static BinaryOpFunc ChooseNormalFunc(BinaryOpUGen *unit) { BinaryOpFunc func = &zero_1; int rateA = INRATE(0); int rateB = INRATE(1); switch (rateA) { case calc_FullRate: switch (rateB) { case calc_FullRate: switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_aa; break; case opSub : func = &sub_aa; break; case opMul : func = &mul_aa; break; case opFDiv : func = &div_aa; break; case opIDiv : func = &idiv_aa; break; case opMod : func = &mod_aa; break; case opEQ : func = &eq_aa; break; case opNE : func = &neq_aa; break; case opLT : func = <_aa; break; case opGT : func = >_aa; break; case opLE : func = &le_aa; break; case opGE : func = &ge_aa; break; case opMin : func = &min_aa; break; case opMax : func = &max_aa; break; case opBitAnd : func = &and_aa; break; case opBitOr : func = &or_aa; break; case opBitXor : func = &xor_aa; break; case opShiftRight : func = &rightShift_aa; break; case opShiftLeft : func = &leftShift_aa; break; case opLCM : func = &lcm_aa; break; case opGCD : func = &gcd_aa; break; case opRound : func = &round_aa; break; case opRoundUp : func = &roundUp_aa; break; case opTrunc : func = &trunc_aa; break; case opAtan2 : func = &atan2_aa; break; case opHypot : func = &hypot_aa; break; case opHypotx : func = &hypotx_aa; break; case opPow : func = &pow_aa; break; case opRing1 : func = &ring1_aa; break; case opRing2 : func = &ring2_aa; break; case opRing3 : func = &ring3_aa; break; case opRing4 : func = &ring4_aa; break; case opDifSqr : func = &difsqr_aa; break; case opSumSqr : func = &sumsqr_aa; break; case opSqrSum : func = &sqrsum_aa; break; case opSqrDif : func = &sqrdif_aa; break; case opAbsDif : func = &absdif_aa; break; case opThresh : func = &thresh_aa; break; case opAMClip : func = &amclip_aa; break; case opScaleNeg : func = &scaleneg_aa; break; case opClip2 : func = &clip2_aa; break; case opFold2 : func = &fold2_aa; break; case opWrap2 : func = &wrap2_aa; break; case opExcess : func = &excess_aa; break; case opRandRange : func = &rrand_aa; break; case opExpRandRange : func = &exprand_aa; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_aa; break; } break; case calc_BufRate : switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ak; break; case opSub : func = &sub_ak; break; case opMul : func = &mul_ak; break; case opFDiv : func = &div_ak; break; case opIDiv : func = &idiv_ak; break; case opMod : func = &mod_ak; break; case opEQ : func = &eq_ak; break; case opNE : func = &neq_ak; break; case opLT : func = <_ak; break; case opGT : func = >_ak; break; case opLE : func = &le_ak; break; case opGE : func = &ge_ak; break; case opMin : func = &min_ak; break; case opMax : func = &max_ak; break; case opBitAnd : func = &and_ak; break; case opBitOr : func = &or_ak; break; case opBitXor : func = &xor_ak; break; case opShiftRight : func = &rightShift_ak; break; case opShiftLeft : func = &leftShift_ak; break; case opLCM : func = &lcm_ak; break; case opGCD : func = &gcd_ak; break; case opRound : func = &round_ak; break; case opRoundUp : func = &roundUp_ak; break; case opTrunc : func = &trunc_ak; break; case opAtan2 : func = &atan2_ak; break; case opHypot : func = &hypot_ak; break; case opHypotx : func = &hypotx_ak; break; case opPow : func = &pow_ak; break; case opRing1 : func = &ring1_ak; break; case opRing2 : func = &ring2_ak; break; case opRing3 : func = &ring3_ak; break; case opRing4 : func = &ring4_ak; break; case opDifSqr : func = &difsqr_ak; break; case opSumSqr : func = &sumsqr_ak; break; case opSqrSum : func = &sqrsum_ak; break; case opSqrDif : func = &sqrdif_ak; break; case opAbsDif : func = &absdif_ak; break; case opThresh : func = &thresh_ak; break; case opAMClip : func = &amclip_ak; break; case opScaleNeg : func = &scaleneg_ak; break; case opClip2 : func = &clip2_ak; break; case opFold2 : func = &fold2_ak; break; case opWrap2 : func = &wrap2_ak; break; case opExcess : func = &excess_ak; break; case opRandRange : func = &rrand_ak; break; case opExpRandRange : func = &exprand_ak; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ak; break; } break; case calc_ScalarRate : switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ai; break; case opSub : func = &sub_ai; break; case opMul : func = &mul_ai; break; case opFDiv : func = &div_ai; break; case opIDiv : func = &idiv_ai; break; case opMod : func = &mod_ai; break; case opEQ : func = &eq_ai; break; case opNE : func = &neq_ai; break; case opLT : func = <_ai; break; case opGT : func = >_ai; break; case opLE : func = &le_ai; break; case opGE : func = &ge_ai; break; case opMin : func = &min_ai; break; case opMax : func = &max_ai; break; case opBitAnd : func = &and_ai; break; case opBitOr : func = &or_ai; break; case opBitXor : func = &xor_ai; break; case opShiftRight : func = &rightShift_ai; break; case opShiftLeft : func = &leftShift_ai; break; case opLCM : func = &lcm_ai; break; case opGCD : func = &gcd_ai; break; case opRound : func = &round_ai; break; case opRoundUp : func = &roundUp_ai; break; case opTrunc : func = &trunc_ai; break; case opAtan2 : func = &atan2_ai; break; case opHypot : func = &hypot_ai; break; case opHypotx : func = &hypotx_ai; break; case opPow : func = &pow_ai; break; case opRing1 : func = &ring1_ai; break; case opRing2 : func = &ring2_ai; break; case opRing3 : func = &ring3_ai; break; case opRing4 : func = &ring4_ai; break; case opDifSqr : func = &difsqr_ai; break; case opSumSqr : func = &sumsqr_ai; break; case opSqrSum : func = &sqrsum_ai; break; case opSqrDif : func = &sqrdif_ai; break; case opAbsDif : func = &absdif_ai; break; case opThresh : func = &thresh_ai; break; case opAMClip : func = &amclip_ai; break; case opScaleNeg : func = &scaleneg_ai; break; case opClip2 : func = &clip2_ai; break; case opFold2 : func = &fold2_ai; break; case opWrap2 : func = &wrap2_ai; break; case opExcess : func = &excess_ai; break; case opRandRange : func = &rrand_ai; break; case opExpRandRange : func = &exprand_ai; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ai; break; } } break; case calc_BufRate : if (rateB == calc_FullRate) { switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ka; break; case opSub : func = &sub_ka; break; case opMul : func = &mul_ka; break; case opFDiv : func = &div_ka; break; case opIDiv : func = &idiv_ka; break; case opMod : func = &mod_ka; break; case opEQ : func = &eq_ka; break; case opNE : func = &neq_ka; break; case opLT : func = <_ka; break; case opGT : func = >_ka; break; case opLE : func = &le_ka; break; case opGE : func = &ge_ka; break; case opMin : func = &min_ka; break; case opMax : func = &max_ka; break; case opBitAnd : func = &and_ka; break; case opBitOr : func = &or_ka; break; case opBitXor : func = &xor_ka; break; case opShiftRight : func = &rightShift_ka; break; case opShiftLeft : func = &leftShift_ka; break; case opLCM : func = &lcm_ka; break; case opGCD : func = &gcd_ka; break; case opRound : func = &round_ka; break; case opRoundUp : func = &roundUp_ka; break; case opTrunc : func = &trunc_ka; break; case opAtan2 : func = &atan2_ka; break; case opHypot : func = &hypot_ka; break; case opHypotx : func = &hypotx_ka; break; case opPow : func = &pow_ka; break; case opRing1 : func = &ring1_ka; break; case opRing2 : func = &ring2_ka; break; case opRing3 : func = &ring3_ka; break; case opRing4 : func = &ring4_ka; break; case opDifSqr : func = &difsqr_ka; break; case opSumSqr : func = &sumsqr_ka; break; case opSqrSum : func = &sqrsum_ka; break; case opSqrDif : func = &sqrdif_ka; break; case opAbsDif : func = &absdif_ka; break; case opThresh : func = &thresh_ka; break; case opAMClip : func = &amclip_ka; break; case opScaleNeg : func = &scaleneg_ka; break; case opClip2 : func = &clip2_ka; break; case opFold2 : func = &fold2_ka; break; case opWrap2 : func = &wrap2_ka; break; case opExcess : func = &excess_ka; break; case opRandRange : func = &rrand_ka; break; case opExpRandRange : func = &exprand_ka; break; //case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ka; break; } } else { // this should have been caught by mBufLength == 1 func = &zero_aa; } break; case calc_ScalarRate : if (rateB == calc_FullRate) { switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ia; break; case opSub : func = &sub_ia; break; case opMul : func = &mul_ia; break; case opFDiv : func = &div_ia; break; case opIDiv : func = &idiv_ia; break; case opMod : func = &mod_ia; break; case opEQ : func = &eq_ia; break; case opNE : func = &neq_ia; break; case opLT : func = <_ia; break; case opGT : func = >_ia; break; case opLE : func = &le_ia; break; case opGE : func = &ge_ia; break; case opMin : func = &min_ia; break; case opMax : func = &max_ia; break; case opBitAnd : func = &and_ia; break; case opBitOr : func = &or_ia; break; case opBitXor : func = &xor_ia; break; case opShiftRight : func = &rightShift_ia; break; case opShiftLeft : func = &leftShift_ia; break; case opLCM : func = &lcm_ia; break; case opGCD : func = &gcd_ia; break; case opRound : func = &round_ia; break; case opRoundUp : func = &roundUp_ia; break; case opTrunc : func = &trunc_ia; break; case opAtan2 : func = &atan2_ia; break; case opHypot : func = &hypot_ia; break; case opHypotx : func = &hypotx_ia; break; case opPow : func = &pow_ia; break; case opRing1 : func = &ring1_ia; break; case opRing2 : func = &ring2_ia; break; case opRing3 : func = &ring3_ia; break; case opRing4 : func = &ring4_ia; break; case opDifSqr : func = &difsqr_ia; break; case opSumSqr : func = &sumsqr_ia; break; case opSqrSum : func = &sqrsum_ia; break; case opSqrDif : func = &sqrdif_ia; break; case opAbsDif : func = &absdif_ia; break; case opThresh : func = &thresh_ia; break; case opAMClip : func = &amclip_ia; break; case opScaleNeg : func = &scaleneg_ia; break; case opClip2 : func = &clip2_ia; break; case opFold2 : func = &fold2_ia; break; case opWrap2 : func = &wrap2_ia; break; case opExcess : func = &excess_ia; break; case opRandRange : func = &rrand_ia; break; case opExpRandRange : func = &exprand_ia; break; //case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ia; break; } } else { // this should have been caught by mBufLength == 1 func = &zero_aa; } break; } return func; } #ifdef NOVA_SIMD static BinaryOpFunc ChooseNovaSimdFunc_64(BinaryOpUGen *unit) { BinaryOpFunc func = &zero_1; int rateA = INRATE(0); int rateB = INRATE(1); switch (rateA) { case calc_FullRate: switch (rateB) { case calc_FullRate: switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_aa_nova_64; break; case opSub : func = &sub_aa_nova_64; break; case opMul : func = &mul_aa_nova_64; break; case opFDiv : func = &div_aa_nova; break; case opIDiv : func = &idiv_aa; break; case opMod : func = &mod_aa; break; case opEQ : func = &eq_aa_nova_64; break; case opNE : func = &neq_aa_nova_64; break; case opLT : func = <_aa_nova_64; break; case opGT : func = >_aa_nova_64; break; case opLE : func = &le_aa_nova_64; break; case opGE : func = &ge_aa_nova_64; break; case opMin : func = &min_aa_nova_64; break; case opMax : func = &max_aa_nova_64; break; case opBitAnd : func = &and_aa; break; case opBitOr : func = &or_aa; break; case opBitXor : func = &xor_aa; break; case opShiftRight : func = &rightShift_aa; break; case opShiftLeft : func = &leftShift_aa; break; case opLCM : func = &lcm_aa; break; case opGCD : func = &gcd_aa; break; case opRound : func = &round_aa; break; case opRoundUp : func = &roundUp_aa; break; case opTrunc : func = &trunc_aa; break; case opAtan2 : func = &atan2_aa; break; case opHypot : func = &hypot_aa; break; case opHypotx : func = &hypotx_aa; break; case opPow : func = &pow_aa_nova; break; case opRing1 : func = &ring1_aa_nova_64; break; case opRing2 : func = &ring2_aa_nova_64; break; case opRing3 : func = &ring3_aa_nova_64; break; case opRing4 : func = &ring4_aa_nova_64; break; case opDifSqr : func = &difsqr_aa_nova_64; break; case opSumSqr : func = &sumsqr_aa_nova_64; break; case opSqrSum : func = &sqrsum_aa_nova_64; break; case opSqrDif : func = &sqrdif_aa_nova_64; break; case opAbsDif : func = &absdif_aa; break; case opThresh : func = &thresh_aa; break; case opAMClip : func = &amclip_aa; break; case opScaleNeg : func = &scaleneg_aa; break; case opClip2 : func = &clip2_aa_nova_64; break; case opFold2 : func = &fold2_aa; break; case opWrap2 : func = &wrap2_aa; break; case opExcess : func = &excess_aa; break; case opRandRange : func = &rrand_aa; break; case opExpRandRange : func = &exprand_aa; break; case opFirstArg : func = &firstarg_aa_nova; break; //case opSecondArg : func = &secondarg_aa_nova; break; default : func = &add_aa; break; } break; case calc_BufRate : switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ak_nova_64; break; case opSub : func = &sub_ak_nova_64; break; case opMul : func = &mul_ak_nova_64; break; case opFDiv : func = &div_ak_nova; break; case opIDiv : func = &idiv_ak; break; case opMod : func = &mod_ak; break; case opEQ : func = &eq_ak_nova_64; break; case opNE : func = &neq_ak_nova_64; break; case opLT : func = <_ak_nova_64; break; case opGT : func = >_ak_nova_64; break; case opLE : func = &le_ak_nova_64; break; case opGE : func = &ge_ak_nova_64; break; case opMin : func = &min_ak_nova_64; break; case opMax : func = &max_ak_nova_64; break; case opBitAnd : func = &and_ak; break; case opBitOr : func = &or_ak; break; case opBitXor : func = &xor_ak; break; case opShiftRight : func = &rightShift_ak; break; case opShiftLeft : func = &leftShift_ak; break; case opLCM : func = &lcm_ak; break; case opGCD : func = &gcd_ak; break; case opRound : func = &round_ak; break; case opRoundUp : func = &roundUp_ak; break; case opTrunc : func = &trunc_ak; break; case opAtan2 : func = &atan2_ak; break; case opHypot : func = &hypot_ak; break; case opHypotx : func = &hypotx_ak; break; case opPow : func = &pow_ak_nova; break; case opRing1 : func = &ring1_ak; break; case opRing2 : func = &ring2_ak; break; case opRing3 : func = &ring3_ak; break; case opRing4 : func = &ring4_ak; break; case opDifSqr : func = &difsqr_ak_nova_64; break; case opSumSqr : func = &sumsqr_ak_nova_64; break; case opSqrSum : func = &sqrsum_ak_nova_64; break; case opSqrDif : func = &sqrdif_ak_nova_64; break; case opAbsDif : func = &absdif_ak; break; case opThresh : func = &thresh_ak; break; case opAMClip : func = &amclip_ak; break; case opScaleNeg : func = &scaleneg_ak; break; case opClip2 : func = &clip2_ak_nova_64; break; case opFold2 : func = &fold2_ak; break; case opWrap2 : func = &wrap2_ak; break; case opExcess : func = &excess_ak; break; case opRandRange : func = &rrand_ak; break; case opExpRandRange : func = &exprand_ak; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ak; break; } break; case calc_ScalarRate : switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ai_nova_64; break; case opSub : func = &sub_ai_nova_64; break; case opMul : func = &mul_ai_nova_64; break; case opFDiv : func = &div_ai_nova; break; case opIDiv : func = &idiv_ai; break; case opMod : func = &mod_ai; break; case opEQ : func = &eq_ai_nova_64; break; case opNE : func = &neq_ai_nova_64; break; case opLT : func = <_ai_nova_64; break; case opGT : func = >_ai_nova_64; break; case opLE : func = &le_ai_nova_64; break; case opGE : func = &ge_ai_nova_64; break; case opMin : func = &min_ai_nova_64; break; case opMax : func = &max_ai_nova_64; break; case opBitAnd : func = &and_ai; break; case opBitOr : func = &or_ai; break; case opBitXor : func = &xor_ai; break; case opShiftRight : func = &rightShift_ai; break; case opShiftLeft : func = &leftShift_ai; break; case opLCM : func = &lcm_ai; break; case opGCD : func = &gcd_ai; break; case opRound : func = &round_ai; break; case opRoundUp : func = &roundUp_ai; break; case opTrunc : func = &trunc_ai; break; case opAtan2 : func = &atan2_ai; break; case opHypot : func = &hypot_ai; break; case opHypotx : func = &hypotx_ai; break; case opPow : func = &pow_ai_nova; break; case opRing1 : func = &ring1_ai_nova_64; break; case opRing2 : func = &ring2_ai_nova_64; break; case opRing3 : func = &ring3_ai_nova_64; break; case opRing4 : func = &ring4_ai_nova_64; break; case opDifSqr : func = &difsqr_ai_nova_64; break; case opSumSqr : func = &sumsqr_ai_nova_64; break; case opSqrSum : func = &sqrsum_ai_nova_64; break; case opSqrDif : func = &sqrdif_ai_nova_64; break; case opAbsDif : func = &absdif_ai; break; case opThresh : func = &thresh_ai; break; case opAMClip : func = &amclip_ai; break; case opScaleNeg : func = &scaleneg_ai; break; case opClip2 : func = &clip2_ai_nova_64; break; case opFold2 : func = &fold2_ai; break; case opWrap2 : func = &wrap2_ai; break; case opExcess : func = &excess_ai; break; case opRandRange: func = &rrand_ai; break; case opExpRandRange: func = &exprand_ai; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ai; break; } } break; case calc_BufRate : if (rateB == calc_FullRate) { switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ka_nova_64; break; case opSub : func = &sub_ka_nova_64; break; case opMul : func = &mul_ka_nova_64; break; case opFDiv : func = &div_ka_nova; break; case opIDiv : func = &idiv_ka; break; case opMod : func = &mod_ka; break; case opEQ : func = &eq_ka_nova_64; break; case opNE : func = &neq_ka_nova_64; break; case opLT : func = <_ka_nova_64; break; case opGT : func = >_ka_nova_64; break; case opLE : func = &le_ka_nova_64; break; case opGE : func = &ge_ka_nova_64; break; case opMin : func = &min_ka_nova_64; break; case opMax : func = &max_ka_nova_64; break; case opBitAnd : func = &and_ka; break; case opBitOr : func = &or_ka; break; case opBitXor : func = &xor_ka; break; case opShiftRight : func = &rightShift_ka; break; case opShiftLeft : func = &leftShift_ka; break; case opLCM : func = &lcm_ka; break; case opGCD : func = &gcd_ka; break; case opRound : func = &round_ka; break; case opRoundUp : func = &roundUp_ka; break; case opTrunc : func = &trunc_ka; break; case opAtan2 : func = &atan2_ka; break; case opHypot : func = &hypot_ka; break; case opHypotx : func = &hypotx_ka; break; case opPow : func = &pow_ka_nova; break; case opRing1 : func = &ring1_ka; break; case opRing2 : func = &ring2_ka; break; case opRing3 : func = &ring3_ka; break; case opRing4 : func = &ring4_ka; break; case opDifSqr : func = &difsqr_ka_nova_64; break; case opSumSqr : func = &sumsqr_ka_nova_64; break; case opSqrSum : func = &sqrsum_ka_nova_64; break; case opSqrDif : func = &sqrdif_ka_nova_64; break; case opAbsDif : func = &absdif_ka; break; case opThresh : func = &thresh_ka; break; case opAMClip : func = &amclip_ka; break; case opScaleNeg : func = &scaleneg_ka; break; case opClip2 : func = &clip2_ka_nova_64; break; case opFold2 : func = &fold2_ka; break; case opWrap2 : func = &wrap2_ka; break; case opExcess : func = &excess_ka; break; case opRandRange : func = &rrand_ka; break; case opExpRandRange : func = &exprand_ka; break; //case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ka; break; } } else { // this should have been caught by mBufLength == 1 func = &zero_aa; } break; case calc_ScalarRate : if (rateB == calc_FullRate) { switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ia_nova_64; break; case opSub : func = &sub_ia_nova_64; break; case opMul : func = &mul_ia_nova_64; break; case opFDiv : func = &div_ia_nova; break; case opIDiv : func = &idiv_ia; break; case opMod : func = &mod_ia; break; case opEQ : func = &eq_ia_nova_64; break; case opNE : func = &neq_ia_nova_64; break; case opLT : func = <_ia_nova_64; break; case opGT : func = >_ia_nova_64; break; case opLE : func = &le_ia_nova_64; break; case opGE : func = &ge_ia_nova_64; break; case opMin : func = &min_ia_nova_64; break; case opMax : func = &max_ia_nova_64; break; case opBitAnd : func = &and_ia; break; case opBitOr : func = &or_ia; break; case opBitXor : func = &xor_ia; break; case opShiftRight : func = &rightShift_ia; break; case opShiftLeft : func = &leftShift_ia; break; case opLCM : func = &lcm_ia; break; case opGCD : func = &gcd_ia; break; case opRound : func = &round_ia; break; case opRoundUp : func = &roundUp_ia; break; case opTrunc : func = &trunc_ia; break; case opAtan2 : func = &atan2_ia; break; case opHypot : func = &hypot_ia; break; case opHypotx : func = &hypotx_ia; break; case opPow : func = &pow_ia_nova; break; case opRing1 : func = &ring1_ia_nova_64; break; case opRing2 : func = &ring2_ia_nova_64; break; case opRing3 : func = &ring3_ia_nova_64; break; case opRing4 : func = &ring4_ia_nova_64; break; case opDifSqr : func = &difsqr_ia_nova_64; break; case opSumSqr : func = &sumsqr_ia_nova_64; break; case opSqrSum : func = &sqrsum_ia_nova_64; break; case opSqrDif : func = &sqrdif_ia_nova_64; break; case opAbsDif : func = &absdif_ia; break; case opThresh : func = &thresh_ia; break; case opAMClip : func = &amclip_ia; break; case opScaleNeg : func = &scaleneg_ia; break; case opClip2 : func = &clip2_ia_nova_64; break; case opFold2 : func = &fold2_ia; break; case opWrap2 : func = &wrap2_ia; break; case opExcess : func = &excess_ia; break; case opRandRange : func = &rrand_ia; break; case opExpRandRange : func = &exprand_ia; break; //case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ia; break; } } else { // this should have been caught by mBufLength == 1 func = &zero_aa; } break; } return func; } static BinaryOpFunc ChooseNovaSimdFunc(BinaryOpUGen *unit) { if (BUFLENGTH == 64) return ChooseNovaSimdFunc_64(unit); BinaryOpFunc func = &zero_1; int rateA = INRATE(0); int rateB = INRATE(1); switch (rateA) { case calc_FullRate: switch (rateB) { case calc_FullRate: switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_aa_nova; break; case opSub : func = &sub_aa_nova; break; case opMul : func = &mul_aa_nova; break; case opFDiv : func = &div_aa_nova; break; case opIDiv : func = &idiv_aa; break; case opMod : func = &mod_aa; break; case opEQ : func = &eq_aa_nova; break; case opNE : func = &neq_aa_nova; break; case opLT : func = <_aa_nova; break; case opGT : func = >_aa_nova; break; case opLE : func = &le_aa_nova; break; case opGE : func = &ge_aa_nova; break; case opMin : func = &min_aa_nova; break; case opMax : func = &max_aa_nova; break; case opBitAnd : func = &and_aa; break; case opBitOr : func = &or_aa; break; case opBitXor : func = &xor_aa; break; case opShiftRight : func = &rightShift_aa; break; case opShiftLeft : func = &leftShift_aa; break; case opLCM : func = &lcm_aa; break; case opGCD : func = &gcd_aa; break; case opRound : func = &round_aa; break; case opRoundUp : func = &roundUp_aa; break; case opTrunc : func = &trunc_aa; break; case opAtan2 : func = &atan2_aa; break; case opHypot : func = &hypot_aa; break; case opHypotx : func = &hypotx_aa; break; case opPow : func = &pow_aa_nova; break; case opRing1 : func = &ring1_aa_nova; break; case opRing2 : func = &ring2_aa_nova; break; case opRing3 : func = &ring3_aa_nova; break; case opRing4 : func = &ring4_aa_nova; break; case opDifSqr : func = &difsqr_aa_nova; break; case opSumSqr : func = &sumsqr_aa_nova; break; case opSqrSum : func = &sqrsum_aa_nova; break; case opSqrDif : func = &sqrdif_aa_nova; break; case opAbsDif : func = &absdif_aa; break; case opThresh : func = &thresh_aa; break; case opAMClip : func = &amclip_aa; break; case opScaleNeg : func = &scaleneg_aa; break; case opClip2 : func = &clip2_aa_nova; break; case opFold2 : func = &fold2_aa; break; case opWrap2 : func = &wrap2_aa; break; case opExcess : func = &excess_aa; break; case opRandRange : func = &rrand_aa; break; case opExpRandRange : func = &exprand_aa; break; case opFirstArg : func = &firstarg_aa_nova; break; //case opSecondArg : func = &secondarg_aa_nova; break; default : func = &add_aa; break; } break; case calc_BufRate : switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ak_nova; break; case opSub : func = &sub_ak_nova; break; case opMul : func = &mul_ak_nova; break; case opFDiv : func = &div_ak_nova; break; case opIDiv : func = &idiv_ak; break; case opMod : func = &mod_ak; break; case opEQ : func = &eq_ak_nova; break; case opNE : func = &neq_ak_nova; break; case opLT : func = <_ak_nova; break; case opGT : func = >_ak_nova; break; case opLE : func = &le_ak_nova; break; case opGE : func = &ge_ak_nova; break; case opMin : func = &min_ak_nova; break; case opMax : func = &max_ak_nova; break; case opBitAnd : func = &and_ak; break; case opBitOr : func = &or_ak; break; case opBitXor : func = &xor_ak; break; case opShiftRight : func = &rightShift_ak; break; case opShiftLeft : func = &leftShift_ak; break; case opLCM : func = &lcm_ak; break; case opGCD : func = &gcd_ak; break; case opRound : func = &round_ak; break; case opRoundUp : func = &roundUp_ak; break; case opTrunc : func = &trunc_ak; break; case opAtan2 : func = &atan2_ak; break; case opHypot : func = &hypot_ak; break; case opHypotx : func = &hypotx_ak; break; case opPow : func = &pow_ak_nova; break; case opRing1 : func = &ring1_ak; break; case opRing2 : func = &ring2_ak; break; case opRing3 : func = &ring3_ak; break; case opRing4 : func = &ring4_ak; break; case opDifSqr : func = &difsqr_ak_nova; break; case opSumSqr : func = &sumsqr_ak_nova; break; case opSqrSum : func = &sqrsum_ak_nova; break; case opSqrDif : func = &sqrdif_ak_nova; break; case opAbsDif : func = &absdif_ak; break; case opThresh : func = &thresh_ak; break; case opAMClip : func = &amclip_ak; break; case opScaleNeg : func = &scaleneg_ak; break; case opClip2 : func = &clip2_ak_nova; break; case opFold2 : func = &fold2_ak; break; case opWrap2 : func = &wrap2_ak; break; case opExcess : func = &excess_ak; break; case opRandRange : func = &rrand_ak; break; case opExpRandRange : func = &exprand_ak; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ak; break; } break; case calc_ScalarRate : switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ai_nova; break; case opSub : func = &sub_ai_nova; break; case opMul : func = &mul_ai_nova; break; case opFDiv : func = &div_ai_nova; break; case opIDiv : func = &idiv_ai; break; case opMod : func = &mod_ai; break; case opEQ : func = &eq_ai_nova; break; case opNE : func = &neq_ai_nova; break; case opLT : func = <_ai_nova; break; case opGT : func = >_ai_nova; break; case opLE : func = &le_ai_nova; break; case opGE : func = &ge_ai_nova; break; case opMin : func = &min_ai_nova; break; case opMax : func = &max_ai_nova; break; case opBitAnd : func = &and_ai; break; case opBitOr : func = &or_ai; break; case opBitXor : func = &xor_ai; break; case opShiftRight : func = &rightShift_ai; break; case opShiftLeft : func = &leftShift_ai; break; case opLCM : func = &lcm_ai; break; case opGCD : func = &gcd_ai; break; case opRound : func = &round_ai; break; case opRoundUp : func = &roundUp_ai; break; case opTrunc : func = &trunc_ai; break; case opAtan2 : func = &atan2_ai; break; case opHypot : func = &hypot_ai; break; case opHypotx : func = &hypotx_ai; break; case opPow : func = &pow_ai_nova; break; case opRing1 : func = &ring1_ai_nova; break; case opRing2 : func = &ring2_ai_nova; break; case opRing3 : func = &ring3_ai_nova; break; case opRing4 : func = &ring4_ai_nova; break; case opDifSqr : func = &difsqr_ai_nova; break; case opSumSqr : func = &sumsqr_ai_nova; break; case opSqrSum : func = &sqrsum_ai_nova; break; case opSqrDif : func = &sqrdif_ai_nova; break; case opAbsDif : func = &absdif_ai; break; case opThresh : func = &thresh_ai; break; case opAMClip : func = &amclip_ai; break; case opScaleNeg : func = &scaleneg_ai; break; case opClip2 : func = &clip2_ai_nova; break; case opFold2 : func = &fold2_ai; break; case opWrap2 : func = &wrap2_ai; break; case opExcess : func = &excess_ai; break; case opRandRange : func = &rrand_ai; break; case opExpRandRange : func = &exprand_ai; break; case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ai; break; } } break; case calc_BufRate : if (rateB == calc_FullRate) { switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ka_nova; break; case opSub : func = &sub_ka_nova; break; case opMul : func = &mul_ka_nova; break; case opFDiv : func = &div_ka_nova; break; case opIDiv : func = &idiv_ka; break; case opMod : func = &mod_ka; break; case opEQ : func = &eq_ka_nova; break; case opNE : func = &neq_ka_nova; break; case opLT : func = <_ka_nova; break; case opGT : func = >_ka_nova; break; case opLE : func = &le_ka_nova; break; case opGE : func = &ge_ka_nova; break; case opMin : func = &min_ka_nova; break; case opMax : func = &max_ka_nova; break; case opBitAnd : func = &and_ka; break; case opBitOr : func = &or_ka; break; case opBitXor : func = &xor_ka; break; case opShiftRight : func = &rightShift_ka; break; case opShiftLeft : func = &leftShift_ka; break; case opLCM : func = &lcm_ka; break; case opGCD : func = &gcd_ka; break; case opRound : func = &round_ka; break; case opRoundUp : func = &roundUp_ka; break; case opTrunc : func = &trunc_ka; break; case opAtan2 : func = &atan2_ka; break; case opHypot : func = &hypot_ka; break; case opHypotx : func = &hypotx_ka; break; case opPow : func = &pow_ka_nova; break; case opRing1 : func = &ring1_ka; break; case opRing2 : func = &ring2_ka; break; case opRing3 : func = &ring3_ka; break; case opRing4 : func = &ring4_ka; break; case opDifSqr : func = &difsqr_ka_nova; break; case opSumSqr : func = &sumsqr_ka_nova; break; case opSqrSum : func = &sqrsum_ka_nova; break; case opSqrDif : func = &sqrdif_ka_nova; break; case opAbsDif : func = &absdif_ka; break; case opThresh : func = &thresh_ka; break; case opAMClip : func = &amclip_ka; break; case opScaleNeg : func = &scaleneg_ka; break; case opClip2 : func = &clip2_ka_nova; break; case opFold2 : func = &fold2_ka; break; case opWrap2 : func = &wrap2_ka; break; case opExcess : func = &excess_ka; break; case opRandRange : func = &rrand_ka; break; case opExpRandRange : func = &exprand_ka; break; //case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ka; break; } } else { // this should have been caught by mBufLength == 1 func = &zero_aa; } break; case calc_ScalarRate : if (rateB == calc_FullRate) { switch (unit->mSpecialIndex) { //case opSilence2 : func = &zero_aa; break; case opAdd : func = &add_ia_nova; break; case opSub : func = &sub_ia_nova; break; case opMul : func = &mul_ia_nova; break; case opFDiv : func = &div_ia_nova; break; case opIDiv : func = &idiv_ia; break; case opMod : func = &mod_ia; break; case opEQ : func = &eq_ia_nova; break; case opNE : func = &neq_ia_nova; break; case opLT : func = <_ia_nova; break; case opGT : func = >_ia_nova; break; case opLE : func = &le_ia_nova; break; case opGE : func = &ge_ia_nova; break; case opMin : func = &min_ia_nova; break; case opMax : func = &max_ia_nova; break; case opBitAnd : func = &and_ia; break; case opBitOr : func = &or_ia; break; case opBitXor : func = &xor_ia; break; case opShiftRight : func = &rightShift_ia; break; case opShiftLeft : func = &leftShift_ia; break; case opLCM : func = &lcm_ia; break; case opGCD : func = &gcd_ia; break; case opRound : func = &round_ia; break; case opRoundUp : func = &roundUp_ia; break; case opTrunc : func = &trunc_ia; break; case opAtan2 : func = &atan2_ia; break; case opHypot : func = &hypot_ia; break; case opHypotx : func = &hypotx_ia; break; case opPow : func = &pow_ia_nova; break; case opRing1 : func = &ring1_ia_nova; break; case opRing2 : func = &ring2_ia_nova; break; case opRing3 : func = &ring3_ia_nova; break; case opRing4 : func = &ring4_ia_nova; break; case opDifSqr : func = &difsqr_ia_nova; break; case opSumSqr : func = &sumsqr_ia_nova; break; case opSqrSum : func = &sqrsum_ia_nova; break; case opSqrDif : func = &sqrdif_ia_nova; break; case opAbsDif : func = &absdif_ia; break; case opThresh : func = &thresh_ia; break; case opAMClip : func = &amclip_ia; break; case opScaleNeg : func = &scaleneg_ia; break; case opClip2 : func = &clip2_ia_nova; break; case opFold2 : func = &fold2_ia; break; case opWrap2 : func = &wrap2_ia; break; case opExcess : func = &excess_ia; break; case opRandRange : func = &rrand_ia; break; case opExpRandRange : func = &rrand_ia; break; //case opFirstArg : func = &firstarg_aa; break; //case opSecondArg : func = &secondarg_aa; break; default : func = &add_ia; break; } } else { // this should have been caught by mBufLength == 1 func = &zero_aa; } break; } return func; } #endif bool ChooseOperatorFunc(BinaryOpUGen *unit) { //Print("->ChooseOperatorFunc %d\n", unit->mSpecialIndex); BinaryOpFunc func = &zero_aa; bool ret = false; if (BUFLENGTH == 1) { if (unit->mCalcRate == calc_DemandRate) { func = ChooseDemandFunc(unit); } else { func = ChooseOneSampleFunc(unit); } #if defined(NOVA_SIMD) } else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) { /* select normal function for initialization */ func = ChooseNormalFunc(unit); func(unit, 1); /* select simd function */ func = ChooseNovaSimdFunc(unit); ret = true; #endif } else { func = ChooseNormalFunc(unit); } unit->mCalcFunc = (UnitCalcFunc)func; //Print("<-ChooseOperatorFunc %p\n", func); //Print("calc %d\n", unit->mCalcRate); return ret; } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(BinaryOp) { ft = inTable; DefineSimpleUnit(BinaryOpUGen); } SuperCollider-Source/server/plugins/ChaosUGens.cpp000644 000765 000024 00000112154 12321461511 023347 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Chaos Ugens created by Lance Putnam on Mon Jul 19 2004. */ #include "SC_PlugIn.h" #define TWOPI 6.283185307179586 #define PI 3.141592653589793 #define RECPI 0.3183098861837907 #define RECTWOPI 0.1591549430918953 #define ONESIXTH 0.1666666666666667 static InterfaceTable *ft; struct NonLinear : public Unit { double x0, y0, xn, yn, xnm1, ynm1; float counter; //bool stable; }; struct CuspN : public NonLinear { }; struct CuspL : public CuspN { double frac; }; struct GbmanN : public NonLinear { }; struct GbmanL : public GbmanN { double frac; }; struct HenonN : public Unit { double x0, x1, xn, xnm1, xnm2, a, b; float counter; bool stable; }; struct HenonL : public HenonN { double frac; }; struct HenonC : public HenonL { double xnm3,c0,c1,c2,c3; }; struct LatoocarfianN : public NonLinear { }; struct LatoocarfianL : public LatoocarfianN { double frac; }; struct LatoocarfianC : public LatoocarfianL { double xnm3, xnm2, c0,c1,c2,c3; }; struct LinCongN : public NonLinear { }; struct LinCongL : public LinCongN { double frac; }; struct LinCongC : public LinCongL { double xnm3, xnm2, c0,c1,c2,c3; }; struct LorenzN : public NonLinear { double z0, zn, znm1; }; struct LorenzL : public LorenzN { double frac; }; struct QuadN : public NonLinear { }; struct QuadL : public QuadN { double frac; }; struct QuadC : public QuadL { double xnm3, xnm2; double c0,c1,c2,c3; }; struct StandardN : public NonLinear { }; struct StandardL : public StandardN { double frac; }; struct FBSineN : public NonLinear { }; struct FBSineL : public FBSineN { double frac; }; struct FBSineC : public FBSineL { double xnm3, xnm2; double c0,c1,c2,c3; }; extern "C" { void CuspN_next(CuspN *unit, int inNumSamples); void CuspN_Ctor(CuspN *unit); void CuspL_next(CuspL *unit, int inNumSamples); void CuspL_Ctor(CuspL *unit); void GbmanN_next(GbmanN *unit, int inNumSamples); void GbmanN_Ctor(GbmanN *unit); void GbmanL_next(GbmanL *unit, int inNumSamples); void GbmanL_Ctor(GbmanL *unit); void HenonN_next(HenonN *unit, int inNumSamples); void HenonN_Ctor(HenonN *unit); void HenonL_next(HenonL *unit, int inNumSamples); void HenonL_Ctor(HenonL *unit); void HenonC_next(HenonC *unit, int inNumSamples); void HenonC_Ctor(HenonC *unit); void LinCongN_next(LinCongN *unit, int inNumSamples); void LinCongN_Ctor(LinCongN *unit); void LinCongL_next(LinCongL *unit, int inNumSamples); void LinCongL_Ctor(LinCongL *unit); void LinCongC_next(LinCongC *unit, int inNumSamples); void LinCongC_Ctor(LinCongC *unit); void LatoocarfianN_next(LatoocarfianN *unit, int inNumSamples); void LatoocarfianN_Ctor(LatoocarfianN *unit); void LatoocarfianL_next(LatoocarfianL *unit, int inNumSamples); void LatoocarfianL_Ctor(LatoocarfianL *unit); void LatoocarfianC_next(LatoocarfianC *unit, int inNumSamples); void LatoocarfianC_Ctor(LatoocarfianC *unit); void LorenzL_next(LorenzL *unit, int inNumSamples); void LorenzL_Ctor(LorenzL *unit); void QuadN_next(QuadN *unit, int inNumSamples); void QuadN_Ctor(QuadN *unit); void QuadL_next(QuadL *unit, int inNumSamples); void QuadL_Ctor(QuadL *unit); void QuadC_next(QuadC *unit, int inNumSamples); void QuadC_Ctor(QuadC *unit); void StandardN_next(StandardN *unit, int inNumSamples); void StandardN_Ctor(StandardN *unit); void StandardL_next(StandardL *unit, int inNumSamples); void StandardL_Ctor(StandardL *unit); void FBSineN_next(FBSineN *unit, int inNumSamples); void FBSineN_Ctor(FBSineN *unit); void FBSineL_next(FBSineL *unit, int inNumSamples); void FBSineL_Ctor(FBSineL *unit); void FBSineC_next(FBSineC *unit, int inNumSamples); void FBSineC_Ctor(FBSineC *unit); } //////////////////////////////////////////////////////////////////////////////// // calc 3rd order interpolation coefs from four points static inline void ipol3Coef( double xnm3, double xnm2, double xnm1, double xn, double &c0, double &c1, double &c2, double &c3) { c0 = xnm2; c1 = 0.5f * (xnm1 - xnm3); c2 = xnm3 - (2.5f * xnm2) + xnm1 + xnm1 - 0.5f * xn; c3 = 0.5f * (xn - xnm3) + 1.5f * (xnm2 - xnm1); } // do 3rd order interpolation using coefs static inline double ipol3(float frac, double c0, double c1, double c2, double c3){ return ((c3 * frac + c2) * frac + c1) * frac + c0; } // quick 2pi modulo inline double mod2pi(double in) { const double lo = (double)0.; const double hi = TWOPI; if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < lo) { in += hi; if (in >= lo) return in; } else return in; return in - hi * (double)((int)(in * RECTWOPI)); } //////////////////////////////////////////////////////////////////////////////// void CuspN_next(CuspN *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double x0 = ZIN0(3); double xn = unit->xn; float counter = unit->counter; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; if(unit->x0 != x0){ unit->x0 = xn = x0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; xn = a - (b * sqrt(sc_abs(xn))); } counter++; ZXP(out) = xn; } unit->xn = xn; unit->counter = counter; } void CuspN_Ctor(CuspN* unit) { SETCALC(CuspN_next); unit->x0 = ZIN0(3); unit->xn = unit->x0; unit->counter = 0.f; CuspN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void CuspL_next(CuspL *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double x0 = ZIN0(3); double xn = unit->xn; float counter = unit->counter; double xnm1 = unit->xnm1; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } if(unit->x0 != x0){ xnm1 = xn; unit->x0 = xn = x0; } double dx = xn - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; xnm1 = xn; xn = a - (b * sqrt(sc_abs(xn))); dx = xn - xnm1; } counter++; ZXP(out) = xnm1 + dx * frac; frac += slope; } unit->xn = xn; unit->counter = counter; unit->xnm1 = xnm1; unit->frac = frac; } void CuspL_Ctor(CuspL* unit){ SETCALC(CuspL_next); unit->x0 = ZIN0(3); unit->xn = unit->x0; unit->xnm1 = unit->x0; unit->counter = 0.f; unit->frac = 0.f; CuspL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void FBSineN_next(FBSineN *unit, int inNumSamples){ float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double d = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double xn = unit->xn; double yn = unit->yn; float counter = unit->counter; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; if((unit->x0 != x0) || (unit->y0 != y0) ){ unit->x0 = xn = x0; unit->y0 = yn = y0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; xn = sin(a*yn + b*xn); yn = c*yn + d; yn = mod2pi(yn); } counter++; ZXP(out) = xn; } unit->xn = xn; unit->yn = yn; unit->counter = counter; } void FBSineN_Ctor(FBSineN *unit){ SETCALC(FBSineN_next); unit->x0 = ZIN0(5); unit->y0 = ZIN0(6); unit->xn = unit->x0; unit->yn = unit->y0; unit->counter = 0.f; FBSineN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void FBSineL_next(FBSineL *unit, int inNumSamples){ float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double d = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double xn = unit->xn; double yn = unit->yn; double xnm1 = unit->xnm1; float counter = unit->counter; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } if((unit->x0 != x0) || (unit->y0 != y0) ){ xnm1 = xn; unit->x0 = xn = x0; unit->y0 = yn = y0; } double dx = xn - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.0; xnm1 = xn; xn = sin(a*yn + b*xn); yn = c*yn + d; yn = mod2pi(yn); dx = xn - xnm1; } counter++; ZXP(out) = xnm1 + dx * frac; frac += slope; } unit->xn = xn; unit->yn = yn; unit->xnm1 = xnm1; unit->counter = counter; unit->frac = frac; } void FBSineL_Ctor(FBSineL *unit){ SETCALC(FBSineL_next); unit->x0 = ZIN0(5); unit->y0 = ZIN0(6); unit->xn = unit->x0; unit->yn = unit->y0; unit->xnm1 = unit->x0; unit->counter = 0.f; unit->frac = 0.0; FBSineL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void FBSineC_next(FBSineC *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double d = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; double xnm3 = unit->xnm3; double yn = unit->yn; float counter = unit->counter; double frac = unit->frac; double c0 = unit->c0; double c1 = unit->c1; double c2 = unit->c2; double c3 = unit->c3; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else samplesPerCycle = slope = 1.f; if((unit->x0 != x0) || (unit->y0 != y0)){ unit->x0 = xn = x0; unit->y0 = y0; xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.0; xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; xn = sin(a*yn + b*xn); yn = c*yn + d; yn = mod2pi(yn); ipol3Coef(xnm3, xnm2, xnm1, xn, c0, c1, c2, c3); } counter++; ZXP(out) = ipol3(frac, c0, c1, c2, c3); frac += slope; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->xnm3 = xnm3; unit->yn = yn; unit->counter = counter; unit->frac = frac; unit->c0 = c0; unit->c1 = c1; unit->c2 = c2; unit->c3 = c3; } void FBSineC_Ctor(FBSineC* unit) { SETCALC(FBSineC_next); unit->x0 = ZIN0(5); unit->y0 = ZIN0(6); unit->xn = unit->x0; unit->yn = unit->y0; unit->xnm1 = unit->xnm2 = unit->xnm3 = unit->x0; unit->counter = 0.f; unit->frac = 0.0; unit->c0 = unit->c1 = unit->c2 = unit->c3 = 0.; FBSineC_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void GbmanN_next(GbmanN *unit, int inNumSamples){ float *out = ZOUT(0); float freq = ZIN0(0); double xn = unit->xn; double yn = unit->yn; float counter = unit->counter; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; double xPrev = xn; if(xPrev < 0.f) xn = 1.f - yn - xPrev; else xn = 1.f - yn + xPrev; yn = xPrev; } counter++; ZXP(out) = xn; } unit->xn = xn; unit->yn = yn; unit->counter = counter; } void GbmanN_Ctor(GbmanN *unit){ SETCALC(GbmanN_next); unit->xn = ZIN0(1); unit->yn = ZIN0(2); unit->counter = 0.f; GbmanN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void GbmanL_next(GbmanL *unit, int inNumSamples){ float *out = ZOUT(0); float freq = ZIN0(0); double xn = unit->xn; double yn = unit->yn; float counter = unit->counter; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } double diff = xn - yn; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; double xPrev = xn; if(xPrev < 0.f) xn = 1.f - yn - xPrev; else xn = 1.f - yn + xPrev; yn = xPrev; diff = xn - xPrev; } counter++; ZXP(out) = yn + (frac * diff); frac += slope; } unit->xn = xn; unit->yn = yn; unit->counter = counter; unit->frac = frac; } void GbmanL_Ctor(GbmanL *unit){ SETCALC(GbmanL_next); unit->xn = ZIN0(1); unit->yn = ZIN0(2); unit->counter = 0.f; unit->frac = 0.f; GbmanL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void HenonN_next(HenonN *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double x0 = ZIN0(3); double x1 = ZIN0(4); double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; float counter = unit->counter; bool stable = unit->stable; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; if( (unit->a != a) || (unit->b != b) || (unit->x0 != x0) || (unit->x1 != x1)){ if(!stable){ xnm2 = x0; xnm1 = x0; xn = x1; } stable = true; unit->a = a; unit->b = b; unit->x0 = x0; unit->x1 = x1; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; if(stable){ xn = 1.f - (a * xnm1 * xnm1) + (b * xnm2); //Print("%g, ", xn); if((xn > 1.5f) || (xn < -1.5f)){ stable = false; xn = 0.f; xnm2 = x0; xnm1 = x1; } else{ xnm2 = xnm1; xnm1 = xn; } } } counter++; ZXP(out) = xnm2; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->counter = counter; unit->stable = stable; } void HenonN_Ctor(HenonN* unit) { SETCALC(HenonN_next); unit->x0 = ZIN0(3); unit->x1 = ZIN0(4); unit->xn = unit->x1; unit->xnm1 = unit->x0; unit->xnm2 = unit->x1; unit->a = ZIN0(1); unit->b = ZIN0(2); unit->counter = 0.f; unit->stable = true; HenonN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void HenonL_next(HenonL *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double x0 = ZIN0(3); double x1 = ZIN0(4); double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; float counter = unit->counter; bool stable = unit->stable; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else samplesPerCycle = slope = 1.f; if( (unit->a != a) || (unit->b != b) || (unit->x0 != x0) || (unit->x1 != x1)){ if(!stable){ xnm2 = x0; xnm1 = x0; xn = x1; } stable = true; unit->a = a; unit->b = b; unit->x0 = x0; unit->x1 = x1; } double diff = xnm1 - xnm2; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; if(stable){ xn = 1.f - (a * xnm1 * xnm1) + (b * xnm2); if(xn > 1.5f || xn < -1.5f){ stable = false; diff = 0.f; xn = 1.f; xnm1 = 0.f; xnm2 = 0.f; } else{ xnm2 = xnm1; xnm1 = xn; diff = xnm1 - xnm2; } frac = 0.f; } //Print("slope %g, x2 %g\n", slope, x2); } counter++; ZXP(out) = xnm2 + (diff * frac); frac += slope; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->counter = counter; unit->stable = stable; unit->frac = frac; } void HenonL_Ctor(HenonL* unit) { SETCALC(HenonL_next); unit->x0 = ZIN0(3); unit->x1 = ZIN0(4); unit->xn = unit->x1; unit->xnm1 = unit->x0; unit->xnm2 = unit->x1; unit->a = ZIN0(1); unit->b = ZIN0(2); unit->counter = 0.f; unit->stable = true; unit->frac = 0.; HenonL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void HenonC_next(HenonC *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double x0 = ZIN0(3); double x1 = ZIN0(4); double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; double xnm3 = unit->xnm3; float counter = unit->counter; bool stable = unit->stable; double frac = unit->frac; double c0 = unit->c0; double c1 = unit->c1; double c2 = unit->c2; double c3 = unit->c3; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else samplesPerCycle = slope = 1.f; if( (unit->a != a) || (unit->b != b) || (unit->x0 != x0) || (unit->x1 != x1)){ if(!stable){ xnm3 = xnm2; xnm2 = x0; xnm1 = x0; xn = x1; } stable = true; unit->a = a; unit->b = b; unit->x0 = x0; unit->x1 = x1; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.0; if(stable){ xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; xn = 1.f - (a * xnm1 * xnm1) + (b * xnm2); if( (xn > 1.5) || (xn < -1.5) ){ stable = false; xn = 1.; xnm1 = xnm2 = xnm3 = 0.; } ipol3Coef(xnm3, xnm2, xnm1, xn, c0, c1, c2, c3); } //Print("slope %g, x2 %g\n", slope, x2); } counter++; ZXP(out) = ipol3(frac, c0, c1, c2, c3); frac += slope; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->xnm3 = xnm3; unit->counter = counter; unit->stable = stable; unit->frac = frac; unit->c0 = c0; unit->c1 = c1; unit->c2 = c2; unit->c3 = c3; } void HenonC_Ctor(HenonC* unit) { SETCALC(HenonC_next); unit->x0 = ZIN0(3); unit->x1 = ZIN0(4); unit->xn = unit->x1; unit->xnm1 = unit->x0; unit->xnm2 = unit->xnm3 = unit->x1; unit->a = ZIN0(1); unit->b = ZIN0(2); unit->counter = 0.f; unit->stable = true; unit->frac = 0.0; unit->c0 = unit->c1 = unit->c2 = unit->c3 = 0.; HenonC_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LatoocarfianN_next(LatoocarfianN *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double d = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double xn = unit->xn; double yn = unit->yn; float counter = unit->counter; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; if((unit->x0 != x0) || (unit->y0 != y0)){ unit->x0 = xn = x0; unit->y0 = yn = y0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; const double xnm1 = xn; xn = sin(yn * b) + c*sin(xnm1 * b); yn = sin(xnm1 * a) + d*sin(yn * a); } counter++; ZXP(out) = xn; } unit->xn = xn; unit->yn = yn; unit->counter = counter; } void LatoocarfianN_Ctor(LatoocarfianN* unit){ SETCALC(LatoocarfianN_next); unit->x0 = ZIN0(5); unit->y0 = ZIN0(6); unit->xn = unit->x0; unit->yn = unit->y0; unit->counter = 0.f; LatoocarfianN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LatoocarfianL_next(LatoocarfianL *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double d = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double xn = unit->xn; double yn = unit->yn; float counter = unit->counter; double xnm1 = unit->xnm1; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } if((unit->x0 != x0) || (unit->y0 != y0)){ xnm1 = xn; unit->x0 = xn = x0; unit->y0 = yn = y0; } double dx = xn - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; xnm1 = xn; xn = sin(yn * b) + c*sin(xnm1 * b); yn = sin(xnm1 * a) + d*sin(yn * a); dx = xn - xnm1; } counter++; ZXP(out) = xnm1 + dx * frac; frac += slope; } unit->xn = xn; unit->yn = yn; unit->counter = counter; unit->xnm1 = xnm1; unit->frac = frac; } void LatoocarfianL_Ctor(LatoocarfianL* unit){ SETCALC(LatoocarfianL_next); unit->x0 = ZIN0(5); unit->y0 = ZIN0(6); unit->xn = unit->x0; unit->yn = unit->y0; unit->xnm1 = unit->x0; unit->counter = 0.f; unit->frac = 0.f; LatoocarfianL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LatoocarfianC_next(LatoocarfianC *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double d = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; double xnm3 = unit->xnm3; double yn = unit->yn; float counter = unit->counter; double frac = unit->frac; double c0 = unit->c0; double c1 = unit->c1; double c2 = unit->c2; double c3 = unit->c3; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else samplesPerCycle = slope = 1.f; if( (unit->x0 != x0) || (unit->y0 != y0)){ xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; unit->x0 = xn = x0; unit->y0 = yn = y0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.0; xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; xn = sin(yn * b) + c*sin(xnm1 * b); yn = sin(xnm1 * a) + d*sin(yn * a); ipol3Coef(xnm3, xnm2, xnm1, xn, c0, c1, c2, c3); } counter++; ZXP(out) = ipol3(frac, c0, c1, c2, c3); frac += slope; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->xnm3 = xnm3; unit->yn = yn; unit->counter = counter; unit->frac = frac; unit->c0 = c0; unit->c1 = c1; unit->c2 = c2; unit->c3 = c3; } void LatoocarfianC_Ctor(LatoocarfianC* unit) { SETCALC(LatoocarfianC_next); unit->x0 = ZIN0(5); unit->y0 = ZIN0(6); unit->xn = unit->x0; unit->yn = unit->y0; unit->xnm1 = unit->xnm2 = unit->xnm3 = unit->x0; unit->counter = 0.f; unit->frac = 0.0; unit->c0 = unit->c1 = unit->c2 = unit->c3 = unit->x0; LatoocarfianC_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LinCongN_next(LinCongN *unit, int inNumSamples){ float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); //multiplier double c = ZIN0(2); //increment double m = sc_max(ZIN0(3), 0.001f); //modulus double xn = unit->xn; float counter = unit->counter; double scaleFactor = 2.f / m; double xscaled = (xn * scaleFactor) - 1.f; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; xn = (xn * a) + c; xn = sc_mod(xn, m); xscaled = (xn * scaleFactor) - 1.f; } counter++; ZXP(out) = xscaled; } unit->xn = xn; unit->counter = counter; } void LinCongN_Ctor(LinCongN *unit){ SETCALC(LinCongN_next); unit->xn = ZIN0(4); // initial x unit->counter = 0.f; LinCongN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LinCongL_next(LinCongL *unit, int inNumSamples){ float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); //multiplier double c = ZIN0(2); //increment double m = sc_max(ZIN0(3), 0.001f); //modulus double xn = unit->xn; float counter = unit->counter; double xnm1 = unit->xnm1; double frac = unit->frac; double scaleFactor = 2.f / m; double xscaled = (xn * scaleFactor) - 1.f; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } double diff = xscaled - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; xnm1 = xscaled; xn = (xn * a) + c; xn = sc_mod(xn, m); xscaled = (xn * scaleFactor) - 1.f; diff = xscaled - xnm1; } counter++; ZXP(out) = xnm1 + (frac * diff); frac += slope; } unit->xn = xn; unit->counter = counter; unit->xnm1 = xnm1; unit->frac = frac; } void LinCongL_Ctor(LinCongL *unit){ SETCALC(LinCongL_next); unit->xn = ZIN0(4); unit->counter = 0.f; unit->xnm1 = unit->xn; unit->frac = 0.f; LinCongL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LinCongC_next(LinCongC *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); //multiplier double c = ZIN0(2); //increment double m = sc_max(ZIN0(3), 0.001f); //modulus double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; double xnm3 = unit->xnm3; float counter = unit->counter; double frac = unit->frac; double c0 = unit->c0; double c1 = unit->c1; double c2 = unit->c2; double c3 = unit->c3; double scaleFactor = 2.f / m; double xscaled = (xn * scaleFactor) - 1.f; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else samplesPerCycle = slope = 1.f; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.0; xnm3 = xnm2; xnm2 = xnm1; xnm1 = xscaled; xn = (xn * a) + c; xn = sc_mod(xn, m); xscaled = (xn * scaleFactor) - 1.f; ipol3Coef(xnm3, xnm2, xnm1, xscaled, c0, c1, c2, c3); } counter++; ZXP(out) = ipol3(frac, c0, c1, c2, c3); frac += slope; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->xnm3 = xnm3; unit->counter = counter; unit->frac = frac; unit->c0 = c0; unit->c1 = c1; unit->c2 = c2; unit->c3 = c3; } void LinCongC_Ctor(LinCongC* unit) { SETCALC(LinCongC_next); unit->x0 = ZIN0(4); unit->xn = unit->x0; unit->xnm1 = unit->xnm2 = unit->xnm3 = unit->x0; unit->counter = 0.f; unit->frac = 0.0; unit->c0 = unit->c1 = unit->c2 = unit->c3 = unit->x0; LinCongC_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void LorenzL_next(LorenzL *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double s = ZIN0(1); double r = ZIN0(2); double b = ZIN0(3); double h = ZIN0(4); double x0 = ZIN0(5); double y0 = ZIN0(6); double z0 = ZIN0(7); double xn = unit->xn; double yn = unit->yn; double zn = unit->zn; float counter = unit->counter; double xnm1 = unit->xnm1; double ynm1 = unit->ynm1; double znm1 = unit->znm1; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } if((unit->x0 != x0) || (unit->y0 != y0) || (unit->z0 != z0)){ xnm1 = xn; ynm1 = yn; znm1 = zn; unit->x0 = xn = x0; unit->y0 = yn = y0; unit->z0 = zn = z0; } double dx = xn - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; xnm1 = xn; ynm1 = yn; znm1 = zn; double k1x, k2x, k3x, k4x, k1y, k2y, k3y, k4y, k1z, k2z, k3z, k4z, kxHalf, kyHalf, kzHalf; double hTimesS = h*s; // 4th order Runge-Kutta k1x = hTimesS * (ynm1 - xnm1); k1y = h * (xnm1 * (r - znm1) - ynm1); k1z = h * (xnm1 * ynm1 - b * znm1); kxHalf = k1x * 0.5; kyHalf = k1y * 0.5; kzHalf = k1z * 0.5; k2x = hTimesS * (ynm1 + kyHalf - xnm1 - kxHalf); k2y = h * ((xnm1 + kxHalf) * (r - znm1 - kzHalf) - (ynm1 + kyHalf)); k2z = h * ((xnm1 + kxHalf) * (ynm1 + kyHalf) - b * (znm1 + kzHalf)); kxHalf = k2x * 0.5; kyHalf = k2y * 0.5; kzHalf = k2z * 0.5; k3x = hTimesS * (ynm1 + kyHalf - xnm1 - kxHalf); k3y = h * ((xnm1 + kxHalf) * (r - znm1 - kzHalf) - (ynm1 + kyHalf)); k3z = h * ((xnm1 + kxHalf) * (ynm1 + kyHalf) - b * (znm1 + kzHalf)); k4x = hTimesS * (ynm1 + k3y - xnm1 - k3x); k4y = h * ((xnm1 + k3x) * (r - znm1 - k3z) - (ynm1 + k3y)); k4z = h * ((xnm1 + k3x) * (ynm1 + k3y) - b * (znm1 + k3z)); xn = xn + (k1x + 2.0*(k2x + k3x) + k4x) * ONESIXTH; yn = yn + (k1y + 2.0*(k2y + k3y) + k4y) * ONESIXTH; zn = zn + (k1z + 2.0*(k2z + k3z) + k4z) * ONESIXTH; // Euler's method // xn = xnm1 + h * (s * (ynm1 - xnm1)); // yn = ynm1 + h * (xnm1 * (r - znm1) - ynm1); // zn = znm1 + h * (xnm1 * ynm1 - b * znm1); dx = xn - xnm1; } counter++; ZXP(out) = (xnm1 + dx * frac) * 0.04f; frac += slope; } unit->xn = xn; unit->yn = yn; unit->zn = zn; unit->counter = counter; unit->xnm1 = xnm1; unit->ynm1 = ynm1; unit->znm1 = znm1; unit->frac = frac; } void LorenzL_Ctor(LorenzL* unit){ SETCALC(LorenzL_next); unit->x0 = unit->xn = unit->xnm1 = ZIN0(5); unit->y0 = unit->yn = unit->ynm1 = ZIN0(6); unit->z0 = unit->zn = unit->znm1 = ZIN0(7); unit->counter = 0.f; unit->frac = 0.f; LorenzL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void QuadN_next(QuadN *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double x0 = ZIN0(4); double xn = unit->xn; float counter = unit->counter; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; if(unit->x0 != x0){ unit->x0 = xn = x0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; xn = a * xn * xn + b * xn + c; } counter++; ZXP(out) = xn; } unit->xn = xn; unit->counter = counter; } void QuadN_Ctor(QuadN* unit) { SETCALC(QuadN_next); unit->x0 = ZIN0(4); unit->xn = unit->x0; unit->counter = 0.f; QuadN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void QuadL_next(QuadL *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double x0 = ZIN0(4); double xn = unit->xn; float counter = unit->counter; double xnm1 = unit->xnm1; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } if(unit->x0 != x0){ xnm1 = xn; unit->x0 = xn = x0; } double dx = xn - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; xnm1 = xn; xn = a * xn * xn + b * xn + c; dx = xn - xnm1; } counter++; ZXP(out) = xnm1 + dx * frac; frac += slope; } unit->xn = xn; unit->counter = counter; unit->xnm1 = xnm1; unit->frac = frac; } void QuadL_Ctor(QuadL* unit){ SETCALC(QuadL_next); unit->x0 = ZIN0(4); unit->xn = unit->x0; unit->xnm1 = unit->x0; unit->counter = 0.f; unit->frac = 0.f; QuadL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void QuadC_next(QuadC *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double a = ZIN0(1); double b = ZIN0(2); double c = ZIN0(3); double x0 = ZIN0(4); double xn = unit->xn; double xnm1 = unit->xnm1; double xnm2 = unit->xnm2; double xnm3 = unit->xnm3; float counter = unit->counter; double frac = unit->frac; double c0 = unit->c0; double c1 = unit->c1; double c2 = unit->c2; double c3 = unit->c3; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else samplesPerCycle = slope = 1.f; if(unit->x0 != x0){ xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; unit->x0 = xn = x0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.0; xnm3 = xnm2; xnm2 = xnm1; xnm1 = xn; xn = a * xn * xn + b * xn + c; ipol3Coef(xnm3, xnm2, xnm1, xn, c0, c1, c2, c3); } counter++; ZXP(out) = ipol3(frac, c0, c1, c2, c3); frac += slope; } unit->xn = xn; unit->xnm1 = xnm1; unit->xnm2 = xnm2; unit->xnm3 = xnm3; unit->counter = counter; unit->frac = frac; unit->c0 = c0; unit->c1 = c1; unit->c2 = c2; unit->c3 = c3; } void QuadC_Ctor(QuadC* unit) { SETCALC(QuadC_next); unit->x0 = ZIN0(4); unit->xn = unit->x0; unit->xnm1 = unit->xnm2 = unit->xnm3 = unit->x0; unit->c0 = unit->c1 = unit->c2 = unit->c3 = unit->x0; unit->counter = 0.f; unit->frac = 0.0; QuadC_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void StandardN_next(StandardN *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double k = ZIN0(1); double x0 = ZIN0(2); double y0 = ZIN0(3); double xn = unit->xn; double output = (xn - PI) * RECPI; double yn = unit->yn; float counter = unit->counter; float samplesPerCycle; if(freq < unit->mRate->mSampleRate) samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); else samplesPerCycle = 1.f; if((unit->x0 != x0) || (unit->y0 != y0)){ unit->x0 = xn = x0; unit->y0 = yn = y0; } for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; yn = yn + k * sin(xn); yn = mod2pi(yn); xn = xn + yn; xn = mod2pi(xn); output = (xn - PI) * RECPI; } counter++; ZXP(out) = output; } unit->xn = xn; unit->yn = yn; unit->counter = counter; } void StandardN_Ctor(StandardN* unit) { SETCALC(StandardN_next); unit->x0 = ZIN0(2); unit->y0 = ZIN0(3); unit->xn = unit->x0; unit->yn = unit->y0; unit->counter = 0.f; StandardN_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// void StandardL_next(StandardL *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); double k = ZIN0(1); double x0 = ZIN0(2); double y0 = ZIN0(3); double xn = unit->xn; double yn = unit->yn; float counter = unit->counter; double xnm1 = unit->xnm1; double frac = unit->frac; float samplesPerCycle; double slope; if(freq < unit->mRate->mSampleRate){ samplesPerCycle = unit->mRate->mSampleRate / sc_max(freq, 0.001f); slope = 1.f / samplesPerCycle; } else { samplesPerCycle = 1.f; slope = 1.f; } if((unit->x0 != x0) || (unit->y0 != y0)){ xnm1 = xn; unit->x0 = xn = x0; unit->y0 = yn = y0; } double dx = xn - xnm1; for (int i=0; i= samplesPerCycle){ counter -= samplesPerCycle; frac = 0.f; xnm1 = xn; yn = yn + k * sin(xn); yn = mod2pi(yn); xn = xn + yn; xn = mod2pi(xn); dx = xn - xnm1; } counter++; ZXP(out) = (xnm1 + dx * frac - PI) * RECPI; frac += slope; } unit->xn = xn; unit->yn = yn; unit->counter = counter; unit->xnm1 = xnm1; unit->frac = frac; } void StandardL_Ctor(StandardL* unit){ SETCALC(StandardL_next); unit->x0 = ZIN0(2); unit->y0 = ZIN0(3); unit->xn = unit->x0; unit->yn = unit->y0; unit->xnm1 = unit->x0; unit->counter = 0.f; unit->frac = 0.f; StandardL_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////// PluginLoad(Chaos) { ft = inTable; DefineSimpleUnit(CuspN); DefineSimpleUnit(CuspL); DefineSimpleUnit(FBSineN); DefineSimpleUnit(FBSineL); DefineSimpleUnit(FBSineC); DefineSimpleUnit(GbmanN); DefineSimpleUnit(GbmanL); DefineSimpleUnit(HenonN); DefineSimpleUnit(HenonL); DefineSimpleUnit(HenonC); DefineSimpleUnit(LatoocarfianN); DefineSimpleUnit(LatoocarfianL); DefineSimpleUnit(LatoocarfianC); DefineSimpleUnit(LinCongN); DefineSimpleUnit(LinCongL); DefineSimpleUnit(LinCongC); DefineSimpleUnit(LorenzL); DefineSimpleUnit(QuadN); DefineSimpleUnit(QuadL); DefineSimpleUnit(QuadC); DefineSimpleUnit(StandardN); DefineSimpleUnit(StandardL); } SuperCollider-Source/server/plugins/CMakeLists.txt000644 000765 000024 00000017353 12760322424 023417 0ustar00crucialstaff000000 000000 if(NOT NO_LIBSNDFILE) find_package(Sndfile) else() add_definitions("-DNO_LIBSNDFILE") endif() include_directories( ${CMAKE_SOURCE_DIR}/include/common ${CMAKE_SOURCE_DIR}/common ${CMAKE_SOURCE_DIR}/include/plugin_interface ) # large file support if (CMAKE_SIZEOF_VOID_P MATCHES "4") execute_process(COMMAND getconf LFS_CFLAGS OUTPUT_VARIABLE LFS_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) elseif(CMAKE_SIZEOF_VOID_P MATCHES "8") execute_process(COMMAND getconf LFS64_CFLAGS OUTPUT_VARIABLE LFS_CFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LFS_CFLAGS}") set(plugin_sources BinaryOpUGens.cpp ChaosUGens.cpp DelayUGens.cpp DemandUGens.cpp DynNoiseUGens.cpp FilterUGens.cpp GendynUGens.cpp GrainUGens.cpp IOUGens.cpp LFUGens.cpp MulAddUGens.cpp NoiseUGens.cpp OscUGens.cpp PanUGens.cpp PhysicalModelingUGens.cpp ReverbUGens.cpp TestUGens.cpp TriggerUGens.cpp UnaryOpUGens.cpp UnpackFFTUGens.cpp ) set(plugins "") set(supernova_plugins "") set(CMAKE_SHARED_MODULE_PREFIX "") if(APPLE OR WIN32) set(CMAKE_SHARED_MODULE_SUFFIX ".scx") endif() if (${CMAKE_COMPILER_IS_GNUCXX}) add_definitions(-fno-finite-math-only) if(NOT WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden") endif() endif() foreach(plugin ${plugin_sources}) string(REPLACE .cpp "" plugin_name ${plugin} ) add_library(${plugin_name} MODULE ${plugin}) list(APPEND plugins ${plugin_name}) endforeach(plugin) if (APPLE) add_library(UIUGens MODULE UIUGens.mm) else() add_library(UIUGens MODULE UIUGens.cpp) endif() set(uiugens UIUGens) list(APPEND plugins UIUGens) if (WIN32) if(MSVC) include_directories (../../platform/windows/compat_stuff) # for stdbool.h endif() endif() add_library(FFT_UGens MODULE FFTInterfaceTable.cpp FFT_UGens.cpp PV_UGens.cpp PartitionedConvolution.cpp ${scplugin_common_sources} ) add_library(PV_ThirdParty MODULE Convolution.cpp FFT2InterfaceTable.cpp FeatureDetection.cpp PV_ThirdParty.cpp ${scplugin_common_sources} ) add_library(ML_UGens MODULE ML.cpp Loudness.cpp BeatTrack.cpp Onsets.cpp onsetsds.c KeyTrack.cpp MFCC.cpp BeatTrack2.cpp ML_SpecStats.cpp BeatTrack.h BeatTrack2.h ML.h Onsets.h onsetsds.h ${scplugin_common_sources} ) if(NOT NO_LIBSNDFILE) set(diskio_sources DiskIO_UGens.cpp) add_library(DiskIO_UGens MODULE ${diskio_sources}) if(SNDFILE_FOUND) target_include_directories(DiskIO_UGens PUBLIC ${SNDFILE_INCLUDE_DIR}) target_link_libraries(DiskIO_UGens ${SNDFILE_LIBRARIES}) list(APPEND plugins DiskIO_UGens) else() message(SEND_ERROR "Cannot find libsndfile") endif(SNDFILE_FOUND) endif() set(fft_ugens FFT_UGens PV_ThirdParty ML_UGens) list(APPEND plugins FFT_UGens PV_ThirdParty ML_UGens) if (FFTW3F_FOUND) include_directories (${FFTW3F_INCLUDE_DIR}) endif() if (SUPERNOVA) foreach(plugin ${plugin_sources}) string(REPLACE .cpp "_supernova" plugin_name ${plugin} ) add_library(${plugin_name} MODULE ${plugin}) list(APPEND supernova_plugins ${plugin_name}) endforeach(plugin) add_library(FFT_UGens_supernova MODULE FFTInterfaceTable.cpp FFT_UGens.cpp PV_UGens.cpp PartitionedConvolution.cpp ${scplugin_common_sources} ) add_library(PV_ThirdParty_supernova MODULE Convolution.cpp FFT2InterfaceTable.cpp FeatureDetection.cpp PV_ThirdParty.cpp ${scplugin_common_sources} ) add_library(ML_UGens_supernova MODULE ML.cpp Loudness.cpp BeatTrack.cpp Onsets.cpp onsetsds.c KeyTrack.cpp MFCC.cpp BeatTrack2.cpp ML_SpecStats.cpp ${scplugin_common_sources} ) list(APPEND fft_ugens FFT_UGens_supernova PV_ThirdParty_supernova ML_UGens_supernova) list(APPEND supernova_plugins FFT_UGens_supernova PV_ThirdParty_supernova ML_UGens_supernova UIUGens_supernova) if (APPLE) add_library(UIUGens_supernova MODULE UIUGens.mm) else() add_library(UIUGens_supernova MODULE UIUGens.cpp) endif() list(APPEND uiugens UIUGens_supernova) if(NOT NO_LIBSNDFILE) add_library(DiskIO_UGens_supernova MODULE DiskIO_UGens.cpp) if(SNDFILE_FOUND) target_include_directories(DiskIO_UGens_supernova PUBLIC ${SNDFILE_INCLUDE_DIR}) target_link_libraries(DiskIO_UGens_supernova ${SNDFILE_LIBRARIES} ${MATH_LIBRARY} ${Boost_THREAD_LIBRARY}) list(APPEND supernova_plugins DiskIO_UGens_supernova) else() message(SEND_ERROR "Cannot find libsndfile") endif(SNDFILE_FOUND) endif() endif(SUPERNOVA) foreach(ugen ${fft_ugens}) target_link_libraries(${ugen} ${MATH_LIBRARY}) if(APPLE) target_link_libraries(${ugen} "-framework Accelerate") endif() endforeach() foreach(ugen ${uiugens}) target_link_libraries(${ugen} ${Boost_THREAD_LIBRARY}) endforeach() foreach(plugin ${plugins}) if(WIN32) target_link_libraries(${plugin} wsock32 ws2_32) endif() endforeach() if(NOVA_SIMD) foreach(plugin ${plugins} ${supernova_plugins}) target_include_directories(${plugin} PUBLIC ${CMAKE_SOURCE_DIR}/external_libraries/nova-simd) target_compile_definitions(${plugin} PUBLIC NOVA_SIMD) endforeach() endif() foreach(plugin ${supernova_plugins}) target_compile_definitions(${plugin} PUBLIC SUPERNOVA) if (WIN32) target_link_libraries(${plugin} ws2_32) endif() endforeach() if (CMAKE_SYSTEM_NAME MATCHES "Linux") find_package(X11 REQUIRED) if (NOT X11_Xt_FOUND) message(FATAL_ERROR "libxt not found") endif() include_directories(${X11_Xt_INCLUDE_PATH}) foreach (ugen ${uiugens}) target_link_libraries(${ugen} ${X11_X11_LIB}) endforeach() elseif (APPLE) foreach (ugen ${uiugens}) target_link_libraries(${ugen} "-framework CoreServices -framework AppKit") endforeach() if(NOT NO_LIBSNDFILE) target_link_libraries(DiskIO_UGens "-framework CoreServices") endif() endif() if (WIN32) foreach(plugin ${plugins} ${supernova_plugins}) add_custom_command(TARGET ${plugin} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/plugins COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/plugins COMMAND ${CMAKE_COMMAND} -E make_directory $/plugins COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/plugins ) endforeach() if(SC_IDE) foreach(plugin ${plugins} ${supernova_plugins}) add_custom_command(TARGET ${plugin} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/plugins COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/plugins ) endforeach() endif(SC_IDE) if(SUPERNOVA) foreach(plugin ${supernova_plugins}) add_custom_command(TARGET ${plugin} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/plugins COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/plugins ) endforeach() endif(SUPERNOVA) install(TARGETS ${plugins} ${supernova_plugins} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE DESTINATION "${SC_WIN_BUNDLE_NAME}/plugins" ) elseif(APPLE) foreach(plugin ${plugins} ${supernova_plugins}) add_custom_command(TARGET ${plugin} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/../Resources/plugins/ COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $/../Resources/plugins/) endforeach() else() install(TARGETS ${plugins} ${supernova_plugins} DESTINATION "lib/SuperCollider/plugins" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endif() set_property(TARGET ${plugins} ${supernova_plugins} PROPERTY FOLDER UnitGenerators) set(plugins "${plugins}" PARENT_SCOPE) set(supernova_plugins "${supernova_plugins}" PARENT_SCOPE) SuperCollider-Source/server/plugins/Convolution.cpp000644 000765 000024 00000105415 12756531745 023714 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //Convolution by nick collins for sc3 (later input from Marije as below, Dan Stowell and Nick worked on sc_fft compatibility late 2008) //see ch18 http://www.dspguide.com/ch18.htm Steven W Smith //Convolution2 adapted by marije baalman for triggered kernel swap, with help from alberto de campo //Convolution2L (with linear crossfade) by marije baalman //Convolution3 (time-based) by marije baalman #include "FFT_UGens.h" //#include "SC_fftlib.h" #include struct Convolution : Unit { int m_pos, m_framesize, m_fftsize; float *m_inbuf1,*m_inbuf2, *m_fftbuf1, *m_fftbuf2, *m_outbuf,*m_overlapbuf; scfft *m_scfft1, *m_scfft2, *m_scfftR; }; struct Convolution2 : Unit { int m_pos, m_framesize, m_fftsize; float m_prevtrig; float *m_inbuf1, *m_fftbuf1, *m_fftbuf2, *m_outbuf,*m_overlapbuf; scfft *m_scfft1, *m_scfft2, *m_scfftR; }; struct Convolution2L : Unit { int m_pos, m_framesize, m_fftsize; int m_cfpos, m_cflength, m_curbuf; // for crossfading int m_log2n; float m_prevtrig; float *m_inbuf1, *m_fftbuf1, *m_fftbuf2, *m_outbuf,*m_overlapbuf; float *m_tempbuf, *m_fftbuf3; // for crossfading scfft *m_scfft1, *m_scfft2, *m_scfft3, *m_scfftR, *m_scfftR2; //source plus two kernels forwards, and two inverse from outbuf and from tempbuf }; //could be done also using complex signal fft and appropriate unwrapping, but sc_fft doesn't support that struct StereoConvolution2L : Unit { int m_pos, m_framesize, m_fftsize; int m_cfpos, m_cflength, m_curbuf; // for crossfading int m_log2n; float m_prevtrig; float *m_inbuf1, *m_fftbuf1; // input float *m_fftbuf2[2], *m_outbuf[2],*m_overlapbuf[2]; // output float *m_tempbuf[2], *m_fftbuf3[2]; // for crossfading scfft *m_scfft1, *m_scfft2[2], *m_scfft3[2], *m_scfftR[2], *m_scfftR2[2]; }; struct Convolution3 : Unit { int m_pos, m_framesize; float m_prevtrig; float *m_inbuf1, *m_inbuf2, *m_outbuf; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void Convolution_next(Convolution *unit, int wrongNumSamples); void Convolution_Ctor(Convolution *unit); void Convolution_Dtor(Convolution *unit); void Convolution2_next(Convolution2 *unit, int wrongNumSamples); void Convolution2_Ctor(Convolution2 *unit); void Convolution2_Dtor(Convolution2 *unit); void Convolution2L_next(Convolution2L *unit, int wrongNumSamples); void Convolution2L_Ctor(Convolution2L *unit); void Convolution2L_Dtor(Convolution2L *unit); void StereoConvolution2L_next(StereoConvolution2L *unit, int wrongNumSamples); void StereoConvolution2L_Ctor(StereoConvolution2L *unit); void StereoConvolution2L_Dtor(StereoConvolution2L *unit); void Convolution3_next_a(Convolution3 *unit); void Convolution3_next_k(Convolution3 *unit); void Convolution3_Ctor(Convolution3 *unit); void Convolution3_Dtor(Convolution3 *unit); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //PROPER CONVOLVER //two possibilities- fixed kernel (in which case can derive the kernel spectrum in the constructor) //and changing kernel (same size as target) void Convolution_Ctor(Convolution *unit) { //require size N+M-1 to be a power of two unit->m_framesize=(int)ZIN0(2); unit->m_fftsize=2*(unit->m_framesize); //just use memory for the input buffers and fft buffers int framesize_f = unit->m_framesize * sizeof(float); int fftsize_f = unit->m_fftsize * sizeof(float); unit->m_inbuf1 = (float*)RTAlloc(unit->mWorld, framesize_f); unit->m_inbuf2 = (float*)RTAlloc(unit->mWorld, framesize_f); unit->m_fftbuf1 = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_fftbuf2 = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_outbuf = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_overlapbuf = (float*)RTAlloc(unit->mWorld, framesize_f); memset(unit->m_outbuf, 0, fftsize_f); memset(unit->m_overlapbuf, 0, framesize_f); unit->m_pos = 0; SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft1 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_fftbuf1, kForward, alloc); unit->m_scfft2 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2, unit->m_fftbuf2, kForward, alloc); unit->m_scfftR = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_outbuf, kBackward, alloc); SETCALC(Convolution_next); } void Convolution_Dtor(Convolution *unit) { RTFree(unit->mWorld, unit->m_inbuf1); RTFree(unit->mWorld, unit->m_inbuf2); RTFree(unit->mWorld, unit->m_fftbuf1); RTFree(unit->mWorld, unit->m_fftbuf2); RTFree(unit->mWorld, unit->m_outbuf); RTFree(unit->mWorld, unit->m_overlapbuf); SCWorld_Allocator alloc(ft, unit->mWorld); scfft_destroy(unit->m_scfft1, alloc); scfft_destroy(unit->m_scfft2, alloc); scfft_destroy(unit->m_scfftR, alloc); } void Convolution_next(Convolution *unit, int numSamples) { float *in1 = IN(0); float *in2 = IN(1); float *out1 = unit->m_inbuf1 + unit->m_pos; float *out2 = unit->m_inbuf2 + unit->m_pos; //int numSamples = unit->mWorld->mFullRate.mBufLength; // copy input Copy(numSamples, out1, in1); Copy(numSamples, out2, in2); unit->m_pos += numSamples; int framesize= unit->m_framesize; if (unit->m_pos & framesize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter int memsize= framesize*sizeof(float); // copy to fftbuf memcpy(unit->m_fftbuf1, unit->m_inbuf1, memsize); memcpy(unit->m_fftbuf2, unit->m_inbuf2, memsize); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_framesize, 0, memsize); memset(unit->m_fftbuf2+unit->m_framesize, 0, memsize); // do fft //in place transform for now scfft_dofft(unit->m_scfft1); scfft_dofft(unit->m_scfft2); //complex multiply time float * p1= unit->m_fftbuf1; float * p2= unit->m_fftbuf2; p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; im_overlapbuf, unit->m_outbuf+unit->m_framesize, memsize); //inverse fft into outbuf memcpy(unit->m_outbuf, unit->m_fftbuf1, unit->m_fftsize * sizeof(float)); //in place scfft_doifft(unit->m_scfftR); } //write out samples copied from outbuf, with overlap added in float *output = ZOUT(0); float *out= unit->m_outbuf+unit->m_pos; float *overlap= unit->m_overlapbuf+unit->m_pos; for (int i=0; imWorld; if (bufnum >= world->mNumSndBufs) { int localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if (localBufNum <= parent->localMaxBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { if (unit->mWorld->mVerbosity > -1) Print("%s: invalid buffer number (%d).\n", ugenName, bufnum); goto handle_failure; } } else { buf = world->mSndBufs + bufnum; } if (buf->data == NULL) { if (unit->mWorld->mVerbosity > -1) Print("%s: uninitialized buffer (%i).\n", ugenName, bufnum); goto handle_failure; } return buf; handle_failure: SETCALC(*ClearUnitOutputs); ClearUnitOutputs(unit, inNumSamples); unit->mDone = true; return NULL; } void Convolution2_Ctor(Convolution2 *unit) { //require size N+M-1 to be a power of two unit->m_framesize=(int)ZIN0(3); uint32 kernelbufnum = (int)ZIN0(1); World *world = unit->mWorld; SndBuf *kernelbuf = ConvGetBuffer(unit, kernelbufnum, "Convolution2", 1); if(kernelbuf) { if ( unit->m_framesize <= 0 ){ // if smaller than zero, we use the size of the buffer unit->m_framesize=kernelbuf->frames; } unit->m_fftsize=2*(unit->m_framesize); if(unit->m_fftsize > SC_FFT_ABSOLUTE_MAXSIZE){ printf( "Convolution2: FFT size is larger than SC_FFT_ABSOLUTE_MAXSIZE, cannot run. We suggest PartConv instead.\n" ); SETCALC(*ClearUnitOutputs); } // allocate memory internally for the input buffers and fft buffers int framesize_f = unit->m_framesize * sizeof(float); int fftsize_f = unit->m_fftsize * sizeof(float); unit->m_inbuf1 = (float*)RTAlloc(world, framesize_f); unit->m_fftbuf1 = (float*)RTAlloc(world, fftsize_f); unit->m_fftbuf2 = (float*)RTAlloc(world, fftsize_f); unit->m_outbuf = (float*)RTAlloc(world, fftsize_f); memset(unit->m_outbuf, 0, fftsize_f); unit->m_overlapbuf = (float*)RTAlloc(world, framesize_f); memset(unit->m_overlapbuf, 0, framesize_f); unit->m_pos = 0; SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft1 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_fftbuf1, kForward, alloc); unit->m_scfft2 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2, unit->m_fftbuf2, kForward, alloc); unit->m_scfftR = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_outbuf, kBackward, alloc); if(!unit->m_scfft1 || !unit->m_scfft2 || !unit->m_scfftR){ printf( "Could not create scfft.\n" ); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } //calculate fft for kernel straight away // we cannot use a kernel larger than the fft size, so truncate if needed. the kernel may be smaller though. uint32 framesize = unit->m_framesize; size_t kernelcopysize = sc_min(kernelbuf->frames, framesize); memcpy(unit->m_fftbuf2, kernelbuf->data, kernelcopysize * sizeof(float)); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf2 + kernelcopysize, 0, (2 * framesize - kernelcopysize) * sizeof(float)); scfft_dofft(unit->m_scfft2); unit->m_pos = 0; unit->m_prevtrig = 0.f; unit->m_prevtrig = ZIN0(2); if ( unit->m_framesize >= world->mFullRate.mBufLength ) { SETCALC(Convolution2_next); } else { printf( "Convolution2 framesize smaller than blocksize \n" ); SETCALC(*ClearUnitOutputs); unit->mDone = true; } } else { unit->m_scfft2 = unit->m_scfft1 = unit->m_scfftR = NULL; printf("Convolution2_Ctor: can't get kernel buffer, giving up.\n"); SETCALC(*ClearUnitOutputs); } } void Convolution2_Dtor(Convolution2 *unit) { RTFree(unit->mWorld, unit->m_inbuf1); RTFree(unit->mWorld, unit->m_fftbuf1); RTFree(unit->mWorld, unit->m_fftbuf2); RTFree(unit->mWorld, unit->m_outbuf); RTFree(unit->mWorld, unit->m_overlapbuf); SCWorld_Allocator alloc(ft, unit->mWorld); scfft_destroy(unit->m_scfft1, alloc); scfft_destroy(unit->m_scfft2, alloc); scfft_destroy(unit->m_scfftR, alloc); } void Convolution2_next(Convolution2 *unit, int wrongNumSamples) { float *in1 = IN(0); float curtrig = ZIN0(2); float *inbuf1writepos = unit->m_inbuf1 + unit->m_pos; int numSamples = unit->mWorld->mFullRate.mBufLength; uint32 framesize = unit->m_framesize; uint32 framesize_f = framesize * sizeof(float); // copy input Copy(numSamples, inbuf1writepos, in1); unit->m_pos += numSamples; if (unit->m_prevtrig <= 0.f && curtrig > 0.f){ SndBuf *kernelbuf = ConvGetBuffer(unit,(uint32)ZIN0(1), "Convolution2", numSamples); if (!kernelbuf) return; LOCK_SNDBUF_SHARED(kernelbuf); // we cannot use a kernel larger than the fft size, so truncate if needed. the kernel may be smaller though. size_t kernelcopysize = sc_min(kernelbuf->frames, framesize); memcpy(unit->m_fftbuf2, kernelbuf->data, kernelcopysize * sizeof(float)); memset(unit->m_fftbuf2 + kernelcopysize, 0, (2 * framesize - kernelcopysize) * sizeof(float)); scfft_dofft(unit->m_scfft2); } if (unit->m_pos >= framesize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter // copy to fftbuf memcpy(unit->m_fftbuf1, unit->m_inbuf1, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft1); //complex multiply time int numbins = unit->m_fftsize >> 1; float * p1= unit->m_fftbuf1; float * p2= unit->m_fftbuf2; p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; im_overlapbuf, unit->m_outbuf+unit->m_framesize, framesize_f); //inverse fft into outbuf scfft_doifft(unit->m_scfftR); } //write out samples copied from outbuf, with overlap added in float *output = ZOUT(0); float *out= unit->m_outbuf+unit->m_pos; float *overlap= unit->m_overlapbuf+unit->m_pos; unit->m_prevtrig = curtrig; for (int i=0; im_framesize=(int)ZIN0(3); unit->m_cflength = (int)ZIN0(4); unit->m_curbuf = 0; unit->m_cfpos = unit->m_cflength; unit->m_fftsize=2*(unit->m_framesize); //just use memory for the input buffers and fft buffers int framesize_f = unit->m_framesize * sizeof(float); int fftsize_f = unit->m_fftsize * sizeof(float); unit->m_inbuf1 = (float*)RTAlloc(unit->mWorld, framesize_f); unit->m_fftbuf1 = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_fftbuf2 = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_fftbuf3 = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, fftsize_f); uint32 bufnum = (int)ZIN0(1); //fbufnum; SndBuf *buf = ConvGetBuffer(unit, bufnum, "Convolution2L", 1); if(buf) { unit->m_outbuf = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_overlapbuf = (float*)RTAlloc(unit->mWorld, framesize_f); memset(unit->m_outbuf, 0, fftsize_f); memset(unit->m_overlapbuf, 0, framesize_f); //calculate fft for kernel straight away memcpy(unit->m_fftbuf2, buf->data, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf2+unit->m_framesize, 0, framesize_f); SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft1 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_fftbuf1, kForward, alloc); unit->m_scfft2 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2, unit->m_fftbuf2, kForward, alloc); unit->m_scfft3 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf3, unit->m_fftbuf3, kForward, alloc); unit->m_scfftR = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_outbuf, unit->m_outbuf, kBackward, alloc); unit->m_scfftR2 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_tempbuf, unit->m_tempbuf, kBackward, alloc); scfft_dofft(unit->m_scfft2); unit->m_pos = 0; unit->m_prevtrig = 0.f; SETCALC(Convolution2L_next); } else { unit->m_scfft1 = unit->m_scfft2 = unit->m_scfft3 = unit->m_scfftR = unit->m_scfftR2 = NULL; } } void Convolution2L_Dtor(Convolution2L *unit) { SCWorld_Allocator alloc(ft, unit->mWorld); scfft_destroy(unit->m_scfft1, alloc); scfft_destroy(unit->m_scfft2, alloc); scfft_destroy(unit->m_scfft3, alloc); scfft_destroy(unit->m_scfftR, alloc); scfft_destroy(unit->m_scfftR2, alloc); RTFree(unit->mWorld, unit->m_inbuf1); RTFree(unit->mWorld, unit->m_fftbuf1); RTFree(unit->mWorld, unit->m_fftbuf2); RTFree(unit->mWorld, unit->m_fftbuf3); RTFree(unit->mWorld, unit->m_tempbuf); RTFree(unit->mWorld, unit->m_outbuf); RTFree(unit->mWorld, unit->m_overlapbuf); } void Convolution2L_next(Convolution2L *unit, int numSamples) { float *in1 = IN(0); float curtrig = ZIN0(2); float *out1 = unit->m_inbuf1 + unit->m_pos; int framesize_f = unit->m_framesize * sizeof(float); // copy input memcpy(out1,in1,numSamples*sizeof(float)); unit->m_pos += numSamples; if (unit->m_prevtrig <= 0.f && curtrig > 0.f){ uint32 bufnum = (int)ZIN0(1); SndBuf *buf = ConvGetBuffer(unit, bufnum, "Convolution2L", numSamples); if (!buf) return; unit->m_cflength = (int)ZIN0(4); unit->m_cfpos = 0; if ( unit->m_curbuf == 1 ) { LOCK_SNDBUF_SHARED(buf); memcpy(unit->m_fftbuf2, buf->data, framesize_f); memset(unit->m_fftbuf2+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft2); } else if ( unit->m_curbuf == 0 ) { LOCK_SNDBUF_SHARED(buf); memcpy(unit->m_fftbuf3, buf->data, framesize_f); memset(unit->m_fftbuf3+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft3); } } if (unit->m_pos & unit->m_framesize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter // copy to fftbuf memcpy(unit->m_fftbuf1, unit->m_inbuf1, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_framesize, 0, framesize_f); //in place transform for now scfft_dofft(unit->m_scfft1); //rffts(unit->m_fftbuf1, log2n, 1, cosTable[log2n]); //complex multiply time int numbins = unit->m_fftsize >> 1; //unit->m_fftsize - 2 >> 1; float * p1= unit->m_fftbuf1; float * p2; if ( unit->m_curbuf == 0 ) p2 = unit->m_fftbuf2; else p2= unit->m_fftbuf3; float * p3= unit->m_tempbuf; // multiply the dc and nyquist components p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; im_overlapbuf, unit->m_outbuf+unit->m_framesize, unit->m_framesize * sizeof(float)); //inverse fft into outbuf memcpy(unit->m_outbuf, unit->m_tempbuf, unit->m_fftsize * sizeof(float)); //in place scfft_doifft(unit->m_scfftR); if ( unit->m_cfpos < unit->m_cflength ) // do crossfade { if ( unit->m_curbuf == 0 ) p2= unit->m_fftbuf3; else p2= unit->m_fftbuf2; // multiply the dc and nyquist components p1[0] *= p2[0]; p1[1] *= p2[1]; //complex multiply for (int i=1; ibin[i]; p1[imagind]= imag; } //copy second part from before to overlap //inverse fft into tempbuf memcpy(unit->m_tempbuf, unit->m_fftbuf1, unit->m_fftsize * sizeof(float)); scfft_doifft(unit->m_scfftR2); // now crossfade between outbuf and tempbuf float fact1 = (float) unit->m_cfpos/unit->m_cflength; // crossfade amount startpoint float rc = 1.f/(unit->m_cflength*unit->m_framesize); //crossfade amount increase per sample float * p4 = unit->m_outbuf; float * p5 = unit->m_tempbuf; for ( int i=0; i < unit->m_framesize; i++ ) { float res; res = (1-fact1)*p4[i] + fact1*p5[i]; fact1 += rc; p4[i] = res; } if ( unit->m_cflength == 1 ) memcpy(unit->m_outbuf+unit->m_framesize, unit->m_tempbuf+unit->m_framesize, framesize_f); else { for ( int i=unit->m_framesize+1; i < unit->m_fftsize; i++ ) { float res = (1-fact1)*p4[i] + fact1*p5[i]; fact1 += rc; p4[i] = res; } } unit->m_cfpos++; if ( unit->m_cfpos == unit->m_cflength ) // at end of crossfade, update the current buffer index { if ( unit->m_curbuf == 0 ) unit->m_curbuf = 1; else unit->m_curbuf = 0; } } } //write out samples copied from outbuf, with overlap added in float *output = ZOUT(0); float *out= unit->m_outbuf+unit->m_pos; float *overlap= unit->m_overlapbuf+unit->m_pos; unit->m_prevtrig = curtrig; for (int i=0; im_framesize=(int)ZIN0(4); unit->m_cflength = (int)ZIN0(5); unit->m_curbuf = 0; unit->m_cfpos = unit->m_cflength; unit->m_fftsize=2*(unit->m_framesize); //just use memory for the input buffers and fft buffers int framesize_f = unit->m_framesize * sizeof(float); int fftsize_f = unit->m_fftsize * sizeof(float); unit->m_inbuf1 = (float*)RTAlloc(unit->mWorld, framesize_f); // source: unit->m_fftbuf1 = (float*)RTAlloc(unit->mWorld, fftsize_f); // 2 channel buffer: unit->m_fftbuf2[0] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_fftbuf2[1] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_fftbuf3[0] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_fftbuf3[1] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_tempbuf[0] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_tempbuf[1] = (float*)RTAlloc(unit->mWorld, fftsize_f); // unit->m_tempfftbuf[0] = (float*)RTAlloc(unit->mWorld, fftsize_f); // unit->m_tempfftbuf[1] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_outbuf[0] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_overlapbuf[0] = (float*)RTAlloc(unit->mWorld, framesize_f); unit->m_outbuf[1] = (float*)RTAlloc(unit->mWorld, fftsize_f); unit->m_overlapbuf[1] = (float*)RTAlloc(unit->mWorld, framesize_f); memset(unit->m_outbuf[0], 0, fftsize_f); memset(unit->m_overlapbuf[0], 0, framesize_f); memset(unit->m_outbuf[1], 0, fftsize_f); memset(unit->m_overlapbuf[1], 0, framesize_f); SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft1 = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf1, unit->m_fftbuf1, kForward, alloc); unit->m_scfft2[0] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2[0], unit->m_fftbuf2[0], kForward, alloc); unit->m_scfft3[0] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf2[1], unit->m_fftbuf2[1], kForward, alloc); unit->m_scfftR[0] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf3[0], unit->m_fftbuf3[0], kForward, alloc); unit->m_scfftR2[0] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_fftbuf3[1], unit->m_fftbuf3[1], kForward, alloc); unit->m_scfft2[1] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_outbuf[0], unit->m_outbuf[0], kBackward, alloc); unit->m_scfft3[1] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_tempbuf[0], unit->m_tempbuf[0], kBackward, alloc); unit->m_scfftR[1] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_outbuf[1], unit->m_outbuf[1], kBackward, alloc); unit->m_scfftR2[1] = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_tempbuf[1], unit->m_tempbuf[1], kBackward, alloc); float fbufnum = ZIN0(1); uint32 bufnumL = (int)fbufnum; fbufnum = ZIN0(2); uint32 bufnumR = (int)fbufnum; //printf("bufnum %i \n", bufnum); //unit->m_log2n = LOG2CEIL(unit->m_fftsize); //int log2n = unit->m_log2n; SndBuf *buf = ConvGetBuffer(unit, bufnumL, "StereoConvolution2L", 1); if (buf) { LOCK_SNDBUF_SHARED(buf); //calculate fft for kernel straight away memcpy(unit->m_fftbuf2[0], buf->data, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf2[0]+unit->m_framesize, 0, framesize_f); //in place transform for now scfft_dofft(unit->m_scfft2[0]); } else return; buf = ConvGetBuffer(unit, bufnumR, "StereoConvolution2L", 1); if (buf) { LOCK_SNDBUF(buf); //calculate fft for kernel straight away memcpy(unit->m_fftbuf2[1], buf->data, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf2[1]+unit->m_framesize, 0, framesize_f); //in place transform for now scfft_dofft(unit->m_scfft2[1]); unit->m_pos = 0; unit->m_prevtrig = 0.f; SETCALC(StereoConvolution2L_next); } } void StereoConvolution2L_Dtor(StereoConvolution2L *unit) { SCWorld_Allocator alloc(ft, unit->mWorld); scfft_destroy(unit->m_scfft1, alloc); scfft_destroy(unit->m_scfft2[0], alloc); scfft_destroy(unit->m_scfft3[0], alloc); scfft_destroy(unit->m_scfftR[0], alloc); scfft_destroy(unit->m_scfftR2[0], alloc); scfft_destroy(unit->m_scfft2[1], alloc); scfft_destroy(unit->m_scfft3[1], alloc); scfft_destroy(unit->m_scfftR[1], alloc); scfft_destroy(unit->m_scfftR2[1], alloc); RTFree(unit->mWorld, unit->m_inbuf1); RTFree(unit->mWorld, unit->m_fftbuf1); RTFree(unit->mWorld, unit->m_fftbuf2[0]); RTFree(unit->mWorld, unit->m_fftbuf3[0]); RTFree(unit->mWorld, unit->m_tempbuf[0]); RTFree(unit->mWorld, unit->m_outbuf[0]); RTFree(unit->mWorld, unit->m_overlapbuf[0]); RTFree(unit->mWorld, unit->m_fftbuf2[1]); RTFree(unit->mWorld, unit->m_fftbuf3[1]); RTFree(unit->mWorld, unit->m_tempbuf[1]); RTFree(unit->mWorld, unit->m_outbuf[1]); RTFree(unit->mWorld, unit->m_overlapbuf[1]); } void StereoConvolution2L_next(StereoConvolution2L *unit, int wrongNumSamples) { float *in1 = IN(0); float curtrig = ZIN0(3); float *out1 = unit->m_inbuf1 + unit->m_pos; int numSamples = unit->mWorld->mFullRate.mBufLength; uint32 framesize_f=unit->m_framesize * sizeof(float); // copy input Copy(numSamples, out1, in1); unit->m_pos += numSamples; if (unit->m_prevtrig <= 0.f && curtrig > 0.f){ float fbufnum = ZIN0(1); uint32 bufnumL = (int)fbufnum; fbufnum = ZIN0(2); uint32 bufnumR = (int)fbufnum; unit->m_cflength = (int)ZIN0(5); SndBuf *bufL = ConvGetBuffer(unit, bufnumL, "StereoConvolution2L", numSamples); SndBuf *bufR = ConvGetBuffer(unit, bufnumR, "StereoConvolution2L", numSamples); if (!bufL || !bufL) return; unit->m_cfpos = 0; if ( unit->m_curbuf == 1 ) { LOCK_SNDBUF2_SHARED(bufL, bufR); memcpy(unit->m_fftbuf2[0], bufL->data, framesize_f); memset(unit->m_fftbuf2[0]+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft2[0]); memcpy(unit->m_fftbuf2[1], bufR->data, framesize_f); memset(unit->m_fftbuf2[1]+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft2[1]); } else if ( unit->m_curbuf == 0 ) { LOCK_SNDBUF2_SHARED(bufL, bufR); memcpy(unit->m_fftbuf3[0], bufL->data, framesize_f); memset(unit->m_fftbuf3[0]+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft3[0]); memcpy(unit->m_fftbuf3[1], bufR->data, framesize_f); memset(unit->m_fftbuf3[1]+unit->m_framesize, 0, framesize_f); scfft_dofft(unit->m_scfft3[1]); } } if (unit->m_pos & unit->m_framesize) { //have collected enough samples to transform next frame unit->m_pos = 0; //reset collection counter // copy to fftbuf memcpy(unit->m_fftbuf1, unit->m_inbuf1, framesize_f); //zero pad second part of buffer to allow for convolution memset(unit->m_fftbuf1+unit->m_framesize, 0, framesize_f); //in place transform for now scfft_dofft(unit->m_scfft1); //complex multiply time int numbins = unit->m_fftsize >> 1; //unit->m_fftsize - 2 >> 1; float * p1= unit->m_fftbuf1; float * p2L, * p2R; if ( unit->m_curbuf == 0 ){ p2L = unit->m_fftbuf2[0]; p2R = unit->m_fftbuf2[1]; } else { p2L = unit->m_fftbuf3[0]; p2R = unit->m_fftbuf3[1]; } float * p3L = unit->m_tempbuf[0]; float * p3R = unit->m_tempbuf[1]; //complex multiply for (int i=1; ibin[i]; p3L[imagind] = imagL; p3R[realind] = realR; //p2->bin[i]; p3R[imagind] = imagR; } for ( int i=0; i < 2; i++ ){ //copy second part from before to overlap memcpy(unit->m_overlapbuf[i], unit->m_outbuf[i]+unit->m_framesize, unit->m_framesize * sizeof(float)); //inverse fft into outbuf memcpy(unit->m_outbuf[i], unit->m_tempbuf[i], unit->m_fftsize * sizeof(float)); //in place scfft_doifft(unit->m_scfftR[i]); } if ( unit->m_cfpos < unit->m_cflength ) // do crossfade { if ( unit->m_curbuf == 0 ){ p2L= unit->m_fftbuf3[0]; p2R= unit->m_fftbuf3[1]; } else { p2L= unit->m_fftbuf2[0]; p2R= unit->m_fftbuf2[1]; } //complex multiply for (int i=1; ibin[i]; p3L[imagind] = imagL; p3R[realind] = realR; //p2->bin[i]; p3R[imagind] = imagR; } scfft_doifft(unit->m_scfftR2[0]); scfft_doifft(unit->m_scfftR2[1]); // now crossfade between outbuf and tempbuf float fact1 = (float) unit->m_cfpos/unit->m_cflength; // crossfade amount startpoint float rc = 1.f/(unit->m_cflength*unit->m_framesize); //crossfade amount increase per sample float * p4L = unit->m_outbuf[0]; float * p5L = unit->m_tempbuf[0]; float * p4R = unit->m_outbuf[1]; float * p5R = unit->m_tempbuf[1]; for ( int i=0; i < unit->m_framesize; i++ ) { float res; res = (1-fact1)*p4L[i] + fact1*p5L[i]; p4L[i] = res; res = (1-fact1)*p4R[i] + fact1*p5R[i]; p4R[i] = res; fact1 += rc; } if ( unit->m_cflength == 1 ) // in the overlap the convolution is already at the new buffer { memcpy(unit->m_outbuf[0]+unit->m_framesize, unit->m_tempbuf[0]+unit->m_framesize,unit->m_framesize * sizeof(float)); memcpy(unit->m_outbuf[1]+unit->m_framesize, unit->m_tempbuf[1]+unit->m_framesize,unit->m_framesize * sizeof(float)); } else { for ( int i=unit->m_framesize+1; i < unit->m_fftsize; i++ ) { float res; res = (1-fact1)*p4L[i] + fact1*p5L[i]; p4L[i] = res; res = (1-fact1)*p4R[i] + fact1*p5R[i]; p4R[i] = res; fact1 += rc; } } unit->m_cfpos++; if ( unit->m_cfpos == unit->m_cflength ) // at end of crossfade, update the current buffer index { if ( unit->m_curbuf == 0 ) unit->m_curbuf = 1; else unit->m_curbuf = 0; } } } //write out samples copied from outbuf, with overlap added in float *outputL = ZOUT(0); float *outputR = ZOUT(1); float *outL= unit->m_outbuf[0]+unit->m_pos; float *overlapL= unit->m_overlapbuf[0]+unit->m_pos; float *outR= unit->m_outbuf[1]+unit->m_pos; float *overlapR= unit->m_overlapbuf[1]+unit->m_pos; unit->m_prevtrig = curtrig; for (int i=0; im_framesize=(int)ZIN0(3); float fbufnum = ZIN0(1); uint32 bufnum = (int)fbufnum; SndBuf *buf = ConvGetBuffer(unit, bufnum, "Convolution3", 1); if (buf) { if ( unit->m_framesize <= 0 ) // if smaller than zero, equal to size of buffer { unit->m_framesize=buf->frames; } //just use memory for the input buffers and out buffer int framesize_f = unit->m_framesize * sizeof(float); unit->m_inbuf1 = (float*)RTAlloc(unit->mWorld, framesize_f); unit->m_inbuf2 = (float*)RTAlloc(unit->mWorld, framesize_f); LOCK_SNDBUF_SHARED(buf); //calculate fft for kernel straight away memcpy(unit->m_inbuf2, buf->data, framesize_f); unit->m_pos = 0; unit->m_outbuf = (float*)RTAlloc(unit->mWorld, framesize_f); memset(unit->m_outbuf, 0, framesize_f); unit->m_prevtrig = 0.f; if ( INRATE(0) == calc_FullRate ) SETCALC(Convolution3_next_a); else SETCALC(Convolution3_next_k); } } void Convolution3_Dtor(Convolution3 *unit) { RTFree(unit->mWorld, unit->m_inbuf1); RTFree(unit->mWorld, unit->m_inbuf2); RTFree(unit->mWorld, unit->m_outbuf); } void Convolution3_next_a(Convolution3 *unit) { float *in = IN(0); float curtrig = ZIN0(2); float *pin1 = unit->m_inbuf1; int numSamples = unit->mWorld->mFullRate.mBufLength; // copy input Copy(numSamples, pin1, in); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) { uint32 framesize_f=unit->m_framesize * sizeof(float); float fbufnum = ZIN0(1); uint32 bufnum = (int)fbufnum; SndBuf *buf = ConvGetBuffer(unit, bufnum, "Convolution3", numSamples); LOCK_SNDBUF_SHARED(buf); memcpy(unit->m_inbuf2, buf->data, framesize_f); } float * pin2= unit->m_inbuf2; float * pout=unit->m_outbuf; int pos = unit->m_pos; int size = unit->m_framesize; for ( int j=0; j < numSamples; ++j) { float input = pin1[j]; for ( int i=0; i < size; ++i ) { int ind = (pos+i+j)%(size); pout[ind] = pout[ind] + pin2[i]*input; } } float *output = ZOUT(0); for (int i=0; i size ) { unit->m_pos = pos - size; //reset collection counter } else { unit->m_pos += numSamples; } unit->m_prevtrig = curtrig; } void Convolution3_next_k(Convolution3 *unit) { float input = ZIN0(0); float curtrig = ZIN0(2); uint32 framesize_f=unit->m_framesize * sizeof(float); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) { float fbufnum = ZIN0(1); uint32 bufnum = (int)fbufnum; SndBuf *buf= ConvGetBuffer(unit, bufnum, "Convolution3", 1); if (!buf) return; LOCK_SNDBUF_SHARED(buf); memcpy(unit->m_inbuf2, buf->data, framesize_f); } float * pin= unit->m_inbuf2; float * pout=unit->m_outbuf; int pos = unit->m_pos; int size = unit->m_framesize; for ( int i=0; i < size; ++i ) { int ind = (pos+i)%(size); pout[ind] = pout[ind] + pin[i]*input; } float *output = OUT(0); *output = pout[pos]; if ( ++pos > size ) unit->m_pos = 0; //reset collection counter else unit->m_pos++; unit->m_prevtrig = curtrig; } void initConvolution(InterfaceTable *it) { DefineDtorUnit(Convolution); DefineDtorUnit(Convolution2); DefineDtorUnit(Convolution2L); DefineDtorUnit(StereoConvolution2L); DefineDtorUnit(Convolution3); } SuperCollider-Source/server/plugins/DelayUGens.cpp000644 000765 000024 00000625524 12766171707 023404 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef NOVA_SIMD #include "simd_memory.hpp" #endif #include "SC_PlugIn.h" #include #include using namespace std; // for math functions const int kMAXMEDIANSIZE = 32; static InterfaceTable *ft; struct ScopeOut : public Unit { SndBuf *m_buf; SndBufUpdates *m_bufupdates; float m_fbufnum; uint32 m_framepos, m_framecount; float **mIn; }; struct PlayBuf : public Unit { double m_phase; float m_prevtrig; float m_fbufnum; float m_failedBufNum; SndBuf *m_buf; }; struct Grain { double phase, rate; double b1, y1, y2; // envelope float pan1, pan2; int counter; int bufnum; int chan; int interp; }; const int kMaxGrains = 64; struct TGrains : public Unit { float mPrevTrig; int mNumActive; Grain mGrains[kMaxGrains]; }; #if NOTYET struct SimpleLoopBuf : public Unit { int m_phase; float m_prevtrig; float m_fbufnum; SndBuf *m_buf; }; #endif struct BufRd : public Unit { float m_fbufnum; float m_failedBufNum; SndBuf *m_buf; }; struct BufWr : public Unit { float m_fbufnum; SndBuf *m_buf; }; struct RecordBuf : public Unit { float m_fbufnum; SndBuf *m_buf; int32 m_writepos; float m_recLevel, m_preLevel; float m_prevtrig; float **mIn; }; struct Pitch : public Unit { float m_values[kMAXMEDIANSIZE]; int m_ages[kMAXMEDIANSIZE]; float *m_buffer; float m_freq, m_minfreq, m_maxfreq, m_hasfreq, m_srate, m_ampthresh, m_peakthresh; int m_minperiod, m_maxperiod, m_execPeriod, m_index, m_readp, m_size; int m_downsamp, m_maxlog2bins, m_medianSize; int m_state; bool m_getClarity; }; struct InterpolationUnit { static const int minDelaySamples = 1; }; struct CubicInterpolationUnit { static const int minDelaySamples = 2; }; struct BufDelayUnit : public Unit { float m_fbufnum; SndBuf *m_buf; float m_dsamp; float m_delaytime; long m_iwrphase; uint32 m_numoutput; }; struct BufDelayN : public BufDelayUnit, InterpolationUnit {}; struct BufDelayL : public BufDelayUnit, InterpolationUnit {}; struct BufDelayC : public BufDelayUnit, CubicInterpolationUnit {}; struct BufFeedbackDelay : public BufDelayUnit { float m_feedbk, m_decaytime; }; struct BufCombN : public BufFeedbackDelay, InterpolationUnit {}; struct BufCombL : public BufFeedbackDelay, InterpolationUnit {}; struct BufCombC : public BufFeedbackDelay, CubicInterpolationUnit {}; struct BufAllpassN : public BufFeedbackDelay, InterpolationUnit {}; struct BufAllpassL : public BufFeedbackDelay, InterpolationUnit {}; struct BufAllpassC : public BufFeedbackDelay, CubicInterpolationUnit {}; struct DelayUnit : public Unit { float *m_dlybuf; float m_dsamp, m_fdelaylen; float m_delaytime, m_maxdelaytime; long m_iwrphase, m_idelaylen, m_mask; long m_numoutput; }; struct DelayN : public DelayUnit, InterpolationUnit {}; struct DelayL : public DelayUnit, InterpolationUnit {}; struct DelayC : public DelayUnit, InterpolationUnit {}; struct FeedbackDelay : public DelayUnit { float m_feedbk, m_decaytime; }; struct CombN : public FeedbackDelay, InterpolationUnit {}; struct CombL : public FeedbackDelay, InterpolationUnit {}; struct CombC : public FeedbackDelay, CubicInterpolationUnit {}; struct AllpassN : public FeedbackDelay, InterpolationUnit {}; struct AllpassL : public FeedbackDelay, InterpolationUnit {}; struct AllpassC : public FeedbackDelay, CubicInterpolationUnit {}; struct BufInfoUnit : public Unit { float m_fbufnum; SndBuf *m_buf; }; struct Pluck : public FeedbackDelay, CubicInterpolationUnit { float m_lastsamp, m_prevtrig, m_coef; long m_inputsamps; }; struct LocalBuf : public Unit { SndBuf *m_buf; void * chunk; }; struct MaxLocalBufs : public Unit { }; struct SetBuf : public Unit {}; struct ClearBuf : public Unit {}; struct DelTapWr : public Unit { SndBuf *m_buf; float m_fbufnum; uint32 m_phase; }; struct DelTapRd : public Unit { SndBuf *m_buf; float m_fbufnum, m_delTime; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void SampleRate_Ctor(Unit *unit, int inNumSamples); void ControlRate_Ctor(Unit *unit, int inNumSamples); void SampleDur_Ctor(Unit *unit, int inNumSamples); void ControlDur_Ctor(Unit *unit, int inNumSamples); void SubsampleOffset_Ctor(Unit *unit, int inNumSamples); void RadiansPerSample_Ctor(Unit *unit, int inNumSamples); void NumInputBuses_Ctor(Unit *unit, int inNumSamples); void NumOutputBuses_Ctor(Unit *unit, int inNumSamples); void NumAudioBuses_Ctor(Unit *unit, int inNumSamples); void NumControlBuses_Ctor(Unit *unit, int inNumSamples); void NumBuffers_Ctor(Unit *unit, int inNumSamples); void NodeID_Ctor(Unit *unit, int inNumSamples); void NumRunningSynths_Ctor(Unit *unit, int inNumSamples); void NumRunningSynths_next(Unit *unit, int inNumSamples); void BufSampleRate_next(BufInfoUnit *unit, int inNumSamples); void BufSampleRate_Ctor(BufInfoUnit *unit, int inNumSamples); void BufFrames_next(BufInfoUnit *unit, int inNumSamples); void BufFrames_Ctor(BufInfoUnit *unit, int inNumSamples); void BufDur_next(BufInfoUnit *unit, int inNumSamples); void BufDur_Ctor(BufInfoUnit *unit, int inNumSamples); void BufChannels_next(BufInfoUnit *unit, int inNumSamples); void BufChannels_Ctor(BufInfoUnit *unit, int inNumSamples); void BufSamples_next(BufInfoUnit *unit, int inNumSamples); void BufSamples_Ctor(BufInfoUnit *unit, int inNumSamples); void BufRateScale_next(BufInfoUnit *unit, int inNumSamples); void BufRateScale_Ctor(BufInfoUnit *unit, int inNumSamples); void PlayBuf_next_aa(PlayBuf *unit, int inNumSamples); void PlayBuf_next_ak(PlayBuf *unit, int inNumSamples); void PlayBuf_next_ka(PlayBuf *unit, int inNumSamples); void PlayBuf_next_kk(PlayBuf *unit, int inNumSamples); void PlayBuf_Ctor(PlayBuf* unit); void TGrains_next(TGrains *unit, int inNumSamples); void TGrains_Ctor(TGrains* unit); #if NOTYET void SimpleLoopBuf_next_kk(SimpleLoopBuf *unit, int inNumSamples); void SimpleLoopBuf_Ctor(SimpleLoopBuf* unit); void SimpleLoopBuf_Dtor(SimpleLoopBuf* unit); #endif void BufRd_Ctor(BufRd *unit); void BufRd_next_4(BufRd *unit, int inNumSamples); void BufRd_next_2(BufRd *unit, int inNumSamples); void BufRd_next_1(BufRd *unit, int inNumSamples); void BufWr_Ctor(BufWr *unit); void BufWr_next(BufWr *unit, int inNumSamples); void RecordBuf_Ctor(RecordBuf *unit); void RecordBuf_Dtor(RecordBuf *unit); void RecordBuf_next(RecordBuf *unit, int inNumSamples); void RecordBuf_next_10(RecordBuf *unit, int inNumSamples); void Pitch_Ctor(Pitch *unit); void Pitch_next_a(Pitch *unit, int inNumSamples); void Pitch_next_k(Pitch *unit, int inNumSamples); void LocalBuf_Ctor(LocalBuf *unit); void LocalBuf_Dtor(LocalBuf *unit); void MaxLocalBufs_Ctor(MaxLocalBufs *unit); void SetBuf_Ctor(SetBuf *unit); void ClearBuf_Ctor(ClearBuf *unit); void BufDelayN_Ctor(BufDelayN *unit); void BufDelayN_next(BufDelayN *unit, int inNumSamples); void BufDelayN_next_z(BufDelayN *unit, int inNumSamples); void BufDelayN_next_a(BufDelayN *unit, int inNumSamples); void BufDelayN_next_a_z(BufDelayN *unit, int inNumSamples); void BufDelayL_Ctor(BufDelayL *unit); void BufDelayL_next(BufDelayL *unit, int inNumSamples); void BufDelayL_next_z(BufDelayL *unit, int inNumSamples); void BufDelayL_next_a(BufDelayL *unit, int inNumSamples); void BufDelayL_next_a_z(BufDelayL *unit, int inNumSamples); void BufDelayC_Ctor(BufDelayC *unit); void BufDelayC_next(BufDelayC *unit, int inNumSamples); void BufDelayC_next_z(BufDelayC *unit, int inNumSamples); void BufDelayC_next_a(BufDelayC *unit, int inNumSamples); void BufDelayC_next_a_z(BufDelayC *unit, int inNumSamples); void BufCombN_Ctor(BufCombN *unit); void BufCombN_next(BufCombN *unit, int inNumSamples); void BufCombN_next_z(BufCombN *unit, int inNumSamples); void BufCombN_next_a(BufCombN *unit, int inNumSamples); void BufCombN_next_a_z(BufCombN *unit, int inNumSamples); void BufCombL_Ctor(BufCombL *unit); void BufCombL_next(BufCombL *unit, int inNumSamples); void BufCombL_next_z(BufCombL *unit, int inNumSamples); void BufCombL_next_a(BufCombL *unit, int inNumSamples); void BufCombL_next_a_z(BufCombL *unit, int inNumSamples); void BufCombC_Ctor(BufCombC *unit); void BufCombC_next(BufCombC *unit, int inNumSamples); void BufCombC_next_z(BufCombC *unit, int inNumSamples); void BufCombC_next_a(BufCombC *unit, int inNumSamples); void BufCombC_next_a_z(BufCombC *unit, int inNumSamples); void BufAllpassN_Ctor(BufAllpassN *unit); void BufAllpassN_next(BufAllpassN *unit, int inNumSamples); void BufAllpassN_next_z(BufAllpassN *unit, int inNumSamples); void BufAllpassN_next_a(BufAllpassN *unit, int inNumSamples); void BufAllpassN_next_a_z(BufAllpassN *unit, int inNumSamples); void BufAllpassL_Ctor(BufAllpassL *unit); void BufAllpassL_next(BufAllpassL *unit, int inNumSamples); void BufAllpassL_next_z(BufAllpassL *unit, int inNumSamples); void BufAllpassL_next_a(BufAllpassL *unit, int inNumSamples); void BufAllpassL_next_a_z(BufAllpassL *unit, int inNumSamples); void BufAllpassC_Ctor(BufAllpassC *unit); void BufAllpassC_next(BufAllpassC *unit, int inNumSamples); void BufAllpassC_next_z(BufAllpassC *unit, int inNumSamples); void BufAllpassC_next_a(BufAllpassC *unit, int inNumSamples); void BufAllpassC_next_a_z(BufAllpassC *unit, int inNumSamples); void DelayUnit_Dtor(DelayUnit *unit); void DelayN_Ctor(DelayN *unit); void DelayN_next(DelayN *unit, int inNumSamples); void DelayN_next_z(DelayN *unit, int inNumSamples); void DelayN_next_a(DelayN *unit, int inNumSamples); void DelayN_next_a_z(DelayN *unit, int inNumSamples); void DelayL_Ctor(DelayL *unit); void DelayL_next(DelayL *unit, int inNumSamples); void DelayL_next_z(DelayL *unit, int inNumSamples); void DelayL_next_a(DelayL *unit, int inNumSamples); void DelayL_next_a_z(DelayL *unit, int inNumSamples); void DelayC_Ctor(DelayC *unit); void DelayC_next(DelayC *unit, int inNumSamples); void DelayC_next_z(DelayC *unit, int inNumSamples); void DelayC_next_a(DelayC *unit, int inNumSamples); void DelayC_next_a_z(DelayC *unit, int inNumSamples); void CombN_Ctor(CombN *unit); void CombN_next(CombN *unit, int inNumSamples); void CombN_next_z(CombN *unit, int inNumSamples); void CombN_next_a(CombN *unit, int inNumSamples); void CombN_next_a_z(CombN *unit, int inNumSamples); void CombL_Ctor(CombL *unit); void CombL_next(CombL *unit, int inNumSamples); void CombL_next_z(CombL *unit, int inNumSamples); void CombL_next_a(CombL *unit, int inNumSamples); void CombL_next_a_z(CombL *unit, int inNumSamples); void CombC_Ctor(CombC *unit); void CombC_next(CombC *unit, int inNumSamples); void CombC_next_z(CombC *unit, int inNumSamples); void CombC_next_a(CombC *unit, int inNumSamples); void CombC_next_a_z(CombC *unit, int inNumSamples); void AllpassN_Ctor(AllpassN *unit); void AllpassN_next(AllpassN *unit, int inNumSamples); void AllpassN_next_z(AllpassN *unit, int inNumSamples); void AllpassN_next_a(AllpassN *unit, int inNumSamples); void AllpassN_next_a_z(AllpassN *unit, int inNumSamples); void AllpassL_Ctor(AllpassL *unit); void AllpassL_next(AllpassL *unit, int inNumSamples); void AllpassL_next_z(AllpassL *unit, int inNumSamples); void AllpassL_next_a(AllpassL *unit, int inNumSamples); void AllpassL_next_a_z(AllpassL *unit, int inNumSamples); void AllpassC_Ctor(AllpassC *unit); void AllpassC_next(AllpassC *unit, int inNumSamples); void AllpassC_next_z(AllpassC *unit, int inNumSamples); void AllpassC_next_a(AllpassC *unit, int inNumSamples); void AllpassC_next_a_z(AllpassC *unit, int inNumSamples); void ScopeOut_next(ScopeOut *unit, int inNumSamples); void ScopeOut_Ctor(ScopeOut *unit); void ScopeOut_Dtor(ScopeOut *unit); void Pluck_Ctor(Pluck* unit); void Pluck_next_aa(Pluck *unit, int inNumSamples); void Pluck_next_aa_z(Pluck *unit, int inNumSamples); void Pluck_next_kk(Pluck *unit, int inNumSamples); void Pluck_next_kk_z(Pluck *unit, int inNumSamples); void Pluck_next_ka(Pluck *unit, int inNumSamples); void Pluck_next_ka_z(Pluck *unit, int inNumSamples); void Pluck_next_ak(Pluck *unit, int inNumSamples); void Pluck_next_ak_z(Pluck *unit, int inNumSamples); void DelTapWr_Ctor(DelTapWr* unit); void DelTapWr_next(DelTapWr *unit, int inNumSamples); void DelTapWr_next_simd(DelTapWr *unit, int inNumSamples); void DelTapRd_Ctor(DelTapRd* unit); void DelTapRd_next1_a(DelTapRd *unit, int inNumSamples); void DelTapRd_next2_a(DelTapRd *unit, int inNumSamples); void DelTapRd_next4_a(DelTapRd *unit, int inNumSamples); void DelTapRd_next1_k(DelTapRd *unit, int inNumSamples); void DelTapRd_next1_k_simd(DelTapRd *unit, int inNumSamples); void DelTapRd_next2_k(DelTapRd *unit, int inNumSamples); void DelTapRd_next4_k(DelTapRd *unit, int inNumSamples); } ////////////////////////////////////////////////////////////////////////////////////////////////// void SampleRate_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mSampleRate; } void ControlRate_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mBufRate.mSampleRate; } void SampleDur_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mFullRate.mSampleDur; } void ControlDur_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mFullRate.mBufDuration; } void RadiansPerSample_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mFullRate.mRadiansPerSample; } void BlockSize_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mFullRate.mBufLength; } void SubsampleOffset_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mParent->mSubsampleOffset; } void NumInputBuses_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mNumInputs; } void NumOutputBuses_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mNumOutputs; } void NumAudioBuses_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mNumAudioBusChannels; } void NumControlBuses_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mNumControlBusChannels; } void NumBuffers_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mNumSndBufs; } void NodeID_Ctor(Unit *unit, int inNumSamples) { ZOUT0(0) = (float) unit->mParent->mNode.mID; } ////////////////////////////////////////////////////////////////////////////////////////////////// void NumRunningSynths_Ctor(Unit *unit, int inNumSamples) { if(INRATE(0) != calc_ScalarRate) { SETCALC(NumRunningSynths_next); } ZOUT0(0) = unit->mWorld->mNumGraphs; } void NumRunningSynths_next(Unit *unit, int inNumSamples) { ZOUT0(0) = unit->mWorld->mNumGraphs; } ////////////////////////////////////////////////////////////////////////////////////////////////// #define CTOR_GET_BUF \ float fbufnum = ZIN0(0); \ fbufnum = sc_max(0.f, fbufnum); \ uint32 bufnum = (int)fbufnum; \ World *world = unit->mWorld; \ SndBuf *buf; \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ buf = world->mSndBufs + bufnum; \ } \ } else { \ buf = world->mSndBufs + bufnum; \ } void BufSampleRate_next(BufInfoUnit *unit, int inNumSamples) { SIMPLE_GET_BUF_SHARED ZOUT0(0) = buf->samplerate; } void BufSampleRate_Ctor(BufInfoUnit *unit, int inNumSamples) { SETCALC(BufSampleRate_next); CTOR_GET_BUF unit->m_fbufnum = fbufnum; unit->m_buf = buf; ZOUT0(0) = buf->samplerate; } void BufFrames_next(BufInfoUnit *unit, int inNumSamples) { SIMPLE_GET_BUF_SHARED ZOUT0(0) = buf->frames; } void BufFrames_Ctor(BufInfoUnit *unit, int inNumSamples) { SETCALC(BufFrames_next); CTOR_GET_BUF unit->m_fbufnum = fbufnum; unit->m_buf = buf; ZOUT0(0) = buf->frames; } void BufDur_next(BufInfoUnit *unit, int inNumSamples) { SIMPLE_GET_BUF_SHARED ZOUT0(0) = buf->frames * buf->sampledur; } void BufDur_Ctor(BufInfoUnit *unit, int inNumSamples) { SETCALC(BufDur_next); CTOR_GET_BUF unit->m_fbufnum = fbufnum; unit->m_buf = buf; ZOUT0(0) = buf->frames * buf->sampledur; } void BufChannels_next(BufInfoUnit *unit, int inNumSamples) { SIMPLE_GET_BUF_SHARED ZOUT0(0) = buf->channels; } void BufChannels_Ctor(BufInfoUnit *unit, int inNumSamples) { SETCALC(BufChannels_next); CTOR_GET_BUF unit->m_fbufnum = fbufnum; unit->m_buf = buf; ZOUT0(0) = buf->channels; } void BufSamples_next(BufInfoUnit *unit, int inNumSamples) { SIMPLE_GET_BUF_SHARED ZOUT0(0) = buf->samples; } void BufSamples_Ctor(BufInfoUnit *unit, int inNumSamples) { SETCALC(BufSamples_next); CTOR_GET_BUF unit->m_fbufnum = fbufnum; unit->m_buf = buf; ZOUT0(0) = buf->samples; } void BufRateScale_next(BufInfoUnit *unit, int inNumSamples) { SIMPLE_GET_BUF_SHARED ZOUT0(0) = buf->samplerate * unit->mWorld->mFullRate.mSampleDur; } void BufRateScale_Ctor(BufInfoUnit *unit, int inNumSamples) { SETCALC(BufRateScale_next); CTOR_GET_BUF unit->m_fbufnum = fbufnum; unit->m_buf = buf; ZOUT0(0) = buf->samplerate * unit->mWorld->mFullRate.mSampleDur; } ////////////////////////////////////////////////////////////////////////////////////////////////// inline int32 BUFMASK(int32 x) { return (1 << (31 - CLZ(x))) - 1; } static void LocalBuf_allocBuffer(LocalBuf *unit, SndBuf *buf, int numChannels, int numFrames) { int numSamples = numFrames * numChannels; // Print("bufnum: %i, allocating %i channels and %i frames. memsize: %i\n", (int)unit->m_fbufnum, numChannels, numFrames, numSamples * sizeof(float)); const int alignment = 128; // in bytes unit->chunk = (float*)RTAlloc(unit->mWorld, numSamples * sizeof(float) + alignment); if (!unit->chunk) { if(unit->mWorld->mVerbosity > -2){ Print("failed to allocate memory for LocalBuffer\n"); } return; } buf->data = (float*) ((intptr_t)((char*)unit->chunk + (alignment - 1)) & -alignment); buf->channels = numChannels; buf->frames = numFrames; buf->samples = numSamples; buf->mask = BUFMASK(numSamples); // for delay lines buf->mask1 = buf->mask - 1; // for oscillators buf->samplerate = unit->mWorld->mSampleRate; buf->sampledur = 1. / buf->samplerate; #if SUPERNOVA buf->isLocal = true; #endif } void LocalBuf_Ctor(LocalBuf *unit) { Graph *parent = unit->mParent; int offset = unit->mWorld->mNumSndBufs; int bufnum = parent->localBufNum; float fbufnum; if (parent->localBufNum >= parent->localMaxBufNum) { fbufnum = -1.f; if(unit->mWorld->mVerbosity > -2) printf("warning: LocalBuf tried to allocate too many local buffers.\n"); } else { fbufnum = (float) (bufnum + offset); unit->m_buf = parent->mLocalSndBufs + bufnum; parent->localBufNum = parent->localBufNum + 1; LocalBuf_allocBuffer(unit, unit->m_buf, (int)IN0(0), (int)IN0(1)); } OUT0(0) = fbufnum; } void LocalBuf_Dtor(LocalBuf *unit) { RTFree(unit->mWorld, unit->chunk); if(unit->mParent->localBufNum <= 1) { // only the last time. for (int i = 0; i != unit->mParent->localMaxBufNum; ++i) unit->mParent->mLocalSndBufs[i].~SndBuf(); RTFree(unit->mWorld, unit->mParent->mLocalSndBufs); unit->mParent->localMaxBufNum = 0; } else unit->mParent->localBufNum = unit->mParent->localBufNum - 1; } ////////////////////////////////////////////////////////////////////////////////////////////////// void MaxLocalBufs_Ctor(MaxLocalBufs *unit) { Graph *parent = unit->mParent; int maxBufNum = (int)(IN0(0) + .5f); if(!parent->localMaxBufNum) { parent->mLocalSndBufs = (SndBuf*)RTAlloc(unit->mWorld, maxBufNum * sizeof(SndBuf)); #ifdef SUPERNOVA for (int i = 0; i != maxBufNum; ++i) new(&parent->mLocalSndBufs[i]) SndBuf(); #endif parent->localMaxBufNum = maxBufNum; } else printf("warning: MaxLocalBufs - maximum number of local buffers is already declared (%i) and must remain unchanged.\n", parent->localMaxBufNum); } ////////////////////////////////////////////////////////////////////////////////////////////////// void SetBuf_Ctor(SetBuf *unit) { OUT0(0) = 0.f; CTOR_GET_BUF if (!buf || !buf->data) { if(unit->mWorld->mVerbosity > -2){ Print("SetBuf: no valid buffer\n"); } return; } int offset = (int)IN0(1); int numArgs = (int)IN0(2); int end = sc_min(buf->samples, numArgs + offset); int j = 3; for(int i=offset; idata[i] = IN0(j); } } ////////////////////////////////////////////////////////////////////////////////////////////////// void ClearBuf_Ctor(ClearBuf *unit) { OUT0(0) = 0.f; CTOR_GET_BUF if (!buf || !buf->data) { if(unit->mWorld->mVerbosity > -2){ Print("ClearBuf: no valid buffer\n"); } return; } Clear(buf->samples, buf->data); } //////////////////////////////////////////////////////////////////////////////////////////////////////// inline double sc_loop(Unit *unit, double in, double hi, int loop) { // avoid the divide if possible if (in >= hi) { if (!loop) { unit->mDone = true; return hi; } in -= hi; if (in < hi) return in; } else if (in < 0.) { if (!loop) { unit->mDone = true; return 0.; } in += hi; if (in >= 0.) return in; } else return in; return in - hi * floor(in/hi); } #define CHECK_BUF \ if (!bufData) { \ unit->mDone = true; \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } static inline bool checkBuffer(Unit * unit, const float * bufData, uint32 bufChannels, uint32 expectedChannels, int inNumSamples) { if (!bufData) goto handle_failure; if (expectedChannels > bufChannels) { if(unit->mWorld->mVerbosity > -1 && !unit->mDone) Print("Buffer UGen channel mismatch: expected %i, yet buffer has %i channels\n", expectedChannels, bufChannels); goto handle_failure; } return true; handle_failure: unit->mDone = true; ClearUnitOutputs(unit, inNumSamples); return false; } #define SETUP_IN(offset) \ uint32 numInputs = unit->mNumInputs - (uint32)offset; \ if (numInputs != bufChannels) { \ if(unit->mWorld->mVerbosity > -1 && !unit->mDone){ \ Print("buffer-writing UGen channel mismatch: numInputs %i, yet buffer has %i channels\n", numInputs, bufChannels); \ } \ unit->mDone = true; \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } \ if(!unit->mIn){ \ unit->mIn = (float**)RTAlloc(unit->mWorld, numInputs * sizeof(float*)); \ if (unit->mIn == NULL) { \ unit->mDone = true; \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } \ } \ float **in = unit->mIn; \ for (uint32 i=0; imIn){ \ RTFree(unit->mWorld, unit->mIn); \ } #define LOOP_INNER_BODY_1(SAMPLE_INDEX) \ OUT(channel)[SAMPLE_INDEX] = table1[index]; \ #define LOOP_INNER_BODY_2(SAMPLE_INDEX) \ float b = table1[index]; \ float c = table2[index]; \ OUT(channel)[SAMPLE_INDEX] = b + fracphase * (c - b); \ #define LOOP_INNER_BODY_4(SAMPLE_INDEX) \ float a = table0[index]; \ float b = table1[index]; \ float c = table2[index]; \ float d = table3[index]; \ OUT(channel)[SAMPLE_INDEX] = cubicinterp(fracphase, a, b, c, d); \ #define LOOP_BODY_4(SAMPLE_INDEX) \ phase = sc_loop((Unit*)unit, phase, loopMax, loop); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase * bufChannels; \ const float* table0 = table1 - bufChannels; \ const float* table2 = table1 + bufChannels; \ const float* table3 = table2 + bufChannels; \ if (iphase == 0) { \ if (loop) { \ table0 += bufSamples; \ } else { \ table0 += bufChannels; \ } \ } else if (iphase >= guardFrame) { \ if (iphase == guardFrame) { \ if (loop) { \ table3 -= bufSamples; \ } else { \ table3 -= bufChannels; \ } \ } else { \ if (loop) { \ table2 -= bufSamples; \ table3 -= bufSamples; \ } else { \ table2 -= bufChannels; \ table3 -= 2 * bufChannels; \ } \ } \ } \ int32 index = 0; \ float fracphase = phase - (double)iphase; \ if(numOutputs == bufChannels) { \ for (uint32 channel=0; channel guardFrame) { \ if (loop) { \ table2 -= bufSamples; \ } else { \ table2 -= bufChannels; \ } \ } \ int32 index = 0; \ float fracphase = phase - (double)iphase; \ if(numOutputs == bufChannels) { \ for (uint32 channel=0; channelmWorld->mVerbosity > -1 && !unit->mDone && (unit->m_failedBufNum != fbufnum)) { \ Print("Buffer UGen: no buffer data\n"); \ unit->m_failedBufNum = fbufnum; \ } \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } else { \ if (bufChannels != numOutputs) { \ if(unit->mWorld->mVerbosity > -1 && !unit->mDone && (unit->m_failedBufNum != fbufnum)) { \ Print("Buffer UGen channel mismatch: expected %i, yet buffer has %i channels\n", \ numOutputs, bufChannels); \ unit->m_failedBufNum = fbufnum; \ } \ } \ } \ void PlayBuf_Ctor(PlayBuf *unit) { if (INRATE(1) == calc_FullRate) { if (INRATE(2) == calc_FullRate) { SETCALC(PlayBuf_next_aa); } else { SETCALC(PlayBuf_next_ak); } } else { if (INRATE(2) == calc_FullRate) { SETCALC(PlayBuf_next_ka); } else { SETCALC(PlayBuf_next_kk); } } unit->m_fbufnum = -1e9f; unit->m_failedBufNum = -1e9f; unit->m_prevtrig = 0.; unit->m_phase = ZIN0(3); ClearUnitOutputs(unit, 1); } void PlayBuf_next_aa(PlayBuf *unit, int inNumSamples) { float *ratein = ZIN(1); float *trigin = ZIN(2); int32 loop = (int32)ZIN0(4); float fbufnum = ZIN0(0); if (fbufnum != unit->m_fbufnum) { uint32 bufnum = (int)fbufnum; World *world = unit->mWorld; if (bufnum >= world->mNumSndBufs) bufnum = 0; unit->m_fbufnum = fbufnum; unit->m_buf = world->mSndBufs + bufnum; } const SndBuf *buf = unit->m_buf; ACQUIRE_SNDBUF_SHARED(buf); const float *bufData __attribute__((__unused__)) = buf->data; uint32 bufChannels __attribute__((__unused__)) = buf->channels; uint32 bufSamples __attribute__((__unused__)) = buf->samples; uint32 bufFrames = buf->frames; int mask __attribute__((__unused__)) = buf->mask; int guardFrame __attribute__((__unused__)) = bufFrames - 2; int numOutputs = unit->mNumOutputs; CHECK_BUFFER_DATA; double loopMax = (double)(loop ? bufFrames : bufFrames - 1); double phase = unit->m_phase; float prevtrig = unit->m_prevtrig; for (int i=0; i 0.f && prevtrig <= 0.f) { unit->mDone = false; phase = ZIN0(3); } prevtrig = trig; LOOP_BODY_4(i) phase += ZXP(ratein); } RELEASE_SNDBUF_SHARED(buf); if(unit->mDone) DoneAction((int)ZIN0(5), unit); unit->m_phase = phase; unit->m_prevtrig = prevtrig; } void PlayBuf_next_ak(PlayBuf *unit, int inNumSamples) { float *ratein = ZIN(1); float trig = ZIN0(2); int32 loop = (int32)ZIN0(4); float fbufnum = ZIN0(0); if (fbufnum != unit->m_fbufnum) { uint32 bufnum = (int)fbufnum; World *world = unit->mWorld; if (bufnum >= world->mNumSndBufs) bufnum = 0; unit->m_fbufnum = fbufnum; unit->m_buf = world->mSndBufs + bufnum; } const SndBuf *buf = unit->m_buf; ACQUIRE_SNDBUF_SHARED(buf); const float *bufData __attribute__((__unused__)) = buf->data; uint32 bufChannels __attribute__((__unused__)) = buf->channels; uint32 bufSamples __attribute__((__unused__)) = buf->samples; uint32 bufFrames = buf->frames; int mask __attribute__((__unused__)) = buf->mask; int guardFrame __attribute__((__unused__)) = bufFrames - 2; int numOutputs = unit->mNumOutputs; CHECK_BUFFER_DATA double loopMax = (double)(loop ? bufFrames : bufFrames - 1); double phase = unit->m_phase; if(phase == -1.) phase = bufFrames; if (trig > 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; phase = ZIN0(3); } unit->m_prevtrig = trig; for (int i=0; imDone) DoneAction((int)ZIN0(5), unit); unit->m_phase = phase; } void PlayBuf_next_kk(PlayBuf *unit, int inNumSamples) { float rate = ZIN0(1); float trig = ZIN0(2); int32 loop = (int32)ZIN0(4); GET_BUF_SHARED int numOutputs = unit->mNumOutputs; CHECK_BUFFER_DATA double loopMax = (double)(loop ? bufFrames : bufFrames - 1); double phase = unit->m_phase; if (trig > 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; phase = ZIN0(3); } unit->m_prevtrig = trig; for (int i=0; imDone) DoneAction((int)ZIN0(5), unit); unit->m_phase = phase; } void PlayBuf_next_ka(PlayBuf *unit, int inNumSamples) { float rate = ZIN0(1); float *trigin = ZIN(2); int32 loop = (int32)ZIN0(4); GET_BUF_SHARED int numOutputs = unit->mNumOutputs; CHECK_BUFFER_DATA double loopMax = (double)(loop ? bufFrames : bufFrames - 1); double phase = unit->m_phase; float prevtrig = unit->m_prevtrig; for (int i=0; i 0.f && prevtrig <= 0.f) { unit->mDone = false; if (INRATE(3) == calc_FullRate) phase = IN(3)[i]; else phase = ZIN0(3); } prevtrig = trig; LOOP_BODY_4(i) phase += rate; } if(unit->mDone) DoneAction((int)ZIN0(5), unit); unit->m_phase = phase; unit->m_prevtrig = prevtrig; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufRd_Ctor(BufRd *unit) { int interp = (int)ZIN0(3); switch (interp) { case 1 : SETCALC(BufRd_next_1); break; case 2 : SETCALC(BufRd_next_2); break; default : SETCALC(BufRd_next_4); break; } unit->m_fbufnum = -1e9f; unit->m_failedBufNum = -1e9f; BufRd_next_1(unit, 1); } void BufRd_next_4(BufRd *unit, int inNumSamples) { float *phasein = ZIN(1); int32 loop = (int32)ZIN0(2); GET_BUF_SHARED uint32 numOutputs = unit->mNumOutputs; CHECK_BUFFER_DATA double loopMax = (double)(loop ? bufFrames : bufFrames - 1); for (int i=0; imNumOutputs; CHECK_BUFFER_DATA double loopMax = (double)(loop ? bufFrames : bufFrames - 1); for (int i=0; imNumOutputs; CHECK_BUFFER_DATA double loopMax = (double)(loop ? bufFrames : bufFrames - 1); for (int i=0; im_fbufnum = -1e9f; ClearUnitOutputs(unit, 1); } void BufWr_next(BufWr *unit, int inNumSamples) { float *phasein = ZIN(1); int32 loop = (int32)ZIN0(2); GET_BUF uint32 numInputChannels = unit->mNumInputs - 3; if (!checkBuffer(unit, bufData, bufChannels, numInputChannels, inNumSamples)) return; double loopMax = (double)(bufFrames - (loop ? 0 : 1)); for (int32 k=0; kmNumInputs - 8; unit->m_fbufnum = -1e9f; unit->mIn = 0; unit->m_writepos = (int32)ZIN0(1) * numInputs; unit->m_recLevel = ZIN0(2); unit->m_preLevel = ZIN0(3); unit->m_prevtrig = 0.f; if (INRATE(2) == calc_ScalarRate && INRATE(3) == calc_ScalarRate && unit->m_recLevel == 1.0 && unit->m_preLevel == 0.0) { SETCALC(RecordBuf_next_10); } else { SETCALC(RecordBuf_next); } ClearUnitOutputs(unit, 1); } void RecordBuf_Dtor(RecordBuf *unit) { TAKEDOWN_IN } void RecordBuf_next(RecordBuf *unit, int inNumSamples) { //printf("RecordBuf_next\n"); GET_BUF CHECK_BUF SETUP_IN(8) float recLevel = ZIN0(2); float preLevel = ZIN0(3); float run = ZIN0(4); int32 loop = (int32)ZIN0(5); float trig = ZIN0(6); //printf("loop %d run %g\n", loop, run); int32 writepos = unit->m_writepos; float recLevel_slope = CALCSLOPE(recLevel, unit->m_recLevel); float preLevel_slope = CALCSLOPE(preLevel, unit->m_preLevel); /* reset recLevel and preLevel to use the previous value ... bug fix */ recLevel = unit->m_recLevel; preLevel = unit->m_preLevel; if (loop) { if (trig > 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; writepos = (int32)ZIN0(1) * bufChannels; } if (writepos < 0) writepos = bufSamples - bufChannels; else if (writepos >= (int32)bufSamples) writepos = 0; if (run > 0.f) { if (bufChannels == 1) { for (int32 k=0; k= (int32)bufSamples) writepos = 0; recLevel += recLevel_slope; preLevel += preLevel_slope; } } else if (bufChannels == 2 && numInputs == 2) { for (int32 k=0; k= (int32)bufSamples) writepos = 0; recLevel += recLevel_slope; preLevel += preLevel_slope; } } else { for (int32 k=0; k= (int32)bufSamples) writepos = 0; recLevel += recLevel_slope; preLevel += preLevel_slope; } } } else if (run < 0.f) { if (bufChannels == 1) { for (int32 k=0; k 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; writepos = (int32)ZIN0(1) * bufChannels; } if (run > 0.f) { int nsmps = bufSamples - writepos; nsmps = sc_clip(nsmps, 0, inNumSamples * bufChannels); if (bufChannels == 1) { for (int32 k=0; k= (int32)bufSamples){ unit->mDone = true; DoneAction(IN0(7), unit); } } unit->m_prevtrig = trig; unit->m_writepos = writepos; unit->m_recLevel = recLevel; unit->m_preLevel = preLevel; } void RecordBuf_next_10(RecordBuf *unit, int inNumSamples) { // printf("RecordBuf_next_10\n"); GET_BUF CHECK_BUF SETUP_IN(8) float run = ZIN0(4); int32 loop = (int32)ZIN0(5); float trig = ZIN0(6); //printf("loop %d run %g\n", loop, run); int32 writepos = unit->m_writepos; if (loop) { if (trig > 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; writepos = (int32)ZIN0(1) * bufChannels; } if (writepos < 0) writepos = bufSamples - bufChannels; else if (writepos >= (int32)bufSamples) writepos = 0; if (run > 0.f) { if (bufChannels == 1) { for (int32 k=0; k= (int32)bufSamples) writepos = 0; } } else if (bufChannels == 2) { for (int32 k=0; k= (int32)bufSamples) writepos = 0; } } else { for (int32 k=0; k= (int32)bufSamples) writepos = 0; } } } else if (run < 0.f) { if (bufChannels == 1) { for (int32 k=0; k 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; writepos = (int32)ZIN0(1) * bufChannels; } if (run > 0.f) { int nsmps = bufSamples - writepos; nsmps = sc_clip(nsmps, 0, inNumSamples * bufChannels); if (bufChannels == 1) { for (int32 k=0; k= (int32)bufSamples){ unit->mDone = true; DoneAction(IN0(7), unit); } } unit->m_prevtrig = trig; unit->m_writepos = writepos; } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// static float insertMedian(float* values, int* ages, int size, float value) { int pos=-1; // keeps a sorted list of the previous n=size values // the oldest is removed and the newest is inserted. // values between the oldest and the newest are shifted over by one. // values and ages are both arrays that are 'size' int. // the median value is always values[size>>1] int last = size - 1; // find oldest bin and age the other bins. for (int i=0; i values[pos+1]) { values[pos] = values[pos+1]; ages[pos] = ages[pos+1]; pos++; } values[pos] = value; ages[pos] = 0; // this is the newest bin, age = 0 return values[size>>1]; } static void initMedian(float* values, int* ages, int size, float value) { // initialize the arrays with the first value for (int i=0; im_freq = ZIN0(kPitchInitFreq); unit->m_minfreq = ZIN0(kPitchMinFreq); unit->m_maxfreq = ZIN0(kPitchMaxFreq); float execfreq = ZIN0(kPitchExecFreq); execfreq = sc_clip(execfreq, unit->m_minfreq, unit->m_maxfreq); int maxbins = (int)ZIN0(kPitchMaxBins); unit->m_maxlog2bins = LOG2CEIL(maxbins); unit->m_medianSize = sc_clip((int)ZIN0(0), 0, kMAXMEDIANSIZE); // (int)ZIN0(kPitchMedian); unit->m_ampthresh = ZIN0(kPitchAmpThreshold); unit->m_peakthresh = ZIN0(kPitchPeakThreshold); int downsamp = (int)ZIN0(kPitchDownsamp); if (INRATE(kPitchIn) == calc_FullRate) { SETCALC(Pitch_next_a); unit->m_downsamp = sc_clip(downsamp, 1, unit->mWorld->mFullRate.mBufLength); unit->m_srate = FULLRATE / (float)unit->m_downsamp; } else { SETCALC(Pitch_next_k); unit->m_downsamp = sc_max(downsamp, 1); unit->m_srate = FULLRATE / (float) (unit->mWorld->mFullRate.mBufLength*unit->m_downsamp); } unit->m_minperiod = (long)(unit->m_srate / unit->m_maxfreq); unit->m_maxperiod = (long)(unit->m_srate / unit->m_minfreq); unit->m_execPeriod = (int)(unit->m_srate / execfreq); unit->m_execPeriod = sc_max(unit->m_execPeriod, unit->mWorld->mFullRate.mBufLength); unit->m_size = sc_max(unit->m_maxperiod << 1, unit->m_execPeriod); unit->m_buffer = (float*)RTAlloc(unit->mWorld, unit->m_size * sizeof(float)); unit->m_index = 0; unit->m_readp = 0; unit->m_hasfreq = 0.f; initMedian(unit->m_values, unit->m_ages, unit->m_medianSize, unit->m_freq); unit->m_getClarity = ZIN0(kPitchGetClarity) > 0.f; ZOUT0(0) = 0.f; ZOUT0(1) = 0.f; } void Pitch_Dtor(Pitch *unit) { RTFree(unit->mWorld, unit->m_buffer); } void Pitch_next_a(Pitch *unit, int inNumSamples) { bool foundPeak; float* in = ZIN(kPitchIn); uint32 size = unit->m_size; uint32 index = unit->m_index; int downsamp = unit->m_downsamp; int readp = unit->m_readp; int ksamps = unit->mWorld->mFullRate.mBufLength; float *bufData = unit->m_buffer; float freq = unit->m_freq; float hasfreq = unit->m_hasfreq; //printf("> %d %d readp %d ksamps %d ds %d\n", index, size, readp, ksamps, downsamp); do { float z = in[readp]; bufData[index++] = z; readp += downsamp; if (index >= size) { float ampthresh = unit->m_ampthresh; bool ampok = false; hasfreq = 0.f; // assume failure int minperiod = unit->m_minperiod; int maxperiod = unit->m_maxperiod; //float maxamp = 0.f; // check for amp threshold for (int j = 0; j < maxperiod; ++j) { if (fabs(bufData[j]) >= ampthresh) { ampok = true; break; } //if (fabs(bufData[j]) > maxamp) maxamp = fabs(bufData[j]); } //printf("ampok %d maxperiod %d maxamp %g\n", ampok, maxperiod, maxamp); // if amplitude is too small then don't even look for pitch float ampsum; if (ampok) { int maxlog2bins = unit->m_maxlog2bins; int octave; // calculate the zero lag value and compute the threshold based on that float zerolagval = 0.f; for (int j = 0; j < maxperiod; ++j) { zerolagval += bufData[j] * bufData[j]; } float threshold = zerolagval * unit->m_peakthresh; // skip until drop below threshold int binstep, peakbinstep = 0; int i; for (i = 1; i <= maxperiod; i += binstep) { // compute sum of one lag ampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { ampsum += bufData[i+j] * bufData[j]; } if (ampsum < threshold) break; octave = LOG2CEIL(i); if (octave <= maxlog2bins) { binstep = 1; } else { binstep = 1L << (octave - maxlog2bins); } } int startperiod = i; int period = startperiod; //printf("startperiod %d\n", startperiod); // find the first peak float maxsum = threshold; foundPeak = false; for (i = startperiod; i <= maxperiod; i += binstep) { if (i >= minperiod) { ampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { ampsum += bufData[i+j] * bufData[j]; } if (ampsum > threshold) { if (ampsum > maxsum) { foundPeak = true; maxsum = ampsum; peakbinstep = binstep; period = i; } } else if (foundPeak) break; } octave = LOG2CEIL(i); if (octave <= maxlog2bins) { binstep = 1; } else { binstep = 1L << (octave - maxlog2bins); } } //printf("found %d thr %g maxs %g per %d bs %d\n", foundPeak, threshold, maxsum, period, peakbinstep); if (foundPeak) { float prevampsum, nextampsum; // find amp sums immediately surrounding max prevampsum = 0.f; if (period > 0) { i = period - 1; for (int j = 0; j < maxperiod; ++j) { prevampsum += bufData[i+j] * bufData[j]; } } nextampsum = 0.f; if (period < maxperiod) { i = period + 1; for (int j = 0; j < maxperiod; ++j) { nextampsum += bufData[i+j] * bufData[j]; } } //printf("prevnext %g %g %g %d\n", prevampsum, maxsum, nextampsum, period); // not on a peak yet. This can happen if binstep > 1 while (prevampsum > maxsum && period > 0) { nextampsum = maxsum; maxsum = prevampsum; period--; i = period - 1; prevampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { prevampsum += bufData[i+j] * bufData[j]; } //printf("slide left %g %g %g %d\n", prevampsum, maxsum, nextampsum, period); } while (nextampsum > maxsum && period < maxperiod) { prevampsum = maxsum; maxsum = nextampsum; period++; i = period + 1; nextampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { nextampsum += bufData[i+j] * bufData[j]; } //printf("slide right %g %g %g %d\n", prevampsum, maxsum, nextampsum, period); } // make a fractional period float beta = 0.5f * (nextampsum - prevampsum); float gamma = 2.f * maxsum - nextampsum - prevampsum; float fperiod = (float)period + (beta/gamma); // calculate frequency float tempfreq = unit->m_srate / fperiod; //printf("freq %g %g / %g %g %g %d\n", tempfreq, unit->m_srate, fperiod, // unit->m_minfreq, unit->m_maxfreq, // tempfreq >= unit->m_minfreq && tempfreq <= unit->m_maxfreq); if (tempfreq >= unit->m_minfreq && tempfreq <= unit->m_maxfreq) { freq = tempfreq; // median filter if (unit->m_medianSize > 1) { freq = insertMedian(unit->m_values, unit->m_ages, unit->m_medianSize, freq); } if(unit->m_getClarity) hasfreq = maxsum / zerolagval; // "clarity" measure is normalised size of first peak else hasfreq = 1.f; startperiod = (ksamps+downsamp-1)/downsamp; } } }/* else { printf("amp too low \n"); }*/ // shift buffer for next fill int execPeriod = unit->m_execPeriod; int interval = size - execPeriod; //printf("interval %d sz %d ep %d\n", interval, size, execPeriod); for (int i = 0; i < interval; i++) { bufData[i] = bufData[i + execPeriod]; } index = interval; } } while (readp < ksamps); ZOUT0(0) = freq; ZOUT0(1) = hasfreq; unit->m_readp = readp - ksamps; unit->m_index = index; unit->m_freq = freq; unit->m_hasfreq = hasfreq; } // control rate pitch tracking (nescivi 11/2008) void Pitch_next_k(Pitch *unit, int inNumSamples) { bool foundPeak; float in = ZIN0(kPitchIn); // one sample, current input uint32 size = unit->m_size; uint32 index = unit->m_index; int downsamp = unit->m_downsamp; int readp = unit->m_readp; // int ksamps = unit->mWorld->mFullRate.mBufLength; float *bufData = unit->m_buffer; float freq = unit->m_freq; float hasfreq = unit->m_hasfreq; // printf("> %d %d readp %d downsamp %d exec %d\n", index, size, readp, downsamp, unit->m_execPeriod); readp++; if ( readp == downsamp ){ // do { // float z = in[readp]; float z = in; bufData[index++] = z; readp = 0; // readp += downsamp; if (index >= size) { float ampthresh = unit->m_ampthresh; bool ampok = false; hasfreq = 0.f; // assume failure int minperiod = unit->m_minperiod; int maxperiod = unit->m_maxperiod; //float maxamp = 0.f; // check for amp threshold for (int j = 0; j < maxperiod; ++j) { if (fabs(bufData[j]) >= ampthresh) { ampok = true; break; } //if (fabs(bufData[j]) > maxamp) maxamp = fabs(bufData[j]); } //printf("ampok %d maxperiod %d maxamp %g\n", ampok, maxperiod, maxamp); // if amplitude is too small then don't even look for pitch float ampsum; if (ampok) { int maxlog2bins = unit->m_maxlog2bins; int octave; // calculate the zero lag value and compute the threshold based on that float zerolagval = 0.f; for (int j = 0; j < maxperiod; ++j) { zerolagval += bufData[j] * bufData[j]; } float threshold = zerolagval * unit->m_peakthresh; // skip until drop below threshold int binstep, peakbinstep = 0; int i; for (i = 1; i <= maxperiod; i += binstep) { // compute sum of one lag ampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { ampsum += bufData[i+j] * bufData[j]; } if (ampsum < threshold) break; octave = LOG2CEIL(i); if (octave <= maxlog2bins) { binstep = 1; } else { binstep = 1L << (octave - maxlog2bins); } } int startperiod = i; int period = startperiod; //printf("startperiod %d\n", startperiod); // find the first peak float maxsum = threshold; foundPeak = false; for (i = startperiod; i <= maxperiod; i += binstep) { if (i >= minperiod) { ampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { ampsum += bufData[i+j] * bufData[j]; } if (ampsum > threshold) { if (ampsum > maxsum) { foundPeak = true; maxsum = ampsum; peakbinstep = binstep; period = i; } } else if (foundPeak) break; } octave = LOG2CEIL(i); if (octave <= maxlog2bins) { binstep = 1; } else { binstep = 1L << (octave - maxlog2bins); } } //printf("found %d thr %g maxs %g per %d bs %d\n", foundPeak, threshold, maxsum, period, peakbinstep); if (foundPeak) { float prevampsum, nextampsum; // find amp sums immediately surrounding max prevampsum = 0.f; if (period > 0) { i = period - 1; for (int j = 0; j < maxperiod; ++j) { prevampsum += bufData[i+j] * bufData[j]; } } nextampsum = 0.f; if (period < maxperiod) { i = period + 1; for (int j = 0; j < maxperiod; ++j) { nextampsum += bufData[i+j] * bufData[j]; } } //printf("prevnext %g %g %g %d\n", prevampsum, maxsum, nextampsum, period); // not on a peak yet. This can happen if binstep > 1 while (prevampsum > maxsum && period > 0) { nextampsum = maxsum; maxsum = prevampsum; period--; i = period - 1; prevampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { prevampsum += bufData[i+j] * bufData[j]; } //printf("slide left %g %g %g %d\n", prevampsum, maxsum, nextampsum, period); } while (nextampsum > maxsum && period < maxperiod) { prevampsum = maxsum; maxsum = nextampsum; period++; i = period + 1; nextampsum = 0.f; for (int j = 0; j < maxperiod; ++j) { nextampsum += bufData[i+j] * bufData[j]; } //printf("slide right %g %g %g %d\n", prevampsum, maxsum, nextampsum, period); } // make a fractional period float beta = 0.5 * (nextampsum - prevampsum); float gamma = 2.0 * maxsum - nextampsum - prevampsum; float fperiod = (float)period + (beta/gamma); // calculate frequency float tempfreq = unit->m_srate / fperiod; //printf("freq %g %g / %g %g %g %d\n", tempfreq, unit->m_srate, fperiod, // unit->m_minfreq, unit->m_maxfreq, // tempfreq >= unit->m_minfreq && tempfreq <= unit->m_maxfreq); if (tempfreq >= unit->m_minfreq && tempfreq <= unit->m_maxfreq) { freq = tempfreq; // median filter if (unit->m_medianSize > 1) { freq = insertMedian(unit->m_values, unit->m_ages, unit->m_medianSize, freq); } if(unit->m_getClarity) hasfreq = maxsum / zerolagval; // "clarity" measure is normalised size of first peak else hasfreq = 1.f; // nescivi: not sure about this one? startperiod = 1; // (ksamps+downsamp-1)/downsamp; } } }/* else { printf("amp too low \n"); }*/ // shift buffer for next fill int execPeriod = unit->m_execPeriod; int interval = size - execPeriod; //printf("interval %d sz %d ep %d\n", interval, size, execPeriod); for (int i = 0; i < interval; i++) { bufData[i] = bufData[i + execPeriod]; } index = interval; } } //while (readp < ksamps); ZOUT0(0) = freq; ZOUT0(1) = hasfreq; // unit->m_readp = readp - ksamps; unit->m_readp = readp; unit->m_index = index; unit->m_freq = freq; unit->m_hasfreq = hasfreq; } //////////////////////////////////////////////////////////////////////////////////////////////////////// #if 0 void DelayUnit_AllocDelayLine(DelayUnit *unit) { long delaybufsize = (long)ceil(unit->m_maxdelaytime * SAMPLERATE + 1.f); delaybufsize = delaybufsize + BUFLENGTH; delaybufsize = NEXTPOWEROFTWO(delaybufsize); // round up to next power of two unit->m_fdelaylen = unit->m_idelaylen = delaybufsize; RTFree(unit->mWorld, unit->m_dlybuf); int size = delaybufsize * sizeof(float); //Print("->RTAlloc %d\n", size); unit->m_dlybuf = (float*)RTAlloc(unit->mWorld, size); //Print("<-RTAlloc %p\n", unit->m_dlybuf); unit->m_mask = delaybufsize - 1; } #endif template static float BufCalcDelay(const Unit * unit, int bufSamples, float delayTime) { float minDelay = Unit::minDelaySamples; return sc_clip(delayTime * (float)SAMPLERATE, minDelay, (float)(PREVIOUSPOWEROFTWO(bufSamples))-1); } template static void BufDelayUnit_Reset(Unit *unit) { //Print("->DelayUnit_Reset\n"); //unit->m_maxdelaytime = ZIN0(1); unit->m_delaytime = ZIN0(2); //Print("unit->m_delaytime %g\n", unit->m_delaytime); //unit->m_dlybuf = 0; unit->m_fbufnum = -1e9f; //DelayUnit_AllocDelayLine(unit); //Print("->GET_BUF\n"); GET_BUF //Print("<-GET_BUF\n"); unit->m_dsamp = BufCalcDelay(unit, bufSamples, unit->m_delaytime); unit->m_numoutput = 0; unit->m_iwrphase = 0; } //////////////////////////////////////////////////////////////////////////////////////////////////////// template static void BufFeedbackDelay_Reset(Unit *unit) { BufDelayUnit_Reset(unit); unit->m_decaytime = ZIN0(3); unit->m_feedbk = sc_CalcFeedback(unit->m_delaytime, unit->m_decaytime); } //////////////////////////////////////////////////////////////////////////////////////////////////////// namespace { /* helper classes for delay functionality */ template struct DelayN_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, long mask) { long irdphase = iwrphase - idsamp; bufData[iwrphase & mask] = ZXP(in); ZXP(out) = bufData[irdphase & mask]; iwrphase++; } /* the frac argument is unneeded. the compiler should make sure, that it won't be computed */ static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask) { perform(in, out, bufData, iwrphase, idsamp, mask); } }; template <> struct DelayN_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, long mask) { long irdphase = iwrphase - idsamp; bufData[iwrphase & mask] = ZXP(in); if (irdphase < 0) ZXP(out) = 0.f; else ZXP(out) = bufData[irdphase & mask]; iwrphase++; } static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask) { perform(in, out, bufData, iwrphase, idsamp, mask); } }; template static inline void DelayN_delay_loop(float * out, const float * in, long & iwrphase, float dsamp, long mask, float * dlybuf, int inNumSamples, int idelaylen) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = dlybuf - ZOFF; float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyN = dlybuf1 + idelaylen; long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; if (initializing) { long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { if ((dlywr - dlyrd) > nsmps) { #ifdef NOVA_SIMD if ((nsmps & (nova::vec::size - 1)) == 0) { nova::copyvec_nn_simd(dlywr + ZOFF, in + ZOFF, nsmps); nova::zerovec_na_simd(out + ZOFF, nsmps); } else #endif { ZCopy(nsmps, dlywr, in); ZClear(nsmps, out); } out += nsmps; in += nsmps; dlyrd += nsmps; dlywr += nsmps; } else { LOOP(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = 0.f; ); dlyrd += nsmps; } } else { LOOP(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = ZXP(dlyrd); ); } irdphase += nsmps; if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } else { long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (std::abs((float)(dlyrd - dlywr)) > nsmps) { #ifdef NOVA_SIMD if ((nsmps & 15) == 0) { nova::copyvec_nn_simd(dlywr + ZOFF, in + ZOFF, nsmps); nova::copyvec_nn_simd(out + ZOFF, dlyrd + ZOFF, nsmps); } else #endif { ZCopy(nsmps, dlywr, in); ZCopy(nsmps, out, dlyrd); } out += nsmps; in += nsmps; dlyrd += nsmps; dlywr += nsmps; } else LOOP(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = ZXP(dlyrd); ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } } iwrphase += inNumSamples; } template struct DelayL_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask) { bufData[iwrphase & mask] = ZXP(in); long irdphase = iwrphase - idsamp; long irdphaseb = irdphase - 1; float d1 = bufData[irdphase & mask]; float d2 = bufData[irdphaseb & mask]; ZXP(out) = lininterp(frac, d1, d2); iwrphase++; } }; template <> struct DelayL_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask) { bufData[iwrphase & mask] = ZXP(in); long irdphase = iwrphase - idsamp; long irdphaseb = irdphase - 1; if (irdphase < 0) { ZXP(out) = 0.f; } else if (irdphaseb < 0) { float d1 = bufData[irdphase & mask]; ZXP(out) = d1 - frac * d1; } else { float d1 = bufData[irdphase & mask]; float d2 = bufData[irdphaseb & mask]; ZXP(out) = lininterp(frac, d1, d2); } iwrphase++; } }; template struct DelayC_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask) { bufData[iwrphase & mask] = ZXP(in); long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = bufData[irdphase0 & mask]; float d1 = bufData[irdphase1 & mask]; float d2 = bufData[irdphase2 & mask]; float d3 = bufData[irdphase3 & mask]; ZXP(out) = cubicinterp(frac, d0, d1, d2, d3); iwrphase++; } }; template <> struct DelayC_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask) { long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; bufData[iwrphase & mask] = ZXP(in); if (irdphase0 < 0) { ZXP(out) = 0.f; } else { float d0, d1, d2, d3; if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = bufData[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; d2 = bufData[irdphase2 & mask]; } else { d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; d2 = bufData[irdphase2 & mask]; d3 = bufData[irdphase3 & mask]; } ZXP(out) = cubicinterp(frac, d0, d1, d2, d3); } iwrphase++; } }; template struct CombN_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, long mask, float feedbk) { long irdphase = iwrphase - idsamp; float value = bufData[irdphase & mask]; bufData[iwrphase & mask] = ZXP(in) + feedbk * value; ZXP(out) = value; ++iwrphase; } /* the frac argument is unneeded. the compiler should make sure, that it won't be computed */ static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { perform(in, out, bufData, iwrphase, idsamp, mask, feedbk); } }; template <> struct CombN_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, long mask, float feedbk) { long irdphase = iwrphase - idsamp; if (irdphase < 0) { bufData[iwrphase & mask] = ZXP(in); ZXP(out) = 0.f; } else { float value = bufData[irdphase & mask]; bufData[iwrphase & mask] = ZXP(in) + feedbk * value; ZXP(out) = value; } iwrphase++; } static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { perform(in, out, bufData, iwrphase, idsamp, mask, feedbk); } }; template struct CombL_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase = iwrphase - idsamp; long irdphaseb = irdphase - 1; float d1 = bufData[irdphase & mask]; float d2 = bufData[irdphaseb & mask]; float value = lininterp(frac, d1, d2); bufData[iwrphase & mask] = ZXP(in) + feedbk * value; ZXP(out) = value; iwrphase++; } }; template <> struct CombL_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase = iwrphase - idsamp; long irdphaseb = irdphase - 1; float zin = ZXP(in); if (irdphase < 0) { bufData[iwrphase & mask] = zin; ZXP(out) = 0.f; } else if (irdphaseb < 0) { float d1 = bufData[irdphase & mask]; float value = d1 - frac * d1; bufData[iwrphase & mask] = zin + feedbk * value; ZXP(out) = value; } else { float d1 = bufData[irdphase & mask]; float d2 = bufData[irdphaseb & mask]; float value = lininterp(frac, d1, d2); bufData[iwrphase & mask] = zin + feedbk * value; ZXP(out) = value; } iwrphase++; } }; template struct CombC_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = bufData[irdphase0 & mask]; float d1 = bufData[irdphase1 & mask]; float d2 = bufData[irdphase2 & mask]; float d3 = bufData[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); bufData[iwrphase & mask] = ZXP(in) + feedbk * value; ZXP(out) = value; iwrphase++; } }; template <> struct CombC_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (irdphase0 < 0) { bufData[iwrphase & mask] = ZXP(in); ZXP(out) = 0.f; } else { float d0, d1, d2, d3; if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = bufData[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; d2 = bufData[irdphase2 & mask]; } else { d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; d2 = bufData[irdphase2 & mask]; d3 = bufData[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); bufData[iwrphase & mask] = ZXP(in) + feedbk * value; ZXP(out) = value; } iwrphase++; } }; template struct AllpassN_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, long mask, float feedbk) { long irdphase = iwrphase - idsamp; float value = bufData[irdphase & mask]; float dwr = value * feedbk + ZXP(in); bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; ++iwrphase; } /* the frac argument is unneeded. the compiler should make sure, that it won't be computed */ static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { perform(in, out, bufData, iwrphase, idsamp, mask, feedbk); } }; template <> struct AllpassN_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, long mask, float feedbk) { long irdphase = iwrphase - idsamp; if (irdphase < 0) { float dwr = ZXP(in); bufData[iwrphase & mask] = dwr; ZXP(out) = -feedbk * dwr; } else { float value = bufData[irdphase & mask]; float dwr = feedbk * value + ZXP(in); bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; } ++iwrphase; } static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { perform(in, out, bufData, iwrphase, idsamp, mask, feedbk); } }; template struct AllpassL_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase = iwrphase - idsamp; long irdphaseb = irdphase - 1; float d1 = bufData[irdphase & mask]; float d2 = bufData[irdphaseb & mask]; float value = lininterp(frac, d1, d2); float dwr = ZXP(in) + feedbk * value; bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; iwrphase++; } }; template <> struct AllpassL_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase = iwrphase - idsamp; long irdphaseb = irdphase - 1; float zin = ZXP(in); if (irdphase < 0) { bufData[iwrphase & mask] = zin; ZXP(out) = - feedbk * zin; } else if (irdphaseb < 0) { float d1 = bufData[irdphase & mask]; float value = d1 - frac * d1; float dwr = zin + feedbk * value; bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; } else { float d1 = bufData[irdphase & mask]; float d2 = bufData[irdphaseb & mask]; float value = lininterp(frac, d1, d2); float dwr = zin + feedbk * value; bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; } iwrphase++; } }; template struct AllpassC_helper { static const bool checked = false; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; float d0 = bufData[irdphase0 & mask]; float d1 = bufData[irdphase1 & mask]; float d2 = bufData[irdphase2 & mask]; float d3 = bufData[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float dwr = ZXP(in) + feedbk * value; bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; iwrphase++; } }; template <> struct AllpassC_helper { static const bool checked = true; static inline void perform(const float *& in, float *& out, float * bufData, long & iwrphase, long idsamp, float frac, long mask, float feedbk) { long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (irdphase0 < 0) { bufData[iwrphase & mask] = ZXP(in); ZXP(out) = 0.f; } else { float d0, d1, d2, d3; if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = bufData[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; d2 = bufData[irdphase2 & mask]; } else { d0 = bufData[irdphase0 & mask]; d1 = bufData[irdphase1 & mask]; d2 = bufData[irdphase2 & mask]; d3 = bufData[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float dwr = ZXP(in) + feedbk * value; bufData[iwrphase & mask] = dwr; ZXP(out) = value - feedbk * dwr; } iwrphase++; } }; } //////////////////////////////////////////////////////////////////////////////////////////////////////// /* template function to generate buffer-based delay ugen function, control-rate delay time */ template inline void BufDelayX_perform(BufDelayX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; if (delaytime == unit->m_delaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; LOOP1(inNumSamples, PerformClass::perform(in, out, bufData, iwrphase, idsamp, frac, mask); ); } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); LOOP1(inNumSamples, dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, bufData, iwrphase, idsamp, frac, mask); ); unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; } unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) unit->mCalcFunc = resetFunc; } } /* template function to generate buffer-based delay ugen function, audio-rate delay time */ template inline void BufDelayX_perform_a(BufDelayX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(1); float * delaytime = ZIN(2); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; LOOP1(inNumSamples, float dsamp = BufCalcDelay(unit, bufSamples, ZXP(delaytime)); long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, bufData, iwrphase, idsamp, frac, mask); ); unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) unit->mCalcFunc = resetFunc; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufDelayN_Ctor(BufDelayN *unit) { if(INRATE(2) == calc_FullRate) SETCALC(BufDelayN_next_a_z); else SETCALC(BufDelayN_next_z); BufDelayUnit_Reset(unit); ZOUT0(0) = 0.f; } void BufDelayN_next(BufDelayN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; if (delaytime == unit->m_delaytime) { DelayN_delay_loop(out, in, iwrphase, dsamp, mask, bufData, inNumSamples, PREVIOUSPOWEROFTWO(bufSamples)); } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); LOOP1(inNumSamples, dsamp += dsamp_slope; long idsamp = (long)dsamp; DelayN_helper::perform(in, out, bufData, iwrphase, idsamp, mask); ); unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; } unit->m_iwrphase = iwrphase; } void BufDelayN_next_z(BufDelayN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; if (delaytime == unit->m_delaytime) { DelayN_delay_loop(out, in, iwrphase, dsamp, mask, bufData, inNumSamples, PREVIOUSPOWEROFTWO(bufSamples)); } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); LOOP1(inNumSamples, dsamp += dsamp_slope; long idsamp = (long)dsamp; DelayN_helper::perform(in, out, bufData, iwrphase, idsamp, mask); ); unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; } unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) SETCALC(BufDelayN_next); } template inline void BufDelayN_perform_a(BufDelayN *unit, int inNumSamples) { BufDelayX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufDelayN_next_a); } void BufDelayN_next_a(BufDelayN *unit, int inNumSamples) { BufDelayN_perform_a(unit, inNumSamples); } void BufDelayN_next_a_z(BufDelayN *unit, int inNumSamples) { BufDelayN_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufDelayL_Ctor(BufDelayL *unit) { BufDelayUnit_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufDelayL_next_a_z); else SETCALC(BufDelayL_next_z); ZOUT0(0) = 0.f; } template inline void BufDelayL_perform(BufDelayL *unit, int inNumSamples) { BufDelayX_perform >(unit, inNumSamples, (UnitCalcFunc)BufDelayL_next); } void BufDelayL_next(BufDelayL *unit, int inNumSamples) { BufDelayL_perform(unit, inNumSamples); } void BufDelayL_next_z(BufDelayL *unit, int inNumSamples) { BufDelayL_perform(unit, inNumSamples); } template inline void BufDelayL_perform_a(BufDelayL *unit, int inNumSamples) { BufDelayX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufDelayL_next_a); } void BufDelayL_next_a(BufDelayL *unit, int inNumSamples) { BufDelayL_perform_a(unit, inNumSamples); } void BufDelayL_next_a_z(BufDelayL *unit, int inNumSamples) { BufDelayL_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufDelayC_Ctor(BufDelayC *unit) { BufDelayUnit_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufDelayC_next_a_z); else SETCALC(BufDelayC_next_z); ZOUT0(0) = 0.f; } template inline void BufDelayC_perform(BufDelayC *unit, int inNumSamples) { BufDelayX_perform >(unit, inNumSamples, (UnitCalcFunc)BufDelayC_next); } void BufDelayC_next(BufDelayC *unit, int inNumSamples) { BufDelayC_perform(unit, inNumSamples); } void BufDelayC_next_z(BufDelayC *unit, int inNumSamples) { BufDelayC_perform(unit, inNumSamples); } template inline void BufDelayC_perform_a(BufDelayC *unit, int inNumSamples) { BufDelayX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufDelayL_next_a); } void BufDelayC_next_a(BufDelayC *unit, int inNumSamples) { BufDelayC_perform_a(unit, inNumSamples); } void BufDelayC_next_a_z(BufDelayC *unit, int inNumSamples) { BufDelayC_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// template inline void BufFilterX_perform(BufCombX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); float decaytime = ZIN0(3); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; LOOP1(inNumSamples, PerformClass::perform(in, out, bufData, iwrphase, idsamp, frac, mask, feedbk); ); } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, bufData, iwrphase, idsamp, frac, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) unit->mCalcFunc = resetFunc; } } template inline void BufFilterX_perform_a(BufCombX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(1); float * delaytime = ZIN(2); float decaytime = ZIN0(3); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; LOOP1(inNumSamples, float del = ZXP(delaytime); float dsamp = BufCalcDelay(unit, bufSamples, del); float feedbk = sc_CalcFeedback(del, decaytime); long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, bufData, iwrphase, idsamp, frac, mask, feedbk); ); unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) unit->mCalcFunc = resetFunc; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufCombN_Ctor(BufCombN *unit) { BufFeedbackDelay_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufCombN_next_a_z); else SETCALC(BufCombN_next_z); ZOUT0(0) = 0.f; } void BufCombN_next(BufCombN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); float decaytime = ZIN0(3); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; //postbuf("BufCombN_next %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = bufData - ZOFF; float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyN = dlybuf1 + PREVIOUSPOWEROFTWO(bufSamples); if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP1(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP1(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; feedbk += feedbk_slope; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } iwrphase += inNumSamples; } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; CombN_helper::perform(in, out, bufData, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; } void BufCombN_next_z(BufCombN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); float decaytime = ZIN0(3); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; //Print("BufCombN_next_z %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = bufData - ZOFF; float* dlyN = dlybuf1 + PREVIOUSPOWEROFTWO(bufSamples); if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyrd = dlybuf1 + (irdphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { LOOP1(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = 0.f; ); } else { LOOP1(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; ); } iwrphase += nsmps; irdphase += nsmps; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { feedbk += nsmps * feedbk_slope; dlyrd += nsmps; LOOP1(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = 0.f; ); } else { LOOP1(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; feedbk += feedbk_slope; ); } iwrphase += nsmps; irdphase += nsmps; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; CombN_helper::perform(in, out, bufData, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) SETCALC(BufCombN_next); } template inline void BufCombN_perform_a(BufCombN *unit, int inNumSamples) { BufFilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufCombN_next_a); } void BufCombN_next_a(BufCombN *unit, int inNumSamples) { BufCombN_perform_a(unit, inNumSamples); } void BufCombN_next_a_z(BufCombN *unit, int inNumSamples) { BufCombN_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufCombL_Ctor(BufCombL *unit) { BufFeedbackDelay_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufCombL_next_a_z); else SETCALC(BufCombL_next_z); ZOUT0(0) = 0.f; } template inline void BufCombL_perform(BufCombL *unit, int inNumSamples) { BufFilterX_perform >(unit, inNumSamples, (UnitCalcFunc)BufCombL_next); } void BufCombL_next(BufCombL *unit, int inNumSamples) { BufCombL_perform(unit, inNumSamples); } void BufCombL_next_z(BufCombL *unit, int inNumSamples) { BufCombL_perform(unit, inNumSamples); } template inline void BufCombL_perform_a(BufCombL *unit, int inNumSamples) { BufFilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufCombL_next_a); } void BufCombL_next_a(BufCombL *unit, int inNumSamples) { BufCombL_perform_a(unit, inNumSamples); } void BufCombL_next_a_z(BufCombL *unit, int inNumSamples) { BufCombL_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufCombC_Ctor(BufCombC *unit) { BufFeedbackDelay_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufCombC_next_a_z); else SETCALC(BufCombC_next_z); ZOUT0(0) = 0.f; } template inline void BufCombC_perform(BufCombC *unit, int inNumSamples) { BufFilterX_perform >(unit, inNumSamples, (UnitCalcFunc)BufCombC_next); } void BufCombC_next(BufCombC *unit, int inNumSamples) { BufCombC_perform(unit, inNumSamples); } void BufCombC_next_z(BufCombC *unit, int inNumSamples) { BufCombC_perform(unit, inNumSamples); } template inline void BufCombC_perform_a(BufCombC *unit, int inNumSamples) { BufFilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufCombC_next_a); } void BufCombC_next_a(BufCombC *unit, int inNumSamples) { BufCombC_perform_a(unit, inNumSamples); } void BufCombC_next_a_z(BufCombC *unit, int inNumSamples) { BufCombC_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufAllpassN_Ctor(BufAllpassN *unit) { BufFeedbackDelay_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufAllpassN_next_a_z); else SETCALC(BufAllpassN_next_z); ZOUT0(0) = 0.f; } void BufAllpassN_next(BufAllpassN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); float decaytime = ZIN0(3); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; //postbuf("BufAllpassN_next %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = bufData - ZOFF; float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyN = dlybuf1 + PREVIOUSPOWEROFTWO(bufSamples); if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP1(nsmps, float value = ZXP(dlyrd); float dwr = value * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = value - feedbk * dwr; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP1(nsmps, float value = ZXP(dlyrd); float dwr = value * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = value - feedbk * dwr; feedbk += feedbk_slope; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } iwrphase += inNumSamples; } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; AllpassN_helper::perform(in, out, bufData, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; } void BufAllpassN_next_z(BufAllpassN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(1); float delaytime = ZIN0(2); float decaytime = ZIN0(3); GET_BUF CHECK_BUF long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; //postbuf("BufAllpassN_next_z %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = bufData - ZOFF; float* dlyN = dlybuf1 + PREVIOUSPOWEROFTWO(bufSamples); if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyrd = dlybuf1 + (irdphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { feedbk = -feedbk; LOOP1(nsmps, float dwr = ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = feedbk * dwr; ); feedbk = -feedbk; } else { LOOP1(nsmps, float x1 = ZXP(dlyrd); float dwr = x1 * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = x1 - feedbk * dwr; ); } iwrphase += nsmps; irdphase += nsmps; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { dlyrd += nsmps; LOOP1(nsmps, float dwr = ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = -feedbk * dwr; feedbk += feedbk_slope; ); } else { LOOP1(nsmps, float x1 = ZXP(dlyrd); float dwr = x1 * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = x1 - feedbk * dwr; feedbk += feedbk_slope; ); } iwrphase += nsmps; irdphase += nsmps; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } } else { float next_dsamp = BufCalcDelay(unit, bufSamples, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; AllpassN_helper::perform(in, out, bufData, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= bufSamples) SETCALC(BufAllpassN_next); } template inline void BufAllpassN_perform_a(BufAllpassN *unit, int inNumSamples) { BufFilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufAllpassN_next_a); } void BufAllpassN_next_a(BufAllpassN *unit, int inNumSamples) { BufAllpassN_perform_a(unit, inNumSamples); } void BufAllpassN_next_a_z(BufAllpassN *unit, int inNumSamples) { BufAllpassN_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufAllpassL_Ctor(BufAllpassL *unit) { BufFeedbackDelay_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufAllpassL_next_a_z); else SETCALC(BufAllpassL_next_z); ZOUT0(0) = 0.f; } template inline void BufAllpassL_perform(BufAllpassL *unit, int inNumSamples) { BufFilterX_perform >(unit, inNumSamples, (UnitCalcFunc)BufAllpassL_next); } void BufAllpassL_next(BufAllpassL *unit, int inNumSamples) { BufAllpassL_perform(unit, inNumSamples); } void BufAllpassL_next_z(BufAllpassL *unit, int inNumSamples) { BufAllpassL_perform(unit, inNumSamples); } template inline void BufAllpassL_perform_a(BufAllpassL *unit, int inNumSamples) { BufFilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufAllpassL_next_a); } void BufAllpassL_next_a(BufAllpassL *unit, int inNumSamples) { BufAllpassL_perform_a(unit, inNumSamples); } void BufAllpassL_next_a_z(BufAllpassL *unit, int inNumSamples) { BufAllpassL_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void BufAllpassC_Ctor(BufAllpassC *unit) { BufFeedbackDelay_Reset(unit); if(INRATE(2) == calc_FullRate) SETCALC(BufAllpassC_next_a_z); else SETCALC(BufAllpassC_next_z); ZOUT0(0) = 0.f; } template inline void BufAllpassC_perform(BufAllpassC *unit, int inNumSamples) { BufFilterX_perform >(unit, inNumSamples, (UnitCalcFunc)BufAllpassC_next); } void BufAllpassC_next(BufAllpassC *unit, int inNumSamples) { BufAllpassC_perform(unit, inNumSamples); } void BufAllpassC_next_z(BufAllpassC *unit, int inNumSamples) { BufAllpassC_perform(unit, inNumSamples); } template inline void BufAllpassC_perform_a(BufAllpassC *unit, int inNumSamples) { BufFilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)BufAllpassC_next_a); } void BufAllpassC_next_a(BufAllpassC *unit, int inNumSamples) { BufAllpassC_perform_a(unit, inNumSamples); } void BufAllpassC_next_a_z(BufAllpassC *unit, int inNumSamples) { BufAllpassC_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// static bool DelayUnit_AllocDelayLine(DelayUnit *unit, const char * className) { long delaybufsize = (long)ceil(unit->m_maxdelaytime * SAMPLERATE + 1.f); delaybufsize = delaybufsize + BUFLENGTH; delaybufsize = NEXTPOWEROFTWO(delaybufsize); // round up to next power of two unit->m_fdelaylen = unit->m_idelaylen = delaybufsize; if (unit->m_dlybuf) RTFree(unit->mWorld, unit->m_dlybuf); unit->m_dlybuf = (float*)RTAlloc(unit->mWorld, delaybufsize * sizeof(float)); #if 0 // for debugging we may want to fill the buffer with nans std::fill_n(unit->m_dlybuf, delaybufsize, std::numeric_limits::signaling_NaN()); #endif if (unit->m_dlybuf == NULL) { SETCALC(ft->fClearUnitOutputs); ClearUnitOutputs(unit, 1); if(unit->mWorld->mVerbosity > -2) Print("Failed to allocate memory for %s ugen.\n", className); } unit->m_mask = delaybufsize - 1; return (unit->m_dlybuf != NULL); } template static float CalcDelay(Unit *unit, float delaytime) { float minDelay = Unit::minDelaySamples; float next_dsamp = delaytime * (float)SAMPLERATE; return sc_clip(next_dsamp, minDelay, unit->m_fdelaylen); } template static bool DelayUnit_Reset(Unit *unit, const char * className) { unit->m_maxdelaytime = ZIN0(1); unit->m_delaytime = ZIN0(2); unit->m_dlybuf = 0; if (!DelayUnit_AllocDelayLine(unit, className)) return false; unit->m_dsamp = CalcDelay(unit, unit->m_delaytime); unit->m_numoutput = 0; unit->m_iwrphase = 0; return true; } void DelayUnit_Dtor(DelayUnit *unit) { RTFree(unit->mWorld, unit->m_dlybuf); } //////////////////////////////////////////////////////////////////////////////////////////////////////// template static bool FeedbackDelay_Reset(Unit *unit, const char * className) { unit->m_decaytime = ZIN0(3); bool allocationSucessful = DelayUnit_Reset(unit, className); if (!allocationSucessful) return false; unit->m_feedbk = sc_CalcFeedback(unit->m_delaytime, unit->m_decaytime); return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////// /* template function to generate delay ugen function, control-rate delay time */ template inline void DelayX_perform(DelayX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; long mask = unit->m_mask; if (delaytime == unit->m_delaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; LOOP1(inNumSamples, PerformClass::perform(in, out, dlybuf, iwrphase, idsamp, frac, mask); ); } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); LOOP1(inNumSamples, dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, dlybuf, iwrphase, idsamp, frac, mask); ); unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; } unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) unit->mCalcFunc = resetFunc; } } /* template function to generate delay ugen function, audio-rate delay time */ template inline void DelayX_perform_a(DelayX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(0); float * delaytime = ZIN(2); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; long mask = unit->m_mask; LOOP1(inNumSamples, float dsamp = CalcDelay(unit, ZXP(delaytime)); long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, dlybuf, iwrphase, idsamp, frac, mask); ); unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) unit->mCalcFunc = resetFunc; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Delay_next_0(DelayUnit *unit, int inNumSamples) { float *out = OUT(0); const float *in = IN(0); memcpy(out, in, inNumSamples * sizeof(float)); } void Delay_next_0_nop(DelayUnit *unit, int inNumSamples) {} #ifdef NOVA_SIMD void Delay_next_0_nova(DelayUnit *unit, int inNumSamples) { nova::copyvec_simd(OUT(0), IN(0), inNumSamples); } #endif static bool DelayUnit_init_0(DelayUnit *unit) { if (INRATE(2) == calc_ScalarRate && ZIN0(2) == 0) { if (ZIN(0) == ZOUT(0)) SETCALC(Delay_next_0_nop); #ifdef NOVA_SIMD else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Delay_next_0_nova); #endif else SETCALC(Delay_next_0); ZOUT0(0) = ZIN0(0); return true; } else return false; } enum { initializationComplete, initializationIncomplete }; template static int Delay_Ctor(Delay *unit, const char *className) { bool allocationSucessful = DelayUnit_Reset(unit, className); if (!allocationSucessful) return initializationComplete; // optimize for a constant delay of zero if (DelayUnit_init_0(unit)) return initializationComplete; return initializationIncomplete; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void DelayN_Ctor(DelayN *unit) { if (Delay_Ctor(unit, "DelayN") == initializationComplete) return; if (INRATE(2) == calc_FullRate) SETCALC(DelayN_next_a_z); else SETCALC(DelayN_next_z); ZOUT0(0) = 0.f; } void DelayN_next(DelayN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; long mask = unit->m_mask; //Print("DelayN_next %p %g %g %d %d\n", unit, delaytime, dsamp, mask, iwrphase); if (delaytime == unit->m_delaytime) { DelayN_delay_loop(out, in, iwrphase, dsamp, mask, dlybuf, inNumSamples, unit->m_idelaylen); } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); LOOP1(inNumSamples, dsamp += dsamp_slope; DelayN_helper::perform(in, out, dlybuf, iwrphase, (long)dsamp, mask); ); unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; } unit->m_iwrphase = iwrphase; } void DelayN_next_z(DelayN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; long mask = unit->m_mask; if (delaytime == unit->m_delaytime) { DelayN_delay_loop(out, in, iwrphase, dsamp, mask, dlybuf, inNumSamples, unit->m_idelaylen); } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); LOOP1(inNumSamples, dsamp += dsamp_slope; DelayN_helper::perform(in, out, dlybuf, iwrphase, (long)dsamp, mask); ); unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; } unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) SETCALC(DelayN_next); } template inline void DelayN_perform_a(DelayN *unit, int inNumSamples) { DelayX_perform_a >(unit, inNumSamples, (UnitCalcFunc)DelayN_next_a); } void DelayN_next_a(DelayN *unit, int inNumSamples) { DelayN_perform_a(unit, inNumSamples); } void DelayN_next_a_z(DelayN *unit, int inNumSamples) { DelayN_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void DelayL_Ctor(DelayL *unit) { if (Delay_Ctor(unit, "DelayL") == initializationComplete) return; if (INRATE(2) == calc_FullRate) SETCALC(DelayL_next_a_z); else SETCALC(DelayL_next_z); ZOUT0(0) = 0.f; } template inline void DelayL_perform(DelayL *unit, int inNumSamples) { DelayX_perform >(unit, inNumSamples, (UnitCalcFunc)DelayL_next); } void DelayL_next(DelayL *unit, int inNumSamples) { DelayL_perform(unit, inNumSamples); } void DelayL_next_z(DelayL *unit, int inNumSamples) { DelayL_perform(unit, inNumSamples); } template inline void DelayL_perform_a(DelayL *unit, int inNumSamples) { DelayX_perform_a >(unit, inNumSamples, (UnitCalcFunc)DelayL_next_a); } void DelayL_next_a(DelayL *unit, int inNumSamples) { DelayL_perform_a(unit, inNumSamples); } void DelayL_next_a_z(DelayL *unit, int inNumSamples) { DelayL_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void DelayC_Ctor(DelayC *unit) { if (Delay_Ctor(unit, "DelayC") == initializationComplete) return; if (INRATE(2) == calc_FullRate) SETCALC(DelayC_next_a_z); else SETCALC(DelayC_next_z); ZOUT0(0) = 0.f; } template inline void DelayC_perform(DelayC *unit, int inNumSamples) { DelayX_perform >(unit, inNumSamples, (UnitCalcFunc)DelayC_next); } void DelayC_next(DelayC *unit, int inNumSamples) { DelayC_perform(unit, inNumSamples); } void DelayC_next_z(DelayC *unit, int inNumSamples) { DelayC_perform(unit, inNumSamples); } template inline void DelayC_perform_a(DelayC *unit, int inNumSamples) { DelayX_perform_a >(unit, inNumSamples, (UnitCalcFunc)DelayC_next_a); } void DelayC_next_a(DelayC *unit, int inNumSamples) { DelayC_perform_a(unit, inNumSamples); } void DelayC_next_a_z(DelayC *unit, int inNumSamples) { DelayC_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// template inline void FilterX_perform(BufCombX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float decaytime = ZIN0(3); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; LOOP1(inNumSamples, PerformClass::perform(in, out, dlybuf, iwrphase, idsamp, frac, mask, feedbk); ); } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, dlybuf, iwrphase, idsamp, frac, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) unit->mCalcFunc = resetFunc; } } template inline void FilterX_perform_a(CombX *unit, int inNumSamples, UnitCalcFunc resetFunc) { float *out = ZOUT(0); const float *in = ZIN(0); float * delaytime = ZIN(2); float decaytime = ZIN0(3); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; long mask = unit->m_mask; LOOP1(inNumSamples, float del = ZXP(delaytime); float dsamp = CalcDelay(unit, del); float feedbk = sc_CalcFeedback(del, decaytime); long idsamp = (long)dsamp; float frac = dsamp - idsamp; PerformClass::perform(in, out, dlybuf, iwrphase, idsamp, frac, mask, feedbk); ); unit->m_iwrphase = iwrphase; if (PerformClass::checked) { unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) unit->mCalcFunc = resetFunc; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void CombN_Ctor(CombN *unit) { bool allocationSucessful = FeedbackDelay_Reset(unit, "CombN"); if (!allocationSucessful) return; if(INRATE(2) == calc_FullRate) SETCALC(CombN_next_a_z); else SETCALC(CombN_next_z); ZOUT0(0) = 0.f; } void CombN_next(CombN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float decaytime = ZIN0(3); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; //postbuf("CombN_next %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = dlybuf - ZOFF; float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyN = dlybuf1 + unit->m_idelaylen; if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; feedbk += feedbk_slope; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } iwrphase += inNumSamples; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; CombN_helper::perform(in, out, dlybuf, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; } void CombN_next_z(CombN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float decaytime = ZIN0(3); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; //postbuf("CombN_next_z %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = dlybuf - ZOFF; float* dlyN = dlybuf1 + unit->m_idelaylen; if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyrd = dlybuf1 + (irdphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { LOOP(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = 0.f; ); } else { LOOP(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; ); } iwrphase += nsmps; irdphase += nsmps; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { feedbk += nsmps * feedbk_slope; dlyrd += nsmps; LOOP(nsmps, ZXP(dlywr) = ZXP(in); ZXP(out) = 0.f; ); } else { LOOP(nsmps, float value = ZXP(dlyrd); ZXP(dlywr) = value * feedbk + ZXP(in); ZXP(out) = value; feedbk += feedbk_slope; ); } iwrphase += nsmps; irdphase += nsmps; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; CombN_helper::perform(in, out, dlybuf, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) SETCALC(CombN_next); } template inline void CombN_perform_a(CombN *unit, int inNumSamples) { FilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)CombN_next_a); } void CombN_next_a(CombN *unit, int inNumSamples) { CombN_perform_a(unit, inNumSamples); } void CombN_next_a_z(CombN *unit, int inNumSamples) { CombN_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void CombL_Ctor(CombL *unit) { bool allocationSucessful = FeedbackDelay_Reset(unit, "CombL"); if (!allocationSucessful) return; if(INRATE(2) == calc_FullRate) SETCALC(CombL_next_a_z); else SETCALC(CombL_next_z); ZOUT0(0) = 0.f; } template inline void CombL_perform(CombL *unit, int inNumSamples) { FilterX_perform >(unit, inNumSamples, (UnitCalcFunc)CombL_next); } void CombL_next(CombL *unit, int inNumSamples) { CombL_perform(unit, inNumSamples); } void CombL_next_z(CombL *unit, int inNumSamples) { CombL_perform(unit, inNumSamples); } template inline void CombL_perform_a(CombL *unit, int inNumSamples) { FilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)CombL_next_a); } void CombL_next_a(CombL *unit, int inNumSamples) { CombL_perform_a(unit, inNumSamples); } void CombL_next_a_z(CombL *unit, int inNumSamples) { CombL_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void CombC_Ctor(CombC *unit) { bool allocationSucessful = FeedbackDelay_Reset(unit, "CombC"); if (!allocationSucessful) return; if(INRATE(2) == calc_FullRate) SETCALC(CombC_next_a_z); else SETCALC(CombC_next_z); ZOUT0(0) = 0.f; } template inline void CombC_perform(CombC *unit, int inNumSamples) { FilterX_perform >(unit, inNumSamples, (UnitCalcFunc)CombC_next); } void CombC_next(CombC *unit, int inNumSamples) { CombC_perform(unit, inNumSamples); } void CombC_next_z(CombC *unit, int inNumSamples) { CombC_perform(unit, inNumSamples); } template inline void CombC_perform_a(CombC *unit, int inNumSamples) { FilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)CombC_next_a); } void CombC_next_a(CombC *unit, int inNumSamples) { CombC_perform_a(unit, inNumSamples); } void CombC_next_a_z(CombC *unit, int inNumSamples) { CombC_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void AllpassN_Ctor(AllpassN *unit) { bool allocationSucessful = FeedbackDelay_Reset(unit, "AllpassN"); if (!allocationSucessful) return; if(INRATE(2) == calc_FullRate) SETCALC(AllpassN_next_a_z); else SETCALC(AllpassN_next_z); ZOUT0(0) = 0.f; } void AllpassN_next(AllpassN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float decaytime = ZIN0(3); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; //postbuf("AllpassN_next %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = dlybuf - ZOFF; float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyN = dlybuf1 + unit->m_idelaylen; if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP(nsmps, float value = ZXP(dlyrd); float dwr = value * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = value - feedbk * dwr; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; LOOP(nsmps, float value = ZXP(dlyrd); float dwr = value * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = value - feedbk * dwr; feedbk += feedbk_slope; ); if (dlyrd == dlyN) dlyrd = dlybuf1; if (dlywr == dlyN) dlywr = dlybuf1; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } iwrphase += inNumSamples; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; AllpassN_helper::perform(in, out, dlybuf, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; } void AllpassN_next_z(AllpassN *unit, int inNumSamples) { float *out = ZOUT(0); const float *in = ZIN(0); float delaytime = ZIN0(2); float decaytime = ZIN0(3); float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; //postbuf("AllpassN_next_z %g %g %g %g %d %d %d\n", delaytime, decaytime, feedbk, dsamp, mask, iwrphase, zorg); if (delaytime == unit->m_delaytime) { long irdphase = iwrphase - (long)dsamp; float* dlybuf1 = dlybuf - ZOFF; float* dlyN = dlybuf1 + unit->m_idelaylen; if (decaytime == unit->m_decaytime) { long remain = inNumSamples; while (remain) { float* dlywr = dlybuf1 + (iwrphase & mask); float* dlyrd = dlybuf1 + (irdphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { feedbk = -feedbk; LOOP(nsmps, float dwr = ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = feedbk * dwr; ); feedbk = -feedbk; } else { LOOP(nsmps, float x1 = ZXP(dlyrd); float dwr = x1 * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = x1 - feedbk * dwr; ); } iwrphase += nsmps; irdphase += nsmps; } } else { float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); long remain = inNumSamples; while (remain) { float* dlyrd = dlybuf1 + (irdphase & mask); float* dlywr = dlybuf1 + (iwrphase & mask); long rdspace = dlyN - dlyrd; long wrspace = dlyN - dlywr; long nsmps = sc_min(rdspace, wrspace); nsmps = sc_min(remain, nsmps); remain -= nsmps; if (irdphase < 0) { dlyrd += nsmps; LOOP(nsmps, float dwr = ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = -feedbk * dwr; feedbk += feedbk_slope; ); } else { LOOP(nsmps, float x1 = ZXP(dlyrd); float dwr = x1 * feedbk + ZXP(in); ZXP(dlywr) = dwr; ZXP(out) = x1 - feedbk * dwr; feedbk += feedbk_slope; ); } iwrphase += nsmps; irdphase += nsmps; } unit->m_feedbk = feedbk; unit->m_decaytime = decaytime; } } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); LOOP1(inNumSamples, dsamp += dsamp_slope; feedbk += feedbk_slope; AllpassN_helper::perform(in, out, dlybuf, iwrphase, (long)dsamp, mask, feedbk); ); unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) SETCALC(AllpassN_next); } template inline void AllpassN_perform_a(AllpassN *unit, int inNumSamples) { FilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)AllpassN_next_a); } void AllpassN_next_a(AllpassN *unit, int inNumSamples) { AllpassN_perform_a(unit, inNumSamples); } void AllpassN_next_a_z(AllpassN *unit, int inNumSamples) { AllpassN_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void AllpassL_Ctor(AllpassL *unit) { bool allocationSucessful = FeedbackDelay_Reset(unit, "AllpassL"); if (!allocationSucessful) return; if(INRATE(2) == calc_FullRate) SETCALC(AllpassL_next_a_z); else SETCALC(AllpassL_next_z); ZOUT0(0) = 0.f; } template inline void AllpassL_perform(AllpassL *unit, int inNumSamples) { FilterX_perform >(unit, inNumSamples, (UnitCalcFunc)AllpassL_next); } void AllpassL_next(AllpassL *unit, int inNumSamples) { AllpassL_perform(unit, inNumSamples); } void AllpassL_next_z(AllpassL *unit, int inNumSamples) { AllpassL_perform(unit, inNumSamples); } template inline void AllpassL_perform_a(AllpassL *unit, int inNumSamples) { FilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)AllpassL_next_a); } void AllpassL_next_a(AllpassL *unit, int inNumSamples) { AllpassL_perform_a(unit, inNumSamples); } void AllpassL_next_a_z(AllpassL *unit, int inNumSamples) { AllpassL_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void AllpassC_Ctor(AllpassC *unit) { bool allocationSucessful = FeedbackDelay_Reset(unit, "AllpassC"); if (!allocationSucessful) return; if(INRATE(2) == calc_FullRate) SETCALC(AllpassC_next_a_z); else SETCALC(AllpassC_next_z); ZOUT0(0) = 0.f; } template inline void AllpassC_perform(AllpassC *unit, int inNumSamples) { FilterX_perform >(unit, inNumSamples, (UnitCalcFunc)AllpassC_next); } void AllpassC_next(AllpassC *unit, int inNumSamples) { AllpassC_perform(unit, inNumSamples); } void AllpassC_next_z(AllpassC *unit, int inNumSamples) { AllpassC_perform(unit, inNumSamples); } template inline void AllpassC_perform_a(AllpassC *unit, int inNumSamples) { FilterX_perform_a >(unit, inNumSamples, (UnitCalcFunc)AllpassC_next_a); } void AllpassC_next_a(AllpassC *unit, int inNumSamples) { AllpassC_perform_a(unit, inNumSamples); } void AllpassC_next_a_z(AllpassC *unit, int inNumSamples) { AllpassC_perform_a(unit, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// inline double sc_loop1(int32 in, int32 lo, int32 hi) { // avoid the divide if possible if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < lo) { in += hi; if (in >= lo) return in; } else return in; int32 range = hi - lo; return lo + range * (in-lo) / range; } #if NOTYET void SimpleLoopBuf_next_kk(SimpleLoopBuf *unit, int inNumSamples) { float trig = ZIN0(1); double loopstart = (double)ZIN0(2); double loopend = (double)ZIN0(3); GET_BUF int numOutputs = unit->mNumOutputs; if (!checkBuffer(unit, bufData, bufChannels, numOutputs, inNumSamples)) return; loopend = sc_max(loopend, bufFrames); int32 phase = unit->m_phase; if (trig > 0.f && unit->m_prevtrig <= 0.f) { unit->mDone = false; phase = (int32)ZIN0(2); } unit->m_prevtrig = trig; for (int i=0; im_phase = phase; } void SimpleLoopBuf_Ctor(SimpleLoopBuf *unit) { SETCALC(SimpleLoopBuf_next_kk); unit->m_fbufnum = -1e9f; unit->m_prevtrig = 0.; unit->m_phase = ZIN0(2); ClearUnitOutputs(unit, 1); } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// #define GET_SCOPEBUF \ float fbufnum = ZIN0(0); \ if (fbufnum != unit->m_fbufnum) { \ World *world = unit->mWorld; \ if (!world->mNumSndBufs) { \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } \ uint32 bufnum = (int)fbufnum; \ if (bufnum >= world->mNumSndBufs) bufnum = 0; \ unit->m_fbufnum = fbufnum; \ unit->m_buf = world->mSndBufs + bufnum; \ unit->m_bufupdates = world->mSndBufUpdates + bufnum; \ } \ SndBuf *buf = unit->m_buf; \ LOCK_SNDBUF(buf); \ SndBufUpdates *bufupdates = unit->m_bufupdates; \ float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufFrames __attribute__((__unused__)) = buf->frames; \ void ScopeOut_next(ScopeOut *unit, int inNumSamples) { GET_SCOPEBUF if (!bufData) { unit->m_framepos = 0; return; } SETUP_IN(1) uint32 framepos = unit->m_framepos; if (framepos >= bufFrames) { unit->m_framepos = 0; } if (bufupdates->reads != bufupdates->writes) { unit->m_framepos += inNumSamples; return; } bufData += framepos * bufChannels; int remain = (bufFrames - framepos), wrap = 0; if(inNumSamples <= remain) { remain = inNumSamples; wrap = 0; } else wrap = inNumSamples - remain; if (bufChannels > 2) { for (int j=0; jdata; for (int j=0; jdata; for (int j=0; jdata; for (int j=0; jm_framepos += inNumSamples; unit->m_framecount += inNumSamples; if (unit->m_framecount >= bufFrames) { bufupdates->writes++; unit->m_framecount = 0; } } void ScopeOut_Ctor(ScopeOut *unit) { unit->m_fbufnum = -1e9; unit->m_framepos = 0; unit->m_framecount = 0; unit->mIn = 0; SETCALC(ScopeOut_next); } void ScopeOut_Dtor(ScopeOut *unit) { TAKEDOWN_IN } //////////////////////////////////////////////////////////////////////////////////////////////////////// struct ScopeOut2 : public Unit { ScopeBufferHnd m_buffer; float **m_inBuffers; int m_maxPeriod; uint32 m_phase; }; void ScopeOut2_next(ScopeOut2 *unit, int inNumSamples) { if( !unit->m_buffer ) return; const int inputOffset = 3; int numChannels = unit->mNumInputs - inputOffset; uint32 period = (uint32)ZIN0(2); uint32 framepos = unit->m_phase; period = std::max((uint32)inNumSamples, std::min(unit->m_buffer.maxFrames, period)); if( framepos >= period ) framepos = 0; int remain = period - framepos, wrap = 0; if(inNumSamples <= remain) remain = inNumSamples; else wrap = inNumSamples - remain; for (int i = 0; i != numChannels; ++i) { float * inBuf = unit->m_buffer.channel_data(i); const float * in = IN(inputOffset + i); memcpy(inBuf + framepos, in, remain * sizeof(float)); } if(framepos + inNumSamples >= period) (*ft->fPushScopeBuffer)(unit->mWorld, unit->m_buffer, period); if (wrap) { for (int i = 0; i != numChannels; ++i) { float * inBuf = unit->m_buffer.channel_data(i); const float * in = IN(inputOffset + i); memcpy(inBuf, in + remain, wrap * sizeof(float)); } } framepos += inNumSamples; if (framepos >= period) framepos = wrap; unit->m_phase = framepos; } void ScopeOut2_Ctor(ScopeOut2 *unit) { uint32 numChannels = unit->mNumInputs - 3; uint32 scopeNum = (uint32)ZIN0(0); uint32 maxFrames = (uint32)ZIN0(1); bool ok = (*ft->fGetScopeBuffer)(unit->mWorld, scopeNum, numChannels, maxFrames, unit->m_buffer); if( !ok ) { if( unit->mWorld->mVerbosity > -1 && !unit->mDone) Print("ScopeOut2: Requested scope buffer unavailable! (index: %d, channels: %d, size: %d)\n", scopeNum, numChannels, maxFrames); } else { unit->m_phase = 0; } SETCALC(ScopeOut2_next); } void ScopeOut2_Dtor(ScopeOut2 *unit) { if( unit->m_buffer ) (*ft->fReleaseScopeBuffer)(unit->mWorld, unit->m_buffer); } //////////////////////////////////////////////////////////////////////////////////////////////////////// struct PitchShift : public Unit { float *dlybuf; float dsamp1, dsamp1_slope, ramp1, ramp1_slope; float dsamp2, dsamp2_slope, ramp2, ramp2_slope; float dsamp3, dsamp3_slope, ramp3, ramp3_slope; float dsamp4, dsamp4_slope, ramp4, ramp4_slope; float fdelaylen, slope; long iwrphase, idelaylen, mask; long counter, stage, numoutput, framesize; }; void PitchShift_next(PitchShift *unit, int inNumSamples); void PitchShift_next(PitchShift *unit, int inNumSamples) { float *out, *in, *dlybuf; float disppchratio, pchratio, pchratio1, value; float dsamp1, dsamp1_slope, ramp1, ramp1_slope; float dsamp2, dsamp2_slope, ramp2, ramp2_slope; float dsamp3, dsamp3_slope, ramp3, ramp3_slope; float dsamp4, dsamp4_slope, ramp4, ramp4_slope; float fdelaylen, d1, d2, frac, slope, samp_slope, startpos, winsize, pchdisp, timedisp; long remain, nsmps, idelaylen, irdphase, irdphaseb, iwrphase, mask, idsamp; long counter, stage, framesize; RGET out = ZOUT(0); in = ZIN(0); pchratio = ZIN0(2); winsize = ZIN0(1); pchdisp = ZIN0(3); timedisp = ZIN0(4); timedisp = sc_clip(timedisp, 0.f, winsize) * SAMPLERATE; dlybuf = unit->dlybuf; fdelaylen = unit->fdelaylen; idelaylen = unit->idelaylen; iwrphase = unit->iwrphase; counter = unit->counter; stage = unit->stage; mask = unit->mask; framesize = unit->framesize; dsamp1 = unit->dsamp1; dsamp2 = unit->dsamp2; dsamp3 = unit->dsamp3; dsamp4 = unit->dsamp4; dsamp1_slope = unit->dsamp1_slope; dsamp2_slope = unit->dsamp2_slope; dsamp3_slope = unit->dsamp3_slope; dsamp4_slope = unit->dsamp4_slope; ramp1 = unit->ramp1; ramp2 = unit->ramp2; ramp3 = unit->ramp3; ramp4 = unit->ramp4; ramp1_slope = unit->ramp1_slope; ramp2_slope = unit->ramp2_slope; ramp3_slope = unit->ramp3_slope; ramp4_slope = unit->ramp4_slope; slope = unit->slope; remain = inNumSamples; while (remain) { if (counter <= 0) { counter = framesize >> 2; unit->stage = stage = (stage + 1) & 3; disppchratio = pchratio; if (pchdisp != 0.f) { disppchratio += (pchdisp * frand2(s1,s2,s3)); } disppchratio = sc_clip(disppchratio, 0.f, 4.f); pchratio1 = disppchratio - 1.f; samp_slope = -pchratio1; startpos = pchratio1 < 0.f ? 2.f : framesize * pchratio1 + 2.f; startpos += (timedisp * frand(s1,s2,s3)); switch(stage) { case 0 : unit->dsamp1_slope = dsamp1_slope = samp_slope; dsamp1 = startpos; ramp1 = 0.0; unit->ramp1_slope = ramp1_slope = slope; unit->ramp3_slope = ramp3_slope = -slope; break; case 1 : unit->dsamp2_slope = dsamp2_slope = samp_slope; dsamp2 = startpos; ramp2 = 0.0; unit->ramp2_slope = ramp2_slope = slope; unit->ramp4_slope = ramp4_slope = -slope; break; case 2 : unit->dsamp3_slope = dsamp3_slope = samp_slope; dsamp3 = startpos; ramp3 = 0.0; unit->ramp3_slope = ramp3_slope = slope; unit->ramp1_slope = ramp1_slope = -slope; break; case 3 : unit->dsamp4_slope = dsamp4_slope = samp_slope; dsamp4 = startpos; ramp4 = 0.0; unit->ramp2_slope = ramp2_slope = -slope; unit->ramp4_slope = ramp4_slope = slope; break; } /*Print("%d %d %g %g %g %g %g %g %g %g %g %g %g %g\n", counter, stage, dsamp1_slope, dsamp2_slope, dsamp3_slope, dsamp4_slope, dsamp1, dsamp2, dsamp3, dsamp4, ramp1, ramp2, ramp3, ramp4);*/ } nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; LOOP(nsmps, iwrphase = (iwrphase + 1) & mask; dsamp1 += dsamp1_slope; idsamp = (long)dsamp1; frac = dsamp1 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value = (d1 + frac * (d2 - d1)) * ramp1; ramp1 += ramp1_slope; dsamp2 += dsamp2_slope; idsamp = (long)dsamp2; frac = dsamp2 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp2; ramp2 += ramp2_slope; dsamp3 += dsamp3_slope; idsamp = (long)dsamp3; frac = dsamp3 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp3; ramp3 += ramp3_slope; dsamp4 += dsamp4_slope; idsamp = (long)dsamp4; frac = dsamp4 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp4; ramp4 += ramp4_slope; dlybuf[iwrphase] = ZXP(in); ZXP(out) = value *= 0.5; ); } unit->counter = counter; unit->dsamp1 = dsamp1; unit->dsamp2 = dsamp2; unit->dsamp3 = dsamp3; unit->dsamp4 = dsamp4; unit->ramp1 = ramp1; unit->ramp2 = ramp2; unit->ramp3 = ramp3; unit->ramp4 = ramp4; unit->iwrphase = iwrphase; RPUT } void PitchShift_next_z(PitchShift *unit, int inNumSamples); void PitchShift_next_z(PitchShift *unit, int inNumSamples) { float *out, *in, *dlybuf; float disppchratio, pchratio, pchratio1, value; float dsamp1, dsamp1_slope, ramp1, ramp1_slope; float dsamp2, dsamp2_slope, ramp2, ramp2_slope; float dsamp3, dsamp3_slope, ramp3, ramp3_slope; float dsamp4, dsamp4_slope, ramp4, ramp4_slope; float fdelaylen, d1, d2, frac, slope, samp_slope, startpos, winsize, pchdisp, timedisp; long remain, nsmps, idelaylen, irdphase, irdphaseb, iwrphase; long mask, idsamp; long counter, stage, framesize, numoutput; RGET out = ZOUT(0); in = ZIN(0); pchratio = ZIN0(2); winsize = ZIN0(1); pchdisp = ZIN0(3); timedisp = ZIN0(4); timedisp = sc_clip(timedisp, 0.f, winsize) * SAMPLERATE; dlybuf = unit->dlybuf; fdelaylen = unit->fdelaylen; idelaylen = unit->idelaylen; iwrphase = unit->iwrphase; numoutput = unit->numoutput; counter = unit->counter; stage = unit->stage; mask = unit->mask; framesize = unit->framesize; dsamp1 = unit->dsamp1; dsamp2 = unit->dsamp2; dsamp3 = unit->dsamp3; dsamp4 = unit->dsamp4; dsamp1_slope = unit->dsamp1_slope; dsamp2_slope = unit->dsamp2_slope; dsamp3_slope = unit->dsamp3_slope; dsamp4_slope = unit->dsamp4_slope; ramp1 = unit->ramp1; ramp2 = unit->ramp2; ramp3 = unit->ramp3; ramp4 = unit->ramp4; ramp1_slope = unit->ramp1_slope; ramp2_slope = unit->ramp2_slope; ramp3_slope = unit->ramp3_slope; ramp4_slope = unit->ramp4_slope; slope = unit->slope; remain = inNumSamples; while (remain) { if (counter <= 0) { counter = framesize >> 2; unit->stage = stage = (stage + 1) & 3; disppchratio = pchratio; if (pchdisp != 0.f) { disppchratio += (pchdisp * frand2(s1,s2,s3)); } disppchratio = sc_clip(disppchratio, 0.f, 4.f); pchratio1 = disppchratio - 1.f; samp_slope = -pchratio1; startpos = pchratio1 < 0.f ? 2.f : framesize * pchratio1 + 2.f; startpos += (timedisp * frand(s1,s2,s3)); switch(stage) { case 0 : unit->dsamp1_slope = dsamp1_slope = samp_slope; dsamp1 = startpos; ramp1 = 0.0; unit->ramp1_slope = ramp1_slope = slope; unit->ramp3_slope = ramp3_slope = -slope; break; case 1 : unit->dsamp2_slope = dsamp2_slope = samp_slope; dsamp2 = startpos; ramp2 = 0.0; unit->ramp2_slope = ramp2_slope = slope; unit->ramp4_slope = ramp4_slope = -slope; break; case 2 : unit->dsamp3_slope = dsamp3_slope = samp_slope; dsamp3 = startpos; ramp3 = 0.0; unit->ramp3_slope = ramp3_slope = slope; unit->ramp1_slope = ramp1_slope = -slope; break; case 3 : unit->dsamp4_slope = dsamp4_slope = samp_slope; dsamp4 = startpos; ramp4 = 0.0; unit->ramp2_slope = ramp2_slope = -slope; unit->ramp4_slope = ramp4_slope = slope; break; } /*Print("z %d %d %g %g %g %g %g %g %g %g %g %g %g %g\n", counter, stage, dsamp1_slope, dsamp2_slope, dsamp3_slope, dsamp4_slope, dsamp1, dsamp2, dsamp3, dsamp4, ramp1, ramp2, ramp3, ramp4);*/ } nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; while (nsmps--) { numoutput++; iwrphase = (iwrphase + 1) & mask; dsamp1 += dsamp1_slope; idsamp = (long)dsamp1; frac = dsamp1 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; if (numoutput < idelaylen) { if (irdphase > iwrphase) { value = 0.f; } else if (irdphaseb > iwrphase) { d1 = dlybuf[irdphase]; value = (d1 - frac * d1) * ramp1; } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value = (d1 + frac * (d2 - d1)) * ramp1; } } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value = (d1 + frac * (d2 - d1)) * ramp1; } ramp1 += ramp1_slope; dsamp2 += dsamp2_slope; idsamp = (long)dsamp2; frac = dsamp2 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; if (numoutput < idelaylen) { if (irdphase > iwrphase) { //value += 0.f; } else if (irdphaseb > iwrphase) { d1 = dlybuf[irdphase]; value += (d1 - frac * d1) * ramp2; } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp2; } } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp2; } ramp2 += ramp2_slope; dsamp3 += dsamp3_slope; idsamp = (long)dsamp3; frac = dsamp3 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; if (numoutput < idelaylen) { if (irdphase > iwrphase) { //value += 0.f; } else if (irdphaseb > iwrphase) { d1 = dlybuf[irdphase]; value += (d1 - frac * d1) * ramp3; } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp3; } } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp3; } ramp3 += ramp3_slope; dsamp4 += dsamp4_slope; idsamp = (long)dsamp4; frac = dsamp4 - idsamp; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; if (numoutput < idelaylen) { if (irdphase > iwrphase) { //value += 0.f; } else if (irdphaseb > iwrphase) { d1 = dlybuf[irdphase]; value += (d1 - frac * d1) * ramp4; } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp4; } } else { d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; value += (d1 + frac * (d2 - d1)) * ramp4; } ramp4 += ramp4_slope; dlybuf[iwrphase] = ZXP(in); ZXP(out) = value *= 0.5; } } unit->counter = counter; unit->stage = stage; unit->mask = mask; unit->dsamp1 = dsamp1; unit->dsamp2 = dsamp2; unit->dsamp3 = dsamp3; unit->dsamp4 = dsamp4; unit->ramp1 = ramp1; unit->ramp2 = ramp2; unit->ramp3 = ramp3; unit->ramp4 = ramp4; unit->numoutput = numoutput; unit->iwrphase = iwrphase; if (numoutput >= idelaylen) { SETCALC(PitchShift_next); } RPUT } void PitchShift_Ctor(PitchShift *unit); void PitchShift_Ctor(PitchShift *unit) { long delaybufsize; float *out, *in, *dlybuf; float winsize, pchratio; float fdelaylen, slope; long framesize, last; out = ZOUT(0); in = ZIN(0); pchratio = ZIN0(2); winsize = ZIN0(1); delaybufsize = (long)ceil(winsize * SAMPLERATE * 3.f + 3.f); fdelaylen = delaybufsize - 3; delaybufsize = delaybufsize + BUFLENGTH; delaybufsize = NEXTPOWEROFTWO(delaybufsize); // round up to next power of two dlybuf = (float*)RTAlloc(unit->mWorld, delaybufsize * sizeof(float)); SETCALC(PitchShift_next_z); *dlybuf = ZIN0(0); ZOUT0(0) = 0.f; unit->dlybuf = dlybuf; unit->idelaylen = delaybufsize; unit->fdelaylen = fdelaylen; unit->iwrphase = 0; unit->numoutput = 0; unit->mask = last = (delaybufsize - 1); unit->framesize = framesize = ((long)(winsize * SAMPLERATE) + 2) & ~3; unit->slope = slope = 2.f / framesize; unit->stage = 3; unit->counter = framesize >> 2; unit->ramp1 = 0.5; unit->ramp2 = 1.0; unit->ramp3 = 0.5; unit->ramp4 = 0.0; unit->ramp1_slope = -slope; unit->ramp2_slope = -slope; unit->ramp3_slope = slope; unit->ramp4_slope = slope; dlybuf[last ] = 0.f; // put a few zeroes where we start the read heads dlybuf[last-1] = 0.f; dlybuf[last-2] = 0.f; unit->numoutput = 0; // start all read heads 2 samples behind the write head unit->dsamp1 = unit->dsamp2 = unit->dsamp3 = unit->dsamp4 = 2.f; // pch ratio is initially zero for the read heads unit->dsamp1_slope = unit->dsamp2_slope = unit->dsamp3_slope = unit->dsamp4_slope = 1.f; } void PitchShift_Dtor(PitchShift *unit) { RTFree(unit->mWorld, unit->dlybuf); } typedef struct graintap1 { float pos, rate, level, slope, curve; long counter; struct graintap1 *next; } GrainTap1; #define MAXDGRAINS 32 struct GrainTap : public Unit { float m_fbufnum; SndBuf *m_buf; float fdelaylen; long bufsize, iwrphase; long nextTime; GrainTap1 grains[MAXDGRAINS]; GrainTap1 *firstActive, *firstFree; }; // coefs: pos, rate, level, slope, curve, counter void GrainTap_next(GrainTap *unit, int inNumSamples); void GrainTap_next(GrainTap *unit, int inNumSamples) { float *out, *out0; const float * dlybuf; float sdur, rdur, rdur2; float dsamp, dsamp_slope, fdelaylen, d1, d2, frac; float level, slope, curve; float maxpitch, pitch, maxtimedisp, timedisp, density; long remain, nsmps, irdphase, irdphaseb, iwrphase, iwrphase0; long idsamp, koffset; long counter; uint32 bufsize; GrainTap1 *grain, *prevGrain, *nextGrain; GET_BUF_SHARED RGET out0 = ZOUT(0); // bufnum, grainDur, pchRatio, pchDisp, timeDisp, overlap // 0 1 2 3 4 5 density = ZIN0(5); density = sc_max(0.0001, density); bufsize = unit->bufsize; if (bufsize != bufSamples) { ClearUnitOutputs(unit, inNumSamples); return; } dlybuf = bufData; fdelaylen = unit->fdelaylen; iwrphase0 = unit->iwrphase; // initialize buffer to zero out = out0; LOOP1(inNumSamples, ZXP(out) = 0.f;); // do all current grains prevGrain = NULL; grain = unit->firstActive; while (grain) { dsamp = grain->pos; dsamp_slope = grain->rate; level = grain->level; slope = grain->slope; curve = grain->curve; counter = grain->counter; nsmps = sc_min(counter, inNumSamples); iwrphase = iwrphase0; out = out0; LOOP(nsmps, dsamp += dsamp_slope; idsamp = (long)dsamp; frac = dsamp - idsamp; iwrphase = (iwrphase + 1) & mask; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; ZXP(out) += (d1 + frac * (d2 - d1)) * level; level += slope; slope += curve; ); grain->pos = dsamp; grain->level = level; grain->slope = slope; grain->counter -= nsmps; nextGrain = grain->next; if (grain->counter <= 0) { // unlink from active list if (prevGrain) prevGrain->next = nextGrain; else unit->firstActive = nextGrain; // link onto free list grain->next = unit->firstFree; unit->firstFree = grain; } else { prevGrain = grain; } grain = nextGrain; } // start new grains remain = inNumSamples; while (unit->nextTime <= remain) { remain -= unit->nextTime; sdur = ZIN0(1) * SAMPLERATE; sdur = sc_max(sdur, 4.f); grain = unit->firstFree; if (grain) { unit->firstFree = grain->next; grain->next = unit->firstActive; unit->firstActive = grain; koffset = inNumSamples - remain; iwrphase = (iwrphase0 + koffset) & mask; grain->counter = (long)sdur; timedisp = ZIN0(4); timedisp = sc_max(timedisp, 0.f); timedisp = frand(s1,s2,s3) * timedisp * SAMPLERATE; pitch = ZIN0(2) + frand2(s1,s2,s3) * ZIN0(3); if (pitch >= 1.f) { maxpitch = 1.f + (fdelaylen/sdur); pitch = sc_min(pitch, maxpitch); dsamp_slope = 1.f - pitch; grain->rate = dsamp_slope; maxtimedisp = fdelaylen + sdur * dsamp_slope; timedisp = sc_min(timedisp, maxtimedisp); dsamp = BUFLENGTH + koffset + 2.f + timedisp - sdur * dsamp_slope; dsamp = sc_min(dsamp, fdelaylen); } else { maxpitch = -(1.f + (fdelaylen/sdur)); pitch = sc_max(pitch, maxpitch); dsamp_slope = 1.f - pitch; grain->rate = dsamp_slope; maxtimedisp = fdelaylen - sdur * dsamp_slope; timedisp = sc_min(timedisp, maxtimedisp); dsamp = BUFLENGTH + koffset + 2.f + timedisp; dsamp = sc_min(dsamp, fdelaylen); } grain->pos = dsamp; //postbuf("ds %g %g %g\n", dsamp_slope, dsamp, fdelaylen); rdur = 1.f / sdur; rdur2 = rdur * rdur; grain->level = level = 0.f; grain->slope = slope = 4.0 * (rdur - rdur2); // ampslope grain->curve = curve = -8.0 * rdur2; // ampcurve nsmps = remain; out = out0 + koffset; LOOP(nsmps, dsamp += dsamp_slope; idsamp = (long)dsamp; frac = dsamp - idsamp; iwrphase = (iwrphase + 1) & mask; irdphase = (iwrphase - idsamp) & mask; irdphaseb = (irdphase - 1) & mask; d1 = dlybuf[irdphase]; d2 = dlybuf[irdphaseb]; ZXP(out) += (d1 + frac * (d2 - d1)) * level; level += slope; slope += curve; ); grain->pos = dsamp; grain->level = level; grain->slope = slope; grain->counter -= nsmps; if (grain->counter <= 0) { // unlink from active list unit->firstActive = grain->next; // link onto free list grain->next = unit->firstFree; unit->firstFree = grain; } } unit->nextTime = (long)(sdur / density); if (unit->nextTime < 1) unit->nextTime = 1; /*if (grain == NULL) { postbuf("nextTime %d %g %g %p %p %p\n", unit->nextTime, sdur, density, grain, unit->firstActive, unit->firstFree); }*/ } iwrphase = (iwrphase0 + BUFLENGTH) & mask; unit->nextTime -= remain; if (unit->nextTime < 0) unit->nextTime = 0; unit->iwrphase = iwrphase; RPUT } void GrainTap_Ctor(GrainTap *unit); void GrainTap_Ctor(GrainTap *unit) { float fdelaylen; float maxdelaytime; GET_BUF if (!ISPOWEROFTWO(bufSamples)) { Print("GrainTap buffer size not a power of two.\n"); SETCALC(*ClearUnitOutputs); return; } fdelaylen = bufSamples - 2 * BUFLENGTH - 3; maxdelaytime = fdelaylen * SAMPLEDUR; SETCALC(GrainTap_next); ZOUT0(0) = 0.f; unit->bufsize = bufSamples; unit->fdelaylen = fdelaylen; unit->iwrphase = 0; unit->nextTime = 0; for (int i=0; igrains[i].next = unit->grains + (i + 1); } unit->grains[MAXDGRAINS-1].next = NULL; unit->firstFree = unit->grains; unit->firstActive = NULL; } //////////////////////////////////////////////////////////////////////////////////////////////////////// #define GRAIN_BUF \ const SndBuf *buf = NULL; \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - numBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ continue; \ } \ } else { \ buf = bufs + bufnum; \ } \ LOCK_SNDBUF_SHARED(buf); \ const float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples __attribute__((__unused__)) = buf->samples; \ uint32 bufFrames = buf->frames; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; \ inline float IN_AT(Unit* unit, int index, int offset) { if (INRATE(index) == calc_FullRate) return IN(index)[offset]; if (INRATE(index) == calc_DemandRate) return DEMANDINPUT_A(index, offset + 1); return ZIN0(index); } inline double sc_gloop(double in, double hi) { // avoid the divide if possible if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < 0.) { in += hi; if (in >= 0.) return in; } else return in; return in - hi * floor(in/hi); } #define GRAIN_LOOP_BODY_4 \ float amp = y1 * y1; \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase; \ const float* table0 = table1 - 1; \ const float* table2 = table1 + 1; \ const float* table3 = table1 + 2; \ if (iphase == 0) { \ table0 += bufSamples; \ } else if (iphase >= guardFrame) { \ if (iphase == guardFrame) { \ table3 -= bufSamples; \ } else { \ table2 -= bufSamples; \ table3 -= bufSamples; \ } \ } \ float fracphase = phase - (double)iphase; \ float a = table0[0]; \ float b = table1[0]; \ float c = table2[0]; \ float d = table3[0]; \ float outval = amp * cubicinterp(fracphase, a, b, c, d); \ ZXP(out1) += outval * pan1; \ if (numOutputs > 1) { ZXP(out2) += outval * pan2; } \ double y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; \ #define GRAIN_LOOP_BODY_2 \ float amp = y1 * y1; \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase; \ const float* table2 = table1 + 1; \ if (iphase > guardFrame) { \ table2 -= bufSamples; \ } \ float fracphase = phase - (double)iphase; \ float b = table1[0]; \ float c = table2[0]; \ float outval = amp * (b + fracphase * (c - b)); \ ZXP(out1) += outval * pan1; \ if (numOutputs > 1) { ZXP(out2) += outval * pan2; } \ double y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; \ #define GRAIN_LOOP_BODY_1 \ float amp = y1 * y1; \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float outval = amp * bufData[iphase]; \ ZXP(out1) += outval * pan1; \ ZXP(out2) += outval * pan2; \ double y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; \ void TGrains_next(TGrains *unit, int inNumSamples) { float *trigin = IN(0); float prevtrig = unit->mPrevTrig; uint32 numOutputs = unit->mNumOutputs; ClearUnitOutputs(unit, inNumSamples); float *out[16]; for (uint32 i=0; imWorld; SndBuf *bufs = world->mSndBufs; uint32 numBufs = world->mNumSndBufs; for (int i=0; i < unit->mNumActive; ) { Grain *grain = unit->mGrains + i; uint32 bufnum = grain->bufnum; GRAIN_BUF if (bufChannels != 1) { ++i; continue; } double loopMax = (double)bufFrames; float pan1 = grain->pan1; float pan2 = grain->pan2; double rate = grain->rate; double phase = grain->phase; double b1 = grain->b1; double y1 = grain->y1; double y2 = grain->y2; uint32 chan1 = grain->chan; uint32 chan2 = chan1 + 1; if (chan2 >= numOutputs) chan2 = 0; float *out1 = out[chan1]; float *out2 = out[chan2]; //printf("B chan %d %d %p %p", chan1, chan2, out1, out2); int nsmps = sc_min(grain->counter, inNumSamples); if (grain->interp >= 4) { for (int j=0; jinterp >= 2) { for (int j=0; jphase = phase; grain->y1 = y1; grain->y2 = y2; grain->counter -= nsmps; if (grain->counter <= 0) { // remove grain *grain = unit->mGrains[--unit->mNumActive]; } else ++i; } int trigSamples = INRATE(0) == calc_FullRate ? inNumSamples : 1; for (int i=0; i 0.f && prevtrig <= 0.f) { // start a grain if (unit->mNumActive+1 >= kMaxGrains) break; uint32 bufnum = (uint32)IN_AT(unit, 1, i); GRAIN_BUF if (bufChannels != 1) continue; float bufSampleRate = buf->samplerate; float bufRateScale = bufSampleRate * SAMPLEDUR; double loopMax = (double)bufFrames; Grain *grain = unit->mGrains + unit->mNumActive++; grain->bufnum = bufnum; double counter = floor(IN_AT(unit, 4, i) * SAMPLERATE); counter = sc_max(4., counter); grain->counter = (int)counter; double rate = grain->rate = IN_AT(unit, 2, i) * bufRateScale; double centerPhase = IN_AT(unit, 3, i) * bufSampleRate; double phase = centerPhase - 0.5 * counter * rate; float pan = IN_AT(unit, 5, i); float amp = IN_AT(unit, 6, i); grain->interp = (int)IN_AT(unit, 7, i); float panangle; float pan1, pan2; if (numOutputs > 1) { if (numOutputs > 2) { pan = sc_wrap(pan * 0.5f, 0.f, 1.f); float cpan = numOutputs * pan + 0.5f; float ipan = floor(cpan); float panfrac = cpan - ipan; panangle = panfrac * pi2_f; grain->chan = (int)ipan; if (grain->chan >= (int)numOutputs) grain->chan -= numOutputs; } else { grain->chan = 0; pan = sc_clip(pan * 0.5f + 0.5f, 0.f, 1.f); panangle = pan * pi2_f; } pan1 = grain->pan1 = cos(panangle); pan2 = grain->pan2 = sin(panangle); } else { grain->chan = 0; pan1 = grain->pan1 = 1.; pan2 = grain->pan2 = 0.; } double w = pi / counter; double b1 = grain->b1 = 2. * cos(w); double y1 = sin(w); double y2 = 0.; uint32 chan1 = grain->chan; uint32 chan2 = chan1 + 1; if (chan2 >= numOutputs) chan2 = 0; float *out1 = out[chan1] + i; float *out2 = out[chan2] + i; int nsmps = sc_min(grain->counter, inNumSamples - i); if (grain->interp >= 4) { for (int j=0; jinterp >= 2) { for (int j=0; jphase = phase; grain->y1 = y1; grain->y2 = y2; grain->counter -= nsmps; if (grain->counter <= 0) { // remove grain *grain = unit->mGrains[--unit->mNumActive]; } } prevtrig = trig; } unit->mPrevTrig = prevtrig; } void TGrains_Ctor(TGrains *unit) { SETCALC(TGrains_next); unit->mNumActive = 0; unit->mPrevTrig = 0.; ClearUnitOutputs(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// /* Pluck - Karplus-Strong */ void Pluck_Ctor(Pluck *unit) { unit->m_maxdelaytime = IN0(2); unit->m_delaytime = IN0(3); unit->m_decaytime = IN0(4); unit->m_dlybuf = 0; bool allocationSucessful = DelayUnit_AllocDelayLine(unit, "Pluck"); if (!allocationSucessful) return; unit->m_dsamp = CalcDelay(unit, unit->m_delaytime); unit->m_numoutput = 0; unit->m_iwrphase = 0; unit->m_feedbk = sc_CalcFeedback(unit->m_delaytime, unit->m_decaytime); if (INRATE(1) == calc_FullRate) { if(INRATE(5) == calc_FullRate){ SETCALC(Pluck_next_aa_z); } else { SETCALC(Pluck_next_ak_z); //ak } } else { if(INRATE(5) == calc_FullRate){ SETCALC(Pluck_next_ka_z); //ka } else { SETCALC(Pluck_next_kk_z); //kk } } OUT0(0) = unit->m_lastsamp = 0.f; unit->m_prevtrig = 0.f; unit->m_inputsamps = 0; unit->m_coef = IN0(5); } void Pluck_next_aa(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float *trig = IN(1); float delaytime = IN0(3); float decaytime = IN0(4); float *coef = IN(5); float lastsamp = unit->m_lastsamp; unsigned long inputsamps = unit->m_inputsamps; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float thisin, curtrig; float prevtrig = unit->m_prevtrig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); for(int i = 0; i < inNumSamples; i++){ curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; feedbk += feedbk_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_prevtrig = prevtrig; unit->m_inputsamps = inputsamps; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; } void Pluck_next_aa_z(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float *trig = IN(1); float delaytime = IN0(3); float decaytime = IN0(4); float *coef = IN(5); float lastsamp = unit->m_lastsamp; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float d0, d1, d2, d3; float thisin, curtrig; unsigned long inputsamps = unit->m_inputsamps; float prevtrig = unit->m_prevtrig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; } iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); for(int i = 0; i < inNumSamples; i++) { curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; } feedbk += feedbk_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_inputsamps = inputsamps; unit->m_prevtrig = prevtrig; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) { SETCALC(Pluck_next_aa); } } void Pluck_next_kk(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float trig = IN0(1); float delaytime = IN0(3); float decaytime = IN0(4); float coef = IN0(5); float lastsamp = unit->m_lastsamp; unsigned long inputsamps = unit->m_inputsamps; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float thisin; if ((unit->m_prevtrig <= 0.f) && (trig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } unit->m_prevtrig = trig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime && coef == unit->m_coef) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(coef)) * value) + (coef * lastsamp); dlybuf[iwrphase & mask] = thisin + (feedbk * onepole); out[i] = lastsamp = onepole; //value; iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); float curcoef = unit->m_coef; float coef_slope = CALCSLOPE(coef, curcoef); for(int i = 0; i < inNumSamples; i++){ dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(curcoef)) * value) + (curcoef * lastsamp); dlybuf[iwrphase & mask] = thisin + (feedbk * onepole); out[i] = lastsamp = onepole; //value; feedbk += feedbk_slope; curcoef += coef_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_coef = coef; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_inputsamps = inputsamps; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; } void Pluck_next_kk_z(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float trig = IN0(1); float delaytime = IN0(3); float decaytime = IN0(4); float coef = IN0(5); float lastsamp = unit->m_lastsamp; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float d0, d1, d2, d3; float thisin; unsigned long inputsamps = unit->m_inputsamps; if ((unit->m_prevtrig <= 0.f) && (trig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } unit->m_prevtrig = trig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime && coef == unit->m_coef) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(coef)) * value) + (coef * lastsamp); dlybuf[iwrphase & mask] = thisin + (feedbk * onepole); out[i] = lastsamp = onepole; //value; } iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); float curcoef = unit->m_coef; float coef_slope = CALCSLOPE(coef, curcoef); for(int i = 0; i < inNumSamples; i++) { dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(curcoef)) * value) + (curcoef * lastsamp); dlybuf[iwrphase & mask] = thisin + (feedbk * onepole); out[i] = lastsamp = onepole; //value; } feedbk += feedbk_slope; curcoef += coef_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; unit->m_coef = coef; } unit->m_inputsamps = inputsamps; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) { SETCALC(Pluck_next_kk); } } void Pluck_next_ak(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float *trig = IN(1); float delaytime = IN0(3); float decaytime = IN0(4); float coef = IN0(5); float lastsamp = unit->m_lastsamp; unsigned long inputsamps = unit->m_inputsamps; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float thisin, curtrig; float prevtrig = unit->m_prevtrig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(coef)) * value) + (coef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); float curcoef = unit->m_coef; float coef_slope = CALCSLOPE(coef, curcoef); for(int i = 0; i < inNumSamples; i++){ curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(curcoef)) * value) + (curcoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; feedbk += feedbk_slope; curcoef += coef_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; unit->m_coef = coef; } unit->m_prevtrig = prevtrig; unit->m_inputsamps = inputsamps; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; } void Pluck_next_ak_z(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float *trig = IN(1); float delaytime = IN0(3); float decaytime = IN0(4); float coef = IN0(5); float lastsamp = unit->m_lastsamp; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float d0, d1, d2, d3; float thisin, curtrig; unsigned long inputsamps = unit->m_inputsamps; float prevtrig = unit->m_prevtrig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime && coef == unit->m_coef) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(coef)) * value) + (coef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; } iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); float curcoef = unit->m_coef; float coef_slope = CALCSLOPE(coef, curcoef); for(int i = 0; i < inNumSamples; i++) { curtrig = trig[i]; if ((prevtrig <= 0.f) && (curtrig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } prevtrig = curtrig; dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float onepole = ((1. - fabs(curcoef)) * value) + (curcoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; } feedbk += feedbk_slope; curcoef +=coef_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; unit->m_coef = coef; } unit->m_inputsamps = inputsamps; unit->m_prevtrig = prevtrig; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) { SETCALC(Pluck_next_ak); } } void Pluck_next_ka(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float trig = IN0(1); float delaytime = IN0(3); float decaytime = IN0(4); float *coef = IN(5); float lastsamp = unit->m_lastsamp; unsigned long inputsamps = unit->m_inputsamps; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float thisin; if ((unit->m_prevtrig <= 0.f) && (trig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } unit->m_prevtrig = trig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); for(int i = 0; i < inNumSamples; i++){ dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } float d0 = dlybuf[irdphase0 & mask]; float d1 = dlybuf[irdphase1 & mask]; float d2 = dlybuf[irdphase2 & mask]; float d3 = dlybuf[irdphase3 & mask]; float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; feedbk += feedbk_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_inputsamps = inputsamps; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; } void Pluck_next_ka_z(Pluck *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float trig = IN0(1); float delaytime = IN0(3); float decaytime = IN0(4); float *coef = IN(5); float lastsamp = unit->m_lastsamp; float *dlybuf = unit->m_dlybuf; long iwrphase = unit->m_iwrphase; float dsamp = unit->m_dsamp; float feedbk = unit->m_feedbk; long mask = unit->m_mask; float d0, d1, d2, d3; float thisin; unsigned long inputsamps = unit->m_inputsamps; if ((unit->m_prevtrig <= 0.f) && (trig > 0.f)) { inputsamps = (long)(delaytime * unit->mRate->mSampleRate + .5f); } unit->m_prevtrig = trig; if (delaytime == unit->m_delaytime && decaytime == unit->m_decaytime) { long idsamp = (long)dsamp; float frac = dsamp - idsamp; for(int i = 0; i < inNumSamples; i++){ long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; } iwrphase++; }; } else { float next_dsamp = CalcDelay(unit, delaytime); float dsamp_slope = CALCSLOPE(next_dsamp, dsamp); float next_feedbk = sc_CalcFeedback(delaytime, decaytime); float feedbk_slope = CALCSLOPE(next_feedbk, feedbk); for(int i = 0; i < inNumSamples; i++) { dsamp += dsamp_slope; long idsamp = (long)dsamp; float frac = dsamp - idsamp; long irdphase1 = iwrphase - idsamp; long irdphase2 = irdphase1 - 1; long irdphase3 = irdphase1 - 2; long irdphase0 = irdphase1 + 1; if (inputsamps > 0) { thisin = in[i]; --inputsamps; } else { thisin = 0.f; } if (irdphase0 < 0) { dlybuf[iwrphase & mask] = thisin; out[i] = 0.f; } else { if (irdphase1 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; } else if (irdphase2 < 0) { d1 = d2 = d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; } else if (irdphase3 < 0) { d3 = 0.f; d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; } else { d0 = dlybuf[irdphase0 & mask]; d1 = dlybuf[irdphase1 & mask]; d2 = dlybuf[irdphase2 & mask]; d3 = dlybuf[irdphase3 & mask]; } float value = cubicinterp(frac, d0, d1, d2, d3); float thiscoef = coef[i]; float onepole = ((1. - fabs(thiscoef)) * value) + (thiscoef * lastsamp); dlybuf[iwrphase & mask] = thisin + feedbk * onepole; out[i] = lastsamp = onepole; } feedbk += feedbk_slope; iwrphase++; }; unit->m_feedbk = feedbk; unit->m_dsamp = dsamp; unit->m_delaytime = delaytime; unit->m_decaytime = decaytime; } unit->m_inputsamps = inputsamps; unit->m_lastsamp = zapgremlins(lastsamp); unit->m_iwrphase = iwrphase; unit->m_numoutput += inNumSamples; if (unit->m_numoutput >= unit->m_idelaylen) { SETCALC(Pluck_next_ka); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// #define DELTAP_BUF \ World *world = unit->mWorld;\ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ unit->m_buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ unit->m_buf = world->mSndBufs + bufnum; \ } \ } else { \ unit->m_buf = world->mSndBufs + bufnum; \ } \ SndBuf *buf = unit->m_buf; \ float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples = buf->samples; \ uint32 bufFrames = buf->frames; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; \ double loopMax __attribute__((__unused__)) = (double)bufSamples; #define CHECK_DELTAP_BUF \ if ((!bufData) || (bufChannels != 1)) { \ unit->mDone = true; \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } static void DelTapWr_first(DelTapWr *unit, int inNumSamples) { float fbufnum = IN0(0); uint32 bufnum = (uint32)fbufnum; float* in = IN(1); float* out = OUT(0); uint32 phase = unit->m_phase; DELTAP_BUF CHECK_DELTAP_BUF // zero out the buffer! #ifdef NOVA_SIMD if (nova::vec::is_aligned(bufData)) { uint32 unroll = bufSamples & (~(nova::vec::size - 1)); nova::zerovec_simd(bufData, unroll); uint32 remain = bufSamples - unroll; Clear(remain, bufData + unroll); } else Clear(bufSamples, bufData); #else Clear(bufSamples, bufData); #endif out[0] = (float)phase; bufData[phase] = in[0]; phase++; if(phase == bufSamples) phase -= bufSamples; unit->m_phase = phase; } void DelTapWr_Ctor(DelTapWr *unit) { if (BUFLENGTH & 15) SETCALC(DelTapWr_next); else SETCALC(DelTapWr_next_simd); unit->m_phase = 0; unit->m_fbufnum = -1e9f; DelTapWr_first(unit, 1); } template static inline void DelTapWr_perform(DelTapWr *unit, int inNumSamples) { float fbufnum = IN0(0); uint32 bufnum = (uint32)fbufnum; const float* in = ZIN(1); float* out = ZOUT(0); uint32 * phase_out = (uint32*)out; uint32 phase = unit->m_phase; DELTAP_BUF CHECK_DELTAP_BUF LOCK_SNDBUF(buf); int buf_remain = (int)(bufSamples - phase); if (inNumSamples < buf_remain) { /* fast-path */ #ifdef NOVA_SIMD if (simd) nova::copyvec_an_simd(bufData+phase, IN(1), inNumSamples); else #endif Copy(inNumSamples, bufData + phase, IN(1)); LOOP1 (inNumSamples, ZXP(phase_out) = phase++; ) } else { LOOP1 (inNumSamples, bufData[phase] = ZXP(in); ZXP(phase_out) = phase++; if(phase == bufSamples) phase -= bufSamples; ) } unit->m_phase = phase; } void DelTapWr_next(DelTapWr *unit, int inNumSamples) { DelTapWr_perform(unit, inNumSamples); } void DelTapWr_next_simd(DelTapWr *unit, int inNumSamples) { DelTapWr_perform(unit, inNumSamples); } #define SETUP_TAPDELK \ float delTime = unit->m_delTime; \ float newDelTime = IN0(2) * (float)SAMPLERATE; \ float delTimeInc = CALCSLOPE(newDelTime, delTime); \ float * fPhaseIn = IN(1); \ uint32 * iPhaseIn = (uint32*)fPhaseIn; \ uint32 phaseIn = *iPhaseIn; \ float fbufnum = IN0(0); \ uint32 bufnum = (uint32)fbufnum; \ float* out __attribute__((__unused__)) = ZOUT(0); \ #define SETUP_TAPDELA \ float* delTime = ZIN(2); \ float * fPhaseIn = IN(1); \ uint32 * iPhaseIn = (uint32*)fPhaseIn; \ uint32 phaseIn = *iPhaseIn; \ float fbufnum = IN0(0); \ uint32 bufnum = (uint32)fbufnum; \ float* out = ZOUT(0); \ void DelTapRd_Ctor(DelTapRd *unit) { unit->m_fbufnum = -1e9f; unit->m_delTime = IN0(2) * SAMPLERATE; int interp = (int)IN0(3); if (INRATE(2) == calc_FullRate) { if (interp == 2) SETCALC(DelTapRd_next2_a); else if (interp == 4) SETCALC(DelTapRd_next4_a); else SETCALC(DelTapRd_next1_a); } else { if (interp == 2) SETCALC(DelTapRd_next2_k); else if (interp == 4) SETCALC(DelTapRd_next4_k); else if (BUFLENGTH & 15) SETCALC(DelTapRd_next1_k); else { SETCALC(DelTapRd_next1_k_simd); DelTapRd_next1_k(unit, 1); return; } } (unit->mCalcFunc)(unit, 1); } void DelTapRd_next1_a(DelTapRd *unit, int inNumSamples) { SETUP_TAPDELA DELTAP_BUF CHECK_DELTAP_BUF LOCK_SNDBUF_SHARED(buf); LOOP1(inNumSamples, double curDelTimeSamps = ZXP(delTime) * SAMPLERATE; double phase = phaseIn - curDelTimeSamps; if(phase < 0.) phase += loopMax; if(phase >=loopMax) phase -= loopMax; int32 iphase = (int32)phase; ZXP(out) = bufData[iphase]; phaseIn += 1.; ) } template inline void DelTapRd_perform1_k(DelTapRd *unit, int inNumSamples) { SETUP_TAPDELK DELTAP_BUF CHECK_DELTAP_BUF float * zout = ZOUT(0); LOCK_SNDBUF_SHARED(buf); if (delTime == newDelTime) { double phase = (double)phaseIn - delTime; int32 iphase = (int32)phase; if ( (iphase >= 0) // lower bound && iphase + inNumSamples < (bufSamples - 1)) //upper bound { #ifdef NOVA_SIMD if (simd) nova::copyvec_na_simd(OUT(0), bufData + iphase, inNumSamples); else #endif Copy(inNumSamples, OUT(0), bufData + iphase); } else LOOP1(inNumSamples, if(iphase < 0) iphase += bufSamples; if(iphase >= bufSamples) iphase -= bufSamples; ZXP(zout) = bufData[iphase]; ++iphase; ) } else { LOOP1(inNumSamples, double phase = (double)phaseIn - delTime; if(phase < 0.) phase += loopMax; if(phase >=loopMax) phase -= loopMax; int32 iphase = (int32)phase; ZXP(zout) = bufData[iphase]; delTime += delTimeInc; ++phaseIn; ) unit->m_delTime = delTime; } } void DelTapRd_next1_k(DelTapRd *unit, int inNumSamples) { DelTapRd_perform1_k(unit, inNumSamples); } void DelTapRd_next1_k_simd(DelTapRd *unit, int inNumSamples) { DelTapRd_perform1_k(unit, inNumSamples); } void DelTapRd_next2_k(DelTapRd *unit, int inNumSamples) { SETUP_TAPDELK DELTAP_BUF CHECK_DELTAP_BUF int32 iloopMax = (int32)bufSamples; LOCK_SNDBUF_SHARED(buf); if (delTime == newDelTime) { double phase = (double)phaseIn - delTime; double dphase; float fracphase = std::modf(phase, &dphase); int32 iphase = (int32)dphase; if ( (phase >= 0) // lower bound && phase + inNumSamples < (loopMax - 2)) //upper bound { LOOP1(inNumSamples, int32 iphase1 = iphase + 1; float b = bufData[iphase]; float c = bufData[iphase1]; ZXP(out) = (b + fracphase * (c - b)); iphase += 1; ); } else { LOOP1(inNumSamples, if(iphase < 0) iphase += iloopMax; else if(iphase >= bufSamples) phase -= iloopMax; int32 iphase1 = iphase + 1; if(iphase1 >= iloopMax) iphase1 -= iloopMax; float b = bufData[iphase]; float c = bufData[iphase1]; ZXP(out) = (b + fracphase * (c - b)); ++iphase; ); } } else { LOOP1(inNumSamples, double phase = (double)phaseIn - delTime; if(phase < 0.) phase += loopMax; if(phase >= loopMax) phase -= loopMax; int32 iphase = (int32)phase; int32 iphase1 = iphase + 1; if(iphase1 >= iloopMax) iphase1 -= iloopMax; float fracphase = phase - (double)iphase; float b = bufData[iphase]; float c = bufData[iphase1]; ZXP(out) = (b + fracphase * (c - b)); delTime += delTimeInc; ++phaseIn; ); unit->m_delTime = delTime; } } void DelTapRd_next2_a(DelTapRd *unit, int inNumSamples) { SETUP_TAPDELA DELTAP_BUF CHECK_DELTAP_BUF int32 iloopMax = (int32)bufSamples; LOCK_SNDBUF_SHARED(buf); LOOP1(inNumSamples, double curDelTimeSamps = ZXP(delTime) * SAMPLERATE; double phase = (double)phaseIn - curDelTimeSamps; if(phase < 0.) phase += loopMax; if(phase >= loopMax) phase -= loopMax; int32 iphase = (int32)phase; int32 iphase1 = iphase + 1; if(iphase1 >= iloopMax) iphase1 -= iloopMax; float fracphase = phase - (double)iphase; float b = bufData[iphase]; float c = bufData[iphase1]; ZXP(out) = (b + fracphase * (c - b)); ++phaseIn; ); } void DelTapRd_next4_k(DelTapRd *unit, int inNumSamples) { SETUP_TAPDELK DELTAP_BUF CHECK_DELTAP_BUF int32 iloopMax = (int32)loopMax; LOCK_SNDBUF_SHARED(buf); if (delTime == newDelTime) { double phase = (double)phaseIn - delTime; double dphase; float fracphase = std::modf(phase, &dphase); int32 iphase = (int32)dphase; if ( (iphase >= 1) // lower bound && iphase + inNumSamples < (iloopMax - 4)) //upper bound { LOOP1(inNumSamples, int32 iphase0 = iphase - 1; int32 iphase1 = iphase + 1; int32 iphase2 = iphase + 2; float a = bufData[iphase0]; float b = bufData[iphase]; float c = bufData[iphase1]; float d = bufData[iphase2]; ZXP(out) = cubicinterp(fracphase, a, b, c, d); ++iphase; ); } else { LOOP1(inNumSamples, if(iphase < 0) iphase += iloopMax; else if(iphase >= iloopMax) iphase -= iloopMax; int32 iphase0 = iphase - 1; int32 iphase1 = iphase + 1; int32 iphase2 = iphase + 2; if(iphase0 < 0) iphase0 += iloopMax; if(iphase1 > iloopMax) iphase1 -=iloopMax; if(iphase2 > iloopMax) iphase2 -=iloopMax; float a = bufData[iphase0]; float b = bufData[iphase]; float c = bufData[iphase1]; float d = bufData[iphase2]; ZXP(out) = cubicinterp(fracphase, a, b, c, d); ++iphase; ); } } else { LOOP1(inNumSamples, double phase = (double)phaseIn - delTime; double dphase; float fracphase = std::modf(phase, &dphase); int32 iphase = (int32)dphase; if(iphase < 0.) iphase += iloopMax; if(iphase >= iloopMax) iphase -= iloopMax; int32 iphase0 = iphase - 1; int32 iphase1 = iphase + 1; int32 iphase2 = iphase + 2; if(iphase0 < 0) iphase0 += iloopMax; if(iphase1 > iloopMax) iphase1 -=iloopMax; if(iphase2 > iloopMax) iphase2 -=iloopMax; float a = bufData[iphase0]; float b = bufData[iphase]; float c = bufData[iphase1]; float d = bufData[iphase2]; ZXP(out) = cubicinterp(fracphase, a, b, c, d); delTime += delTimeInc; ++phaseIn; ); unit->m_delTime = delTime; } } void DelTapRd_next4_a(DelTapRd *unit, int inNumSamples) { SETUP_TAPDELA DELTAP_BUF CHECK_DELTAP_BUF int32 iloopMax = (int32)loopMax; LOCK_SNDBUF_SHARED(buf); LOOP1(inNumSamples, double curDelTimeSamps = ZXP(delTime) * SAMPLERATE; double phase = (double)phaseIn - curDelTimeSamps; if(phase < 0.) phase += loopMax; if(phase >= loopMax) phase -= loopMax; int32 iphase = (int32)phase; int32 iphase0 = iphase - 1; int32 iphase1 = iphase + 1; int32 iphase2 = iphase + 2; if(iphase0 < 0) iphase0 += iloopMax; if(iphase1 > iloopMax) iphase1 -=iloopMax; if(iphase2 > iloopMax) iphase2 -=iloopMax; float fracphase = phase - (double)iphase; float a = bufData[iphase0]; float b = bufData[iphase]; float c = bufData[iphase1]; float d = bufData[iphase2]; ZXP(out) = cubicinterp(fracphase, a, b, c, d); ++phaseIn; ); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(Delay) { ft = inTable; #define DefineInfoUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(Unit), (UnitCtorFunc)&name##_Ctor, 0, 0); DefineInfoUnit(ControlRate); DefineInfoUnit(SampleRate); DefineInfoUnit(SampleDur); DefineInfoUnit(ControlDur); DefineInfoUnit(SubsampleOffset); DefineInfoUnit(RadiansPerSample); DefineInfoUnit(BlockSize); DefineInfoUnit(NumInputBuses); DefineInfoUnit(NumOutputBuses); DefineInfoUnit(NumAudioBuses); DefineInfoUnit(NumControlBuses); DefineInfoUnit(NumBuffers); DefineInfoUnit(NumRunningSynths); DefineInfoUnit(NodeID); #define DefineBufInfoUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(BufInfoUnit), (UnitCtorFunc)&name##_Ctor, 0, 0); DefineBufInfoUnit(BufSampleRate); DefineBufInfoUnit(BufRateScale); DefineBufInfoUnit(BufSamples); DefineBufInfoUnit(BufFrames); DefineBufInfoUnit(BufChannels); DefineBufInfoUnit(BufDur); DefineSimpleCantAliasUnit(PlayBuf); #if NOTYET DefineSimpleUnit(SimpleLoopBuf); #endif DefineDtorUnit(RecordBuf); DefineSimpleUnit(BufRd); DefineSimpleUnit(BufWr); DefineDtorUnit(Pitch); DefineSimpleUnit(BufDelayN); DefineSimpleUnit(BufDelayL); DefineSimpleUnit(BufDelayC); DefineSimpleUnit(BufCombN); DefineSimpleUnit(BufCombL); DefineSimpleUnit(BufCombC); DefineSimpleUnit(BufAllpassN); DefineSimpleUnit(BufAllpassL); DefineSimpleUnit(BufAllpassC); #define DefineDelayUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(name), (UnitCtorFunc)&name##_Ctor, \ (UnitDtorFunc)&DelayUnit_Dtor, 0); DefineDelayUnit(DelayN); DefineDelayUnit(DelayL); DefineDelayUnit(DelayC); DefineDelayUnit(CombN); DefineDelayUnit(CombL); DefineDelayUnit(CombC); DefineDelayUnit(AllpassN); DefineDelayUnit(AllpassL); DefineDelayUnit(AllpassC); DefineDtorUnit(PitchShift); DefineSimpleUnit(GrainTap); DefineSimpleCantAliasUnit(TGrains); DefineDtorUnit(ScopeOut); DefineDtorUnit(ScopeOut2); DefineDelayUnit(Pluck); DefineSimpleUnit(DelTapWr); DefineSimpleUnit(DelTapRd); DefineDtorUnit(LocalBuf); DefineSimpleUnit(MaxLocalBufs); DefineSimpleUnit(SetBuf); DefineSimpleUnit(ClearBuf); } ////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/plugins/DemandUGens.cpp000644 000765 000024 00000150342 12766171707 023525 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include #include #include using std::floor; using std::numeric_limits; static InterfaceTable *ft; struct Demand : public Unit { float m_prevtrig; float m_prevreset; float *m_prevout; float **m_out; }; struct Duty : public Unit { float m_count; float m_prevreset; float m_prevout; }; struct DemandEnvGen : public Unit { float m_phase; float m_prevreset; double m_a1, m_a2, m_b1, m_y1, m_y2, m_grow, m_level, m_endLevel, m_curve; int m_shape; bool m_release, m_running; }; struct TDuty : public Unit { float m_count; float m_prevreset; }; struct Dseries : public Unit { double m_repeats; int32 m_repeatCount; double m_value; double m_step; }; struct Dgeom : public Unit { double m_repeats; int32 m_repeatCount; double m_value; double m_grow; }; struct Dwhite : public Unit { double m_repeats; int32 m_repeatCount; float m_lo; float m_range; }; struct Dbrown : public Unit { double m_repeats; int32 m_repeatCount; float m_lo; float m_hi; float m_step; float m_val; }; struct Diwhite : public Unit { double m_repeats; int32 m_repeatCount; int32 m_lo; int32 m_range; }; struct Dibrown : public Unit { double m_repeats; int32 m_repeatCount; int32 m_lo; int32 m_hi; int32 m_step; int32 m_val; }; struct Dseq : public Unit { double m_repeats; int32 m_repeatCount; int32 m_index; bool m_needToResetChild; }; struct Dshuf : public Unit { double m_repeats; int32 m_repeatCount; int32 m_index; bool m_needToResetChild; int32 *m_indices; }; struct Dbufrd : public Unit { float m_fbufnum; SndBuf *m_buf; }; struct Dbufwr : public Unit { float m_fbufnum; SndBuf *m_buf; }; struct Dser : public Dseq { }; struct Drand : public Dseq { }; struct Dxrand : public Dseq { }; struct Dwrand : public Dseq { int32 m_weights_size; }; struct Dswitch1 : public Unit { }; struct Dswitch : public Unit { int m_index; }; struct Dstutter : public Unit { double m_repeats; double m_repeatCount; float m_value; }; struct Donce : public Unit { int m_bufcounter; float m_prev; }; struct Dpoll : public Unit { char *m_id_string; bool m_mayprint; float m_id; }; struct Dreset : public Unit { float prev_reset; }; struct Dconst : public Unit { float m_total; float m_runningsum; float m_tolerance; }; extern "C" { void Demand_Ctor(Demand *unit); void Demand_Dtor(Demand *unit); void Demand_next_aa(Demand *unit, int inNumSamples); void Demand_next_ak(Demand *unit, int inNumSamples); void Demand_next_ka(Demand *unit, int inNumSamples); void Duty_Ctor(Duty *unit); void Duty_next_da(Duty *unit, int inNumSamples); void Duty_next_dk(Duty *unit, int inNumSamples); void Duty_next_dd(Duty *unit, int inNumSamples); void TDuty_Ctor(TDuty *unit); void TDuty_next_da(TDuty *unit, int inNumSamples); void TDuty_next_dk(TDuty *unit, int inNumSamples); void TDuty_next_dd(TDuty *unit, int inNumSamples); void DemandEnvGen_Ctor(DemandEnvGen *unit); void DemandEnvGen_next_k(DemandEnvGen *unit, int inNumSamples); void DemandEnvGen_next_a(DemandEnvGen *unit, int inNumSamples); void Dseries_Ctor(Dseries *unit); void Dseries_next(Dseries *unit, int inNumSamples); void Dgeom_Ctor(Dgeom *unit); void Dgeom_next(Dgeom *unit, int inNumSamples); void Dwhite_Ctor(Dwhite *unit); void Dwhite_next(Dwhite *unit, int inNumSamples); void Dbrown_Ctor(Dbrown *unit); void Dbrown_next(Dbrown *unit, int inNumSamples); void Diwhite_Ctor(Diwhite *unit); void Diwhite_next(Diwhite *unit, int inNumSamples); void Dibrown_Ctor(Dibrown *unit); void Dibrown_next(Dibrown *unit, int inNumSamples); void Dseq_Ctor(Dseq *unit); void Dseq_next(Dseq *unit, int inNumSamples); void Dshuf_Ctor(Dshuf *unit); void Dshuf_Dtor(Dshuf *unit); void Dshuf_next(Dshuf *unit, int inNumSamples); void Dbufrd_Ctor(Dbufrd *unit); void Dbufrd_next(Dbufrd *unit, int inNumSamples); void Dbufwr_Ctor(Dbufwr *unit); void Dbufwr_next(Dbufwr *unit, int inNumSamples); void Dser_Ctor(Dser *unit); void Dser_next(Dser *unit, int inNumSamples); void Drand_Ctor(Drand *unit); void Drand_next(Drand *unit, int inNumSamples); void Dxrand_Ctor(Dxrand *unit); void Dxrand_next(Dxrand *unit, int inNumSamples); void Dwrand_Ctor(Dwrand *unit); void Dwrand_next(Dwrand *unit, int inNumSamples); void Dswitch1_Ctor(Dswitch1 *unit); void Dswitch1_next(Dswitch1 *unit, int inNumSamples); void Dswitch_Ctor(Dswitch *unit); void Dswitch_next(Dswitch *unit, int inNumSamples); void Dstutter_Ctor(Dstutter *unit); void Dstutter_next(Dstutter *unit, int inNumSamples); void Dpoll_Ctor(Dpoll *unit); void Dpoll_Ctor(Dpoll *unit); void Dpoll_next(Dpoll *unit, int inNumSamples); void Dreset_Ctor(Dreset *unit); void Dreset_next(Dreset *unit, int inNumSamples); void Donce_Ctor(Donce *unit); void Donce_next(Donce *unit, int inNumSamples); void Dconst_Ctor(Dconst *unit); void Dconst_next(Dconst *unit, int inNumSamples); }; void Demand_next_aa(Demand *unit, int inNumSamples) { float *trig = ZIN(0); float *reset = ZIN(1); float** out = unit->m_out; float* prevout = unit->m_prevout; for (int i=0; imNumOutputs; ++i) { out[i] = OUT(i); } float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; //Print("Demand_next_aa %d %g\n", inNumSamples, prevtrig); for (int i=0; i 0.f && prevreset <= 0.f) { for (int j=2; jmNumInputs; ++j) { RESETINPUT(j); } } if (ztrig > 0.f && prevtrig <= 0.f) { //Print("triggered\n"); for (int j=2, k=0; jmNumInputs; ++j, ++k) { float x = DEMANDINPUT_A(j, i + 1); //printf("in %d %g\n", k, x); if (sc_isnan(x)) { x = prevout[k]; unit->mDone = true; } else prevout[k] = x; out[k][i] = x; } } else { for (int j=2, k=0; jmNumInputs; ++j, ++k) { out[k][i] = prevout[k]; } } prevtrig = ztrig; prevreset = zreset; } unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void Demand_next_ak(Demand *unit, int inNumSamples) { float *trig = ZIN(0); float zreset = IN0(1); float** out = unit->m_out; float *prevout = unit->m_prevout; for (int i=0; imNumOutputs; ++i) { out[i] = OUT(i); } float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; for (int i=0; i 0.f && prevreset <= 0.f) { for (int j=2; jmNumInputs; ++j) { RESETINPUT(j); } } if (ztrig > 0.f && prevtrig <= 0.f) { for (int j=2, k=0; jmNumInputs; ++j, ++k) { float x = DEMANDINPUT_A(j, i + 1); if (sc_isnan(x)) { x = prevout[k]; unit->mDone = true; } else prevout[k] = x; out[k][i] = x; } } else { for (int j=2, k=0; jmNumInputs; ++j, ++k) { out[k][i] = prevout[k]; } } prevtrig = ztrig; prevreset = zreset; } unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void Demand_next_ka(Demand *unit, int inNumSamples) { float ztrig = IN0(0); float *reset = ZIN(1); float** out = unit->m_out; float *prevout = unit->m_prevout; for (int i=0; imNumOutputs; ++i) { out[i] = OUT(i); } float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; for (int i=0; i 0.f && prevreset <= 0.f) { for (int j=2; jmNumInputs; ++j) { RESETINPUT(j); } } if (ztrig > 0.f && prevtrig <= 0.f) { for (int j=2, k=0; jmNumInputs; ++j, ++k) { float x = DEMANDINPUT_A(j, i + 1); if (sc_isnan(x)) { x = prevout[k]; unit->mDone = true; } else prevout[k] = x; out[k][i] = x; } } prevtrig = ztrig; prevreset = zreset; } unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void Demand_Ctor(Demand *unit) { //Print("Demand_Ctor\n"); if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) { SETCALC(Demand_next_aa); } else { SETCALC(Demand_next_ak); } } else { if (INRATE(1) == calc_FullRate) { SETCALC(Demand_next_ka); } else { SETCALC(Demand_next_aa); } } for (int i=0; imNumOutputs; ++i) OUT0(i) = 0.f; char * memoryChunk = (char*)RTAlloc(unit->mWorld, unit->mNumOutputs * (sizeof(float) + sizeof(float*))); if (!memoryChunk) { Print("Demand: RT memory allocation failed\n"); SETCALC(ClearUnitOutputs); return; } unit->m_prevout = (float*)memoryChunk; unit->m_out = (float**)(memoryChunk + unit->mNumOutputs * sizeof(float)); unit->m_prevtrig = 0.f; unit->m_prevreset = 0.f; std::fill_n(unit->m_prevout, unit->mNumOutputs, 0.f); } void Demand_Dtor(Demand* unit) { if(unit->m_prevout) RTFree(unit->mWorld, unit->m_prevout); } ///////////////////////////////////////////////////////////////////////////// enum { duty_dur, duty_reset, duty_doneAction, duty_level }; void Duty_next_da(Duty *unit, int inNumSamples) { float *reset = ZIN(duty_reset); float *out = OUT(0); float prevout = unit->m_prevout; float count = unit->m_count; float prevreset = unit->m_prevreset; float sr = (float) SAMPLERATE; for (int i=0; i 0.f && prevreset <= 0.f) { RESETINPUT(duty_level); RESETINPUT(duty_dur); count = 0.f; } if (count <= 0.f) { count = DEMANDINPUT_A(duty_dur, i + 1) * sr + count; if(sc_isnan(count)) { int doneAction = (int)ZIN0(duty_doneAction); DoneAction(doneAction, unit); } float x = DEMANDINPUT_A(duty_level, i + 1); //printf("in %d\n", count); if(sc_isnan(x)) { x = prevout; int doneAction = (int)ZIN0(duty_doneAction); DoneAction(doneAction, unit); } else { prevout = x; } out[i] = x; } else { out[i] = prevout; } count--; prevreset = zreset; } unit->m_count = count; unit->m_prevreset = prevreset; unit->m_prevout = prevout; } void Duty_next_dk(Duty *unit, int inNumSamples) { float zreset = ZIN0(duty_reset); float *out = OUT(0); float prevout = unit->m_prevout; float count = unit->m_count; float prevreset = unit->m_prevreset; float sr = (float) SAMPLERATE; for (int i=0; i 0.f && prevreset <= 0.f) { RESETINPUT(duty_level); RESETINPUT(duty_dur); count = 0.f; } if (count <= 0.f) { count = DEMANDINPUT_A(duty_dur, i + 1) * sr + count; if(sc_isnan(count)) { int doneAction = (int)ZIN0(duty_doneAction); DoneAction(doneAction, unit); } float x = DEMANDINPUT_A(duty_level, i + 1); if(sc_isnan(x)) { x = prevout; int doneAction = (int)ZIN0(duty_doneAction); DoneAction(doneAction, unit); } else { prevout = x; } out[i] = x; } else { out[i] = prevout; } count--; prevreset = zreset; } unit->m_count = count; unit->m_prevreset = prevreset; unit->m_prevout = prevout; } void Duty_next_dd(Duty *unit, int inNumSamples) { float *out = OUT(0); float prevout = unit->m_prevout; float count = unit->m_count; float reset = unit->m_prevreset; float sr = (float) SAMPLERATE; for (int i=0; im_count = count; unit->m_prevreset = reset; unit->m_prevout = prevout; } void Duty_Ctor(Duty *unit) { if (INRATE(duty_reset) == calc_FullRate) { SETCALC(Duty_next_da); unit->m_prevreset = 0.f; } else { if(INRATE(duty_reset) == calc_DemandRate) { SETCALC(Duty_next_dd); unit->m_prevreset = DEMANDINPUT(duty_reset) * SAMPLERATE; } else { SETCALC(Duty_next_dk); unit->m_prevreset = 0.f; } } unit->m_count = DEMANDINPUT(duty_dur) * SAMPLERATE - 1; unit->m_prevout = DEMANDINPUT(duty_level); OUT0(0) = unit->m_prevout; } ///////////////////////////////////////////////////////////////////////////// enum { d_env_level, d_env_dur, d_env_shape, d_env_curve, d_env_gate, d_env_reset, d_env_levelScale, d_env_levelBias, d_env_timeScale, d_env_doneAction }; enum { shape_Step, shape_Linear, shape_Exponential, shape_Sine, shape_Welch, shape_Curve, shape_Squared, shape_Cubed, shape_Sustain = 9999 }; void DemandEnvGen_next_k(DemandEnvGen *unit, int inNumSamples) { float zreset = ZIN0(d_env_reset); float *out = ZOUT(0); double level = unit->m_level; float phase = unit->m_phase; double curve = unit->m_curve; bool release = unit->m_release; bool running = unit->m_running; int shape = unit->m_shape; // printf("phase %f level %f \n", phase, level); for (int i=0; i 0.f && unit->m_prevreset <= 0.f) { //printf("reset: %f %f \n", zreset, unit->m_prevreset); RESETINPUT(d_env_level); RESETINPUT(d_env_dur); RESETINPUT(d_env_shape); RESETINPUT(d_env_curve); if(zreset <= 1.f) { DEMANDINPUT(d_env_level); // remove first level } else { level = DEMANDINPUT(d_env_level); // jump to first level } release = false; running = true; phase = 0.f; } if (phase <= 0.f && running) { // was a release during last segment? if(release) { running = false; release = false; // printf("release: %f %f \n", phase, level); int doneAction = (int)ZIN0(d_env_doneAction); DoneAction(doneAction, unit); } else { // new time float dur = DEMANDINPUT(d_env_dur); // printf("dur: %f \n", dur); if(sc_isnan(dur)) { release = true; running = false; phase = numeric_limits::max(); } else { phase = dur * ZIN0(d_env_timeScale) * SAMPLERATE + phase; } // new shape float fshape = DEMANDINPUT(d_env_shape); if (sc_isnan(fshape)) shape = unit->m_shape; else shape = (int)fshape; curve = DEMANDINPUT(d_env_curve); if (sc_isnan(curve)) curve = unit->m_curve; float count; if (phase <= 1.f) { shape = 1; // shape_Linear count = 1.f; } else { count = phase; } if(dur * 0.5f < SAMPLEDUR) shape = 1; //printf("shape: %i, curve: %f, dur: %f \n", shape, curve, dur); // new end level double endLevel = DEMANDINPUT(d_env_level); // printf("levels: %f %f\n", level, endLevel); if (sc_isnan(endLevel)) { endLevel = unit->m_endLevel; release = true; phase = 0.f; shape = 0; } else { endLevel = endLevel * ZIN0(d_env_levelScale) + ZIN0(d_env_levelBias); unit->m_endLevel = endLevel; } // calculate shape parameters switch (shape) { case shape_Step : { level = endLevel; } break; case shape_Linear : { unit->m_grow = (endLevel - level) / count; } break; case shape_Exponential : { unit->m_grow = pow(endLevel / level, 1.0 / count); } break; case shape_Sine : { double w = pi / count; unit->m_a2 = (endLevel + level) * 0.5; unit->m_b1 = 2. * cos(w); unit->m_y1 = (endLevel - level) * 0.5; unit->m_y2 = unit->m_y1 * sin(pi * 0.5 - w); level = unit->m_a2 - unit->m_y1; } break; case shape_Welch : { double w = (pi * 0.5) / count; unit->m_b1 = 2. * cos(w); if (endLevel >= level) { unit->m_a2 = level; unit->m_y1 = 0.; unit->m_y2 = -sin(w) * (endLevel - level); } else { unit->m_a2 = endLevel; unit->m_y1 = level - endLevel; unit->m_y2 = cos(w) * (level - endLevel); } level = unit->m_a2 + unit->m_y1; } break; case shape_Curve : { if (fabs(curve) < 0.001) { unit->m_shape = shape = 1; // shape_Linear unit->m_grow = (endLevel - level) / count; } else { double a1 = (endLevel - level) / (1.0 - exp(curve)); unit->m_a2 = level + a1; unit->m_b1 = a1; unit->m_grow = exp(curve / ceil( count) ); } } break; case shape_Squared : { unit->m_y1 = sqrt(level); unit->m_y2 = sqrt(endLevel); unit->m_grow = (unit->m_y2 - unit->m_y1) / count; } break; case shape_Cubed : { unit->m_y1 = pow(level, 0.33333333); unit->m_y2 = pow(endLevel, 0.33333333); unit->m_grow = (unit->m_y2 - unit->m_y1) / count; } break; } } } if(running) { switch (shape) { case shape_Step : { } break; case shape_Linear : { double grow = unit->m_grow; //Print("level %g\n", level); level += grow; } break; case shape_Exponential : { double grow = unit->m_grow; level *= grow; } break; case shape_Sine : { double a2 = unit->m_a2; double b1 = unit->m_b1; double y2 = unit->m_y2; double y1 = unit->m_y1; double y0 = b1 * y1 - y2; level = a2 - y0; y2 = y1; y1 = y0; unit->m_y1 = y1; unit->m_y2 = y2; } break; case shape_Welch : { double a2 = unit->m_a2; double b1 = unit->m_b1; double y2 = unit->m_y2; double y1 = unit->m_y1; double y0 = b1 * y1 - y2; level = a2 + y0; y2 = y1; y1 = y0; unit->m_y1 = y1; unit->m_y2 = y2; } break; case shape_Curve : { double a2 = unit->m_a2; double b1 = unit->m_b1; double grow = unit->m_grow; b1 *= grow; level = a2 - b1; unit->m_b1 = b1; } break; case shape_Squared : { double grow = unit->m_grow; double y1 = unit->m_y1; y1 += grow; level = y1*y1; unit->m_y1 = y1; } break; case shape_Cubed : { double grow = unit->m_grow; double y1 = unit->m_y1; y1 += grow; level = y1*y1*y1; unit->m_y1 = y1; } break; case shape_Sustain : { } break; } phase --; } ZXP(out) = level; } float zgate = ZIN0(d_env_gate); if(zgate >= 1.f) { unit->m_running = true; } else if (zgate > 0.f) { unit->m_running = true; release = true; // release next time. } else { unit->m_running = false; // sample and hold } unit->m_level = level; unit->m_curve = curve; unit->m_shape = shape; unit->m_prevreset = zreset; unit->m_release = release; unit->m_phase = phase; } void DemandEnvGen_next_a(DemandEnvGen *unit, int inNumSamples) { float *reset = ZIN(d_env_reset); float *gate = ZIN(d_env_gate); float *out = ZOUT(0); float prevreset = unit->m_prevreset; double level = unit->m_level; float phase = unit->m_phase; double curve = unit->m_curve; bool release = unit->m_release; bool running = unit->m_running; int shape = unit->m_shape; // printf("phase %f \n", phase); for (int i=0; i 0.f && prevreset <= 0.f) { // printf("reset: %f %f \n", zreset, unit->m_prevreset); RESETINPUT(d_env_level); if(zreset <= 1.f) { DEMANDINPUT_A(d_env_level, i + 1); // remove first level } else { level = DEMANDINPUT_A(d_env_level, i + 1); // jump to first level } RESETINPUT(d_env_dur); RESETINPUT(d_env_shape); release = false; running = true; phase = 0.f; } prevreset = zreset; if (phase <= 0.f && running) { // was a release? if(release) { running = false; release = false; // printf("release: %f %f \n", phase, level); int doneAction = (int)ZIN0(d_env_doneAction); DoneAction(doneAction, unit); } else { // new time float dur = DEMANDINPUT_A(d_env_dur, i + 1); // printf("dur: %f \n", dur); if(sc_isnan(dur)) { release = true; running = false; phase = numeric_limits::max(); } else { phase = dur * ZIN0(d_env_timeScale) * SAMPLERATE + phase; } // new shape float count; curve = DEMANDINPUT_A(d_env_curve, i + 1); // printf("shapes: %i \n", shape); if (sc_isnan(curve)) curve = unit->m_curve; float fshape = DEMANDINPUT_A(d_env_shape, i + 1); if (sc_isnan(fshape)) shape = unit->m_shape; else shape = (int)fshape; if (phase <= 1.f) { shape = 1; // shape_Linear count = 1.f; } else { count = phase; } if(dur * 0.5f < SAMPLEDUR) shape = 1; // new end level double endLevel = DEMANDINPUT_A(d_env_level, i + 1); // printf("levels: %f %f\n", level, endLevel); if (sc_isnan(endLevel)) { endLevel = unit->m_endLevel; release = true; phase = 0.f; shape = 0; } else { endLevel = endLevel * ZIN0(d_env_levelScale) + ZIN0(d_env_levelBias); unit->m_endLevel = endLevel; } // calculate shape parameters switch (shape) { case shape_Step : { level = endLevel; } break; case shape_Linear : { unit->m_grow = (endLevel - level) / count; } break; case shape_Exponential : { unit->m_grow = pow(endLevel / level, 1.0 / count); } break; case shape_Sine : { double w = pi / count; unit->m_a2 = (endLevel + level) * 0.5; unit->m_b1 = 2. * cos(w); unit->m_y1 = (endLevel - level) * 0.5; unit->m_y2 = unit->m_y1 * sin(pi * 0.5 - w); level = unit->m_a2 - unit->m_y1; } break; case shape_Welch : { double w = (pi * 0.5) / count; unit->m_b1 = 2. * cos(w); if (endLevel >= level) { unit->m_a2 = level; unit->m_y1 = 0.; unit->m_y2 = -sin(w) * (endLevel - level); } else { unit->m_a2 = endLevel; unit->m_y1 = level - endLevel; unit->m_y2 = cos(w) * (level - endLevel); } level = unit->m_a2 + unit->m_y1; } break; case shape_Curve : { if (fabs(curve) < 0.001) { unit->m_shape = shape = 1; // shape_Linear unit->m_grow = (endLevel - level) / count; } else { double a1 = (endLevel - level) / (1.0 - exp(curve)); unit->m_a2 = level + a1; unit->m_b1 = a1; unit->m_grow = exp(curve / ceil( count ) ); } } break; case shape_Squared : { unit->m_y1 = sqrt(level); unit->m_y2 = sqrt(endLevel); unit->m_grow = (unit->m_y2 - unit->m_y1) / count; } break; case shape_Cubed : { unit->m_y1 = pow(level, 0.33333333); unit->m_y2 = pow(endLevel, 0.33333333); unit->m_grow = (unit->m_y2 - unit->m_y1) / count; } break; } } } if(running) { switch (shape) { case shape_Step : { } break; case shape_Linear : { double grow = unit->m_grow; //Print("level %g\n", level); level += grow; } break; case shape_Exponential : { double grow = unit->m_grow; level *= grow; } break; case shape_Sine : { double a2 = unit->m_a2; double b1 = unit->m_b1; double y2 = unit->m_y2; double y1 = unit->m_y1; double y0 = b1 * y1 - y2; level = a2 - y0; y2 = y1; y1 = y0; unit->m_y1 = y1; unit->m_y2 = y2; } break; case shape_Welch : { double a2 = unit->m_a2; double b1 = unit->m_b1; double y2 = unit->m_y2; double y1 = unit->m_y1; double y0 = b1 * y1 - y2; level = a2 + y0; y2 = y1; y1 = y0; unit->m_y1 = y1; unit->m_y2 = y2; } break; case shape_Curve : { double a2 = unit->m_a2; double b1 = unit->m_b1; double grow = unit->m_grow; b1 *= grow; level = a2 - b1; unit->m_b1 = b1; } break; case shape_Squared : { double grow = unit->m_grow; double y1 = unit->m_y1; y1 += grow; level = y1*y1; unit->m_y1 = y1; } break; case shape_Cubed : { double grow = unit->m_grow; double y1 = unit->m_y1; y1 += grow; level = y1*y1*y1; unit->m_y1 = y1; } break; case shape_Sustain : { } break; } phase--; } ZXP(out) = level; float zgate = ZXP(gate); if(zgate >= 1.f) { unit->m_running = true; } else if (zgate > 0.f) { unit->m_running = true; release = true; // release next time. } else { unit->m_running = false; // sample and hold } } unit->m_level = level; unit->m_curve = curve; unit->m_shape = shape; unit->m_prevreset = prevreset; unit->m_release = release; unit->m_phase = phase; } void DemandEnvGen_Ctor(DemandEnvGen *unit) { // derive the first level. unit->m_level = DEMANDINPUT(d_env_level); if(sc_isnan(unit->m_level)) { unit->m_level = 0.f; } unit->m_endLevel = unit->m_level; unit->m_release = false; unit->m_prevreset = 0.f; unit->m_phase = 0.f; unit->m_running = ZIN0(d_env_gate) > 0.f; if(INRATE(d_env_gate) == calc_FullRate) { SETCALC(DemandEnvGen_next_a); } else { SETCALC(DemandEnvGen_next_k); } DemandEnvGen_next_k(unit, 1); } ///////////////////////////////////////////////////////////////////////////// void TDuty_next_da(TDuty *unit, int inNumSamples) { float *reset = ZIN(duty_reset); float *out = OUT(0); float count = unit->m_count; float prevreset = unit->m_prevreset; float sr = (float) SAMPLERATE; for (int i=0; i 0.f && prevreset <= 0.f) { RESETINPUT(duty_level); RESETINPUT(duty_dur); count = 0.f; } if (count <= 0.f) { count = DEMANDINPUT_A(duty_dur, i + 1) * sr + count; if(sc_isnan(count)) { int doneAction = (int)ZIN0(2); DoneAction(doneAction, unit); } float x = DEMANDINPUT_A(duty_level, i + 1); //printf("in %d %g\n", k, x); if (sc_isnan(x)) x = 0.f; out[i] = x; } else { out[i] = 0.f; } count--; prevreset = zreset; } unit->m_count = count; unit->m_prevreset = prevreset; } void TDuty_next_dk(TDuty *unit, int inNumSamples) { float zreset = ZIN0(duty_reset); float *out = OUT(0); float count = unit->m_count; float prevreset = unit->m_prevreset; float sr = (float) SAMPLERATE; for (int i=0; i 0.f && prevreset <= 0.f) { RESETINPUT(duty_level); RESETINPUT(duty_dur); count = 0.f; } if (count <= 0.f) { count = DEMANDINPUT_A(duty_dur, i + 1) * sr + count; if(sc_isnan(count)) { int doneAction = (int)ZIN0(2); DoneAction(doneAction, unit); } float x = DEMANDINPUT_A(duty_level, i + 1); //printf("in %d %g\n", k, x); if (sc_isnan(x)) x = 0.f; out[i] = x; } else { out[i] = 0.f; } count--; prevreset = zreset; } unit->m_count = count; unit->m_prevreset = prevreset; } void TDuty_next_dd(TDuty *unit, int inNumSamples) { float *out = OUT(0); float count = unit->m_count; float reset = unit->m_prevreset; float sr = (float) SAMPLERATE; for (int i=0; im_count = count; unit->m_prevreset = reset; } void TDuty_Ctor(TDuty *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(TDuty_next_da); unit->m_prevreset = 0.f; } else { if(INRATE(1) == calc_DemandRate) { SETCALC(TDuty_next_dd); unit->m_prevreset = DEMANDINPUT(1) * SAMPLERATE; } else { SETCALC(TDuty_next_dk); unit->m_prevreset = 0.f; } } // support for gap-first. if(IN0(4)) { unit->m_count = DEMANDINPUT(duty_dur) * SAMPLERATE; } else { unit->m_count = 0.f; } OUT0(0) = 0.f; } ///////////////////////////////////////////////////////////////////////////// void Dseries_next(Dseries *unit, int inNumSamples) { if (inNumSamples) { float step = DEMANDINPUT_A(2, inNumSamples); if(!sc_isnan(step)) { unit->m_step = step; } if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); unit->m_value = DEMANDINPUT_A(1, inNumSamples); } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } OUT0(0) = unit->m_value; unit->m_value += unit->m_step; unit->m_repeatCount++; } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; } } void Dseries_Ctor(Dseries *unit) { SETCALC(Dseries_next); Dseries_next(unit, 0); OUT0(0) = 0.f; } void Dgeom_next(Dgeom *unit, int inNumSamples) { if (inNumSamples) { float grow = DEMANDINPUT_A(2, inNumSamples); if(!sc_isnan(grow)) { unit->m_grow = grow; } if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); unit->m_value = DEMANDINPUT_A(1, inNumSamples); } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } OUT0(0) = unit->m_value; unit->m_value *= unit->m_grow; unit->m_repeatCount++; } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; } } void Dgeom_Ctor(Dgeom *unit) { SETCALC(Dgeom_next); Dgeom_next(unit, 0); OUT0(0) = 0.f; } void Dwhite_next(Dwhite *unit, int inNumSamples) { if (inNumSamples) { if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } unit->m_repeatCount++; float lo = DEMANDINPUT_A(1, inNumSamples); float hi = DEMANDINPUT_A(2, inNumSamples); if(!sc_isnan(lo)) { unit->m_lo = lo;} if(!sc_isnan(hi)) { unit->m_range = hi - lo; } float x = unit->mParent->mRGen->frand() * unit->m_range + unit->m_lo; OUT0(0) = x; } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; } } void Dwhite_Ctor(Dwhite *unit) { SETCALC(Dwhite_next); Dwhite_next(unit, 0); OUT0(0) = 0.f; } void Diwhite_next(Diwhite *unit, int inNumSamples) { if (inNumSamples) { float lo = DEMANDINPUT_A(1, inNumSamples); float hi = DEMANDINPUT_A(2, inNumSamples); if(!sc_isnan(lo)) { unit->m_lo = (int32)floor(DEMANDINPUT_A(1, inNumSamples) + 0.5f); } if(!sc_isnan(hi)) { int32 hi = (int32)floor(DEMANDINPUT_A(2, inNumSamples) + 0.5f); unit->m_range = hi - unit->m_lo + 1; } if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } unit->m_repeatCount++; float x = unit->mParent->mRGen->irand(unit->m_range) + unit->m_lo; OUT0(0) = x; } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; } } void Diwhite_Ctor(Diwhite *unit) { SETCALC(Diwhite_next); Diwhite_next(unit, 0); OUT0(0) = 0.f; } void Dbrown_next(Dbrown *unit, int inNumSamples) { if (inNumSamples) { float lo = DEMANDINPUT_A(1, inNumSamples); if(!sc_isnan(lo)) { unit->m_lo = lo; } float hi = DEMANDINPUT_A(2, inNumSamples); if(!sc_isnan(hi)) { unit->m_hi = hi; } float step = DEMANDINPUT_A(3, inNumSamples); if(!sc_isnan(step)) { unit->m_step = step; } if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); unit->m_val = unit->mParent->mRGen->frand() * (unit->m_hi - unit->m_lo) + unit->m_lo; } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } unit->m_repeatCount++; OUT0(0) = unit->m_val; float x = unit->m_val + unit->mParent->mRGen->frand2() * unit->m_step; unit->m_val = sc_fold(x, unit->m_lo, unit->m_hi); } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; } } void Dbrown_Ctor(Dbrown *unit) { SETCALC(Dbrown_next); Dbrown_next(unit, 0); OUT0(0) = 0.f; } void Dibrown_next(Dibrown *unit, int inNumSamples) { if (inNumSamples) { float lo = DEMANDINPUT_A(1, inNumSamples); if(!sc_isnan(lo)) { unit->m_lo = (int32)lo; } float hi = DEMANDINPUT_A(2, inNumSamples); if(!sc_isnan(hi)) { unit->m_hi = (int32)hi; } float step = DEMANDINPUT_A(3, inNumSamples); if(!sc_isnan(step)) { unit->m_step = (int32)step; } if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); unit->m_val = unit->mParent->mRGen->irand(unit->m_hi - unit->m_lo + 1) + unit->m_lo; } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } OUT0(0) = unit->m_val; int32 z = unit->m_val + unit->mParent->mRGen->irand2(unit->m_step); unit->m_val = sc_fold(z, unit->m_lo, unit->m_hi); } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; } } void Dibrown_Ctor(Dibrown *unit) { SETCALC(Dibrown_next); Dibrown_next(unit, 0); OUT0(0) = 0.f; } void Dseq_next(Dseq *unit, int inNumSamples) { //Print("->Dseq_next %d\n", inNumSamples); if (inNumSamples) { //Print(" unit->m_repeats %d\n", unit->m_repeats); if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } int attempts = 0; while (true) { //Print(" unit->m_index %d unit->m_repeatCount %d\n", unit->m_index, unit->m_repeatCount); if (unit->m_index >= unit->mNumInputs) { unit->m_index = 1; unit->m_repeatCount++; } if (unit->m_repeatCount >= unit->m_repeats) { //Print("done\n"); OUT0(0) = NAN; unit->m_index = 1; return; } if (ISDEMANDINPUT(unit->m_index)) { if (unit->m_needToResetChild) { unit->m_needToResetChild = false; RESETINPUT(unit->m_index); } float x = DEMANDINPUT_A(unit->m_index, inNumSamples); if (sc_isnan(x)) { unit->m_index++; unit->m_needToResetChild = true; } else { OUT0(0) = x; return; } } else { OUT0(0) = DEMANDINPUT_A(unit->m_index, inNumSamples); //Print(" unit->m_index %d OUT0(0) %g\n", unit->m_index, OUT0(0)); unit->m_index++; unit->m_needToResetChild = true; return; } if (attempts++ > unit->mNumInputs) { Print("Warning: empty sequence in Dseq\n"); return; } } } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; unit->m_needToResetChild = true; unit->m_index = 1; } } void Dseq_Ctor(Dseq *unit) { SETCALC(Dseq_next); Dseq_next(unit, 0); OUT0(0) = 0.f; } void Dser_next(Dser *unit, int inNumSamples) { if (inNumSamples) { if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } while (true) { if (unit->m_index >= unit->mNumInputs) { unit->m_index = 1; } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } if (ISDEMANDINPUT(unit->m_index)) { if (unit->m_needToResetChild) { unit->m_needToResetChild = false; RESETINPUT(unit->m_index); } float x = DEMANDINPUT_A(unit->m_index, inNumSamples); if (sc_isnan(x)) { unit->m_index++; unit->m_repeatCount++; unit->m_needToResetChild = true; } else { OUT0(0) = x; return; } } else { OUT0(0) = IN0(unit->m_index); unit->m_index++; unit->m_repeatCount++; unit->m_needToResetChild = true; return; } } } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; unit->m_needToResetChild = true; unit->m_index = 1; } } void Dser_Ctor(Dser *unit) { SETCALC(Dser_next); Dser_next(unit, 0); OUT0(0) = 0.f; } void Drand_next(Drand *unit, int inNumSamples) { if (inNumSamples) { if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } while (true) { if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } if (ISDEMANDINPUT(unit->m_index)) { if (unit->m_needToResetChild) { unit->m_needToResetChild = false; RESETINPUT(unit->m_index); } float x = DEMANDINPUT_A(unit->m_index, inNumSamples); if (sc_isnan(x)) { unit->m_index = unit->mParent->mRGen->irand(unit->mNumInputs - 1) + 1; unit->m_repeatCount++; unit->m_needToResetChild = true; } else { OUT0(0) = x; return; } } else { OUT0(0) = DEMANDINPUT_A(unit->m_index, inNumSamples); unit->m_index = unit->mParent->mRGen->irand(unit->mNumInputs - 1) + 1; unit->m_repeatCount++; unit->m_needToResetChild = true; return; } } } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; unit->m_needToResetChild = true; unit->m_index = unit->mParent->mRGen->irand(unit->mNumInputs - 1) + 1; } } void Drand_Ctor(Drand *unit) { SETCALC(Drand_next); Drand_next(unit, 0); OUT0(0) = 0.f; } void Dxrand_next(Dxrand *unit, int inNumSamples) { if (inNumSamples) { if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } while (true) { if (unit->m_index >= unit->mNumInputs) { unit->m_index = 1; } if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } if (ISDEMANDINPUT(unit->m_index)) { if (unit->m_needToResetChild) { unit->m_needToResetChild = false; RESETINPUT(unit->m_index); } float x = DEMANDINPUT_A(unit->m_index, inNumSamples); if (sc_isnan(x)) { int newindex = unit->mParent->mRGen->irand(unit->mNumInputs - 2) + 1; unit->m_index = newindex < unit->m_index ? newindex : newindex + 1; unit->m_repeatCount++; unit->m_needToResetChild = true; } else { OUT0(0) = x; return; } } else { OUT0(0) = DEMANDINPUT_A(unit->m_index, inNumSamples); int newindex = unit->mParent->mRGen->irand(unit->mNumInputs - 2) + 1; unit->m_index = newindex < unit->m_index ? newindex : newindex + 1; unit->m_repeatCount++; unit->m_needToResetChild = true; return; } } } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; unit->m_needToResetChild = true; int newindex = unit->mParent->mRGen->irand(unit->mNumInputs - 2) + 1; unit->m_index = newindex < unit->m_index ? newindex : newindex + 1; } } void Dxrand_Ctor(Dxrand *unit) { SETCALC(Dxrand_next); Dxrand_next(unit, 0); OUT0(0) = 0.f; } #define WINDEX \ float w, sum = 0.0; \ float r = unit->mParent->mRGen->frand(); \ for (int i=0; i= r) { \ unit->m_index = i + offset; \ break; \ } \ } \ void Dwrand_next(Dwrand *unit, int inNumSamples) { int offset = unit->m_weights_size + 2; int weights_size = unit->mNumInputs - offset; if (inNumSamples) { if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } while (true) { if (unit->m_repeatCount >= unit->m_repeats) { OUT0(0) = NAN; return; } if (ISDEMANDINPUT(unit->m_index)) { if (unit->m_needToResetChild) { unit->m_needToResetChild = false; RESETINPUT(unit->m_index); } float x = DEMANDINPUT_A(unit->m_index, inNumSamples); if (sc_isnan(x)) { WINDEX; unit->m_repeatCount++; unit->m_needToResetChild = true; } else { OUT0(0) = x; return; } } else { OUT0(0) = DEMANDINPUT_A(unit->m_index, inNumSamples); WINDEX; unit->m_repeatCount++; unit->m_needToResetChild = true; return; } } } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; unit->m_needToResetChild = true; WINDEX; } } void Dwrand_Ctor(Dwrand *unit) { SETCALC(Dwrand_next); unit->m_weights_size = IN0(1); Dwrand_next(unit, 0); OUT0(0) = 0.f; } static void Dshuf_scramble(Dshuf *unit); void Dshuf_next(Dshuf *unit, int inNumSamples) { // Print("->Dshuf_next %d\n", inNumSamples); if (inNumSamples) { //Print(" unit->m_repeats %d\n", unit->m_repeats); if (unit->m_repeats < 0.) { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_repeats = sc_isnan(x) ? 0.f : floor(x + 0.5f); } while (true) { //Print(" unit->m_index %d unit->m_repeatCount %d\n", unit->m_index, unit->m_repeatCount); if (unit->m_index >= (unit->mNumInputs - 1)) { unit->m_index = 0; unit->m_repeatCount++; } if (unit->m_repeatCount >= unit->m_repeats) { //Print("done\n"); OUT0(0) = NAN; unit->m_index = 0; return; } if (ISDEMANDINPUT(unit->m_indices[unit->m_index])) { if (unit->m_needToResetChild) { unit->m_needToResetChild = false; RESETINPUT(unit->m_indices[unit->m_index]); } float x = DEMANDINPUT_A(unit->m_indices[unit->m_index], inNumSamples); if (sc_isnan(x)) { unit->m_index++; unit->m_needToResetChild = true; } else { OUT0(0) = x; return; } } else { OUT0(0) = DEMANDINPUT_A(unit->m_indices[unit->m_index], inNumSamples); //Print(" unit->m_index %d OUT0(0) %g\n", unit->m_index, OUT0(0)); unit->m_index++; unit->m_needToResetChild = true; return; } } } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0; unit->m_needToResetChild = true; unit->m_index = 0; Dshuf_scramble(unit); } } void Dshuf_scramble(Dshuf *unit) { int32 i, j, m, k, size; int32 temp; size = (int32)(unit->mNumInputs) - 1; if (size > 1) { k = size; for (i=0, m=k; imParent->mRGen->irand(m); temp = unit->m_indices[i]; unit->m_indices[i] = unit->m_indices[j]; unit->m_indices[j] = temp; } } } void Dshuf_Ctor(Dshuf *unit) { OUT0(0) = 0.f; uint32 size = (unit->mNumInputs) - 1; unit->m_indices = (int32*)RTAlloc(unit->mWorld, size * sizeof(int32)); if (!unit->m_indices) { Print("Dshuf: RT memory allocation failed\n"); SETCALC(ClearUnitOutputs); return; } for(uint32 i=0; i < size; ++i) unit->m_indices[i] = i + 1; SETCALC(Dshuf_next); Dshuf_next(unit, 0); } void Dshuf_Dtor(Dshuf *unit) { RTFree(unit->mWorld, unit->m_indices); } void Dswitch1_next(Dswitch1 *unit, int inNumSamples) { if (inNumSamples) { float x = DEMANDINPUT_A(0, inNumSamples); if (sc_isnan(x)) { OUT0(0) = x; return; } int index = (int32)floor(x + 0.5f); index = sc_wrap(index, 0, unit->mNumInputs - 2) + 1; OUT0(0) = DEMANDINPUT_A(index, inNumSamples); } else { for (int i=0; imNumInputs; ++i) { RESETINPUT(i); } } } void Dswitch1_Ctor(Dswitch1 *unit) { SETCALC(Dswitch1_next); OUT0(0) = 0.f; } ///////////////////////////// void Dswitch_next(Dswitch *unit, int inNumSamples) { if (inNumSamples) { float val = DEMANDINPUT_A(unit->m_index, inNumSamples); //printf("index: %i\n", (int) val); if(sc_isnan(val)) { float ival = DEMANDINPUT_A(0, inNumSamples); if(sc_isnan(ival)) val = ival; else { int index = (int32)floor(ival + 0.5f); index = sc_wrap(index, 0, unit->mNumInputs - 2) + 1; val = DEMANDINPUT_A(index, inNumSamples); RESETINPUT(unit->m_index); // printf("resetting index: %i\n", unit->m_index); unit->m_index = index; } } OUT0(0) = val; } else { printf("...\n"); for (int i=0; imNumInputs; ++i) { RESETINPUT(i); } int index = (int32)floor(DEMANDINPUT(0) + 0.5f); index = sc_wrap(index, 0, unit->mNumInputs - 1) + 1; unit->m_index = index; } } void Dswitch_Ctor(Dswitch *unit) { SETCALC(Dswitch_next); int index = (int32)floor(DEMANDINPUT(0) + 0.5f); index = sc_wrap(index, 0, unit->mNumInputs - 1) + 1; unit->m_index = index; OUT0(0) = 0.f; } ////////////////////////////// void Dstutter_next(Dstutter *unit, int inNumSamples) { if (inNumSamples) { if (unit->m_repeatCount >= unit->m_repeats) { float val = DEMANDINPUT_A(1, inNumSamples); float repeats = DEMANDINPUT_A(0, inNumSamples); if(sc_isnan(repeats) || sc_isnan(val)) { OUT0(0) = NAN; return; } else { unit->m_value = val; unit->m_repeats = floor(repeats + 0.5f); unit->m_repeatCount = 0.f; } } OUT0(0) = unit->m_value; unit->m_repeatCount++; } else { unit->m_repeats = -1.f; unit->m_repeatCount = 0.f; RESETINPUT(0); RESETINPUT(1); } } void Dstutter_Ctor(Dstutter *unit) { SETCALC(Dstutter_next); Dstutter_next(unit, 0); OUT0(0) = 0.f; } ////////////////////////////// void Dconst_next(Dconst *unit, int inNumSamples) { float total, tolerance; if (inNumSamples) { if(sc_isnan(unit->m_runningsum)) { OUT0(0) = NAN; return; } if (unit->m_total < 0.f) { total = DEMANDINPUT_A(0, inNumSamples); tolerance = DEMANDINPUT_A(2, inNumSamples); if(sc_isnan(total) || sc_isnan(tolerance)) { OUT0(0) = NAN; return; } unit->m_total = total; unit->m_tolerance = tolerance; } { total = unit->m_total; tolerance = unit->m_tolerance; } float val = DEMANDINPUT_A(1, inNumSamples); if(sc_isnan(val)) { OUT0(0) = NAN; return; } else { float runningsum = unit->m_runningsum + val; if((runningsum > total) || (fabs(total - runningsum) <= tolerance)) { OUT0(0) = total - unit->m_runningsum; unit->m_runningsum = NAN; // stop next time } else { unit->m_runningsum = runningsum; OUT0(0) = val; } } } else { unit->m_total = -1.f; unit->m_runningsum = 0.f; RESETINPUT(0); RESETINPUT(1); RESETINPUT(2); } } void Dconst_Ctor(Dconst *unit) { SETCALC(Dconst_next); Dconst_next(unit, 0); OUT0(0) = 0.f; } ////////////////////////////// void Dpoll_next(Dpoll *unit, int inNumSamples) { if (inNumSamples) { float x = DEMANDINPUT_A(0, inNumSamples); float run = DEMANDINPUT_A(2, inNumSamples) > 0.f; if(unit->m_mayprint && run) { Print("%s: %g block offset: %d\n", unit->m_id_string, x, inNumSamples - 1); } if(IN0(1) >= 0.0) SendTrigger(&unit->mParent->mNode, (int)IN0(1), x); OUT0(0) = x; } else { RESETINPUT(0); } } void Dpoll_Ctor(Dpoll *unit) { OUT0(0) = 0.f; const int idStringSize = (int)IN0(3); unit->m_id_string = (char*)RTAlloc(unit->mWorld, (idStringSize + 1) * sizeof(char)); if (!unit->m_id_string) { Print("Dpoll: RT memory allocation failed\n"); SETCALC(ClearUnitOutputs); return; } for(int i = 0; i < idStringSize; i++) unit->m_id_string[i] = (char)IN0(4+i); SETCALC(Dpoll_next); unit->m_id_string[idStringSize] = '\0'; unit->m_mayprint = unit->mWorld->mVerbosity >= -1; OUT0(0) = 0.f; } void Dpoll_Dtor(Dpoll* unit) { RTFree(unit->mWorld, unit->m_id_string); } ////////////////////////////// void Dreset_next(Dreset *unit, int inNumSamples) { if (inNumSamples) { float x = DEMANDINPUT_A(0, inNumSamples); float reset = DEMANDINPUT_A(1, inNumSamples); if(sc_isnan(x)) { OUT0(0) = NAN; return; } if(reset > 0.0 && (unit->prev_reset <= 0.0)) { RESETINPUT(0); } unit->prev_reset = reset; OUT0(0) = x; } else { RESETINPUT(0); } } void Dreset_Ctor(Dreset *unit) { SETCALC(Dreset_next); unit->prev_reset = 0.0; Dreset_next(unit, 0); } ////////////////////////////// void Donce_next(Donce *unit, int inNumSamples) { if (inNumSamples) { if (unit->m_bufcounter == unit->mWorld->mBufCounter) { OUT0(0) = unit->m_prev; } else { float x = DEMANDINPUT_A(0, inNumSamples); unit->m_prev = x; OUT0(0) = x; } } else { RESETINPUT(0); } } void Donce_Ctor(Donce *unit) { SETCALC(Donce_next); OUT0(0) = 0.f; } inline double sc_loop(Unit *unit, double in, double hi, int loop) { // avoid the divide if possible if (in >= hi) { if (!loop) { unit->mDone = true; return hi; } in -= hi; if (in < hi) return in; } else if (in < 0.) { if (!loop) { unit->mDone = true; return 0.; } in += hi; if (in >= 0.) return in; } else return in; return in - hi * floor(in/hi); } #define D_CHECK_BUF \ if (!bufData) { \ unit->mDone = true; \ ClearUnitOutputs(unit, 1); \ return; \ } #define D_GET_BUF \ float fbufnum = DEMANDINPUT_A(0, inNumSamples);; \ if (sc_isnan(fbufnum)) { \ OUT0(0) = NAN; \ return; \ } \ fbufnum = sc_max(0.f, fbufnum); \ if (fbufnum != unit->m_fbufnum) { \ int bufnum = (int)fbufnum; \ World *world = unit->mWorld; \ if (bufnum < 0) { bufnum = 0; } \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ unit->m_buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ unit->m_buf = world->mSndBufs + bufnum; \ } \ } else { \ unit->m_buf = world->mSndBufs + bufnum; \ } \ unit->m_fbufnum = fbufnum; \ } \ SndBuf *buf = unit->m_buf; \ LOCK_SNDBUF(buf); \ float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples __attribute__((__unused__)) = buf->samples; \ uint32 bufFrames = buf->frames; \ int mask __attribute__((__unused__)) = buf->mask; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; #define D_GET_BUF_SHARED \ float fbufnum = DEMANDINPUT_A(0, inNumSamples);; \ if (sc_isnan(fbufnum)) { \ OUT0(0) = NAN; \ return; \ } \ fbufnum = sc_max(0.f, fbufnum); \ if (fbufnum != unit->m_fbufnum) { \ int bufnum = (int)fbufnum; \ World *world = unit->mWorld; \ if (bufnum < 0) { bufnum = 0; } \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ unit->m_buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ unit->m_buf = world->mSndBufs + bufnum; \ } \ } else { \ unit->m_buf = world->mSndBufs + bufnum; \ } \ unit->m_fbufnum = fbufnum; \ } \ const SndBuf *buf = unit->m_buf; \ LOCK_SNDBUF_SHARED(buf); \ const float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples __attribute__((__unused__)) = buf->samples; \ uint32 bufFrames = buf->frames; \ int mask __attribute__((__unused__)) = buf->mask; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; void Dbufrd_next(Dbufrd *unit, int inNumSamples) { int32 loop = (int32)DEMANDINPUT_A(2, inNumSamples); D_GET_BUF_SHARED D_CHECK_BUF double loopMax = (double)(loop ? bufFrames : bufFrames - 1); double phase; if (inNumSamples) { float x = DEMANDINPUT_A(1, inNumSamples); if (sc_isnan(x)) { OUT0(0) = NAN; return; } phase = x; phase = sc_loop((Unit*)unit, phase, loopMax, loop); int32 iphase = (int32)phase; const float* table1 = bufData + iphase * bufChannels; OUT0(0) = table1[0]; } else { RESETINPUT(1); } } void Dbufrd_Ctor(Dbufrd *unit) { SETCALC(Dbufrd_next); unit->m_fbufnum = -1e9f; Dbufrd_next(unit, 0); OUT0(0) = 0.f; } //////////////////////////////////// void Dbufwr_next(Dbufwr *unit, int inNumSamples) { int32 loop = (int32)DEMANDINPUT_A(3, inNumSamples); D_GET_BUF D_CHECK_BUF double loopMax = (double)(loop ? bufFrames : bufFrames - 1); double phase; float val; if (inNumSamples) { float x = DEMANDINPUT_A(1, inNumSamples); if (sc_isnan(x)) { OUT0(0) = NAN; return; } phase = x; val = DEMANDINPUT_A(2, inNumSamples); if (sc_isnan(val)) { OUT0(0) = NAN; return; } phase = sc_loop((Unit*)unit, phase, loopMax, loop); int32 iphase = (int32)phase; float* table0 = bufData + iphase * bufChannels; table0[0] = val; OUT0(0) = val; } else { RESETINPUT(1); RESETINPUT(2); } } void Dbufwr_Ctor(Dbufwr *unit) { SETCALC(Dbufwr_next); unit->m_fbufnum = -1e9f; Dbufwr_next(unit, 0); OUT0(0) = 0.f; } ////////////////////////////////////////////////////// PluginLoad(Demand) { ft = inTable; DefineDtorCantAliasUnit(Demand); DefineSimpleCantAliasUnit(Duty); DefineSimpleCantAliasUnit(DemandEnvGen); DefineSimpleCantAliasUnit(TDuty); DefineSimpleUnit(Dseries); DefineSimpleUnit(Dgeom); DefineSimpleUnit(Dwhite); DefineSimpleUnit(Dbrown); DefineSimpleUnit(Diwhite); DefineSimpleUnit(Dibrown); DefineSimpleUnit(Dseq); DefineSimpleUnit(Dser); DefineSimpleUnit(Dbufrd); DefineSimpleUnit(Dbufwr); DefineSimpleUnit(Drand); DefineSimpleUnit(Dwrand); DefineSimpleUnit(Dxrand); DefineDtorUnit(Dshuf); DefineSimpleUnit(Dswitch1); DefineSimpleUnit(Dswitch); DefineSimpleUnit(Dstutter); DefineSimpleUnit(Dconst); DefineSimpleUnit(Donce); DefineSimpleUnit(Dreset); DefineDtorUnit(Dpoll); } SuperCollider-Source/server/plugins/DiskIO_UGens.cpp000644 000765 000024 00000042520 12756531745 023615 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. Copyright (c) 2009 Marije Baalman Copyright (c) 2008 Scott Wilson Copyright (c) 2012 Tim Blechmann http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_SyncCondition.h" #include "SC_PlugIn.h" #include #include #include #include #include #include static InterfaceTable *ft; enum { diskinIdle, diskinStartingEmpty, diskinStartingFull, diskinNormal, diskinLastBuffer, diskinEndSilence }; enum { diskoutIdle, diskoutNormal }; struct DiskIn : public Unit { float m_fbufnum; SndBuf *m_buf; uint32 m_framepos; }; struct DiskOut : public Unit { float m_fbufnum; SndBuf *m_buf; uint32 m_framepos; uint32 m_framewritten; }; struct VDiskIn : public Unit { float m_fbufnum, m_pchRatio, m_rBufSize; double m_framePos, m_bufPos; uint32 m_count; SndBuf *m_buf; uint32 m_iFramePos, m_iBufPos; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void DiskIn_next(DiskIn *unit, int inNumSamples); void DiskIn_Ctor(DiskIn* unit); void DiskOut_next(DiskOut *unit, int inNumSamples); void DiskOut_Ctor(DiskOut* unit); void DiskOut_Dtor(DiskOut* unit); void VDiskIn_next(VDiskIn *unit, int inNumSamples); void VDiskIn_first(VDiskIn *unit, int inNumSamples); void VDiskIn_next_rate1(VDiskIn *unit, int inNumSamples); void VDiskIn_Ctor(VDiskIn* unit); } ////////////////////////////////////////////////////////////////////////////////////////////////// enum { kDiskCmd_Read, kDiskCmd_Write, kDiskCmd_ReadLoop, }; namespace { struct DiskIOMsg { World *mWorld; int16 mCommand; int16 mChannels; int32 mBufNum; int32 mPos; int32 mFrames; void Perform(); }; void DiskIOMsg::Perform() { NRTLock(mWorld); SndBuf *buf = World_GetNRTBuf(mWorld, mBufNum); if (mPos > buf->frames || mPos + mFrames > buf->frames || buf->channels != mChannels) goto leave; sf_count_t count; switch (mCommand) { case kDiskCmd_Read : count = buf->sndfile ? sf_readf_float(buf->sndfile, buf->data + mPos * buf->channels, mFrames) : 0; if (count < mFrames) { memset(buf->data + (mPos + count) * buf->channels, 0, (mFrames - count) * buf->channels * sizeof(float)); World_GetBuf(mWorld, mBufNum)->mask = mPos + count; // NOTE: Possible race condition above: The disk IO thread may write to the rt SndBuf // while the stage3 of the sequenced commands copies the non-rt SndBuf struct to the rt buf. // This only happens if the buffer is modified via an osc command. // We can't use the non-rt SndBuf above since buf->mask won't be reflected to the rt buf. } break; case kDiskCmd_ReadLoop : if (!buf->sndfile) { memset(buf->data + mPos * buf->channels, 0, mFrames * buf->channels * sizeof(float)); goto leave; } count = sf_readf_float(buf->sndfile, buf->data + mPos * buf->channels, mFrames); while (mFrames -= count) { sf_seek(buf->sndfile, 0, SEEK_SET); count = sf_readf_float(buf->sndfile, buf->data + (mPos + count) * buf->channels, mFrames); } break; case kDiskCmd_Write : //printf("kDiskCmd_Write %d %p\n", mBufNum, buf->sndfile); if (!buf->sndfile) goto leave; count = sf_writef_float(buf->sndfile, buf->data + mPos * buf->channels, mFrames); break; } leave: NRTUnlock(mWorld); } struct DiskIOThread { SC_SyncCondition mDiskFifoHasData; #ifdef SUPERNOVA boost::lockfree::queue > mDiskFifo; #else boost::lockfree::spsc_queue > mDiskFifo; #endif std::atomic mRunning; thread mThread; DiskIOThread(): mRunning(false) {} ~DiskIOThread() { if (mRunning) { mRunning.store(false); mDiskFifoHasData.Signal(); mThread.join(); } } void launchThread() { using namespace std; mRunning.store(true); mThread = move( thread( bind(&DiskIOThread::ioThreadFunc, this) ) ); } bool Write(DiskIOMsg& data) { bool pushSucceeded = mDiskFifo.push(data); if (pushSucceeded) mDiskFifoHasData.Signal(); return pushSucceeded; } void ioThreadFunc() { while (mRunning.load()) { mDiskFifoHasData.WaitEach(); DiskIOMsg msg; bool popSucceeded = mDiskFifo.pop(msg); if (popSucceeded) msg.Perform(); } } }; DiskIOThread *gDiskIO; } ////////////////////////////////////////////////////////////////////////////////////////////////// #define SETUP_OUT(offset) \ if (unit->mNumOutputs != bufChannels) { \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } \ float *const * const out = &OUT(offset); #define SETUP_IN(offset) \ if (unit->mNumInputs - (uint32)offset != bufChannels) { \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } \ const float *const * const in = &IN(offset); void DiskIn_Ctor(DiskIn* unit) { unit->m_fbufnum = -1.f; unit->m_buf = unit->mWorld->mSndBufs; unit->m_framepos = 0; SETCALC(DiskIn_next); } void DiskIn_next(DiskIn *unit, int inNumSamples) { GET_BUF_SHARED if (!bufData || ((bufFrames & ((unit->mWorld->mBufLength<<1) - 1)) != 0)) { unit->m_framepos = 0; ClearUnitOutputs(unit, inNumSamples); return; } SETUP_OUT(0) if (unit->m_framepos >= bufFrames) { unit->m_framepos = 0; } bufData += unit->m_framepos * bufChannels; // buffer must be allocated as a multiple of 2*blocksize. if (bufChannels > 2) { for (int j=0; jm_buf->mask1>=0 && unit->m_framepos>=unit->m_buf->mask1) unit->mDone = true; unit->m_framepos += inNumSamples; uint32 bufFrames2 = bufFrames >> 1; if (unit->m_framepos == bufFrames) { unit->m_framepos = 0; goto sendMessage; } else if (unit->m_framepos == bufFrames2) { sendMessage: if (unit->m_buf->mask>=0) unit->m_buf->mask1 = unit->m_buf->mask; if(unit->mWorld->mRealTime){ // send a message to read DiskIOMsg msg; msg.mWorld = unit->mWorld; msg.mCommand = (int)ZIN0(1) ? kDiskCmd_ReadLoop : kDiskCmd_Read; msg.mBufNum = (int)fbufnum; msg.mPos = bufFrames2 - unit->m_framepos; msg.mFrames = bufFrames2; msg.mChannels = bufChannels; gDiskIO->Write(msg); } else { SndBuf *bufr = World_GetNRTBuf(unit->mWorld, (int) fbufnum); uint32 mPos = bufFrames2 - unit->m_framepos; if (mPos > (uint32)bufr->frames || mPos + bufFrames2 > (uint32)bufr->frames || (uint32) bufr->channels != bufChannels) return; sf_count_t count; if ((int)ZIN0(1)) { // loop if (!bufr->sndfile) memset(bufr->data + mPos * bufr->channels, 0, bufFrames2 * bufr->channels * sizeof(float)); count = sf_readf_float(bufr->sndfile, bufr->data + mPos * bufr->channels, bufFrames2); while (bufFrames2 -= count) { sf_seek(bufr->sndfile, 0, SEEK_SET); count = sf_readf_float(bufr->sndfile, bufr->data + (mPos + count) * bufr->channels, bufFrames2); } } else { // non-loop count = bufr->sndfile ? sf_readf_float(bufr->sndfile, bufr->data + mPos * bufr->channels, bufFrames2) : 0; if (count < bufFrames2) { memset(bufr->data + (mPos + count) * bufr->channels, 0, (bufFrames2 - count) * bufr->channels * sizeof(float)); unit->m_buf->mask = mPos + count; } } } } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void DiskOut_Ctor(DiskOut* unit) { unit->m_fbufnum = -1.f; unit->m_buf = unit->mWorld->mSndBufs; unit->m_framepos = 0; unit->m_framewritten = 0; SETCALC(DiskOut_next); } void DiskOut_next(DiskOut *unit, int inNumSamples) { GET_BUF if (!bufData || ((bufFrames & ((unit->mWorld->mBufLength<<1) - 1)) != 0)) { unit->m_framepos = 0; // unit->m_framewritten = 0; return; } SETUP_IN(1) float *out = OUT(0); uint32 framew = unit->m_framewritten; // printf("Start frames %i %i\n", unit->m_framewritten, framew ); if (unit->m_framepos >= bufFrames) unit->m_framepos = 0; bufData += unit->m_framepos * bufChannels; if (bufChannels > 2) { for (int j=0; jm_framepos += inNumSamples; // unit->m_framewritten += inNumSamples; unit->m_framewritten = framew; // printf("frames %i %i\n", unit->m_framewritten, framew ); uint32 bufFrames2 = bufFrames >> 1; if (unit->m_framepos == bufFrames) { unit->m_framepos = 0; goto sendMessage; } else if (unit->m_framepos == bufFrames2) { sendMessage: // send a message to write DiskIOMsg msg; msg.mWorld = unit->mWorld; msg.mCommand = kDiskCmd_Write; msg.mBufNum = (int)fbufnum; msg.mPos = bufFrames2 - unit->m_framepos; msg.mFrames = bufFrames2; msg.mChannels = bufChannels; //printf("sendMessage %d %d %d %d\n", msg.mBufNum, msg.mPos, msg.mFrames, msg.mChannels); gDiskIO->Write(msg); } } void DiskOut_Dtor(DiskOut* unit) { GET_BUF uint32 framepos = unit->m_framepos; uint32 bufFrames2 = bufFrames >> 1; // check that we didn't just write if (framepos != 0 && framepos != bufFrames2) { // if not write the last chunk of samples uint32 writeStart; if (framepos > bufFrames2) { writeStart = bufFrames2; } else { writeStart = 0; } DiskIOMsg msg; msg.mWorld = unit->mWorld; msg.mCommand = kDiskCmd_Write; msg.mBufNum = (int)fbufnum; msg.mPos = writeStart; msg.mFrames = framepos - writeStart; msg.mChannels = bufChannels; //printf("sendMessage %d %d %d %d\n", msg.mBufNum, msg.mPos, msg.mFrames, msg.mChannels); gDiskIO->Write(msg); } } void VDiskIn_Ctor(VDiskIn* unit) { unit->m_fbufnum = -1.f; unit->m_buf = unit->mWorld->mSndBufs; unit->m_framePos = 0.; unit->m_bufPos = 0.; unit->m_pchRatio = sc_max(IN0(1), 0.f); unit->m_count = 0; unit->m_iFramePos = 0; unit->m_iBufPos = 0; if (INRATE(1) == calc_ScalarRate && (unit->m_pchRatio == 1)) SETCALC(VDiskIn_next_rate1); else SETCALC(VDiskIn_first); } static void VDiskIn_request_buffer(VDiskIn * unit, float fbufnum, uint32 bufFrames2, uint32 bufChannels, double bufPos) { if (unit->m_buf->mask>=0) unit->m_buf->mask1 = unit->m_buf->mask; unit->m_count++; if(unit->mWorld->mRealTime) { DiskIOMsg msg; msg.mWorld = unit->mWorld; msg.mCommand = (int)ZIN0(2) ? kDiskCmd_ReadLoop : kDiskCmd_Read; msg.mBufNum = (int)fbufnum; uint32 thisPos; if((uint32)bufPos >= bufFrames2) thisPos = 0; else thisPos = bufFrames2; msg.mPos = thisPos; msg.mFrames = bufFrames2; msg.mChannels = bufChannels; gDiskIO->Write(msg); if((int)ZIN0(3)) { // float outval = bufPos + sc_mod((float)(unit->m_count * bufFrames2), (float)buf->fileinfo.frames); float outval = bufPos + (float)(unit->m_count * bufFrames2); SendNodeReply(&unit->mParent->mNode, (int)ZIN0(3), "/diskin", 1, &outval); } } else { SndBuf *bufr = World_GetNRTBuf(unit->mWorld, (int) fbufnum); uint32 mPos; if((uint32)bufPos >= bufFrames2) mPos = 0; else mPos = bufFrames2; if (mPos > (uint32)bufr->frames || mPos + bufFrames2 > (uint32)bufr->frames || (uint32) bufr->channels != bufChannels) return; sf_count_t count; if ((int)ZIN0(2)) { // loop if (!bufr->sndfile) memset(bufr->data + mPos * bufr->channels, 0, bufFrames2 * bufr->channels * sizeof(float)); count = sf_readf_float(bufr->sndfile, bufr->data + mPos * bufr->channels, bufFrames2); while (bufFrames2 -= count) { sf_seek(bufr->sndfile, 0, SEEK_SET); count = sf_readf_float(bufr->sndfile, bufr->data + (mPos + count) * bufr->channels, bufFrames2); } } else { // non-loop count = bufr->sndfile ? sf_readf_float(bufr->sndfile, bufr->data + mPos * bufr->channels, bufFrames2) : 0; if (count < bufFrames2) { memset(bufr->data + (mPos + count) * bufr->channels, 0, (bufFrames2 - count) * bufr->channels * sizeof(float)); unit->m_buf->mask = mPos + count; } } } } // first time through, the FIRST sample doesn't need the interpolation... the buffer won't be filled 'correctly' for // interpolation, so use the _first function to make this exception template static inline void VDiskIn_next_(VDiskIn *unit, int inNumSamples) { bool test = false; GET_BUF_SHARED if (!bufData || ((bufFrames & ((unit->mWorld->mBufLength<<1) - 1)) != 0)) { unit->m_framePos = 0.; unit->m_count = 0; ClearUnitOutputs(unit, inNumSamples); return; } SETUP_OUT(0); if (First) unit->m_rBufSize = 1. / bufFrames; double framePos = unit->m_framePos; double bufPos = unit->m_bufPos; // where we are in the DiskIn buffer float newPchRatio = sc_max(IN0(1), 0.f); if ((newPchRatio * inNumSamples * unit->m_rBufSize) >= 0.5) { printf("pitch ratio is greater then max allowed (see VDiskIn help)\n"); ClearUnitOutputs(unit, inNumSamples); return; } float pchRatio = unit->m_pchRatio; float pchSlope = CALCSLOPE(newPchRatio, pchRatio); uint32 bufFrames2 = bufFrames >> 1; double fbufFrames2 = (double)bufFrames2; double fbufFrames = (double)bufFrames; if (First) { for (uint32 i = 0; i < bufChannels; i++) out[i][0] = bufData[0 + i]; } const int firstLoopSample = First ? 1 : 0; for (int j = firstLoopSample; j < inNumSamples; ++j){ int32 iBufPos = (int32)bufPos; double frac = bufPos - (double)iBufPos; int table1 = iBufPos * bufChannels; int table0 = table1 - bufChannels; int table2 = table1 + bufChannels; int table3 = table2 + bufChannels; while(table1 >= bufSamples) table1 -= bufSamples; while(table0 < 0) table0 += bufSamples; while(table2 >= bufSamples) table2 -= bufSamples; while(table3 >= bufSamples) table3 -= bufSamples; for (uint32 i = 0; i < bufChannels; i++){ float a, b, c, d; a = bufData[table0 + i]; b = bufData[table1 + i]; c = bufData[table2 + i]; d = bufData[table3 + i]; out[i][j] = cubicinterp(frac, a, b, c, d); }; pchRatio += pchSlope; framePos += pchRatio; const double oldBufPos = bufPos; bufPos += pchRatio; // the +1 is needed for the cubic interpolation... make SURE the old data isn't needed any more before // setting up the new buffer if ((oldBufPos < (fbufFrames2 + 1)) && ((bufPos >= (fbufFrames2 + 1)))){ test = true; } if (bufPos >= (fbufFrames + 1)){ test = true; bufPos -= fbufFrames; } } if (unit->m_buf->mask1>=0 && bufPos>=unit->m_buf->mask1) unit->mDone = true; if ( test ) VDiskIn_request_buffer(unit, fbufnum, bufFrames2, bufChannels, bufPos); unit->m_framePos = framePos; unit->m_pchRatio = pchRatio; unit->m_bufPos = bufPos; if (First) SETCALC(VDiskIn_next); } void VDiskIn_first(VDiskIn *unit, int inNumSamples) { VDiskIn_next_(unit, inNumSamples); } void VDiskIn_next(VDiskIn *unit, int inNumSamples) { VDiskIn_next_(unit, inNumSamples); } void VDiskIn_next_rate1(VDiskIn *unit, int inNumSamples) { bool test = false; GET_BUF_SHARED if (!bufData || ((bufFrames & ((unit->mWorld->mBufLength<<1) - 1)) != 0)) { unit->m_iFramePos = 0.; unit->m_count = 0; ClearUnitOutputs(unit, inNumSamples); return; } SETUP_OUT(0) uint32 framePos = unit->m_iFramePos; uint32 bufPos = unit->m_iBufPos; uint32 bufFrames2 = bufFrames >> 1; for (int sample = 0; sample < inNumSamples; ++sample) { int bufferIndex = bufPos * bufChannels; for (uint32 channel = 0; channel < bufChannels; channel++) out[channel][sample] = bufData[bufferIndex + channel]; const uint32 oldBufPos = bufPos; bufPos += 1; framePos += 1; if ((oldBufPos < bufFrames2) && (bufPos >= bufFrames2)) test = true; if (bufPos >= bufFrames) { test = true; bufPos -= bufFrames; } } if (unit->m_buf->mask1>=0 && bufPos>=unit->m_buf->mask1) unit->mDone = true; if ( test ) VDiskIn_request_buffer(unit, fbufnum, bufFrames2, bufChannels, bufPos); unit->m_iFramePos = framePos; unit->m_iBufPos = bufPos; } //////////////////////////////////////////////////////////////////////////////////////////////////////// C_LINKAGE SC_API_EXPORT void unload(InterfaceTable *inTable) { delete gDiskIO; } PluginLoad(DiskIO) { ft = inTable; gDiskIO = new DiskIOThread(); gDiskIO->launchThread(); DefineSimpleUnit(DiskIn); DefineDtorUnit(DiskOut); DefineSimpleUnit(VDiskIn); } ////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/plugins/DynNoiseUGens.cpp000644 000765 000024 00000020062 12321461511 024036 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * DynNoiseUGens.cpp * xSC3plugins * * Created by Alberto de Campo, Sekhar Ramacrishnan, Julian Rohrhuber on Sun May 30 2004. * Copyright (c) 2004 HfbK. All rights reserved. * */ #include "SC_PlugIn.h" static InterfaceTable *ft; struct LFDNoise0 : public Unit { float mLevel; float mPhase; }; struct LFDNoise1 : public Unit { float mPhase; float mPrevLevel; float mNextLevel; }; struct LFDNoise3 : public Unit { float mPhase; float mLevelA, mLevelB, mLevelC, mLevelD; }; struct LFDClipNoise : public Unit { float mLevel; float mPhase; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void LFDNoise0_next(LFDNoise0 *unit, int inNumSamples); void LFDNoise0_next_k(LFDNoise0 *unit, int inNumSamples); void LFDNoise0_Ctor(LFDNoise0 *unit); void LFDNoise1_next(LFDNoise1 *unit, int inNumSamples); void LFDNoise1_next_k(LFDNoise1 *unit, int inNumSamples); void LFDNoise1_Ctor(LFDNoise1 *unit); void LFDNoise3_next(LFDNoise3 *unit, int inNumSamples); void LFDNoise3_next_k(LFDNoise3 *unit, int inNumSamples); void LFDNoise3_Ctor(LFDNoise3 *unit); void LFDClipNoise_next(LFDClipNoise *unit, int inNumSamples); void LFDClipNoise_Ctor(LFDClipNoise *unit); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFDNoise0_next(LFDNoise0 *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float level = unit->mLevel; float phase = unit->mPhase; float smpdur = SAMPLEDUR; RGET LOOP1(inNumSamples, phase -= ZXP(freq) * smpdur; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); level = frand2(s1,s2,s3); } ZXP(out) = level; ) unit->mLevel = level; unit->mPhase = phase; RPUT } void LFDNoise0_next_k(LFDNoise0 *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float level = unit->mLevel; float phase = unit->mPhase; float smpdur = SAMPLEDUR; float dphase = smpdur * freq; RGET LOOP1(inNumSamples, phase -= dphase; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); level = frand2(s1,s2,s3); } ZXP(out) = level; ) unit->mLevel = level; unit->mPhase = phase; RPUT } void LFDNoise0_Ctor(LFDNoise0* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LFDNoise0_next); } else { SETCALC(LFDNoise0_next_k); } unit->mPhase = 0.f; unit->mLevel = 0.f; LFDNoise0_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFDNoise1_next(LFDNoise1 *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float prevLevel = unit->mPrevLevel; float nextLevel = unit->mNextLevel; float phase = unit->mPhase; float smpdur = SAMPLEDUR; RGET LOOP1(inNumSamples, phase -= ZXP(freq) * smpdur; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); prevLevel = nextLevel; nextLevel = frand2(s1,s2,s3); } ZXP(out) = nextLevel + ( phase * (prevLevel - nextLevel) ); ) unit->mPrevLevel = prevLevel; unit->mNextLevel = nextLevel; unit->mPhase = phase; RPUT } void LFDNoise1_next_k(LFDNoise1 *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float prevLevel = unit->mPrevLevel; float nextLevel = unit->mNextLevel; float phase = unit->mPhase; float smpdur = SAMPLEDUR; float dphase = freq * smpdur; RGET LOOP1(inNumSamples, phase -= dphase; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); prevLevel = nextLevel; nextLevel = frand2(s1,s2,s3); } ZXP(out)= nextLevel + ( phase * (prevLevel - nextLevel) ); ) unit->mPrevLevel = prevLevel; unit->mNextLevel = nextLevel; unit->mPhase = phase; RPUT } void LFDNoise1_Ctor(LFDNoise1* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LFDNoise1_next); } else { SETCALC(LFDNoise1_next_k); } unit->mPhase = 0.f; unit->mPrevLevel = 0.f; unit->mNextLevel = unit->mParent->mRGen->frand2(); LFDNoise1_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LFDNoise3_next(LFDNoise3 *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float a = unit->mLevelA; float b = unit->mLevelB; float c = unit->mLevelC; float d = unit->mLevelD; float phase = unit->mPhase; float smpdur = SAMPLEDUR; RGET LOOP1(inNumSamples, phase -= ZXP(freq) * smpdur; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); a = b; b = c; c = d; d = frand2(s1,s2,s3) * 0.8f; // limits max interpol. overshoot to 1. } ZXP(out) = cubicinterp(1.f - phase, a, b, c, d); ) unit->mLevelA = a; unit->mLevelB = b; unit->mLevelC = c; unit->mLevelD = d; unit->mPhase = phase; RPUT } void LFDNoise3_next_k(LFDNoise3 *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float a = unit->mLevelA; float b = unit->mLevelB; float c = unit->mLevelC; float d = unit->mLevelD; float phase = unit->mPhase; float dphase = freq * SAMPLEDUR; RGET LOOP1(inNumSamples, phase -= dphase; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); a = b; b = c; c = d; d = frand2(s1,s2,s3) * 0.8f; // limits max interpol. overshoot to 1. } ZXP(out) = cubicinterp(1.f - phase, a, b, c, d); ) unit->mLevelA = a; unit->mLevelB = b; unit->mLevelC = c; unit->mLevelD = d; unit->mPhase = phase; RPUT } void LFDNoise3_Ctor(LFDNoise3* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LFDNoise3_next); } else { SETCALC(LFDNoise3_next_k); } RGET unit->mPhase = 0.f; unit->mLevelA = frand2(s1, s2, s3) * 0.8f; // limits max interpol. overshoot to 1. unit->mLevelB = frand2(s1, s2, s3) * 0.8f; unit->mLevelC = frand2(s1, s2, s3) * 0.8f; unit->mLevelD = frand2(s1, s2, s3) * 0.8f; RPUT LFDNoise3_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LFDClipNoise_next(LFDClipNoise *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float level = unit->mLevel; float phase = unit->mPhase; float smpdur = SAMPLEDUR; RGET LOOP1(inNumSamples, phase -= ZXP(freq) * smpdur; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); level = fcoin(s1,s2,s3); } ZXP(out) = level; ) unit->mLevel = level; unit->mPhase = phase; RPUT } void LFDClipNoise_next_k(LFDClipNoise *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float level = unit->mLevel; float phase = unit->mPhase; float smpdur = SAMPLEDUR; float dphase = smpdur * freq; RGET LOOP1(inNumSamples, phase -= dphase; if (phase < 0) { phase = sc_wrap(phase, 0.f, 1.f); level = fcoin(s1,s2,s3); } ZXP(out) = level; ) unit->mLevel = level; unit->mPhase = phase; RPUT } void LFDClipNoise_Ctor(LFDClipNoise* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LFDClipNoise_next); } else { SETCALC(LFDClipNoise_next_k); } unit->mPhase = 0.f; unit->mLevel = 0.f; LFDClipNoise_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(DynNoise) { ft = inTable; DefineSimpleUnit(LFDNoise0); DefineSimpleUnit(LFDNoise1); DefineSimpleUnit(LFDNoise3); DefineSimpleUnit(LFDClipNoise); } //////////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/plugins/FeatureDetection.cpp000644 000765 000024 00000025350 12321461511 024603 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //Feature (Onset) Detection implemented by sick lincoln for sc3 //Jensen,K. & Andersen, T. H. (2003). Real-time Beat Estimation Using Feature Extraction. //In Proceedings of the Computer Music Modeling and RetrievalSymposium, Lecture Notes in Computer Science. Springer Verlag. //Hainsworth, S. (2003) Techniques for the Automated Analysis of Musical Audio. PhD, university of cambridge engineering dept. //possible to make a Goto style Detector for a given band and with history of two samples- //should do separately as PV_GotoBandTrack //next perhaps Duxbury et al/ Mauri et al different conception of high frequency content with ratio of changes #include "FFT_UGens.h" struct PV_OnsetDetectionBase : public Unit { float * m_prevframe; int m_numbins; int m_waiting, m_waitSamp, m_waitLen; }; //FFT onset detector combining 4 advised features from Jensen/Andersen struct PV_JensenAndersen : public PV_OnsetDetectionBase { float m_hfc,m_hfe,m_sc,m_sf; int m_fourkindex; }; //FFT onset detector combining 2 advised features from Hainsworth PhD struct PV_HainsworthFoote : public PV_OnsetDetectionBase { float m_prevNorm; int m_5kindex,m_30Hzindex; }; //for time domain onset detection/RMS struct RunningSum : public Unit { int msamp, mcount; float msum,msum2; //float mmeanmult; float* msquares; }; extern "C" { void PV_OnsetDetectionBase_Ctor(PV_OnsetDetectionBase *unit); void PV_OnsetDetectionBase_Dtor(PV_OnsetDetectionBase *unit); void PV_JensenAndersen_Ctor(PV_JensenAndersen *unit); void PV_JensenAndersen_Dtor(PV_JensenAndersen *unit); void PV_JensenAndersen_next(PV_JensenAndersen *unit, int inNumSamples); void PV_HainsworthFoote_Ctor(PV_HainsworthFoote *unit); void PV_HainsworthFoote_Dtor(PV_HainsworthFoote *unit); void PV_HainsworthFoote_next(PV_HainsworthFoote *unit, int inNumSamples); void RunningSum_next_k(RunningSum *unit, int inNumSamples); void RunningSum_Ctor(RunningSum* unit); void RunningSum_Dtor(RunningSum* unit); } #define PV_FEAT_GET_BUF_UNLOCKED \ uint32 ibufnum = (uint32)fbufnum; \ int bufOK = 1; \ World *world = unit->mWorld; \ SndBuf *buf; \ if (ibufnum >= world->mNumSndBufs) { \ int localBufNum = ibufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufOK = 0; \ buf = world->mSndBufs; \ if(unit->mWorld->mVerbosity > -1){ Print("FFT Ctor error: Buffer number overrun: %i\n", ibufnum); } \ } \ } else { \ buf = world->mSndBufs + ibufnum; \ } \ int numbins = (buf->samples - 2) >> 1; \ if (!buf->data) { \ if(unit->mWorld->mVerbosity > -1){ Print("FFT Ctor error: Buffer %i not initialised.\n", ibufnum); } \ bufOK = 0; \ } #define PV_FEAT_GET_BUF \ PV_FEAT_GET_BUF_UNLOCKED \ LOCK_SNDBUF(buf); void PV_OnsetDetectionBase_Ctor(PV_OnsetDetectionBase *unit) { float fbufnum = ZIN0(0); PV_FEAT_GET_BUF_UNLOCKED unit->m_numbins = numbins; int insize = unit->m_numbins * sizeof(float); if(bufOK) { unit->m_prevframe = (float*)RTAlloc(unit->mWorld, insize); memset(unit->m_prevframe, 0, insize); } unit->m_waiting=0; unit->m_waitSamp=0; unit->m_waitLen=0; } void PV_OnsetDetectionBase_Dtor(PV_OnsetDetectionBase *unit) { if(unit->m_prevframe) RTFree(unit->mWorld, unit->m_prevframe); } void PV_JensenAndersen_Ctor(PV_JensenAndersen *unit) { PV_OnsetDetectionBase_Ctor(unit); unit->m_hfc= 0.0; unit->m_hfe= 0.0; unit->m_sf= 0.0; unit->m_sc= 0.0; unit->m_fourkindex= (int)(4000.0/(unit->mWorld->mSampleRate))*(unit->m_numbins); SETCALC(PV_JensenAndersen_next); } void PV_JensenAndersen_Dtor(PV_JensenAndersen *unit) { PV_OnsetDetectionBase_Dtor(unit); } void PV_JensenAndersen_next(PV_JensenAndersen *unit, int inNumSamples) { float outval=0.0; float fbufnum = ZIN0(0); if(unit->m_waiting==1) { unit->m_waitSamp+=inNumSamples; if(unit->m_waitSamp>=unit->m_waitLen) unit->m_waiting=0; } if (!(fbufnum < 0.f)) //if buffer ready to process { PV_FEAT_GET_BUF SCPolarBuf *p = ToPolarApx(buf); //four spectral features useful for onset detection according to Jensen/Andersen float magsum=0.0, magsumk=0.0, magsumkk=0.0, sfsum=0.0, hfesum=0.0; float * q= unit->m_prevframe; int k4= unit->m_fourkindex; //ignores dc, nyquist for (int i=0; ibin[i]).mag); int k= i+1; float qmag= q[i]; magsum+=mag; magsumk+=k*mag; magsumkk+=k*k*mag; sfsum+= fabs(mag- (qmag)); if(i>k4) hfesum+=mag; } float binmult= 1.f/numbins; //normalise float sc= (magsumk/magsum)*binmult; float hfe= hfesum*binmult; float hfc= magsumkk*binmult*binmult*binmult; float sf= sfsum*binmult; //printf("sc %f hfe %f hfc %f sf %f \n",sc, hfe, hfc, sf); //if(sc<0.0) sc=0.0; //if(hfe<0.0) hfe=0.0; //if(hfc<0.0) hfc=0.0; //if(sf<0.0) sf=0.0; //ratio of current to previous frame perhaps better indicator than first derivative difference float scdiff= sc-(unit->m_sc); float hfediff= hfe-(unit->m_hfe); float hfcdiff= hfc-(unit->m_hfc); float sfdiff= sf-(unit->m_sf); //store as old frame values for taking difference unit->m_sc=sc; unit->m_hfe=hfe; unit->m_hfc=hfc; unit->m_sf=sf; //printf("sc %f hfe %f hfc %f sf %f \n",sc, hfe, hfc, sf); //printf("sc %f hfe %f hfc %f sf %f \n",scdiff, hfediff, hfcdiff, sfdiff); //does this trigger? //may need to take derivatives across previous frames by storing old values float sum = (ZIN0(1)*scdiff)+(ZIN0(2)*hfediff)+(ZIN0(3)*hfcdiff)+(ZIN0(4)*sfdiff); //printf("sum %f thresh %f \n",sum, ZIN0(7)); //if over threshold, may also impose a wait here if(sum>ZIN0(5) && (unit->m_waiting==0)) {//printf("bang! \n"); outval=1.0; unit->m_waiting=1; unit->m_waitSamp=inNumSamples; unit->m_waitLen=(int)(ZIN0(6)*(world->mSampleRate)); } //take copy of this frame's magnitudes as prevframe for (int i=0; ibin[i].mag; } Fill(inNumSamples, &ZOUT0(0), outval); } void PV_HainsworthFoote_Ctor(PV_HainsworthFoote *unit) { PV_OnsetDetectionBase_Ctor(unit); World *world = unit->mWorld; unit->m_5kindex= (int)((5000.0/(world->mSampleRate))*(unit->m_numbins)); unit->m_30Hzindex= (int)((30.0/(world->mSampleRate))*(unit->m_numbins)); unit->m_prevNorm= 1.0; //unit->m_5kindex, unit->m_30Hzindex, //printf("numbins %d sr %d \n", unit->m_numbins, world->mSampleRate); //printf("test %d sr %f 5k %d 30Hz %d\n", unit->m_numbins, world->mSampleRate, unit->m_5kindex, unit->m_30Hzindex); SETCALC(PV_HainsworthFoote_next); } void PV_HainsworthFoote_Dtor(PV_HainsworthFoote *unit) { PV_OnsetDetectionBase_Dtor(unit); } static const float lmult= 1.442695040889; //loge(2) reciprocal void PV_HainsworthFoote_next(PV_HainsworthFoote *unit, int inNumSamples) { float outval=0.0; float fbufnum = ZIN0(0); if(unit->m_waiting==1) { unit->m_waitSamp+=inNumSamples; if(unit->m_waitSamp>=unit->m_waitLen) {unit->m_waiting=0;} } if (!(fbufnum < 0.f)) //if buffer ready to process { PV_FEAT_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float dnk, prevmag, mkl=0.0, footesum=0.0, norm=0.0; float * q= unit->m_prevframe; int k5= unit->m_5kindex; int h30= unit->m_30Hzindex; for (int i=0; ibin[i]).mag); float qmag= q[i]; if(i>=h30 && i0.0) mkl+=dnk; } norm+=mag*mag; footesum+=mag*qmag; } mkl= mkl/(k5-h30); //Foote measure- footediv will be zero initially float footediv= ((sqrt(norm))*(sqrt(unit->m_prevNorm))); if(footediv<0.0001f) footediv=0.0001f; float foote= 1.0- (footesum/footediv); //1.0 - similarity //printf("mkl %f foote %f \n",mkl, foote); unit->m_prevNorm= norm; float sum = (ZIN0(1)*mkl)+(ZIN0(2)*foote); //printf("sum %f thresh %f \n",sum, ZIN0(7)); //if over threshold, may also impose a 50mS wait here if(sum>ZIN0(3) && (unit->m_waiting==0)) { outval=1.0; unit->m_waiting=1; unit->m_waitSamp=inNumSamples; unit->m_waitLen=(int)(ZIN0(4)*(unit->mWorld->mSampleRate)); } //take copy of this frame's magnitudes as prevframe for (int i=0; ibin[i].mag; } Fill(inNumSamples, &ZOUT0(0), outval); } void RunningSum_Ctor( RunningSum* unit ) { SETCALC(RunningSum_next_k); unit->msamp= (int) ZIN0(1); //unit->mmeanmult= 1.0f/(unit->msamp); unit->msum=0.0f; unit->msum2=0.0f; unit->mcount=0; //unit->msamp-1; unit->msquares= (float*)RTAlloc(unit->mWorld, unit->msamp * sizeof(float)); //initialise to zeroes for(int i=0; imsamp; ++i) unit->msquares[i]=0.f; } void RunningSum_Dtor(RunningSum *unit) { RTFree(unit->mWorld, unit->msquares); } //RMS is easy because convolution kernel can be updated just by deleting oldest sample and adding newest- //half hanning window convolution etc requires updating values for all samples in memory on each iteration void RunningSum_next_k( RunningSum *unit, int inNumSamples ) { float *in = ZIN(0); float *out = ZOUT(0); int count= unit->mcount; int samp= unit->msamp; float * data= unit->msquares; float sum= unit->msum; //avoids floating point error accumulation over time- thanks to Ross Bencina float sum2= unit->msum2; int todo=0; int done=0; while(donemcount =count; unit->msum = sum; unit->msum2 = sum2; } void initFeatureDetectors(InterfaceTable *it) { DefineDtorUnit(PV_JensenAndersen); DefineDtorUnit(PV_HainsworthFoote); DefineDtorUnit(RunningSum); } SuperCollider-Source/server/plugins/FFT2InterfaceTable.cpp000644 000765 000024 00000002372 12321461511 024642 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //third party Phase Vocoder UGens #include "FFT_UGens.h" InterfaceTable *ft; //these are defined in the relevant files extern void initConvolution(InterfaceTable *); extern void initPV_ThirdParty(InterfaceTable *); extern void initFeatureDetectors(InterfaceTable *it); PluginLoad(PV_ThirdParty) { ft= inTable; initConvolution(inTable); initPV_ThirdParty(inTable); initFeatureDetectors(inTable); } SuperCollider-Source/server/plugins/FFT_UGens.cpp000644 000765 000024 00000030103 12321461511 023061 0ustar00crucialstaff000000 000000 /* Improved FFT and IFFT UGens for SuperCollider 3 Copyright (c) 2007-2008 Dan Stowell, incorporating code from SuperCollider 3 Copyright (c) 2002 James McCartney. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "FFT_UGens.h" // We include vDSP even if not using for FFT, since we want to use some vectorised add/mul tricks #if defined(__APPLE__) && !defined(SC_IPHONE) #include #endif struct FFTBase : public Unit { SndBuf *m_fftsndbuf; float *m_fftbuf; int m_pos, m_fullbufsize, m_audiosize; // "fullbufsize" includes any zero-padding, "audiosize" does not. int m_log2n_full, m_log2n_audio; uint32 m_fftbufnum; scfft* m_scfft; int m_hopsize, m_shuntsize; // These add up to m_audiosize int m_wintype; int m_numSamples; }; struct FFT : public FFTBase { float *m_inbuf; }; struct IFFT : public FFTBase { float *m_olabuf; int m_numSamples; }; struct FFTTrigger : public FFTBase { int m_numPeriods, m_periodsRemain, m_polar; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void FFT_Ctor(FFT* unit); void FFT_ClearUnitOutputs(FFT *unit, int wrongNumSamples); void FFT_next(FFT *unit, int inNumSamples); void FFT_Dtor(FFT* unit); void IFFT_Ctor(IFFT* unit); void IFFT_next(IFFT *unit, int inNumSamples); void IFFT_Dtor(IFFT* unit); void FFTTrigger_Ctor(FFTTrigger* unit); void FFTTrigger_next(FFTTrigger* unit, int inNumSamples); } ////////////////////////////////////////////////////////////////////////////////////////////////// static int FFTBase_Ctor(FFTBase *unit, int frmsizinput) { World *world = unit->mWorld; uint32 bufnum = (uint32)ZIN0(0); SndBuf *buf; if (bufnum >= world->mNumSndBufs) { int localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localMaxBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { if(unit->mWorld->mVerbosity > -1){ Print("FFTBase_Ctor error: invalid buffer number: %i.\n", bufnum); } return 0; } } else { buf = world->mSndBufs + bufnum; } if (!buf->data) { if(unit->mWorld->mVerbosity > -1){ Print("FFTBase_Ctor error: Buffer %i not initialised.\n", bufnum); } return 0; } unit->m_fftsndbuf = buf; unit->m_fftbufnum = bufnum; unit->m_fullbufsize = buf->samples; int framesize = (int)ZIN0(frmsizinput); if(framesize < 1) unit->m_audiosize = buf->samples; else unit->m_audiosize = sc_min(buf->samples, framesize); unit->m_log2n_full = LOG2CEIL(unit->m_fullbufsize); unit->m_log2n_audio = LOG2CEIL(unit->m_audiosize); // Although FFTW allows non-power-of-two buffers (vDSP doesn't), this would complicate the windowing, so we don't allow it. if (!ISPOWEROFTWO(unit->m_fullbufsize)) { Print("FFTBase_Ctor error: buffer size (%i) not a power of two.\n", unit->m_fullbufsize); return 0; } else if (!ISPOWEROFTWO(unit->m_audiosize)) { Print("FFTBase_Ctor error: audio frame size (%i) not a power of two.\n", unit->m_audiosize); return 0; } else if (unit->m_audiosize < SC_FFT_MINSIZE || (((int)(unit->m_audiosize / unit->mWorld->mFullRate.mBufLength)) * unit->mWorld->mFullRate.mBufLength != unit->m_audiosize)) { Print("FFTBase_Ctor error: audio frame size (%i) not a multiple of the block size (%i).\n", unit->m_audiosize, unit->mWorld->mFullRate.mBufLength); return 0; } unit->m_pos = 0; ZOUT0(0) = ZIN0(0); return 1; } ////////////////////////////////////////////////////////////////////////////////////////////////// void FFT_Ctor(FFT *unit) { int winType = sc_clip((int)ZIN0(3), -1, 1); // wintype may be used by the base ctor unit->m_wintype = winType; if(!FFTBase_Ctor(unit, 5)){ SETCALC(FFT_ClearUnitOutputs); // These zeroes are to prevent the dtor freeing things that don't exist: unit->m_inbuf = 0; unit->m_scfft = 0; return; } int audiosize = unit->m_audiosize * sizeof(float); int hopsize = (int)(sc_max(sc_min(ZIN0(2), 1.f), 0.f) * unit->m_audiosize); if (hopsize < unit->mWorld->mFullRate.mBufLength) { Print("FFT_Ctor: hopsize smaller than SC's block size (%i) - automatically corrected.\n", hopsize, unit->mWorld->mFullRate.mBufLength); hopsize = unit->mWorld->mFullRate.mBufLength; } else if (((int)(hopsize / unit->mWorld->mFullRate.mBufLength)) * unit->mWorld->mFullRate.mBufLength != hopsize) { Print("FFT_Ctor: hopsize (%i) not an exact multiple of SC's block size (%i) - automatically corrected.\n", hopsize, unit->mWorld->mFullRate.mBufLength); hopsize = ((int)(hopsize / unit->mWorld->mFullRate.mBufLength)) * unit->mWorld->mFullRate.mBufLength; } unit->m_hopsize = hopsize; unit->m_shuntsize = unit->m_audiosize - hopsize; unit->m_inbuf = (float*)RTAlloc(unit->mWorld, audiosize); SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft = scfft_create(unit->m_fullbufsize, unit->m_audiosize, (SCFFT_WindowFunction)unit->m_wintype, unit->m_inbuf, unit->m_fftsndbuf->data, kForward, alloc); if (!unit->m_scfft) { SETCALC(*ClearUnitOutputs); return; } memset(unit->m_inbuf, 0, audiosize); //Print("FFT_Ctor: hopsize %i, shuntsize %i, bufsize %i, wintype %i, \n", // unit->m_hopsize, unit->m_shuntsize, unit->m_bufsize, unit->m_wintype); if (INRATE(1) == calc_FullRate) { unit->m_numSamples = unit->mWorld->mFullRate.mBufLength; } else { unit->m_numSamples = 1; } SETCALC(FFT_next); } void FFT_Dtor(FFT *unit) { SCWorld_Allocator alloc(ft, unit->mWorld); if(unit->m_scfft) scfft_destroy(unit->m_scfft, alloc); if(unit->m_inbuf) RTFree(unit->mWorld, unit->m_inbuf); } // Ordinary ClearUnitOutputs outputs zero, potentially telling the IFFT (+ PV UGens) to act on buffer zero, so let's skip that: void FFT_ClearUnitOutputs(FFT *unit, int wrongNumSamples) { ZOUT0(0) = -1; } void FFT_next(FFT *unit, int wrongNumSamples) { float *in = IN(1); float *out = unit->m_inbuf + unit->m_pos + unit->m_shuntsize; int numSamples = unit->m_numSamples; // copy input memcpy(out, in, numSamples * sizeof(float)); unit->m_pos += numSamples; bool gate = ZIN0(4) > 0.f; // Buffer shunting continues, but no FFTing if (unit->m_pos != unit->m_hopsize || !unit->m_fftsndbuf->data || unit->m_fftsndbuf->samples != unit->m_fullbufsize) { if(unit->m_pos == unit->m_hopsize) unit->m_pos = 0; ZOUT0(0) = -1.f; } else { unit->m_pos = 0; if(gate){ scfft_dofft(unit->m_scfft); unit->m_fftsndbuf->coord = coord_Complex; ZOUT0(0) = unit->m_fftbufnum; } else { ZOUT0(0) = -1; } // Shunt input buf down memmove(unit->m_inbuf, unit->m_inbuf + unit->m_hopsize, unit->m_shuntsize * sizeof(float)); } } ///////////////////////////////////////////////////////////////////////////////////////////// void IFFT_Ctor(IFFT* unit){ int winType = sc_clip((int)ZIN0(1), -1, 1); // wintype may be used by the base ctor unit->m_wintype = winType; if(!FFTBase_Ctor(unit, 2)){ SETCALC(*ClearUnitOutputs); // These zeroes are to prevent the dtor freeing things that don't exist: unit->m_olabuf = 0; return; } // This will hold the transformed and progressively overlap-added data ready for outputting. unit->m_olabuf = (float*)RTAlloc(unit->mWorld, unit->m_audiosize * sizeof(float)); memset(unit->m_olabuf, 0, unit->m_audiosize * sizeof(float)); SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft = scfft_create(unit->m_fullbufsize, unit->m_audiosize, (SCFFT_WindowFunction)unit->m_wintype, unit->m_fftsndbuf->data, unit->m_fftsndbuf->data, kBackward, alloc); if (!unit->m_scfft) { SETCALC(*ClearUnitOutputs); unit->m_olabuf = 0; return; } // "pos" will be reset to zero when each frame comes in. Until then, the following ensures silent output at first: unit->m_pos = 0; //unit->m_audiosize; if (unit->mCalcRate == calc_FullRate) { unit->m_numSamples = unit->mWorld->mFullRate.mBufLength; } else { unit->m_numSamples = 1; } SETCALC(IFFT_next); } void IFFT_Dtor(IFFT* unit) { if(unit->m_olabuf) RTFree(unit->mWorld, unit->m_olabuf); SCWorld_Allocator alloc(ft, unit->mWorld); if(unit->m_scfft) scfft_destroy(unit->m_scfft, alloc); } void IFFT_next(IFFT *unit, int wrongNumSamples) { float *out = OUT(0); // NB not ZOUT0 // Load state from struct into local scope int pos = unit->m_pos; int audiosize = unit->m_audiosize; int numSamples = unit->m_numSamples; float *olabuf = unit->m_olabuf; float fbufnum = ZIN0(0); // Only run the IFFT if we're receiving a new block of input data - otherwise just output data already received if (fbufnum >= 0.f){ // Ensure it's in cartesian format, not polar ToComplexApx(unit->m_fftsndbuf); float* fftbuf = unit->m_fftsndbuf->data; scfft_doifft(unit->m_scfft); // Then shunt the "old" time-domain output down by one hop int hopsamps = pos; int shuntsamps = audiosize - hopsamps; if(hopsamps != audiosize) // There's only copying to be done if the position isn't all the way to the end of the buffer memmove(olabuf, olabuf+hopsamps, shuntsamps * sizeof(float)); // Then mix the "new" time-domain data in - adding at first, then just setting (copying) where the "old" is supposed to be zero. #if defined(__APPLE__) && !defined(SC_IPHONE) vDSP_vadd(olabuf, 1, fftbuf, 1, olabuf, 1, shuntsamps); #else // NB we re-use the "pos" variable temporarily here for write rather than read for(pos = 0; pos < shuntsamps; ++pos){ olabuf[pos] += fftbuf[pos]; } #endif memcpy(olabuf + shuntsamps, fftbuf + shuntsamps, (hopsamps) * sizeof(float)); // Move the pointer back to zero, which is where playback will next begin pos = 0; } // End of has-the-chain-fired // Now we can output some stuff, as long as there is still data waiting to be output. // If there is NOT data waiting to be output, we output zero. (Either irregular/negative-overlap // FFT firing, or FFT has given up, or at very start of execution.) if(pos >= audiosize) ClearUnitOutputs(unit, numSamples); else { memcpy(out, olabuf + pos, numSamples * sizeof(float)); pos += numSamples; } unit->m_pos = pos; } ///////////////////////////////////////////////////////////////////////////////////////////// void FFTTrigger_Ctor(FFTTrigger *unit) { World *world = unit->mWorld; /* uint32 bufnum = (uint32)IN0(0); Print("FFTTrigger_Ctor: bufnum is %i\n", bufnum); if (bufnum >= world->mNumSndBufs) bufnum = 0; SndBuf *buf = world->mSndBufs + bufnum; */ uint32 bufnum = (uint32)IN0(0); //Print("FFTTrigger_Ctor: bufnum is %i\n", bufnum); SndBuf *buf; if (bufnum >= world->mNumSndBufs) { int localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localMaxBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { bufnum = 0; buf = world->mSndBufs + bufnum; } } else { buf = world->mSndBufs + bufnum; } LOCK_SNDBUF(buf); unit->m_fftsndbuf = buf; unit->m_fftbufnum = bufnum; unit->m_fullbufsize = buf->samples; int numSamples = unit->mWorld->mFullRate.mBufLength; float dataHopSize = IN0(1); unit->m_numPeriods = unit->m_periodsRemain = (int)(((float)unit->m_fullbufsize * dataHopSize) / numSamples) - 1; buf->coord = (IN0(2) == 1.f) ? coord_Polar : coord_Complex; OUT0(0) = IN0(0); SETCALC(FFTTrigger_next); } void FFTTrigger_next(FFTTrigger *unit, int inNumSamples) { if (unit->m_periodsRemain > 0) { ZOUT0(0) = -1.f; unit->m_periodsRemain--; } else { ZOUT0(0) = unit->m_fftbufnum; unit->m_pos = 0; unit->m_periodsRemain = unit->m_numPeriods; } } void initFFT(InterfaceTable *inTable) { ft = inTable; DefineDtorUnit(FFT); DefineDtorUnit(IFFT); DefineSimpleUnit(FFTTrigger); } SuperCollider-Source/server/plugins/FFTInterfaceTable.cpp000644 000765 000024 00000002324 12321461511 024555 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //third party Phase Vocoder UGens #include "FFT_UGens.h" InterfaceTable *ft; //these are defined in the relevant files extern void initFFT(InterfaceTable *inTable); extern void initPV(InterfaceTable *inTable); extern void initPartConv(InterfaceTable *inTable); PluginLoad(FFT_UGens) { ft= inTable; initFFT(inTable); initPV(inTable); initPartConv(inTable); } SuperCollider-Source/server/plugins/FilterUGens.cpp000644 000765 000024 00000460552 12524671173 023563 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include // NaNs are not equal to any floating point number static const float uninitializedControl = std::numeric_limits::quiet_NaN(); #define PI 3.1415926535898f #define PUSH_LOOPVALS \ int tmp_floops = unit->mRate->mFilterLoops; \ int tmp_fremain = unit->mRate->mFilterRemain; \ unit->mRate->mFilterLoops = 0; \ unit->mRate->mFilterRemain = 1; #define POP_LOOPVALS \ unit->mRate->mFilterLoops = tmp_floops; \ unit->mRate->mFilterRemain = tmp_fremain; using namespace std; // for math functions static InterfaceTable *ft; struct Ramp : public Unit { double m_level, m_slope; int m_counter; }; struct Lag : public Unit { float m_lag; double m_b1, m_y1; }; struct Lag2 : public Unit { float m_lag; double m_b1, m_y1a, m_y1b; }; struct Lag3 : public Unit { float m_lag; double m_b1, m_y1a, m_y1b, m_y1c; }; struct LagUD : public Unit { float m_lagu, m_lagd; double m_b1u, m_b1d, m_y1; }; struct Lag2UD : public Unit { float m_lagu, m_lagd; double m_b1u, m_b1d, m_y1a, m_y1b; }; struct Lag3UD : public Unit { float m_lagu, m_lagd; double m_b1u, m_b1d, m_y1a, m_y1b, m_y1c; }; struct VarLag : public Unit { double m_level, m_slope; int m_counter; float m_in, m_lagTime; }; struct OnePole : public Unit { double m_b1, m_y1; }; struct OneZero : public Unit { double m_b1, m_x1; }; struct Integrator : public Unit { double m_b1, m_y1; }; struct Decay : public Unit { float m_decayTime; double m_y1, m_b1; }; struct Decay2 : public Unit { float m_attackTime; double m_y1a, m_b1a; float m_decayTime; double m_y1b, m_b1b; }; struct LeakDC : public Unit { double m_b1, m_x1, m_y1; }; struct TwoPole : public Unit { float m_freq, m_reson; double m_y1, m_y2, m_b1, m_b2; }; struct APF : public Unit { float m_freq, m_reson; double m_y1, m_y2, m_x1, m_x2, m_b1, m_b2; }; struct TwoZero : public Unit { float m_freq, m_reson; double m_x1, m_x2, m_b1, m_b2; }; struct LPZ1 : public Unit { double m_x1; }; struct HPZ1 : public Unit { double m_x1; }; struct HPZ2 : public Unit { double m_x1, m_x2; }; struct BPZ2 : public Unit { double m_x1, m_x2; }; struct BRZ2 : public Unit { double m_x1, m_x2; }; struct LPZ2 : public Unit { double m_x1, m_x2; }; struct Flip : public Unit { }; struct Delay1 : public Unit { float m_x1; }; struct Delay2 : public Unit { float m_x1, m_x2; }; struct Slope : public Unit { double m_x1; }; struct Slew : public Unit { double mLevel; }; struct RLPF : public Unit { float m_freq, m_reson; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct RHPF : public Unit { float m_freq, m_reson; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct LPF : public Unit { float m_freq; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct HPF : public Unit { float m_freq; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct BPF : public Unit { float m_freq, m_bw; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct BRF : public Unit { float m_freq, m_bw; double m_y1, m_y2, m_a0, m_a1, m_b2; }; struct MidEQ : public Unit { float m_freq, m_bw, m_db; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct Resonz : public Unit { float m_freq, m_rq; double m_y1, m_y2, m_a0, m_b1, m_b2; }; struct Ringz : public Unit { float m_freq, m_decayTime; double m_y1, m_y2, m_b1, m_b2; }; struct FOS : public Unit { double m_y1, m_a0, m_a1, m_b1; }; struct SOS : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; }; struct Formlet : public Unit { float m_freq, m_decayTime, m_attackTime; double m_y01, m_y02, m_b01, m_b02; double m_y11, m_y12, m_b11, m_b12; }; const int kMAXMEDIANSIZE = 32; struct Median : public Unit { float m_medianValue[kMAXMEDIANSIZE]; long m_medianAge[kMAXMEDIANSIZE]; long m_medianSize, m_medianIndex; }; struct Compander : public Unit { float m_prevmaxval, m_gain, m_clamp, m_clampcoef, m_relax, m_relaxcoef; }; struct Normalizer : public Unit { float *m_table, *m_xinbuf, *m_xoutbuf, *m_xmidbuf; long m_flips, m_pos, m_bufsize; float m_slope, m_level, m_curmaxval, m_prevmaxval, m_slopefactor; }; struct Limiter : public Unit { float *m_table, *m_xinbuf, *m_xoutbuf, *m_xmidbuf; long m_flips, m_pos, m_bufsize; float m_slope, m_level, m_curmaxval, m_prevmaxval, m_slopefactor; }; struct Amplitude : public Unit { float m_previn, m_clampcoef, m_relaxcoef, m_clamp_in, m_relax_in; }; struct DetectSilence : public Unit { float mThresh; int32 mCounter, mEndCounter, mDoneAction; }; struct Hilbert : public Unit { double m_coefs[12]; double m_y1[12]; }; struct FreqShift : public Unit { float m_coefs[12]; float m_y1[12]; int32 m_phase; int32 m_phaseoffset, m_lomask; double m_cpstoinc, m_radtoinc, m_phasein; }; struct MoogFF : public Unit { float m_freq, m_k; double m_b0, m_a1; // Resonant freq and corresponding vals; stored because we need to compare against prev vals double m_s1, m_s2, m_s3, m_s4; // 1st order filter states }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void Ramp_next(Ramp *unit, int inNumSamples); void Ramp_next_1(Ramp *unit, int inNumSamples); void Ramp_Ctor(Ramp* unit); void Lag_next(Lag *unit, int inNumSamples); void Lag_Ctor(Lag* unit); void Lag2_Ctor(Lag2* unit); void Lag3_next(Lag3 *unit, int inNumSamples); void Lag3_Ctor(Lag3* unit); void LagUD_next(LagUD *unit, int inNumSamples); void LagUD_Ctor(LagUD* unit); void Lag2UD_next(Lag2UD *unit, int inNumSamples); void Lag2UD_Ctor(Lag2UD* unit); void Lag3UD_next(Lag3UD *unit, int inNumSamples); void Lag3UD_Ctor(Lag3UD* unit); void VarLag_next(VarLag *unit, int inNumSamples); void VarLag_Ctor(VarLag* unit); void OnePole_next_a(OnePole *unit, int inNumSamples); void OnePole_next_k(OnePole *unit, int inNumSamples); void OnePole_Ctor(OnePole* unit); void OneZero_next(OneZero* unit, int inNumSamples); void OneZero_Ctor(OneZero* unit); void Integrator_next(Integrator *unit, int inNumSamples); void Integrator_next_i(Integrator *unit, int inNumSamples); void Integrator_Ctor(Integrator* unit); void Decay_next(Decay *unit, int inNumSamples); void Decay_Ctor(Decay* unit); void Decay2_next(Decay2 *unit, int inNumSamples); void Decay2_Ctor(Decay2* unit); void LeakDC_next(LeakDC *unit, int inNumSamples); void LeakDC_next_1(LeakDC* unit, int inNumSamples); void LeakDC_Ctor(LeakDC* unit); void TwoPole_next(TwoPole *unit, int inNumSamples); void TwoPole_Ctor(TwoPole* unit); void TwoZero_next(TwoZero *unit, int inNumSamples); void TwoZero_Ctor(TwoZero* unit); void APF_next(APF *unit, int inNumSamples); void APF_Ctor(APF* unit); void LPZ1_next(LPZ1 *unit, int inNumSamples); void LPZ1_Ctor(LPZ1* unit); void HPZ1_next(HPZ1 *unit, int inNumSamples); void HPZ1_Ctor(HPZ1* unit); void Slope_next(Slope *unit, int inNumSamples); void Slope_Ctor(Slope* unit); void Delay1_next(Delay1 *unit, int inNumSamples); void Delay1_Ctor(Delay1* unit); void Flip_Ctor(Flip* unit); void Flip_next_even(Flip *unit, int inNumSamples); void Flip_next_odd(Flip *unit, int inNumSamples); void Delay2_next(Delay2 *unit, int inNumSamples); void Delay2_Ctor(Delay2* unit); void LPZ2_next(LPZ2 *unit, int inNumSamples); void LPZ2_Ctor(LPZ2* unit); void HPZ2_next(HPZ2 *unit, int inNumSamples); void HPZ2_Ctor(HPZ2* unit); void BPZ2_next(BPZ2 *unit, int inNumSamples); void BPZ2_Ctor(BPZ2* unit); void BRZ2_next(BRZ2 *unit, int inNumSamples); void BRZ2_Ctor(BRZ2* unit); void Slew_next(Slew *unit, int inNumSamples); void Slew_Ctor(Slew* unit); void RLPF_next(RLPF *unit, int inNumSamples); void RLPF_next_1(RLPF *unit, int inNumSamples); void RLPF_Ctor(RLPF* unit); void RHPF_next(RHPF *unit, int inNumSamples); void RHPF_next_1(RHPF *unit, int inNumSamples); void RHPF_Ctor(RHPF* unit); void LPF_next(LPF *unit, int inNumSamples); void LPF_next_1(LPF *unit, int inNumSamples); void LPF_Ctor(LPF* unit); void HPF_next(HPF *unit, int inNumSamples); void HPF_next_1(HPF *unit, int inNumSamples); void HPF_Ctor(HPF* unit); void BPF_next(BPF *unit, int inNumSamples); void BPF_next_1(BPF *unit, int inNumSamples); void BPF_Ctor(BPF* unit); void BRF_next(BRF *unit, int inNumSamples); void BRF_next_1(BRF *unit, int inNumSamples); void BRF_Ctor(BRF* unit); void Median_next(Median *unit, int inNumSamples); void Median_Ctor(Median* unit); void MidEQ_next(MidEQ *unit, int inNumSamples); void MidEQ_Ctor(MidEQ* unit); void Resonz_next(Resonz *unit, int inNumSamples); void Resonz_Ctor(Resonz* unit); void Ringz_next(Ringz *unit, int inNumSamples); void Ringz_Ctor(Ringz* unit); void Formlet_next(Formlet *unit, int inNumSamples); void Formlet_next_1(Formlet *unit, int inNumSamples); void Formlet_Ctor(Formlet* unit); void FOS_next_k(FOS *unit, int inNumSamples); void FOS_next_a(FOS *unit, int inNumSamples); void FOS_next_1(FOS *unit, int inNumSamples); void FOS_Ctor(FOS* unit); void SOS_next_i(SOS *unit, int inNumSamples); void SOS_next_k(SOS *unit, int inNumSamples); void SOS_next_a(SOS *unit, int inNumSamples); void SOS_next_1(SOS *unit, int inNumSamples); void SOS_Ctor(SOS* unit); void Normalizer_next(Normalizer *unit, int inNumSamples); void Normalizer_Ctor(Normalizer* unit); void Normalizer_Dtor(Normalizer* unit); void Limiter_next(Limiter *unit, int inNumSamples); void Limiter_Ctor(Limiter* unit); void Limiter_Dtor(Limiter* unit); void Compander_next(Compander *unit, int inNumSamples); void Compander_Ctor(Compander* unit); void Amplitude_next(Amplitude *unit, int inNumSamples); void Amplitude_next_kk(Amplitude *unit, int inNumSamples); void Amplitude_next_atok(Amplitude *unit, int inNumSamples); void Amplitude_next_atok_kk(Amplitude *unit, int inNumSamples); void Amplitude_Ctor(Amplitude* unit); void DetectSilence_next(DetectSilence *unit, int inNumSamples); void DetectSilence_next_k(DetectSilence *unit, int inNumSamples); //void DetectSilence_done(DetectSilence *unit, int inNumSamples); void DetectSilence_Ctor(DetectSilence* unit); void Hilbert_Ctor(Hilbert* unit); void Hilbert_next(Hilbert *unit, int inNumSamples); void FreqShift_Ctor(FreqShift* unit); void FreqShift_next_kk(FreqShift *unit, int inNumSamples); void FreqShift_next_aa(FreqShift *unit, int inNumSamples); void FreqShift_next_ak(FreqShift *unit, int inNumSamples); void FreqShift_next_ka(FreqShift *unit, int inNumSamples); void MoogFF_next(MoogFF *unit, int inNumSamples); void MoogFF_Ctor(MoogFF* unit); /* void Lag_next(Lag *unit, int inNumSamples); void Lag_Ctor(Lag* unit); void Lag_next(Lag *unit, int inNumSamples); void Lag_Ctor(Lag* unit); */ } ////////////////////////////////////////////////////////////////////////////////////////////////// void Ramp_next(Ramp *unit, int inNumSamples) { float *out = ZOUT(0); float *in = IN(0); float period = ZIN0(1); double slope = unit->m_slope; double level = unit->m_level; int counter = unit->m_counter; int remain = inNumSamples; while (remain) { int nsmps = sc_min(remain, counter); LOOP(nsmps, ZXP(out) = level; level += slope; ); in += nsmps; counter -= nsmps; remain -= nsmps; if (counter <= 0) { counter = (int)(period * SAMPLERATE); counter = sc_max(1, counter); slope = (*in - level) / counter; } } unit->m_level = level; unit->m_slope = slope; unit->m_counter = counter; } void Ramp_next_1(Ramp *unit, int inNumSamples) { float *out = OUT(0); *out = unit->m_level; unit->m_level += unit->m_slope; if (--unit->m_counter <= 0) { float in = ZIN0(0); float period = ZIN0(1); int counter = (int)(period * SAMPLERATE); unit->m_counter = counter = sc_max(1, counter); unit->m_slope = (in - unit->m_level) / counter; } } void Ramp_Ctor(Ramp* unit) { if (BUFLENGTH == 1) { SETCALC(Ramp_next_1); } else { SETCALC(Ramp_next); } unit->m_counter = 1; unit->m_level = ZIN0(0); unit->m_slope = 0.f; ZOUT0(0) = unit->m_level; } ////////////////////////////////////////////////////////////////////////////////////////////////// void Lag_next(Lag *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lag = ZIN0(1); double y1 = unit->m_y1; double b1 = unit->m_b1; if (lag == unit->m_lag) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * (y1 - y0); ); } else { unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate)); double b1_slope = CALCSLOPE(unit->m_b1, b1); unit->m_lag = lag; LOOP1(inNumSamples, b1 += b1_slope; double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * (y1 - y0); ); } unit->m_y1 = zapgremlins(y1); } void Lag_next_1(Lag *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float lag = IN0(1); double y1 = unit->m_y1; double b1 = unit->m_b1; if (lag == unit->m_lag) { double y0 = *in; *out = y1 = y0 + b1 * (y1 - y0); } else { unit->m_b1 = b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; double y0 = *in; *out = y1 = y0 + b1 * (y1 - y0); } unit->m_y1 = zapgremlins(y1); } void Lag_Ctor(Lag* unit) { if (BUFLENGTH == 1) SETCALC(Lag_next_1); else SETCALC(Lag_next); unit->m_lag = uninitializedControl; unit->m_b1 = 0.f; unit->m_y1 = ZIN0(0); Lag_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LagUD_next(LagUD *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lagu = ZIN0(1); float lagd = ZIN0(2); double y1 = unit->m_y1; double b1u = unit->m_b1u; double b1d = unit->m_b1d; if ( (lagu == unit->m_lagu) && (lagd == unit->m_lagd) ) { LOOP1(inNumSamples, double y0 = ZXP(in); if ( y0 > y1 ) ZXP(out) = y1 = y0 + b1u * (y1 - y0); else ZXP(out) = y1 = y0 + b1d * (y1 - y0); ); } else { unit->m_b1u = lagu == 0.f ? 0.f : exp(log001 / (lagu * unit->mRate->mSampleRate)); double b1u_slope = CALCSLOPE(unit->m_b1u, b1u); unit->m_lagu = lagu; unit->m_b1d = lagd == 0.f ? 0.f : exp(log001 / (lagd * unit->mRate->mSampleRate)); double b1d_slope = CALCSLOPE(unit->m_b1d, b1d); unit->m_lagd = lagd; LOOP1(inNumSamples, b1u += b1u_slope; b1d += b1d_slope; double y0 = ZXP(in); if ( y0 > y1 ) ZXP(out) = y1 = y0 + b1u * (y1 - y0); else ZXP(out) = y1 = y0 + b1d * (y1 - y0); ); } unit->m_y1 = zapgremlins(y1); } void LagUD_Ctor(LagUD* unit) { SETCALC(LagUD_next); unit->m_lagu = uninitializedControl; unit->m_lagd = uninitializedControl; unit->m_b1u = 0.f; unit->m_b1d = 0.f; unit->m_y1 = ZIN0(0); LagUD_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// static void Lag2_next_k(Lag2 *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lag = ZIN0(1); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double b1 = unit->m_b1; if (lag == unit->m_lag) { LOOP1(inNumSamples, double y0a = ZXP(in); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); ZXP(out) = y1b; ); } else { unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate)); double b1_slope = CALCSLOPE(unit->m_b1, b1); unit->m_lag = lag; LOOP1(inNumSamples, b1 += b1_slope; double y0a = ZXP(in); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); ZXP(out) = y1b; ); } unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); } static void Lag2_next_i(Lag2 *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double b1 = unit->m_b1; LOOP1(inNumSamples, double y0a = ZXP(in); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); ZXP(out) = y1b; ); unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); } static void Lag2_next_1_i(Lag2 *unit, int inNumSamples) { double y1a = unit->m_y1a; double y1b = unit->m_y1b; double b1 = unit->m_b1; float y0a = ZIN0(0); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); ZOUT0(0) = y1b; unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); } void Lag2_Ctor(Lag2* unit) { switch (INRATE(1)) { case calc_FullRate: case calc_BufRate: SETCALC(Lag2_next_k); break; default: if (BUFLENGTH == 1) SETCALC(Lag2_next_1_i); else SETCALC(Lag2_next_i); break; } unit->m_lag = uninitializedControl; unit->m_b1 = 0.f; unit->m_y1a = unit->m_y1b = ZIN0(0); Lag2_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Lag2UD_next(Lag2UD *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lagu = ZIN0(1); float lagd = ZIN0(2); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double b1u = unit->m_b1u; double b1d = unit->m_b1d; if ( (lagu == unit->m_lagu) && (lagd == unit->m_lagd) ) { LOOP1(inNumSamples, double y0a = ZXP(in); if ( y0a > y1a ) { y1a = y0a + b1u * (y1a - y0a); } else { y1a = y0a + b1d * (y1a - y0a); } if ( y1a > y1b ) y1b = y1a + b1u * (y1b - y1a); else y1b = y1a + b1d * (y1b - y1a); ZXP(out) = y1b; ); } else { unit->m_b1u = lagu == 0.f ? 0.f : exp(log001 / (lagu * unit->mRate->mSampleRate)); double b1u_slope = CALCSLOPE(unit->m_b1u, b1u); unit->m_lagu = lagu; unit->m_b1d = lagd == 0.f ? 0.f : exp(log001 / (lagd * unit->mRate->mSampleRate)); double b1d_slope = CALCSLOPE(unit->m_b1d, b1d); unit->m_lagd = lagd; LOOP1(inNumSamples, b1u += b1u_slope; b1d += b1d_slope; double y0a = ZXP(in); if ( y0a > y1a ) { y1a = y0a + b1u * (y1a - y0a); } else { y1a = y0a + b1d * (y1a - y0a); } if ( y1a > y1b ) y1b = y1a + b1u * (y1b - y1a); else y1b = y1a + b1d * (y1b - y1a); ZXP(out) = y1b; ); } unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); } void Lag2UD_Ctor(Lag2UD* unit) { SETCALC(Lag2UD_next); unit->m_lagu = 0.f; unit->m_lagd = 0.f; unit->m_b1u = 0.f; unit->m_b1d = 0.f; unit->m_y1a = unit->m_y1b = ZIN0(0); Lag2UD_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Lag3_next(Lag3 *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lag = ZIN0(1); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double y1c = unit->m_y1c; double b1 = unit->m_b1; if (lag == unit->m_lag) { LOOP1(inNumSamples, double y0a = ZXP(in); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); y1c = y1b + b1 * (y1c - y1b); ZXP(out) = y1c; ); } else { unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate)); double b1_slope = CALCSLOPE(unit->m_b1, b1); unit->m_lag = lag; LOOP1(inNumSamples, b1 += b1_slope; double y0a = ZXP(in); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); y1c = y1b + b1 * (y1c - y1b); ZXP(out) = y1c; ); } unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); unit->m_y1c = zapgremlins(y1c); } static void Lag3_next_1_i(Lag3 *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double y1c = unit->m_y1c; double b1 = unit->m_b1; double y0a = ZXP(in); y1a = y0a + b1 * (y1a - y0a); y1b = y1a + b1 * (y1b - y1a); y1c = y1b + b1 * (y1c - y1b); ZXP(out) = y1c; unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); unit->m_y1c = zapgremlins(y1c); } void Lag3_Ctor(Lag3* unit) { switch (INRATE(1)) { case calc_FullRate: case calc_BufRate: SETCALC(Lag3_next); break; default: if (BUFLENGTH == 1) SETCALC(Lag3_next_1_i); else SETCALC(Lag3_next); break; } unit->m_lag = uninitializedControl; unit->m_b1 = 0.f; unit->m_y1a = unit->m_y1b = unit->m_y1c = ZIN0(0); Lag3_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Lag3UD_next(Lag3UD *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lagu = ZIN0(1); float lagd = ZIN0(2); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double y1c = unit->m_y1c; double b1u = unit->m_b1u; double b1d = unit->m_b1d; if ( (lagu == unit->m_lagu) && (lagd == unit->m_lagd) ) { LOOP1(inNumSamples, double y0a = ZXP(in); if ( y0a > y1a ) { y1a = y0a + b1u * (y1a - y0a); } else { y1a = y0a + b1d * (y1a - y0a); } if ( y1a > y1b ) { y1b = y1a + b1u * (y1b - y1a); } else { y1b = y1a + b1d * (y1b - y1a); } if ( y1a > y1b ) { y1c = y1b + b1u * (y1c - y1b); } else { y1c = y1b + b1d * (y1c - y1b); } ZXP(out) = y1c; ); } else { unit->m_b1u = lagu == 0.f ? 0.f : exp(log001 / (lagu * unit->mRate->mSampleRate)); double b1u_slope = CALCSLOPE(unit->m_b1u, b1u); unit->m_lagu = lagu; unit->m_b1d = lagd == 0.f ? 0.f : exp(log001 / (lagd * unit->mRate->mSampleRate)); double b1d_slope = CALCSLOPE(unit->m_b1d, b1d); unit->m_lagd = lagd; LOOP1(inNumSamples, b1u += b1u_slope; b1d += b1d_slope; double y0a = ZXP(in); if ( y0a > y1a ) { y1a = y0a + b1u * (y1a - y0a); } else { y1a = y0a + b1d * (y1a - y0a); } if ( y1a > y1b ) { y1b = y1a + b1u * (y1b - y1a); } else { y1b = y1a + b1d * (y1b - y1a); } if ( y1a > y1b ) { y1c = y1b + b1u * (y1c - y1b); } else { y1c = y1b + b1d * (y1c - y1b); } ZXP(out) = y1c; ); } unit->m_y1a = zapgremlins(y1a); unit->m_y1b = zapgremlins(y1b); unit->m_y1c = zapgremlins(y1c); } void Lag3UD_Ctor(Lag3UD* unit) { SETCALC(Lag3UD_next); unit->m_lagu = uninitializedControl; unit->m_lagd = uninitializedControl; unit->m_b1u = 0.f; unit->m_b1d = 0.f; unit->m_y1a = unit->m_y1b = unit->m_y1c = ZIN0(0); Lag3UD_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void VarLag_next(VarLag *unit, int inNumSamples) { float *out = ZOUT(0); float *in = IN(0); float lagTime = ZIN0(1); double slope = unit->m_slope; double level = unit->m_level; int counter = unit->m_counter; int remain = inNumSamples; if ( *in != unit->m_in) { counter = (int)(lagTime * SAMPLERATE); counter = unit->m_counter = sc_max(1, counter); slope = unit->m_slope = ( *in - unit->m_level) / counter; unit->m_in = *in; unit->m_lagTime = lagTime; } else { if (lagTime != unit->m_lagTime) { float scaleFactor = lagTime/unit->m_lagTime; counter = (int) (unit->m_counter * scaleFactor); counter = unit->m_counter = sc_max(1, counter); slope = unit->m_slope / scaleFactor; unit->m_lagTime = lagTime; } } if(counter >0) { LOOP(remain, ZXP(out) = level; if( counter > 0) { level += slope; --counter; } else { level = unit->m_in; }; ) } else { LOOP(remain, ZXP(out) = level ); } unit->m_level = level; unit->m_slope = slope; unit->m_counter = counter; } void VarLag_next_1(VarLag *unit, int inNumSamples) { float *out = OUT(0); float in = *IN(0); float lagTime = ZIN0(1); int counter = unit->m_counter; if ( in != unit->m_in) { counter = (int)(lagTime * SAMPLERATE); unit->m_counter = counter = sc_max(1, counter); unit->m_slope = ( in - unit->m_level) / counter; unit->m_in = in; unit->m_lagTime = lagTime; } { if (lagTime != unit->m_lagTime) { if (counter != 0) { double scaleFactor = lagTime/unit->m_lagTime; counter = (int) (unit->m_counter * scaleFactor); unit->m_counter = counter = sc_max(1, counter); unit->m_slope = unit->m_slope / scaleFactor; } unit->m_lagTime = lagTime; } } *out = unit->m_level; if (unit->m_counter > 0) { unit->m_level += unit->m_slope; --unit->m_counter; } else { unit->m_level = unit->m_in; } } void VarLag_Ctor(VarLag* unit) { if (BUFLENGTH == 1) { SETCALC(VarLag_next_1); } else { SETCALC(VarLag_next); } float in = *IN(0); float lagTime = ZIN0(1); unit->m_level = ZIN0(2); int counter = (int)(lagTime * SAMPLERATE); unit->m_counter = counter = sc_max(1, counter); unit->m_slope = ( in - unit->m_level) / counter; unit->m_in = in; unit->m_lagTime = lagTime; ZOUT0(0) = unit->m_level; } ////////////////////////////////////////////////////////////////////////////////////////////////// void OnePole_next_a(OnePole *unit, int inNumSamples) { //printf("OnePole_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); float *b1p = ZIN(1); double y1 = unit->m_y1; LOOP1(inNumSamples, double y0 = ZXP(in); double b1 = ZXP(b1p); ZXP(out) = y1 = y0 + b1 * (y1 - y0); ); unit->m_y1 = zapgremlins(y1); } void OnePole_next_k(OnePole *unit, int inNumSamples) { //printf("OnePole_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); double b1 = unit->m_b1; unit->m_b1 = ZIN0(1); double y1 = unit->m_y1; if (b1 == unit->m_b1) { if (b1 >= 0.f) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * (y1 - y0); ); } else { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * (y1 + y0); ); } } else { double b1_slope = CALCSLOPE(unit->m_b1, b1); if (b1 >= 0.f && unit->m_b1 >= 0) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * (y1 - y0); b1 += b1_slope; ); } else if (b1 <= 0.f && unit->m_b1 <= 0) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * (y1 + y0); b1 += b1_slope; ); } else { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = (1.f - std::abs(b1)) * y0 + b1 * y1; b1 += b1_slope; ); } } unit->m_y1 = zapgremlins(y1); } void OnePole_Ctor(OnePole* unit) { if (INRATE(1) == calc_FullRate) { SETCALC(OnePole_next_a); } else { SETCALC(OnePole_next_k); } unit->m_b1 = ZIN0(1); unit->m_y1 = 0.f; OnePole_next_a(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void OneZero_Ctor(OneZero* unit) { SETCALC(OneZero_next); unit->m_b1 = ZIN0(1); unit->m_x1 = ZIN0(0); OneZero_next(unit, 1); } void OneZero_next(OneZero* unit, int inNumSamples) { //printf("OneZero::next\n"); float *out = ZOUT(0); float *in = ZIN(0); double b1 = unit->m_b1; unit->m_b1 = ZIN0(1); double x1 = unit->m_x1; if (b1 == unit->m_b1) { if (b1 >= 0.f) { LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = x0 + b1 * (x1 - x0); x1 = x0; ); } else { LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = x0 + b1 * (x1 + x0); x1 = x0; ); } } else { double b1_slope = CALCSLOPE(unit->m_b1, b1); if (b1 >= 0.f && unit->m_b1 >= 0) { LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = x0 + b1 * (x1 - x0); x1 = x0; b1 += b1_slope; ); } else if (b1 <= 0.f && unit->m_b1 <= 0) { LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = x0 + b1 * (x1 + x0); x1 = x0; b1 += b1_slope; ); } else { LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = (1.f - std::abs(b1)) * x0 + b1 * x1; x1 = x0; b1 += b1_slope; ); } } unit->m_x1 = x1; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Integrator_Ctor(Integrator* unit) { if (INRATE(1) == calc_ScalarRate) SETCALC(Integrator_next_i); else SETCALC(Integrator_next); unit->m_b1 = ZIN0(1); unit->m_y1 = 0.f; Integrator_next(unit, 1); } void Integrator_next_i(Integrator* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double b1 = unit->m_b1; double y1 = unit->m_y1; if (b1 == 1.f) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + y1; ); } else if (b1 == 0.f) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0; ); } else { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * y1; ); } unit->m_y1 = zapgremlins(y1); } void Integrator_next(Integrator* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double newB1 = ZIN0(1); double b1 = unit->m_b1; double y1 = unit->m_y1; if (b1 == newB1) { if (b1 == 1.f) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + y1; ); } else if (b1 == 0.f) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0; ); } else { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * y1; ); } } else { double b1_slope = CALCSLOPE(newB1, b1); LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * y1; b1 += b1_slope; ); unit->m_b1 = newB1; } unit->m_y1 = zapgremlins(y1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Decay_Ctor(Decay* unit) { SETCALC(Decay_next); unit->m_decayTime = uninitializedControl; unit->m_b1 = 0.f; unit->m_y1 = 0.f; Decay_next(unit, 1); } void Decay_next(Decay* unit, int inNumSamples) { //printf("Decay_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); float decayTime = ZIN0(1); double y1 = unit->m_y1; double b1 = unit->m_b1; if (decayTime == unit->m_decayTime) { if (b1 == 0.f) { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0; ); } else { LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * y1; ); } } else { unit->m_b1 = decayTime == 0.f ? 0.f : exp(log001 / (decayTime * SAMPLERATE)); unit->m_decayTime = decayTime; double b1_slope = CALCSLOPE(unit->m_b1, b1); //printf("decayTime %g %g %g\n", unit->m_decayTime, next_b1, b1); LOOP1(inNumSamples, double y0 = ZXP(in); ZXP(out) = y1 = y0 + b1 * y1; b1 += b1_slope; ); } unit->m_y1 = zapgremlins(y1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Decay2_Ctor(Decay2 *unit) { SETCALC(Decay2_next); float attackTime = ZIN0(1); float decayTime = ZIN0(2); unit->m_b1a = decayTime == 0.f ? 0.f : exp(log001 / (decayTime * SAMPLERATE)); unit->m_b1b = attackTime == 0.f ? 0.f : exp(log001 / (attackTime * SAMPLERATE)); unit->m_decayTime = decayTime; unit->m_attackTime = attackTime; float y0 = ZIN0(0); unit->m_y1a = y0; unit->m_y1b = y0; ZOUT0(0) = 0.f; } void Decay2_next(Decay2* unit, int inNumSamples) { //printf("Decay2_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); float attackTime = ZIN0(1); float decayTime = ZIN0(2); double y1a = unit->m_y1a; double y1b = unit->m_y1b; double b1a = unit->m_b1a; double b1b = unit->m_b1b; if (decayTime == unit->m_decayTime && attackTime == unit->m_attackTime) { LOOP1(inNumSamples, double y0 = ZXP(in); y1a = y0 + b1a * y1a; y1b = y0 + b1b * y1b; ZXP(out) = y1a - y1b; ); } else { unit->m_decayTime = decayTime; unit->m_attackTime = attackTime; double next_b1a = decayTime == 0.f ? 0.f : exp(log001 / (decayTime * SAMPLERATE)); double next_b1b = attackTime == 0.f ? 0.f : exp(log001 / (attackTime * SAMPLERATE)); unit->m_decayTime = decayTime; double b1a_slope = CALCSLOPE(next_b1a, b1a); double b1b_slope = CALCSLOPE(next_b1b, b1b); unit->m_b1a = next_b1a; unit->m_b1b = next_b1b; LOOP1(inNumSamples, double y0 = ZXP(in); y1a = y0 + b1a * y1a; y1b = y0 + b1b * y1b; ZXP(out) = y1a - y1b; b1a += b1a_slope; b1b += b1b_slope; ); } unit->m_y1a = y1a; unit->m_y1b = y1b; unit->m_b1a = b1a; unit->m_b1b = b1b; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LeakDC_next_i_4(LeakDC* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double b1 = unit->m_b1; double y1 = unit->m_y1; double x1 = unit->m_x1; LOOP1(inNumSamples/4, double x00 = ZXP(in); double x01 = ZXP(in); double x02 = ZXP(in); double x03 = ZXP(in); float out0 = y1 = x00 - x1 + b1 * y1; float out1 = y1 = x01 - x00 + b1 * y1; float out2 = y1 = x02 - x01 + b1 * y1; float out3 = y1 = x03 - x02 + b1 * y1; ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ZXP(out) = out3; x1 = x03; ); unit->m_x1 = x1; unit->m_y1 = zapgremlins(y1); } void LeakDC_next_i(LeakDC* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double b1 = unit->m_b1; double y1 = unit->m_y1; double x1 = unit->m_x1; LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = y1 = x0 - x1 + b1 * y1; x1 = x0; ); unit->m_x1 = x1; unit->m_y1 = zapgremlins(y1); } void LeakDC_next(LeakDC* unit, int inNumSamples) { if (ZIN0(1) == unit->m_b1) { if ((inNumSamples & 3) == 0) LeakDC_next_i_4(unit, inNumSamples); else LeakDC_next_i(unit, inNumSamples); } else { float *out = ZOUT(0); float *in = ZIN(0); double b1 = unit->m_b1; unit->m_b1 = ZIN0(1); double y1 = unit->m_y1; double x1 = unit->m_x1; double b1_slope = CALCSLOPE(unit->m_b1, b1); LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = y1 = x0 - x1 + b1 * y1; x1 = x0; b1 += b1_slope; ); unit->m_x1 = x1; unit->m_y1 = zapgremlins(y1); } } void LeakDC_next_1(LeakDC* unit, int inNumSamples) { double b1 = unit->m_b1 = ZIN0(1); double y1 = unit->m_y1; double x1 = unit->m_x1; double x0 = ZIN0(0); ZOUT0(0) = y1 = x0 - x1 + b1 * y1; x1 = x0; unit->m_x1 = x1; unit->m_y1 = zapgremlins(y1); } void LeakDC_Ctor(LeakDC *unit) { //printf("LeakDC_Ctor\n"); if (BUFLENGTH == 1) SETCALC(LeakDC_next_1); else { if (INRATE(1) == calc_ScalarRate) { if ((BUFLENGTH & 3) == 0) SETCALC(LeakDC_next_i_4); else SETCALC(LeakDC_next_i); } else SETCALC(LeakDC_next); } unit->m_b1 = 0.0; unit->m_x1 = ZIN0(0); unit->m_y1 = 0.0; LeakDC_next_1(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void TwoPole_Ctor(TwoPole *unit) { //printf("TwoPole_Reset\n"); SETCALC(TwoPole_next); unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_reson = uninitializedControl; PUSH_LOOPVALS TwoPole_next(unit, 1); POP_LOOPVALS } void TwoPole_next(TwoPole* unit, int inNumSamples) { //printf("TwoPole_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float reson = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; if (freq != unit->m_freq || reson != unit->m_reson) { double b1 = unit->m_b1; double b2 = unit->m_b2; double b1_next = 2 * reson * cos(freq * unit->mRate->mRadiansPerSample); double b2_next = -(reson * reson); double b1_slope = (b1_next - b1) * unit->mRate->mFilterSlope; double b2_slope = (b2_next - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, ZXP(out) = y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = y1 = ZXP(in) + b1 * y2 + b2 * y0; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, ZXP(out) = y0 = ZXP(in) + b1 * y1 + b2 * y2; y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_reson = reson; unit->m_b1 = b1_next; unit->m_b2 = b2_next; } else { double b1 = unit->m_b1; double b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, ZXP(out) = y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = y1 = ZXP(in) + b1 * y2 + b2 * y0; ); LOOP(unit->mRate->mFilterRemain, ZXP(out) = y0 = ZXP(in) + b1 * y1 + b2 * y2; y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void TwoZero_Ctor(TwoZero* unit) { //printf("TwoZero_Reset\n"); SETCALC(TwoZero_next); unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_x1 = 0.f; unit->m_x2 = 0.f; unit->m_freq = uninitializedControl; unit->m_reson = uninitializedControl; PUSH_LOOPVALS TwoZero_next(unit, 1); POP_LOOPVALS } void TwoZero_next(TwoZero* unit, int inNumSamples) { //printf("TwoZero_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float reson = ZIN0(2); double x0; double x1 = unit->m_x1; double x2 = unit->m_x2; if (freq != unit->m_freq || reson != unit->m_reson) { double b1 = unit->m_b1; double b2 = unit->m_b2; double b1_next = -2 * reson * cos(freq * unit->mRate->mRadiansPerSample); double b2_next = (reson * reson); double b1_slope = (b1_next - b1) * unit->mRate->mFilterSlope; double b2_slope = (b2_next - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); ZXP(out) = x0 + b1 * x1 + b2 * x2; x2 = ZXP(in); ZXP(out) = x2 + b1 * x0 + b2 * x1; x1 = ZXP(in); ZXP(out) = x1 + b1 * x2 + b2 * x0; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = x0 + b1 * x1 + b2 * x2; x2 = x1; x1 = x0; ); unit->m_freq = freq; unit->m_reson = reson; unit->m_b1 = b1_next; unit->m_b2 = b2_next; } else { double b1 = unit->m_b1; double b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); ZXP(out) = x0 + b1 * x1 + b2 * x2; x2 = ZXP(in); ZXP(out) = x2 + b1 * x0 + b2 * x1; x1 = ZXP(in); ZXP(out) = x1 + b1 * x2 + b2 * x0; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = x0 + b1 * x1 + b2 * x2; x2 = x1; x1 = x0; ); } unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void APF_Ctor(APF* unit) { //printf("APF_Reset\n"); SETCALC(APF_next); unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_x1 = 0.f; unit->m_x2 = 0.f; unit->m_freq = uninitializedControl; unit->m_reson = uninitializedControl; PUSH_LOOPVALS APF_next(unit, 1); POP_LOOPVALS } void APF_next(APF* unit, int inNumSamples) { //printf("APF_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float reson = ZIN0(2); double x0, y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double x1 = unit->m_x1; double x2 = unit->m_x2; if (freq != unit->m_freq || reson != unit->m_reson) { double b1 = unit->m_b1; double b2 = unit->m_b2; double b1_next = 2.f * reson * cos(freq * unit->mRate->mRadiansPerSample); double b2_next = -(reson * reson); double b1_slope = (b1_next - b1) * unit->mRate->mFilterSlope; double b2_slope = (b2_next - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); ZXP(out) = y0 = x0 + b1 * (y1 - x1) + b2 * (y2 - x2); x2 = ZXP(in); ZXP(out) = y2 = x2 + b1 * (y0 - x0) + b2 * (y2 - x1); x1 = ZXP(in); ZXP(out) = y1 = x1 + b1 * (y2 - x2) + b2 * (y2 - x0); b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = y0 = x0 + b1 * (y1 - x1) + b2 * (y2 - x2); y2 = y1; y1 = y0; x2 = x1; x1 = x0; ); unit->m_freq = freq; unit->m_reson = reson; unit->m_b1 = b1_next; unit->m_b2 = b2_next; } else { double b1 = unit->m_b1; double b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, float in0 = ZXP(in); float in1 = ZXP(in); float in2 = ZXP(in); x0 = in0; float out0 = y0 = x0 + b1 * (y1 - x1) + b2 * (y2 - x2); x2 = in1; float out1 = y2 = x2 + b1 * (y0 - x0) + b2 * (y2 - x1); x1 = in2; float out2 = y1 = x1 + b1 * (y2 - x2) + b2 * (y2 - x0); ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = y0 = x0 + b1 * (y1 - x1) + b2 * (y2 - x2); y2 = y1; y1 = y0; x2 = x1; x1 = x0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LPZ1_Ctor(LPZ1* unit) { //printf("LPZ1_Reset\n"); SETCALC(LPZ1_next); unit->m_x1 = ZIN0(0); LPZ1_next(unit, 1); } void LPZ1_next(LPZ1* unit, int inNumSamples) { //printf("LPZ1_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; LOOP(inNumSamples >> 2, x0 = ZXP(in); float out0 = 0.5 * (x0 + x1); x1 = ZXP(in); float out1 = 0.5 * (x1 + x0); x0 = ZXP(in); float out2 = 0.5 * (x0 + x1); x1 = ZXP(in); float out3 = 0.5 * (x1 + x0); ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ZXP(out) = out3; ); LOOP(inNumSamples & 3, x0 = ZXP(in); ZXP(out) = 0.5 * (x0 + x1); x1 = x0; ); unit->m_x1 = x1; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void HPZ1_Ctor(HPZ1* unit) { //printf("HPZ1_Reset\n"); SETCALC(HPZ1_next); unit->m_x1 = ZIN0(0); HPZ1_next(unit, 1); } void HPZ1_next(HPZ1* unit, int inNumSamples) { //printf("HPZ1_next\n"); float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; LOOP(inNumSamples >> 2, x0 = ZXP(in); float out0 = 0.5 * (x0 - x1); x1 = ZXP(in); float out1 = 0.5 * (x1 - x0); x0 = ZXP(in); float out2 = 0.5 * (x0 - x1); x1 = ZXP(in); float out3 = 0.5 * (x1 - x0); ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ZXP(out) = out3; ); LOOP(inNumSamples & 3, x0 = ZXP(in); //printf("%d %d %g %g\n", this, inNumSamples, x0, x1); ZXP(out) = 0.5f * (x0 - x1); x1 = x0; ); unit->m_x1 = x1; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Slope_Ctor(Slope* unit) { //printf("Slope_Reset\n"); SETCALC(Slope_next); unit->m_x1 = ZIN0(0); //printf("Slope_Reset %g\n", unit->m_x1); Slope_next(unit, 1); } void Slope_next(Slope* unit, int inNumSamples) { //printf("Slope_next_a %g\n", unit->m_x1); float *out = ZOUT(0); float *in = ZIN(0); double x1 = unit->m_x1; double sr = SAMPLERATE; LOOP1(inNumSamples, double x0 = ZXP(in); ZXP(out) = sr * (x0 - x1); x1 = x0; ); unit->m_x1 = x1; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Delay1_Ctor(Delay1* unit) { //printf("Delay1_Reset\n"); SETCALC(Delay1_next); unit->m_x1 = ZIN0(0); Delay1_next(unit, 1); } void Delay1_next(Delay1* unit, int inNumSamples) { //printf("Delay1_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); float x0; float x1 = unit->m_x1; LOOP(inNumSamples >> 2, x0 = ZXP(in); ZXP(out) = x1; x1 = ZXP(in); ZXP(out) = x0; x0 = ZXP(in); ZXP(out) = x1; x1 = ZXP(in); ZXP(out) = x0; ); LOOP(inNumSamples & 3, x0 = ZXP(in); ZXP(out) = x1; x1 = x0; ); unit->m_x1 = x1; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Flip_Ctor(Flip* unit) { if (unit->mBufLength & 1) { SETCALC(Flip_next_odd); Flip_next_odd(unit, 1); } else { SETCALC(Flip_next_even); ZOUT0(0) = ZIN0(0); } } void Flip_next_even(Flip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); LOOP(inNumSamples >> 1, ZXP(out) = -ZXP(in); ZXP(out) = ZXP(in); ); } void Flip_next_odd(Flip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); if (unit->mWorld->mBufCounter & 1) { ZXP(out) = ZXP(in); LOOP(inNumSamples >> 1, ZXP(out) = -ZXP(in); ZXP(out) = ZXP(in); ); } else { LOOP(inNumSamples >> 1, ZXP(out) = -ZXP(in); ZXP(out) = ZXP(in); ); ZXP(out) = -ZXP(in); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Delay2_Ctor(Delay2* unit) { SETCALC(Delay2_next); unit->m_x1 = ZIN0(0); ZOUT0(0) = 0.f; } void Delay2_next(Delay2* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; double x2 = unit->m_x2; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); ZXP(out) = x2; x2 = ZXP(in); ZXP(out) = x1; x1 = ZXP(in); ZXP(out) = x0; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = x2; x2 = x1; x1 = x0; ); unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LPZ2_Ctor(LPZ2* unit) { //printf("LPZ2_Reset\n"); SETCALC(LPZ2_next); unit->m_x1 = unit->m_x2 = ZIN0(0); PUSH_LOOPVALS LPZ2_next(unit, 1); POP_LOOPVALS } void LPZ2_next(LPZ2* unit, int inNumSamples) { //printf("LPZ2_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; double x2 = unit->m_x2; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); float out0 = (x0 + 2.0 * x1 + x2) * 0.25; x2 = ZXP(in); float out1 = (x2 + 2.0 * x0 + x1) * 0.25; x1 = ZXP(in); float out2 = (x1 + 2.0 * x2 + x0) * 0.25; ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = (x0 + 2. * x1 + x2) * 0.25; x2 = x1; x1 = x0; ); unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void HPZ2_Ctor(HPZ2* unit) { //printf("HPZ2_Reset\n"); SETCALC(HPZ2_next); unit->m_x1 = unit->m_x2 = ZIN0(0); PUSH_LOOPVALS HPZ2_next(unit, 1); POP_LOOPVALS } void HPZ2_next(HPZ2* unit, int inNumSamples) { //printf("HPZ2_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; double x2 = unit->m_x2; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); float out0 = (x0 - 2.0 * x1 + x2) * 0.25; x2 = ZXP(in); float out1 = (x2 - 2.0 * x0 + x1) * 0.25; x1 = ZXP(in); float out2 = (x1 - 2.0 * x2 + x0) * 0.25; ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = (x0 - 2.0 * x1 + x2) * 0.25; x2 = x1; x1 = x0; ); unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BPZ2_Ctor(BPZ2* unit) { //printf("BPZ2_Reset\n"); SETCALC(BPZ2_next); unit->m_x1 = unit->m_x2 = ZIN0(0); PUSH_LOOPVALS BPZ2_next(unit, 1); POP_LOOPVALS } void BPZ2_next(BPZ2* unit, int inNumSamples) { //printf("BPZ2_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; double x2 = unit->m_x2; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); ZXP(out) = (x0 - x2) * 0.5; x2 = ZXP(in); ZXP(out) = (x2 - x1) * 0.5; x1 = ZXP(in); ZXP(out) = (x1 - x0) * 0.5; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = (x0 - x2) * 0.5; x2 = x1; x1 = x0; ); unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BRZ2_Ctor(BRZ2* unit) { //printf("BRZ2_Reset\n"); SETCALC(BRZ2_next); unit->m_x1 = unit->m_x2 = ZIN0(0); PUSH_LOOPVALS BRZ2_next(unit, 1); POP_LOOPVALS } void BRZ2_next(BRZ2* unit, int inNumSamples) { //printf("BRZ2_next_a\n"); float *out = ZOUT(0); float *in = ZIN(0); double x0; double x1 = unit->m_x1; double x2 = unit->m_x2; LOOP(unit->mRate->mFilterLoops, x0 = ZXP(in); ZXP(out) = (x0 + x2) * 0.5; x2 = ZXP(in); ZXP(out) = (x2 + x1) * 0.5; x1 = ZXP(in); ZXP(out) = (x1 + x0) * 0.5; ); LOOP(unit->mRate->mFilterRemain, x0 = ZXP(in); ZXP(out) = (x0 + x2) * 0.5; x2 = x1; x1 = x0; ); unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Slew_Ctor(Slew* unit) { //printf("Slew_Reset\n"); SETCALC(Slew_next); unit->mLevel = ZIN0(0); Slew_next(unit, 1); } void Slew_next(Slew* unit, int inNumSamples) { //printf("Slew_next_a\n"); float sampleDur = unit->mRate->mSampleDur; float *out = ZOUT(0); float *in = ZIN(0); float upf = ZIN0(1) * sampleDur; float dnf = 0.f - ZIN0(2) * sampleDur; double level = unit->mLevel; LOOP1(inNumSamples, double slope = ZXP(in) - level; level += sc_clip(slope, dnf, upf); ZXP(out) = level; ); unit->mLevel = level; } /*void Slew_next_1(Slew* unit, int inNumSamples) { //printf("Slew_next_a\n"); float *out = ZOUT(0); float in = ZIN0(0); float upf = ZIN0(1); float dnf = ZIN0(2); float level = unit->mLevel; float slope = ZXP(in) - level; if (slope > upf) slope = upf; else if (slope < dnf) slope = dnf; level += slope; ZXP(out) = level; unit->mLevel = level; }*/ //////////////////////////////////////////////////////////////////////////////////////////////////////// void RLPF_Ctor(RLPF* unit) { //printf("RLPF_Reset\n"); if (unit->mBufLength == 1) { SETCALC(RLPF_next_1); } else { SETCALC(RLPF_next); } unit->m_a0 = 0.f; unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_reson = uninitializedControl; RLPF_next_1(unit, 1); } void RLPF_next(RLPF* unit, int inNumSamples) { //printf("RLPF_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float reson = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || reson != unit->m_reson) { double qres = sc_max(0.001, reson); double pfreq = freq * unit->mRate->mRadiansPerSample; double D = tan(pfreq * qres * 0.5); double C = ((1.0-D)/(1.0+D)); double cosf = cos(pfreq); double next_b1 = (1.0 + C) * cosf; double next_b2 = -C; double next_a0 = (1.0 + C - next_b1) * .25; //post("%g %g %g %g %g %g %g %g %g %g\n", *freq, pfreq, qres, D, C, cosf, next_b1, next_b2, next_a0, y1, y2); double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 + 2.0 * y1 + y2; y2 = a0 * ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = y2 + 2.0 * y0 + y1; y1 = a0 * ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = y1 + 2.0 * y2 + y0; a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 + 2.0 * y1 + y2; y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_reson = reson; unit->m_a0 = next_a0; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else { LOOP(unit->mRate->mFilterLoops, y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 + 2.0 * y1 + y2; y2 = a0 * ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = y2 + 2.0 * y0 + y1; y1 = a0 * ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = y1 + 2.0 * y2 + y0; ); LOOP(unit->mRate->mFilterRemain, y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 + 2.0 * y1 + y2; y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void RLPF_next_1(RLPF* unit, int inNumSamples) { //printf("RLPF_next_1\n"); float in = ZIN0(0); float freq = ZIN0(1); float reson = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || reson != unit->m_reson) { double qres = sc_max(0.001f, reson); double pfreq = freq * unit->mRate->mRadiansPerSample; double D = tan(pfreq * qres * 0.5f); double C = ((1.f-D)/(1.f+D)); double cosf = cos(pfreq); b1 = (1.0 + C) * cosf; b2 = -C; a0 = (1.0 + C - b1) * .25; y0 = a0 * in + b1 * y1 + b2 * y2; ZOUT0(0) = y0 + 2.0 * y1 + y2; y2 = y1; y1 = y0; unit->m_freq = freq; unit->m_reson = reson; unit->m_a0 = a0; unit->m_b1 = b1; unit->m_b2 = b2; } else { y0 = a0 * in + b1 * y1 + b2 * y2; ZOUT0(0) = y0 + 2.0 * y1 + y2; y2 = y1; y1 = y0; } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void RHPF_Ctor(RHPF* unit) { if (unit->mBufLength == 1) SETCALC(RHPF_next_1); else SETCALC(RHPF_next); unit->m_a0 = 0.; unit->m_b1 = 0.; unit->m_b2 = 0.; unit->m_y1 = 0.; unit->m_y2 = 0.; unit->m_freq = uninitializedControl; unit->m_reson = uninitializedControl; RHPF_next_1(unit, 1); } void RHPF_next(RHPF* unit, int inNumSamples) { //printf("RHPFs_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float reson = ZIN0(2); double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || reson != unit->m_reson) { double qres = sc_max(0.001f, reson); double pfreq = freq * unit->mRate->mRadiansPerSample; double D = tan(pfreq * qres * 0.5f); double C = ((1.0-D)/(1.0+D)); double cosf = cos(pfreq); double next_b1 = (1.0 + C) * cosf; double next_b2 = -C; double next_a0 = (1.0 + C + next_b1) * .25; //post("%g %g %g %g %g %g %g %g %g %g\n", *freq, pfreq, qres, D, C, cosf, next_b1, next_b2, next_a0, y1, y2); double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, double y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 - 2.0 * y1 + y2; y2 = a0 * ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = y2 - 2.0 * y0 + y1; y1 = a0 * ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = y1 - 2.0 * y2 + y0; a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, double y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 - 2.0 * y1 + y2; y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_reson = reson; unit->m_a0 = next_a0; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else { LOOP(unit->mRate->mFilterLoops, double y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 - 2.0 * y1 + y2; y2 = a0 * ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = y2 - 2.0 * y0 + y1; y1 = a0 * ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = y1 - 2.0 * y2 + y0; ); LOOP(unit->mRate->mFilterRemain, double y0 = a0 * ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = y0 - 2.0 * y1 + y2; y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void RHPF_next_1(RHPF* unit, int inNumSamples) { //printf("RHPFs_next_1\n"); float in = ZIN0(0); float freq = ZIN0(1); float reson = ZIN0(2); double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || reson != unit->m_reson) { double qres = sc_max(0.001f, reson); double pfreq = freq * unit->mRate->mRadiansPerSample; double D = tan(pfreq * qres * 0.5f); double C = ((1.-D)/(1.+D)); double cosf = cos(pfreq); b1 = (1. + C) * cosf; b2 = -C; a0 = (1. + C + b1) * .25; double y0 = a0 * in + b1 * y1 + b2 * y2; ZOUT0(0) = y0 - 2.0 * y1 + y2; y2 = y1; y1 = y0; unit->m_freq = freq; unit->m_reson = reson; unit->m_a0 = a0; unit->m_b1 = b1; unit->m_b2 = b2; } else { double y0 = a0 * in + b1 * y1 + b2 * y2; ZOUT0(0) = y0 - 2.0 * y1 + y2; y2 = y1; y1 = y0; } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LPF_Ctor(LPF* unit) { if (unit->mBufLength == 1) SETCALC(LPF_next_1); else SETCALC(LPF_next); unit->m_a0 = 0.f; unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; LPF_next_1(unit, 1); } void LPF_next(LPF* unit, int inNumSamples) { //printf("LPF_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq) { double pfreq = freq * unit->mRate->mRadiansPerSample * 0.5; double C = 1.f / tan(pfreq); double C2 = C * C; double sqrt2C = C * sqrt2_f; double next_a0 = 1.f / (1.f + sqrt2C + C2); double next_b1 = -2.f * (1.f - C2) * next_a0 ; double next_b2 = -(1.f - sqrt2C + C2) * next_a0; //post("%g %g %g %g %g %g %g %g %g %g\n", *freq, pfreq, qres, D, C, cosf, next_b1, next_b2, next_a0, y1, y2); double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 + 2. * y1 + y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 + 2. * y0 + y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 + 2.f * y2 + y0); a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 + 2. * y1 + y2); y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_a0 = next_a0; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else { LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; float out0 = a0 * (y0 + 2. * y1 + y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; float out1 = a0 * (y2 + 2. * y0 + y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; float out2 = a0 * (y1 + 2. * y2 + y0); ZXP(out) = out0; ZXP(out) = out1; ZXP(out) = out2; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 + 2. * y1 + y2); y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void LPF_next_1(LPF* unit, int inNumSamples) { //printf("LPF_next\n"); float in = ZIN0(0); float freq = ZIN0(1); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq) { double pfreq = freq * unit->mRate->mRadiansPerSample * 0.5; double C = 1.f / tan(pfreq); double C2 = C * C; double sqrt2C = C * sqrt2_f; a0 = 1.f / (1.f + sqrt2C + C2); b1 = -2.f * (1.f - C2) * a0 ; b2 = -(1.f - sqrt2C + C2) * a0; y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * (y0 + 2. * y1 + y2); y2 = y1; y1 = y0; unit->m_freq = freq; unit->m_a0 = a0; unit->m_b1 = b1; unit->m_b2 = b2; } else { y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * (y0 + 2. * y1 + y2); y2 = y1; y1 = y0; } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void HPF_Ctor(HPF* unit) { if (unit->mBufLength == 1) SETCALC(HPF_next_1); else SETCALC(HPF_next); unit->m_a0 = 0.; unit->m_b1 = 0.; unit->m_b2 = 0.; unit->m_y1 = 0.; unit->m_y2 = 0.; unit->m_freq = uninitializedControl; HPF_next_1(unit, 1); } void HPF_next(HPF* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq) { double pfreq = freq * unit->mRate->mRadiansPerSample * 0.5; double C = tan(pfreq); double C2 = C * C; double sqrt2C = C * sqrt2_f; double next_a0 = 1. / (1. + sqrt2C + C2); double next_b1 = 2. * (1. - C2) * next_a0 ; double next_b2 = -(1. - sqrt2C + C2) * next_a0; //post("%g %g %g %g %g %g %g %g %g %g\n", *freq, pfreq, qres, D, C, cosf, next_b1, next_b2, next_a0, y1, y2); double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, double in0 = ZXP(in); double in1 = ZXP(in); double in2 = ZXP(in); double y0 = in0 + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - 2. * y1 + y2); y2 = in1 + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - 2. * y0 + y1); y1 = in2 + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - 2. * y2 + y0); a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, double y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - 2. * y1 + y2); y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_a0 = next_a0; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else { LOOP(unit->mRate->mFilterLoops, double in0 = ZXP(in); double in1 = ZXP(in); double in2 = ZXP(in); double y0 = in0 + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - 2. * y1 + y2); y2 = in1 + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - 2. * y0 + y1); y1 = in2 + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - 2. * y2 + y0); ); LOOP(unit->mRate->mFilterRemain, double y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - 2. * y1 + y2); y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void HPF_next_1(HPF* unit, int inNumSamples) { double in = ZIN0(0); double freq = ZIN0(1); double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq) { double pfreq = freq * unit->mRate->mRadiansPerSample * 0.5f; double C = tan(pfreq); double C2 = C * C; double sqrt2C = C * sqrt2_f; a0 = 1. / (1. + sqrt2C + C2); b1 = 2. * (1. - C2) * a0 ; b2 = -(1. - sqrt2C + C2) * a0; double y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * (y0 - 2. * y1 + y2); y2 = y1; y1 = y0; unit->m_freq = freq; unit->m_a0 = a0; unit->m_b1 = b1; unit->m_b2 = b2; } else { double y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * (y0 - 2. * y1 + y2); y2 = y1; y1 = y0; } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BPF_Ctor(BPF* unit) { //printf("BPF_Reset\n"); if (unit->mBufLength == 1) { SETCALC(BPF_next_1); } else { SETCALC(BPF_next); }; unit->m_a0 = 0.f; unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_bw = uninitializedControl; BPF_next_1(unit, 1); } void BPF_next(BPF* unit, int inNumSamples) { //printf("BPF_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float bw = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || bw != unit->m_bw) { double pfreq = freq * unit->mRate->mRadiansPerSample; double pbw = bw * pfreq * 0.5f; double C = 1.f / tan(pbw); double D = 2.f * cos(pfreq); double next_a0 = 1.f / (1.f + C); double next_b1 = C * D * next_a0 ; double next_b2 = (1.f - C) * next_a0; double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - y0); a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_bw = bw; unit->m_a0 = next_a0; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else { LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - y0); ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BPF_next_1(BPF* unit, int inNumSamples) { //printf("BPF_next_1\n"); float in = ZIN0(0); float freq = ZIN0(1); float bw = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || bw != unit->m_bw) { double pfreq = freq * unit->mRate->mRadiansPerSample; double pbw = bw * pfreq * 0.5; double C = 1.f / tan(pbw); double D = 2.f * cos(pfreq); double a0 = 1.f / (1.f + C); double b1 = C * D * a0 ; double b2 = (1.f - C) * a0; y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * (y0 - y2); y2 = y1; y1 = y0; unit->m_freq = freq; unit->m_bw = bw; unit->m_a0 = a0; unit->m_b1 = b1; unit->m_b2 = b2; } else { y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * (y0 - y2); y2 = y1; y1 = y0; } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BRF_Ctor(BRF* unit) { //printf("BRF_Reset\n"); if (unit->mBufLength == 1) { SETCALC(BRF_next_1); } else { SETCALC(BRF_next); }; unit->m_a0 = 0.f; unit->m_a1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_bw = uninitializedControl; BRF_next_1(unit, 1); } void BRF_next(BRF* unit, int inNumSamples) { //printf("BRF_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float bw = ZIN0(2); double ay; double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double a1 = unit->m_a1; double b2 = unit->m_b2; if (freq != unit->m_freq || bw != unit->m_bw) { double pfreq = freq * unit->mRate->mRadiansPerSample; double pbw = bw * pfreq * 0.5f; double C = tan(pbw); double D = 2.f * cos(pfreq); double next_a0 = 1.f / (1.f + C); double next_a1 = -D * next_a0; double next_b2 = (1.f - C) * next_a0; double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double a1_slope = (next_a1 - a1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, ay = a1 * y1; y0 = ZXP(in) - ay - b2 * y2; ZXP(out) = a0 * (y0 + y2) + ay; ay = a1 * y0; y2 = ZXP(in) - ay - b2 * y1; ZXP(out) = a0 * (y2 + y1) + ay; ay = a1 * y2; y1 = ZXP(in) - ay - b2 * y0; ZXP(out) = a0 * (y1 + y0) + ay; a0 += a0_slope; a1 += a1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, ay = a1 * y1; y0 = ZXP(in) - ay - b2 * y2; ZXP(out) = a0 * (y0 + y2) + ay; y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_bw = bw; unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_b2 = next_b2; } else { LOOP(unit->mRate->mFilterLoops, ay = a1 * y1; y0 = ZXP(in) - ay - b2 * y2; ZXP(out) = a0 * (y0 + y2) + ay; ay = a1 * y0; y2 = ZXP(in) - ay - b2 * y1; ZXP(out) = a0 * (y2 + y1) + ay; ay = a1 * y2; y1 = ZXP(in) - ay - b2 * y0; ZXP(out) = a0 * (y1 + y0) + ay; ); LOOP(unit->mRate->mFilterRemain, ay = a1 * y1; y0 = ZXP(in) - ay - b2 * y2; ZXP(out) = a0 * (y0 + y2) + ay; y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BRF_next_1(BRF* unit, int inNumSamples) { //printf("BRF_next_1\n"); float in = ZIN0(0); float freq = ZIN0(1); float bw = ZIN0(2); double ay; double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double a1 = unit->m_a1; double b2 = unit->m_b2; if (freq != unit->m_freq || bw != unit->m_bw) { double pfreq = freq * unit->mRate->mRadiansPerSample; double pbw = bw * pfreq * 0.5f; double C = tan(pbw); double D = 2.f * cos(pfreq); double a0 = 1.f / (1.f + C); double a1 = -D * a0; double b2 = (1.f - C) * a0; ay = a1 * y1; y0 = in - ay - b2 * y2; ZOUT0(0) = a0 * (y0 + y2) + ay; y2 = y1; y1 = y0; unit->m_freq = freq; unit->m_bw = bw; unit->m_a0 = a0; unit->m_a1 = a1; unit->m_b2 = b2; } else { ay = a1 * y1; y0 = in - ay - b2 * y2; ZOUT0(0) = a0 * (y0 + y2) + ay; y2 = y1; y1 = y0; } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void MidEQ_Ctor(MidEQ* unit) { //printf("MidEQ_Reset\n"); SETCALC(MidEQ_next); unit->m_a0 = 0.f; unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_bw = uninitializedControl; unit->m_db = uninitializedControl; PUSH_LOOPVALS MidEQ_next(unit, 1); POP_LOOPVALS } void MidEQ_next(MidEQ* unit, int inNumSamples) { //printf("MidEQ_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float bw = ZIN0(2); float db = ZIN0(3); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || bw != unit->m_bw || db != unit->m_db) { double amp = sc_dbamp(db) - 1.0f; double pfreq = freq * unit->mRate->mRadiansPerSample; double pbw = bw * pfreq * 0.5f; double C = 1.f / tan(pbw); double D = 2.f * cos(pfreq); double next_a0 = 1.f / (1.f + C); double next_b1 = C * D * next_a0 ; double next_b2 = (1.f - C) * next_a0; next_a0 *= amp; double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; double zin; LOOP(unit->mRate->mFilterLoops, zin = ZXP(in); y0 = zin + b1 * y1 + b2 * y2; ZXP(out) = zin + a0 * (y0 - y2); zin = ZXP(in); y2 = zin + b1 * y0 + b2 * y1; ZXP(out) = zin + a0 * (y2 - y1); zin = ZXP(in); y1 = zin + b1 * y2 + b2 * y0; ZXP(out) = zin + a0 * (y1 - y0); a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, zin = ZXP(in); y0 = zin + b1 * y1 + b2 * y2; ZXP(out) = zin + a0 * (y0 - y2); y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_bw = bw; unit->m_db = db; unit->m_a0 = next_a0; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else { double zin; LOOP(unit->mRate->mFilterLoops, zin = ZXP(in); y0 = zin + b1 * y1 + b2 * y2; ZXP(out) = zin + a0 * (y0 - y2); zin = ZXP(in); y2 = zin + b1 * y0 + b2 * y1; ZXP(out) = zin + a0 * (y2 - y1); zin = ZXP(in); y1 = zin + b1 * y2 + b2 * y0; ZXP(out) = zin + a0 * (y1 - y0); ); LOOP(unit->mRate->mFilterRemain, zin = ZXP(in); y0 = zin + b1 * y1 + b2 * y2; ZXP(out) = zin + a0 * (y0 - y2); y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// static void Median_InitMedian(Median* unit, long size, float value); static float Median_InsertMedian(Median* unit, float value); void Median_Ctor(Median* unit) { //printf("Median_Reset\n"); SETCALC(Median_next); float in = ZIN0(1); unit->m_medianSize = sc_clip((int)ZIN0(0), 0, kMAXMEDIANSIZE); Median_InitMedian(unit, unit->m_medianSize, in); ZOUT0(0) = Median_InsertMedian(unit, in); } float Median_InsertMedian(Median* unit, float value) { long pos=-1; // keeps a sorted list of the previous n=size values // the oldest is removed and the newest is inserted. // values between the oldest and the newest are shifted over by one. // values and ages are both arrays that are 'size' long. // the median value is always values[size>>1] long last = unit->m_medianSize - 1; // find oldest bin and age the other bins. for (int i=0; im_medianSize; ++i) { if (unit->m_medianAge[i] == last) { // is it the oldest bin ? pos = i; } else { unit->m_medianAge[i]++; // age the bin } } // move values to fill in place of the oldest and make a space for the newest // search lower if value is too small for the open space while (pos != 0 && value < unit->m_medianValue[pos-1]) { unit->m_medianValue[pos] = unit->m_medianValue[pos-1]; unit->m_medianAge[pos] = unit->m_medianAge[pos-1]; pos--; } // search higher if value is too big for the open space while (pos != last && value > unit->m_medianValue[pos+1]) { unit->m_medianValue[pos] = unit->m_medianValue[pos+1]; unit->m_medianAge[pos] = unit->m_medianAge[pos+1]; pos++; } unit->m_medianValue[pos] = value; unit->m_medianAge[pos] = 0; // this is the newest bin, age = 0 return unit->m_medianValue[unit->m_medianSize>>1]; } void Median_InitMedian(Median* unit, long size, float value) { // initialize the arrays with the first value unit->m_medianSize = size; for (int i=0; im_medianValue[i] = value; unit->m_medianAge[i] = i; } } void Median_next(Median* unit, int inNumSamples) { //printf("Median_next_a\n"); float *out = ZOUT(0); float *in = ZIN(1); LOOP1(inNumSamples, ZXP(out) = Median_InsertMedian(unit, ZXP(in)); ); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Resonz_Ctor(Resonz* unit) { //printf("Resonz_Reset\n"); SETCALC(Resonz_next); unit->m_a0 = 0.f; unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_rq = 0.f; PUSH_LOOPVALS Resonz_next(unit, 1); POP_LOOPVALS } void Resonz_next(Resonz* unit, int inNumSamples) { //printf("Resonz_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float rq = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || rq != unit->m_rq) { double ffreq = freq * unit->mRate->mRadiansPerSample; double B = ffreq * rq; double R = 1.f - B * 0.5f; double twoR = 2.f * R; double R2 = R * R; double cost = (twoR * cos(ffreq)) / (1.f + R2); double b1_next = twoR * cost; double b2_next = -R2; double a0_next = (1.f - R2) * 0.5f; double a0_slope = (a0_next - a0) * unit->mRate->mFilterSlope; double b1_slope = (b1_next - b1) * unit->mRate->mFilterSlope; double b2_slope = (b2_next - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - y0); a0 += a0_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_rq = rq; unit->m_a0 = a0_next; unit->m_b1 = b1_next; unit->m_b2 = b2_next; } else { LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - y0); ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Ringz_Ctor(Ringz* unit) { //printf("Ringz_ctor\n"); SETCALC(Ringz_next); unit->m_b1 = 0.f; unit->m_b2 = 0.f; unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_freq = uninitializedControl; unit->m_decayTime = 0.f; PUSH_LOOPVALS Ringz_next(unit, 1); POP_LOOPVALS } void Ringz_next(Ringz* unit, int inNumSamples) { //printf("Ringz_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float decayTime = ZIN0(2); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = 0.5f; double b1 = unit->m_b1; double b2 = unit->m_b2; if (freq != unit->m_freq || decayTime != unit->m_decayTime) { double ffreq = freq * unit->mRate->mRadiansPerSample; double R = decayTime == 0.f ? 0.f : exp(log001/(decayTime * SAMPLERATE)); double twoR = 2.f * R; double R2 = R * R; double cost = (twoR * cos(ffreq)) / (1.f + R2); double b1_next = twoR * cost; double b2_next = -R2; double b1_slope = (b1_next - b1) * unit->mRate->mFilterSlope; double b2_slope = (b2_next - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - y0); b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = y1; y1 = y0; ); unit->m_freq = freq; unit->m_decayTime = decayTime; unit->m_b1 = b1_next; unit->m_b2 = b2_next; } else { LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * (y2 - y1); y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * (y1 - y0); ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * (y0 - y2); y2 = y1; y1 = y0; ); } unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Formlet_Ctor(Formlet* unit) { //printf("Formlet_Reset\n"); if (unit->mBufLength == 1) { SETCALC(Formlet_next_1); } else { SETCALC(Formlet_next); }; unit->m_b01 = 0.f; unit->m_b02 = 0.f; unit->m_y01 = 0.f; unit->m_y02 = 0.f; unit->m_b11 = 0.f; unit->m_b12 = 0.f; unit->m_y11 = 0.f; unit->m_y12 = 0.f; unit->m_freq = uninitializedControl; unit->m_attackTime = uninitializedControl; unit->m_decayTime = uninitializedControl; Formlet_next_1(unit, 1); } void Formlet_next(Formlet* unit, int inNumSamples) { //printf("Formlet_next\n"); float *out = ZOUT(0); float *in = ZIN(0); float freq = ZIN0(1); float attackTime = ZIN0(2); float decayTime = ZIN0(3); double y00; double y10; double y01 = unit->m_y01; double y11 = unit->m_y11; double y02 = unit->m_y02; double y12 = unit->m_y12; double b01 = unit->m_b01; double b11 = unit->m_b11; double b02 = unit->m_b02; double b12 = unit->m_b12; double ain; if (freq != unit->m_freq || decayTime != unit->m_decayTime || attackTime != unit->m_attackTime) { double ffreq = freq * unit->mRate->mRadiansPerSample; double R = decayTime == 0.f ? 0.f : exp(log001/(decayTime * SAMPLERATE)); double twoR = 2.f * R; double R2 = R * R; double cost = (twoR * cos(ffreq)) / (1.f + R2); double b01_next = twoR * cost; double b02_next = -R2; double b01_slope = (b01_next - b01) * unit->mRate->mFilterSlope; double b02_slope = (b02_next - b02) * unit->mRate->mFilterSlope; R = attackTime == 0.f ? 0.f : exp(log001/(attackTime * SAMPLERATE)); twoR = 2.f * R; R2 = R * R; cost = (twoR * cos(ffreq)) / (1.f + R2); double b11_next = twoR * cost; double b12_next = -R2; double b11_slope = (b11_next - b11) * unit->mRate->mFilterSlope; double b12_slope = (b12_next - b12) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, ain = ZXP(in); y00 = ain + b01 * y01 + b02 * y02; y10 = ain + b11 * y11 + b12 * y12; ZXP(out) = 0.25 * ((y00 - y02) - (y10 - y12)); ain = ZXP(in); y02 = ain + b01 * y00 + b02 * y01; y12 = ain + b11 * y10 + b12 * y11; ZXP(out) = 0.25 * ((y02 - y01) - (y12 - y11)); ain = ZXP(in); y01 = ain + b01 * y02 + b02 * y00; y11 = ain + b11 * y12 + b12 * y10; ZXP(out) = 0.25 * ((y01 - y00) - (y11 - y10)); b01 += b01_slope; b02 += b02_slope; b11 += b11_slope; b12 += b12_slope; ); LOOP(unit->mRate->mFilterRemain, ain = ZXP(in); y00 = ain + b01 * y01 + b02 * y02; y10 = ain + b11 * y11 + b12 * y12; ZXP(out) = 0.25 * ((y00 - y02) - (y10 - y12)); y02 = y01; y01 = y00; y12 = y11; y11 = y10; ); unit->m_freq = freq; unit->m_attackTime = attackTime; unit->m_decayTime = decayTime; unit->m_b01 = b01_next; unit->m_b02 = b02_next; unit->m_b11 = b11_next; unit->m_b12 = b12_next; } else { LOOP(unit->mRate->mFilterLoops, ain = ZXP(in); y00 = ain + b01 * y01 + b02 * y02; y10 = ain + b11 * y11 + b12 * y12; ZXP(out) = 0.25 * ((y00 - y02) - (y10 - y12)); ain = ZXP(in); y02 = ain + b01 * y00 + b02 * y01; y12 = ain + b11 * y10 + b12 * y11; ZXP(out) = 0.25 * ((y02 - y01) - (y12 - y11)); ain = ZXP(in); y01 = ain + b01 * y02 + b02 * y00; y11 = ain + b11 * y12 + b12 * y10; ZXP(out) = 0.25 * ((y01 - y00) - (y11 - y10)); ); LOOP(unit->mRate->mFilterRemain, ain = ZXP(in); y00 = ain + b01 * y01 + b02 * y02; y10 = ain + b11 * y11 + b12 * y12; ZXP(out) = 0.25 * ((y00 - y02) - (y10 - y12)); y02 = y01; y01 = y00; y12 = y11; y11 = y10; ); } unit->m_y01 = y01; unit->m_y02 = y02; unit->m_y11 = y11; unit->m_y12 = y12; } void Formlet_next_1(Formlet* unit, int inNumSamples) { //printf("Formlet_next\n"); float in = ZIN0(0); float freq = ZIN0(1); float attackTime = ZIN0(2); float decayTime = ZIN0(3); double y00; double y10; double y01 = unit->m_y01; double y11 = unit->m_y11; double y02 = unit->m_y02; double y12 = unit->m_y12; double b01 = unit->m_b01; double b11 = unit->m_b11; double b02 = unit->m_b02; double b12 = unit->m_b12; double ain; if (freq != unit->m_freq || decayTime != unit->m_decayTime || attackTime != unit->m_attackTime) { double ffreq = freq * unit->mRate->mRadiansPerSample; double R = decayTime == 0.f ? 0.f : exp(log001/(decayTime * SAMPLERATE)); double twoR = 2.f * R; double R2 = R * R; double cost = (twoR * cos(ffreq)) / (1.f + R2); b01 = twoR * cost; b02 = -R2; R = attackTime == 0.f ? 0.f : exp(log001/(attackTime * SAMPLERATE)); twoR = 2.f * R; R2 = R * R; cost = (twoR * cos(ffreq)) / (1.f + R2); b11 = twoR * cost; b12 = -R2; ain = in; y00 = ain + b01 * y01 + b02 * y02; y10 = ain + b11 * y11 + b12 * y12; ZOUT0(0) = 0.25f * ((y00 - y02) - (y10 - y12)); y02 = y01; y01 = y00; y12 = y11; y11 = y10; unit->m_freq = freq; unit->m_attackTime = attackTime; unit->m_decayTime = decayTime; unit->m_b01 = b01; unit->m_b02 = b02; unit->m_b11 = b11; unit->m_b12 = b12; } else { ain = in; y00 = ain + b01 * y01 + b02 * y02; y10 = ain + b11 * y11 + b12 * y12; ZOUT0(0) = 0.25f * ((y00 - y02) - (y10 - y12)); y02 = y01; y01 = y00; y12 = y11; y11 = y10; } unit->m_y01 = y01; unit->m_y02 = y02; unit->m_y11 = y11; unit->m_y12 = y12; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void FOS_Ctor(FOS* unit) { //printf("FOS_Reset\n"); if (unit->mBufLength == 1) { SETCALC(FOS_next_1); } else { if (INRATE(1) == calc_FullRate && INRATE(2) == calc_FullRate && INRATE(3) == calc_FullRate) { SETCALC(FOS_next_a); } else { SETCALC(FOS_next_k); } }; unit->m_y1 = 0.f; unit->m_a0 = 0.f; unit->m_a1 = 0.f; unit->m_b1 = 0.f; FOS_next_1(unit, 1); } void FOS_next_a(FOS* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *a0 = ZIN(1); float *a1 = ZIN(2); float *b1 = ZIN(3); double y1 = unit->m_y1; LOOP1(inNumSamples, double y0 = ZXP(in) + ZXP(b1) * y1; ZXP(out) = ZXP(a0) * y0 + ZXP(a1) * y1; y1 = y0; ); unit->m_y1 = zapgremlins(y1); } void FOS_next_1(FOS* unit, int inNumSamples) { float in = ZIN0(0); float a0 = ZIN0(1); float a1 = ZIN0(2); float b1 = ZIN0(3); double y1 = unit->m_y1; double y0 = in + b1 * y1; ZOUT0(0) = a0 * y0 + a1 * y1; y1 = y0; unit->m_y1 = zapgremlins(y1); } void FOS_next_k(FOS* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_a0 = ZIN0(1); float next_a1 = ZIN0(2); float next_b1 = ZIN0(3); double y1 = unit->m_y1; double a0 = unit->m_a0; double a1 = unit->m_a1; double b1 = unit->m_b1; double a0_slope = CALCSLOPE(next_a0, a0); double a1_slope = CALCSLOPE(next_a1, a1); double b1_slope = CALCSLOPE(next_b1, b1); LOOP1(inNumSamples, double y0 = ZXP(in) + b1 * y1; ZXP(out) = a0 * y0 + a1 * y1; y1 = y0; a0 += a0_slope; a1 += a1_slope; b1 += b1_slope; ); unit->m_y1 = zapgremlins(y1); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_b1 = next_b1; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void SOS_Ctor(SOS* unit) { // printf("SOS_Reset\n"); if (unit->mBufLength != 1) { if (INRATE(1) == calc_FullRate && INRATE(2) == calc_FullRate && INRATE(3) == calc_FullRate && INRATE(4) == calc_FullRate && INRATE(5) == calc_FullRate) { SETCALC(SOS_next_a); } else if (INRATE(1) == calc_ScalarRate && INRATE(2) == calc_ScalarRate && INRATE(3) == calc_ScalarRate && INRATE(4) == calc_ScalarRate && INRATE(5) == calc_ScalarRate) { SETCALC(SOS_next_i); } else { SETCALC(SOS_next_k); } } else { SETCALC(SOS_next_1); // printf("SOS_next_1\n"); } unit->m_y1 = 0.f; unit->m_y2 = 0.f; unit->m_a0 = ZIN0(1); unit->m_a1 = ZIN0(2); unit->m_a2 = ZIN0(3); unit->m_b1 = ZIN0(4); unit->m_b2 = ZIN0(5); SOS_next_1(unit, 1); } void SOS_next_a(SOS *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *a0 = ZIN(1); float *a1 = ZIN(2); float *a2 = ZIN(3); float *b1 = ZIN(4); float *b2 = ZIN(5); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; LOOP(unit->mRate->mFilterLoops, y0 = ZXP(in) + ZXP(b1) * y1 + ZXP(b2) * y2; ZXP(out) = ZXP(a0) * y0 + ZXP(a1) * y1 + ZXP(a2) * y2; y2 = ZXP(in) + ZXP(b1) * y0 + ZXP(b2) * y1; ZXP(out) = ZXP(a0) * y2 + ZXP(a1) * y0 + ZXP(a2) * y1; y1 = ZXP(in) + ZXP(b1) * y2 + ZXP(b2) * y0; ZXP(out) = ZXP(a0) * y1 + ZXP(a1) * y2 + ZXP(a2) * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + ZXP(b1) * y1 + ZXP(b2) * y2; ZXP(out) = ZXP(a0) * y0 + ZXP(a1) * y1 + ZXP(a2) * y2; y2 = y1; y1 = y0; ); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void SOS_next_k(SOS *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_a0 = ZIN0(1); float next_a1 = ZIN0(2); float next_a2 = ZIN0(3); float next_b1 = ZIN0(4); float next_b2 = ZIN0(5); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double a1 = unit->m_a1; double a2 = unit->m_a2; double b1 = unit->m_b1; double b2 = unit->m_b2; double a0_slope = (next_a0 - a0) * unit->mRate->mFilterSlope; double a1_slope = (next_a1 - a1) * unit->mRate->mFilterSlope; double a2_slope = (next_a2 - a2) * unit->mRate->mFilterSlope; double b1_slope = (next_b1 - b1) * unit->mRate->mFilterSlope; double b2_slope = (next_b2 - b2) * unit->mRate->mFilterSlope; LOOP(unit->mRate->mFilterLoops, float in0 = ZXP(in); float in1 = ZXP(in); float in2 = ZXP(in); y0 = in0 + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = in1 + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = in2 + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; a0 += a0_slope; a1 += a1_slope; a2 += a2_slope; b1 += b1_slope; b2 += b2_slope; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void SOS_next_i(SOS *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; double a0 = unit->m_a0; double a1 = unit->m_a1; double a2 = unit->m_a2; double b1 = unit->m_b1; double b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, float in0 = ZXP(in); float in1 = ZXP(in); float in2 = ZXP(in); y0 = in0 + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = in1 + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = in2 + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; ); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void SOS_next_1(SOS *unit, int inNumSamples) // optimized for SOS.kr { float in = ZIN0(0); float a0 = ZIN0(1); float a1 = ZIN0(2); float a2 = ZIN0(3); float b1 = ZIN0(4); float b2 = ZIN0(5); double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; y0 = in + b1 * y1 + b2 * y2; ZOUT0(0) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Compander_Ctor(Compander* unit) { //printf("Compander_Reset\n"); SETCALC(Compander_next); unit->m_clamp = 0.f; unit->m_clampcoef = 0.f; unit->m_relax = 0.f; unit->m_relaxcoef = 0.f; unit->m_prevmaxval = 0.f; unit->m_gain = 0.f; Compander_next(unit, 1); } void Compander_next(Compander* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *control = ZIN(1); float thresh = ZIN0(2); float slope_below = ZIN0(3); float slope_above = ZIN0(4); float clamp = ZIN0(5); float relax = ZIN0(6); if (clamp != unit->m_clamp) { unit->m_clampcoef = clamp == 0.0 ? 0.0 : exp(log1/(clamp * SAMPLERATE)); unit->m_clamp = clamp; } if (relax != unit->m_relax) { unit->m_relaxcoef = relax == 0.0 ? 0.0 : exp(log1/(relax * SAMPLERATE)); unit->m_relax = relax; } float gain = unit->m_gain; float relaxcoef = unit->m_relaxcoef; float clampcoef = unit->m_clampcoef; float prevmaxval = unit->m_prevmaxval; float val; LOOP1(inNumSamples, val = std::abs(ZXP(control)); if (val < prevmaxval) { val = val + (prevmaxval - val) * relaxcoef; } else { val = val + (prevmaxval - val) * clampcoef; } prevmaxval = val; ); unit->m_prevmaxval = prevmaxval; float next_gain;//,absx; if (prevmaxval < thresh) { if (slope_below == 1.f) { next_gain = 1.f; } else { next_gain = pow(prevmaxval / thresh, slope_below - 1.f); //blows up here float32 absx = std::abs(next_gain); //zap gremlins, but returns 0. if gain is too small and 1. if gain is too big next_gain = (absx < (float32)1e-15) ? (float32)0. : (absx > (float32)1e15) ? (float32)1. : next_gain; } } else { if (slope_above == 1.f) { next_gain = 1.f; } else { next_gain = pow(prevmaxval / thresh, slope_above - 1.f); } } float gain_slope = CALCSLOPE(next_gain, gain); LOOP1(inNumSamples, ZXP(out) = ZXP(in) * gain; gain += gain_slope;); unit->m_gain = gain; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Normalizer_Dtor(Normalizer* unit) { RTFree(unit->mWorld, unit->m_table); } void Normalizer_Ctor(Normalizer* unit) { SETCALC(Normalizer_next); //printf("Normalizer_Reset\n"); float dur = ZIN0(2); unit->m_bufsize = (long)(ceil(dur * SAMPLERATE)); long allocsize = unit->m_bufsize * 3; //allocsize = NEXTPOWEROFTWO(allocsize); unit->m_table = (float*)RTAlloc(unit->mWorld, allocsize * sizeof(float)); unit->m_pos = 0; unit->m_flips = 0; unit->m_level = 1.f; unit->m_slope = 0.f; unit->m_prevmaxval = 0.0; unit->m_curmaxval = 0.0; unit->m_slopefactor = 1.f / unit->m_bufsize; unit->m_xinbuf = unit->m_table - ZOFF; unit->m_xmidbuf = unit->m_xinbuf + unit->m_bufsize; unit->m_xoutbuf = unit->m_xmidbuf + unit->m_bufsize; Normalizer_next(unit, 1); } void Normalizer_next(Normalizer* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float amp = ZIN0(1); long pos = unit->m_pos; float slope = unit->m_slope; float level = unit->m_level; float curmaxval = unit->m_curmaxval; float val; long bufsize = unit->m_bufsize; long buf_remain = bufsize - pos; long remain = inNumSamples; while (remain > 0) { long nsmps = sc_min(remain, buf_remain); float* xinbuf = unit->m_xinbuf + pos; float* xoutbuf = unit->m_xoutbuf + pos; if (unit->m_flips >= 2) { LOOP(nsmps, ZXP(xinbuf) = val = ZXP(in); ZXP(out) = level * ZXP(xoutbuf); level += slope; val = std::abs(val); if (val > curmaxval) curmaxval = val; ); } else { LOOP(nsmps, ZXP(xinbuf) = val = ZXP(in); ZXP(out) = 0.f; level += slope; val = std::abs(val); if (val > curmaxval) curmaxval = val; ); } pos += nsmps; if (pos >= bufsize) { pos = 0; buf_remain = bufsize; float maxval2 = sc_max(unit->m_prevmaxval, curmaxval); unit->m_prevmaxval = curmaxval; unit->m_curmaxval = curmaxval = 0.f; float next_level; if (maxval2 <= 0.00001f) next_level = 100000.f * amp; else next_level = amp / maxval2; slope = unit->m_slope = (next_level - level) * unit->m_slopefactor; float* temp = unit->m_xoutbuf; unit->m_xoutbuf = unit->m_xmidbuf; unit->m_xmidbuf = unit->m_xinbuf; unit->m_xinbuf = temp; unit->m_flips++; } remain -= nsmps; } unit->m_pos = pos; unit->m_level = level; unit->m_curmaxval = curmaxval; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Limiter_Dtor(Limiter* unit) { RTFree(unit->mWorld, unit->m_table); } void Limiter_Ctor(Limiter* unit) { //printf("Limiter_Reset\n"); SETCALC(Limiter_next); float dur = ZIN0(2); unit->m_bufsize = (long)(ceil(dur * SAMPLERATE)); long allocsize = unit->m_bufsize * 3; allocsize = NEXTPOWEROFTWO(allocsize); unit->m_table = (float*)RTAlloc(unit->mWorld, allocsize * sizeof(float)); unit->m_flips = 0; unit->m_pos = 0; unit->m_slope = 0.f; unit->m_level = 1.f; unit->m_prevmaxval = 0.0; unit->m_curmaxval = 0.0; unit->m_slopefactor = 1.f / unit->m_bufsize; unit->m_xinbuf = unit->m_table - ZOFF; unit->m_xmidbuf = unit->m_xinbuf + unit->m_bufsize; unit->m_xoutbuf = unit->m_xmidbuf + unit->m_bufsize; Limiter_next(unit, 1); } void Limiter_next(Limiter* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float amp = ZIN0(1); long pos = unit->m_pos; float slope = unit->m_slope; float level = unit->m_level; float curmaxval = unit->m_curmaxval; float val; long bufsize = unit->m_bufsize; long buf_remain = bufsize - pos; long remain = inNumSamples; while (remain > 0) { long nsmps = sc_min(remain, buf_remain); float* xinbuf = unit->m_xinbuf + pos; float* xoutbuf = unit->m_xoutbuf + pos; if (unit->m_flips >= 2) { LOOP(nsmps, ZXP(xinbuf) = val = ZXP(in); ZXP(out) = level * ZXP(xoutbuf); level += slope; val = std::abs(val); if (val > curmaxval) curmaxval = val; ); } else { LOOP(nsmps, ZXP(xinbuf) = val = ZXP(in); ZXP(out) = 0.f; level += slope; val = std::abs(val); if (val > curmaxval) curmaxval = val; ); } pos += nsmps; if (pos >= bufsize) { pos = 0; buf_remain = bufsize; float maxval2 = sc_max(unit->m_prevmaxval, curmaxval); unit->m_prevmaxval = curmaxval; unit->m_curmaxval = curmaxval = 0.f; float next_level; if (maxval2 > amp) next_level = amp / maxval2; else next_level = 1.0; slope = unit->m_slope = (next_level - level) * unit->m_slopefactor; float* temp = unit->m_xoutbuf; unit->m_xoutbuf = unit->m_xmidbuf; unit->m_xmidbuf = unit->m_xinbuf; unit->m_xinbuf = temp; unit->m_flips++; } remain -= nsmps; } unit->m_pos = pos; unit->m_level = level; unit->m_curmaxval = curmaxval; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Amplitude_Ctor(Amplitude* unit) { if(INRATE(1) != calc_ScalarRate || INRATE(2) != calc_ScalarRate) { if(INRATE(0) == calc_FullRate && unit->mCalcRate == calc_BufRate){ SETCALC(Amplitude_next_atok_kk); } else { SETCALC(Amplitude_next_kk); } } else { if(INRATE(0) == calc_FullRate && unit->mCalcRate == calc_BufRate){ SETCALC(Amplitude_next_atok); } else { SETCALC(Amplitude_next); } } float clamp = ZIN0(1); unit->m_clampcoef = clamp == 0.0 ? 0.0 : exp(log1/(clamp * SAMPLERATE)); float relax = ZIN0(2); unit->m_relaxcoef = relax == 0.0 ? 0.0 : exp(log1/(relax * SAMPLERATE)); unit->m_previn = std::abs(ZIN0(0)); Amplitude_next(unit, 1); } void Amplitude_next(Amplitude* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float relaxcoef = unit->m_relaxcoef; float clampcoef = unit->m_clampcoef; float previn = unit->m_previn; float val; LOOP1(inNumSamples, val = std::abs(ZXP(in)); if (val < previn) { val = val + (previn - val) * relaxcoef; } else { val = val + (previn - val) * clampcoef; } ZXP(out) = previn = val; ); unit->m_previn = previn; } void Amplitude_next_atok(Amplitude* unit, int inNumSamples) { float *in = ZIN(0); float relaxcoef = unit->m_relaxcoef; float clampcoef = unit->m_clampcoef; float previn = unit->m_previn; float val; LOOP1(FULLBUFLENGTH, val = std::abs(ZXP(in)); if (val < previn) { val = val + (previn - val) * relaxcoef; } else { val = val + (previn - val) * clampcoef; } previn = val; ); ZOUT0(0) = val; unit->m_previn = previn; } void Amplitude_next_kk(Amplitude* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float relaxcoef, clampcoef; if(ZIN0(1) != unit->m_clamp_in) { clampcoef = unit->m_clampcoef = exp(log1/(ZIN0(1) * SAMPLERATE)); unit->m_clamp_in = ZIN0(1); } else { clampcoef = unit->m_clampcoef; } if(ZIN0(2) != unit->m_relax_in) { relaxcoef = unit->m_relaxcoef = exp(log1/(ZIN0(2) * SAMPLERATE)); unit->m_relax_in = ZIN0(2); } else { relaxcoef = unit->m_relaxcoef; } float previn = unit->m_previn; float val; LOOP1(inNumSamples, val = std::abs(ZXP(in)); if (val < previn) { val = val + (previn - val) * relaxcoef; } else { val = val + (previn - val) * clampcoef; } ZXP(out) = previn = val; ); unit->m_previn = previn; } void Amplitude_next_atok_kk(Amplitude* unit, int inNumSamples) { float *in = ZIN(0); float relaxcoef, clampcoef; if(ZIN0(1) != unit->m_clamp_in) { clampcoef = unit->m_clampcoef = exp(log1/(ZIN0(1) * SAMPLERATE)); unit->m_clamp_in = ZIN0(1); } else { clampcoef = unit->m_clampcoef; } if(ZIN0(2) != unit->m_relax_in) { relaxcoef = unit->m_relaxcoef = exp(log1/(ZIN0(2) * SAMPLERATE)); unit->m_relax_in = ZIN0(2); } else { relaxcoef = unit->m_relaxcoef; } float previn = unit->m_previn; float val; LOOP1(FULLBUFLENGTH, val = std::abs(ZXP(in)); if (val < previn) { val = val + (previn - val) * relaxcoef; } else { val = val + (previn - val) * clampcoef; } previn = val; ); ZOUT0(0) = val; unit->m_previn = previn; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void DetectSilence_Ctor(DetectSilence* unit) { //printf("DetectSilence_Reset\n"); if(INRATE(1) == calc_ScalarRate && INRATE(2) == calc_ScalarRate) { unit->mThresh = ZIN0(1); unit->mEndCounter = (int32)(SAMPLERATE * ZIN0(2)); SETCALC(DetectSilence_next); } else { SETCALC(DetectSilence_next_k); } unit->mDoneAction = ZIN0(3); unit->mCounter = -1; } void DetectSilence_next(DetectSilence* unit, int inNumSamples) { float thresh = unit->mThresh; int counter = unit->mCounter; float val; // I thought of a better way to do this... /* for (int i=0; i= thresh) counter = 0; else if (counter >= 0) { if (++counter >= unit->mEndCounter && doneAction) { int doneAction = (int)ZIN0(3); DoneAction(doneAction, unit); SETCALC(DetectSilence_done); } } ZXP(out) = 0.f; } */ float *in = IN(0); float *out = OUT(0); for (int i=0; i thresh) { counter = 0; *out++ = 0.f; } else if (counter >= 0) { if (++counter >= unit->mEndCounter) { DoneAction(unit->mDoneAction, unit); *out++ = 1.f; // SETCALC(DetectSilence_done); } else { *out++ = 0.f; } } else *out++ = 0.f; } unit->mCounter = counter; } void DetectSilence_next_k(DetectSilence* unit, int inNumSamples) { float thresh = ZIN0(1); int endCounter = (int32)(SAMPLERATE * ZIN0(2)); int counter = unit->mCounter; float val; float *in = IN(0); float *out = OUT(0); for (int i=0; i thresh) { counter = 0; *out++ = 0.f; } else if (counter >= 0) { if (++counter >= endCounter) { DoneAction(unit->mDoneAction, unit); *out++ = 1.f; } else { *out++ = 0.f; } } else *out++ = 0.f; } unit->mCounter = counter; } //void DetectSilence_done(DetectSilence* unit, int inNumSamples) //{} /////////////////////////////////////////////////////////////////////////////////////////////////////// // Based on HilbertIIR from SC2 // a 12 pole (6 per side) Hilbert IIR filter // based on Sean Costello and Bernie Hutchins // created by jl anderson - 7 jan 2001 // UGen created by Josh Parmenter #define HILBERT_FILTER \ y0_1 = thisin - (coefs[0]) * y1[0]; \ ay1 = coefs[0] * y0_1 + 1 * y1[0]; \ y1[0] = y0_1; \ y0_2 = ay1 - (coefs[1]) * y1[1]; \ ay2 = coefs[1] * y0_2 + 1 * y1[1]; \ y1[1] = y0_2; \ y0_3 = ay2 - (coefs[2]) * y1[2]; \ ay3 = coefs[2] * y0_3 + 1 * y1[2]; \ y1[2] = y0_3; \ y0_4 = ay3 - (coefs[3]) * y1[3]; \ ay4 =coefs[3] * y0_4 + 1 * y1[3]; \ y1[3] = y0_4; \ y0_5 = ay4 - (coefs[4]) * y1[4]; \ ay5 = coefs[4] * y0_5 + 1 * y1[4]; \ y1[4] = y0_5; \ y0_6 = ay5 - (coefs[5]) * y1[5]; \ ay6 = coefs[5] * y0_6 + 1 * y1[5]; \ y1[5] = y0_6; \ \ y0_7 = thisin - (coefs[6]) * y1[6]; \ ay7 = coefs[6] * y0_7 + 1 * y1[6]; \ y1[6] = y0_7; \ y0_8 = ay7 - (coefs[7]) * y1[7]; \ ay8 = coefs[7] * y0_8 + 1 * y1[7]; \ y1[7] = y0_8; \ y0_9 = ay8 - (coefs[8]) * y1[8]; \ ay9 = coefs[8] * y0_9 + 1 * y1[8]; \ y1[8] = y0_9; \ y0_10 = ay9 - (coefs[9]) * y1[9]; \ ay10 = coefs[9] * y0_10 + 1 * y1[9]; \ y1[9] = y0_10; \ y0_11 = ay10 - (coefs[10]) * y1[10]; \ ay11 = coefs[10] * y0_11 + 1 * y1[10]; \ y1[10] = y0_11; \ y0_12 = ay11 - (coefs[11]) * y1[11]; \ ay12 = coefs[11] * y0_12 + 1 * y1[11]; \ y1[11] = y0_12; \ void Hilbert_Ctor(Hilbert *unit) { // calculate coefs based on SampleRate, store in the struct SETCALC(Hilbert_next); double gamconst = (15.0f * pi_f) / SAMPLERATE; double gamma01 = gamconst * 0.3609f; double gamma02 = gamconst * 2.7412f; double gamma03 = gamconst * 11.1573f; double gamma04 = gamconst * 44.7581f; double gamma05 = gamconst * 179.6242f; double gamma06 = gamconst * 798.4578f; double gamma07 = gamconst * 1.2524f; double gamma08 = gamconst * 5.5671f; double gamma09 = gamconst * 22.3423f; double gamma10 = gamconst * 89.6271f; double gamma11 = gamconst * 364.7914f; double gamma12 = gamconst * 2770.1114f; unit->m_coefs[0] = (gamma01 - 1.f) / (gamma01 + 1.f); unit->m_coefs[1] = (gamma02 - 1.f) / (gamma02 + 1.f); unit->m_coefs[2] = (gamma03 - 1.f) / (gamma03 + 1.f); unit->m_coefs[3] = (gamma04 - 1.f) / (gamma04 + 1.f); unit->m_coefs[4] = (gamma05 - 1.f) / (gamma05 + 1.f); unit->m_coefs[5] = (gamma06 - 1.f) / (gamma06 + 1.f); unit->m_coefs[6] = (gamma07 - 1.f) / (gamma07 + 1.f); unit->m_coefs[7] = (gamma08 - 1.f) / (gamma08 + 1.f); unit->m_coefs[8] = (gamma09 - 1.f) / (gamma09 + 1.f); unit->m_coefs[9] = (gamma10 - 1.f) / (gamma10 + 1.f); unit->m_coefs[10] = (gamma11 - 1.f) / (gamma11 + 1.f); unit->m_coefs[11] = (gamma12 - 1.f) / (gamma12 + 1.f); Clear(12, unit->m_y1); Hilbert_next(unit, 1); } void Hilbert_next(Hilbert *unit, int inNumSamples) { float *in = ZIN(0); float *outcos = ZOUT(0); float *outsin = ZOUT(1); float y1[12]; float coefs[12]; // each filter's last sample for(int i = 0; i < 12; ++i){ y1[i] = unit->m_y1[i]; coefs[i] = unit->m_coefs[i]; } double ay1, ay2, ay3, ay4, ay5, ay6; double ay7, ay8, ay9, ay10, ay11, ay12; double y0_1, y0_2, y0_3, y0_4, y0_5, y0_6; double y0_7, y0_8, y0_9, y0_10, y0_11, y0_12; LOOP1(inNumSamples, float thisin = ZXP(in); HILBERT_FILTER ZXP(outcos) = ay6; ZXP(outsin) = ay12; ) for(int i = 0; i < 12; ++i) unit->m_y1[i] = zapgremlins(y1[i]); } /* Hilbert based SSB FreqShifter */ void FreqShift_Ctor(FreqShift *unit) { // calculate coefs based on SampleRate, store in the struct // SETCALC(FreqShift_next_kk); unit->m_phase = 0; if(INRATE(1) == calc_FullRate) { if(INRATE(2) == calc_FullRate) SETCALC(FreqShift_next_aa); else SETCALC(FreqShift_next_ak); } else { if(INRATE(2) == calc_FullRate) SETCALC(FreqShift_next_ka); else { SETCALC(FreqShift_next_kk); unit->m_phase = (int32)(unit->m_radtoinc * IN0(2)); } } // set up for the oscil for the modualtion int tableSizeSin = ft->mSineSize; unit->m_lomask = (tableSizeSin - 1) << 3; unit->m_radtoinc = tableSizeSin * (rtwopi * 65536.); unit->m_cpstoinc = tableSizeSin * SAMPLEDUR * 65536.; unit->m_phasein = IN0(2); double gamconst = (15.0 * pi) / SAMPLERATE; double gamma01 = gamconst * 0.3609f; double gamma02 = gamconst * 2.7412f; double gamma03 = gamconst * 11.1573f; double gamma04 = gamconst * 44.7581f; double gamma05 = gamconst * 179.6242f; double gamma06 = gamconst * 798.4578f; double gamma07 = gamconst * 1.2524f; double gamma08 = gamconst * 5.5671f; double gamma09 = gamconst * 22.3423f; double gamma10 = gamconst * 89.6271f; double gamma11 = gamconst * 364.7914f; double gamma12 = gamconst * 2770.1114f; unit->m_coefs[0] = (gamma01 - 1.f) / (gamma01 + 1.f); unit->m_coefs[1] = (gamma02 - 1.f) / (gamma02 + 1.f); unit->m_coefs[2] = (gamma03 - 1.f) / (gamma03 + 1.f); unit->m_coefs[3] = (gamma04 - 1.f) / (gamma04 + 1.f); unit->m_coefs[4] = (gamma05 - 1.f) / (gamma05 + 1.f); unit->m_coefs[5] = (gamma06 - 1.f) / (gamma06 + 1.f); unit->m_coefs[6] = (gamma07 - 1.f) / (gamma07 + 1.f); unit->m_coefs[7] = (gamma08 - 1.f) / (gamma08 + 1.f); unit->m_coefs[8] = (gamma09 - 1.f) / (gamma09 + 1.f); unit->m_coefs[9] = (gamma10 - 1.f) / (gamma10 + 1.f); unit->m_coefs[10] = (gamma11 - 1.f) / (gamma11 + 1.f); unit->m_coefs[11] = (gamma12 - 1.f) / (gamma12 + 1.f); Clear(12, unit->m_y1); FreqShift_next_kk(unit, 1); } void FreqShift_next_kk(FreqShift *unit, int inNumSamples) { float *in = ZIN(0); float *out = ZOUT(0); float phasein = ZIN0(2); float freqin = ZIN0(1); float outcos, outsin; // the sample by sample output of the Hilbert float outsinosc, outsinoscHalfPi; // the samples from the oscil. int32 halfPi = (int32)(unit->m_radtoinc * (0.5 * pi)); double y1[12]; double coefs[12]; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; int32 lomask = unit->m_lomask; int32 phase = unit->m_phase; int32 freq = (int32)(unit->m_cpstoinc * freqin); int32 phaseinc = freq + (int32)(CALCSLOPE(phasein, unit->m_phasein) * unit->m_radtoinc); unit->m_phasein = phasein; // each filter's last sample for(int i = 0; i < 12; ++i) { y1[i] = unit->m_y1[i]; coefs[i] = unit->m_coefs[i]; } double ay1, ay2, ay3, ay4, ay5, ay6; double ay7, ay8, ay9, ay10, ay11, ay12; double y0_1, y0_2, y0_3, y0_4, y0_5, y0_6; double y0_7, y0_8, y0_9, y0_10, y0_11, y0_12; LOOP1(inNumSamples, float thisin = ZXP(in); HILBERT_FILTER outcos = ay6; outsin = ay12; outsinosc = lookupi1(table0, table1, phase, lomask); outsinoscHalfPi = lookupi1(table0, table1, phase + halfPi, lomask); ZXP(out) = (outcos * outsinoscHalfPi) + (outsinosc * outsin); phase += phaseinc; ) unit->m_phase = phase; for(int i = 0; i < 12; ++i) unit->m_y1[i] = zapgremlins(y1[i]); } void FreqShift_next_aa(FreqShift *unit, int inNumSamples) { float *in = ZIN(0); float *out = ZOUT(0); float *phasein = ZIN(2); float *freqin = ZIN(1); float outcos, outsin; // the sample by sample output of the Hilbert float outsinosc, outsinoscHalfPi; // the samples from the oscil. int32 halfPi = (int32)(unit->m_radtoinc * (0.5 * pi)); double y1[12]; double coefs[12]; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; int32 lomask = unit->m_lomask; int32 phase = unit->m_phase; // each filter's last sample for(int i = 0; i < 12; ++i){ y1[i] = unit->m_y1[i]; coefs[i] = unit->m_coefs[i]; } double ay1, ay2, ay3, ay4, ay5, ay6; double ay7, ay8, ay9, ay10, ay11, ay12; double y0_1, y0_2, y0_3, y0_4, y0_5, y0_6; double y0_7, y0_8, y0_9, y0_10, y0_11, y0_12; LOOP1(inNumSamples, float thisin = ZXP(in); HILBERT_FILTER outcos = ay6; outsin = ay12; int32 phaseoffset = phase + (int32)(unit->m_radtoinc * ZXP(phasein)); outsinosc = lookupi1(table0, table1, phaseoffset, lomask); outsinoscHalfPi = lookupi1(table0, table1, phaseoffset + halfPi, lomask); phase += (int32)(unit->m_cpstoinc * ZXP(freqin)); ZXP(out) = (outcos * outsinoscHalfPi) + (outsinosc * outsin); ) unit->m_phase = phase; for(int i = 0; i < 12; ++i) unit->m_y1[i] = zapgremlins(y1[i]); } void FreqShift_next_ak(FreqShift *unit, int inNumSamples) { float *in = ZIN(0); float *out = ZOUT(0); float phasein = ZIN0(2); float *freqin = ZIN(1); float outcos, outsin; // the sample by sample output of the Hilbert float outsinosc, outsinoscHalfPi; // the samples from the oscil. int32 halfPi = (int32)(unit->m_radtoinc * (0.5 * pi)); double y1[12]; double coefs[12]; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; int32 lomask = unit->m_lomask; int32 phase = unit->m_phase; float phasemod = unit->m_phasein; float phaseslope = CALCSLOPE(phasein, phasemod); // each filter's last sample for(int i = 0; i < 12; ++i) { y1[i] = unit->m_y1[i]; coefs[i] = unit->m_coefs[i]; } double ay1, ay2, ay3, ay4, ay5, ay6; double ay7, ay8, ay9, ay10, ay11, ay12; double y0_1, y0_2, y0_3, y0_4, y0_5, y0_6; double y0_7, y0_8, y0_9, y0_10, y0_11, y0_12; LOOP1(inNumSamples, float thisin = ZXP(in); HILBERT_FILTER outcos = ay6; outsin = ay12; int32 pphase = phase + (int32)(unit->m_radtoinc * phasemod); phasemod += phaseslope; outsinosc = lookupi1(table0, table1, pphase, lomask); outsinoscHalfPi = lookupi1(table0, table1, pphase + halfPi, lomask); phase += (int32)(unit->m_cpstoinc * ZXP(freqin)); ZXP(out) = (outcos * outsinoscHalfPi) + (outsinosc * outsin); ) unit->m_phase = phase; unit->m_phasein = phasein; for(int i = 0; i < 12; ++i) unit->m_y1[i] = zapgremlins(y1[i]); } void FreqShift_next_ka(FreqShift *unit, int inNumSamples) { float *in = ZIN(0); float *out = ZOUT(0); float *phasein = ZIN(2); float freqin = ZIN0(1); float outcos, outsin; // the sample by sample output of the Hilbert float outsinosc, outsinoscHalfPi; // the samples from the oscil. int32 halfPi = (int32)(unit->m_radtoinc * (0.5 * pi)); double y1[12]; double coefs[12]; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; int32 lomask = unit->m_lomask; int32 phase = unit->m_phase; int32 freq = (int32)(unit->m_cpstoinc * freqin); // each filter's last sample for(int i = 0; i < 12; ++i) { y1[i] = unit->m_y1[i]; coefs[i] = unit->m_coefs[i]; } double ay1, ay2, ay3, ay4, ay5, ay6; double ay7, ay8, ay9, ay10, ay11, ay12; double y0_1, y0_2, y0_3, y0_4, y0_5, y0_6; double y0_7, y0_8, y0_9, y0_10, y0_11, y0_12; LOOP1(inNumSamples, float thisin = ZXP(in); HILBERT_FILTER outcos = ay6; outsin = ay12; int32 phaseoffset = phase + (int32)(unit->m_radtoinc * ZXP(phasein)); outsinosc = lookupi1(table0, table1, phaseoffset, lomask); outsinoscHalfPi = lookupi1(table0, table1, phaseoffset + halfPi, lomask); phase += freq; ZXP(out) = (outcos * outsinoscHalfPi) + (outsinosc * outsin); ) unit->m_phase = phase; for(int i = 0; i < 12; ++i) unit->m_y1[i] = zapgremlins(y1[i]); } /** "MoogFF" - Moog VCF digital implementation. As described in the paper entitled "Preserving the Digital Structure of the Moog VCF" by Federico Fontana appeared in the Proc. ICMC07, Copenhagen, 25-31 August 2007 Original Java code Copyright F. Fontana - August 2007 federico.fontana@univr.it Ported to C++ for SuperCollider by Dan Stowell - August 2007 http://www.mcld.co.uk/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ ////////////////////////////////////////////////////////////////// void MoogFF_Ctor(MoogFF* unit) { SETCALC(MoogFF_next); // initialize the unit generator state variables. unit->m_freq = uninitializedControl; unit->m_k = IN0(2); unit->m_s1 = 0.f; unit->m_s2 = 0.f; unit->m_s3 = 0.f; unit->m_s4 = 0.f; // calculate one sample of output. MoogFF_next(unit, 1); } void MoogFF_next(MoogFF *unit, int inNumSamples) { float k = IN0(2); k = sc_clip(k, 0.f, 4.f); // Load state from the struct double s1 = unit->m_s1; double s2 = unit->m_s2; double s3 = unit->m_s3; double s4 = unit->m_s4; // Reset filter state if requested if(IN0(3)>0) s1 = s2 = s3 = s4 = 0.f; double a1 = unit->m_a1, b0 = unit->m_b0; // Filter coefficient parameters // Update filter coefficients, but only if freq changes since it involves some expensive operations float freqIn = IN0(1); if(unit->m_freq != freqIn) { //Print("Updated freq to %g\n", freq); double T = SAMPLEDUR; double wcD = 2.0 * tan ( T * PI * freqIn ) * SAMPLERATE; if(wcD<0) wcD = 0; // Protect against negative cutoff freq double TwcD = T*wcD; b0 = TwcD/(TwcD + 2.); a1 = (TwcD - 2.)/(TwcD + 2.); unit->m_freq = freqIn; unit->m_b0 = b0; unit->m_a1 = a1; } float *out = ZOUT(0); float *in = ZIN(0); if (unit->m_k == k) { LOOP1(inNumSamples, // compute loop values double o = s4 + b0*(s3 + b0*(s2 + b0*s1)); double ins = ZXP(in); double outs = (b0*b0*b0*b0*ins + o) * sc_reciprocal(1.0 + b0*b0*b0*b0*k); ZXP(out) = outs; double u = ins - k*outs; // update 1st order filter states double past = u; double future = b0*past + s1; s1 = b0*past - a1*future; past = future; future = b0*past + s2; s2 = b0*past - a1*future; past = future; future = b0*past + s3; s3 = b0*past - a1*future; s4 = b0*future - a1*outs; ) } else { float new_k = k; float old_k = unit->m_k; float slope_k = CALCSLOPE(new_k, old_k); k = old_k; LOOP1(inNumSamples, // compute loop values double o = s4 + b0*(s3 + b0*(s2 + b0*s1)); double ins = ZXP(in); double outs = (b0*b0*b0*b0*ins + o) * sc_reciprocal(1.0 + b0*b0*b0*b0*k); ZXP(out) = outs; double u = ins - k*outs; // update 1st order filter states double past = u; double future = b0*past + s1; s1 = b0*past - a1*future; past = future; future = b0*past + s2; s2 = b0*past - a1*future; past = future; future = b0*past + s3; s3 = b0*past - a1*future; s4 = b0*future - a1*outs; k += slope_k; ); unit->m_k = new_k; } // Store state unit->m_s1 = zapgremlins(s1); unit->m_s2 = zapgremlins(s2); unit->m_s3 = zapgremlins(s3); unit->m_s4 = zapgremlins(s4); } /* BEQSuite */ static void inline BPerformFilterLoop(const Unit * unit, float * out, const float * in, double & y1, double & y2, double a0, double a1, double a2, double b1, double b2) { LOOP(unit->mRate->mFilterLoops, double in0 = ZXP(in); double in1 = ZXP(in); double in2 = ZXP(in); double y0 = in0 + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = in1 + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = in2 + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, double y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; ); } static void inline BPerformFilterLoop(const Unit * unit, float * out, const float * in, double & y1, double & y2, double a0, double a1, double a2, double b1, double b2, double a0slope, double a1slope, double a2slope, double b1slope, double b2slope) { LOOP(unit->mRate->mFilterLoops, double in0 = ZXP(in); double in1 = ZXP(in); double in2 = ZXP(in); double y0 = in0 + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = in1 + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = in2 + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; a0 += a0slope; a1 += a1slope; a2 += a2slope; b1 += b1slope; b2 += b2slope; ); LOOP(unit->mRate->mFilterRemain, double y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; ); } struct BLowPass : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_rq; }; extern "C" { void BLowPass_next_ii(BLowPass *unit, int inNumSamples); void BLowPass_next_kk(BLowPass *unit, int inNumSamples); void BLowPass_next_aa(BLowPass *unit, int inNumSamples); void BLowPass_Ctor(BLowPass* unit); } void BLowPass_Ctor(BLowPass* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate)) SETCALC(BLowPass_next_aa); else { if ((INRATE(1) == calc_ScalarRate) && (INRATE(2) == calc_ScalarRate)) SETCALC(BLowPass_next_ii); else SETCALC(BLowPass_next_kk); } float rq = unit->m_rq = ZIN0(2); float freq = unit->m_freq = ZIN0(1); double w0 = twopi * (double)freq * SAMPLEDUR; double cosw0 = cos(w0); double i = 1. - cosw0; double alpha = sin(w0) * 0.5 * (double)rq; double b0rz = 1. / (1. + alpha); double a0 = unit->m_a0 = i * 0.5 * b0rz; unit->m_a1 = i * b0rz; unit->m_a2 = a0; unit->m_b1 = cosw0 * 2. * b0rz; unit->m_b2 = (1. - alpha) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BLowPass_next_kk(unit, 1); POP_LOOPVALS } void BLowPass_next_aa(BLowPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *rq = ZIN(2); double a0, a1, a2, b1, b2, w0, cosw0, i, alpha, b0rz; double y0, y1, y2; float nextfreq, nextrq; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextrq = ZXP(rq); if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq)) { w0 = twopi * (double)nextfreq * SAMPLEDUR; cosw0 = cos(w0); i = 1. - cosw0; alpha = sin(w0) * 0.5 * (double)nextrq; b0rz = 1. / (1. + alpha); a0 = i * 0.5 * b0rz; a1 = i * b0rz; a2 = a0; b1 = cosw0 * 2. * b0rz; b2 = (1. - alpha) * -b0rz; unit->m_freq = nextfreq; unit->m_rq = nextrq; } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = ZXP(freq); unit->m_rq = ZXP(rq); ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BLowPass_next_kk(BLowPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextrq = ZIN0(2); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq)){ double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2, next_w0, next_cosw0, next_i, next_alpha, next_b0rz; next_w0 = twopi * (double)nextfreq * SAMPLEDUR; next_cosw0 = cos(next_w0); next_i = 1. - next_cosw0; next_alpha = sin(next_w0) * 0.5 * (double)nextrq; next_b0rz = 1. / (1. + next_alpha); next_a0 = next_i * 0.5 * next_b0rz; next_a1 = next_i * next_b0rz; next_a2 = next_a0; next_b1 = next_cosw0 * 2. * next_b0rz; next_b2 = ((1. - next_alpha) * -next_b0rz); a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; unit->m_freq = nextfreq; unit->m_rq = nextrq; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BLowPass_next_ii(BLowPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } struct BHiPass : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_rq; }; extern "C" { void BHiPass_next_ii(BHiPass *unit, int inNumSamples); void BHiPass_next_kk(BHiPass *unit, int inNumSamples); void BHiPass_next_aa(BHiPass *unit, int inNumSamples); void BHiPass_Ctor(BHiPass* unit); } void BHiPass_Ctor(BHiPass* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate)) SETCALC(BHiPass_next_aa); else { if ((INRATE(1) == calc_ScalarRate) && (INRATE(2) == calc_ScalarRate)) SETCALC(BHiPass_next_ii); else SETCALC(BHiPass_next_kk); } float freq = unit->m_freq = ZIN0(1); float rq = unit->m_rq = ZIN0(2); double w0 = twopi * (double)freq * SAMPLEDUR; double cosw0 = cos(w0); double i = 1. + cosw0; double alpha = sin(w0) * 0.5 * (double)rq; double b0rz = 1. / (1. + alpha); double a0 = unit->m_a0 = i * 0.5 * b0rz; unit->m_a1 = -i * b0rz; unit->m_a2 = a0; unit->m_b1 = cosw0 * 2. * b0rz; unit->m_b2 = (1. - alpha) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BHiPass_next_kk(unit, 1); POP_LOOPVALS } void BHiPass_next_aa(BHiPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *rq = ZIN(2); double a0, a1, a2, b1, b2, w0, cosw0, i, alpha, b0rz; double y0, y1, y2; float nextfreq, nextrq; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextrq = ZXP(rq); if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq)) { w0 = twopi * (double)nextfreq * SAMPLEDUR; cosw0 = cos(w0); i = 1. + cosw0; alpha = sin(w0) * 0.5 * (double)nextrq; b0rz = 1. / (1. + alpha); a0 = i * 0.5 * b0rz; a1 = -i * b0rz; a2 = a0; b1 = cosw0 * 2. * b0rz; b2 = (1. - alpha) * -b0rz; unit->m_freq = nextfreq; unit->m_rq = nextrq; } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BHiPass_next_kk(BHiPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextrq = ZIN0(2); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq)){ double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2, next_w0, next_cosw0, next_i, next_alpha, next_b0rz; next_w0 = twopi * (double)nextfreq * SAMPLEDUR; next_cosw0 = cos(next_w0); next_i = 1. + next_cosw0; next_alpha = sin(next_w0) * 0.5 * (double)nextrq; next_b0rz = 1. / (1. + next_alpha); next_a0 = next_i * 0.5 * next_b0rz; next_a1 = -next_i * next_b0rz; next_a2 = next_a0; next_b1 = next_cosw0 * 2. * next_b0rz; next_b2 = (1. - next_alpha) * -next_b0rz; a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta0, a0); a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta1, a1); a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta2, a2); b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb1, b1); b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb2, b2); unit->m_freq = nextfreq; unit->m_rq = nextrq; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BHiPass_next_ii(BHiPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } /* BBandPass */ struct BBandPass : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_bw; }; extern "C" { void BBandPass_next_kk(BBandPass *unit, int inNumSamples); void BBandPass_next_aa(BBandPass *unit, int inNumSamples); void BBandPass_Ctor(BBandPass* unit); } void BBandPass_Ctor(BBandPass* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate)) SETCALC(BBandPass_next_aa); else SETCALC(BBandPass_next_kk); float freq = unit->m_freq = ZIN0(1); float bw = unit->m_bw = ZIN0(2); double w0 = twopi * (double)freq * SAMPLEDUR; double sinw0 = sin(w0); double alpha = sinw0 * (sinh((0.34657359027997 * (double)bw * w0) / sinw0)); double b0rz = 1. / (1. + alpha); double a0 = unit->m_a0 = alpha * b0rz; unit->m_a1 = 0.0f; unit->m_a2 = -a0; unit->m_b1 = cos(w0) * 2. * b0rz; unit->m_b2 = (1. - alpha) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BBandPass_next_kk(unit, 1); POP_LOOPVALS } void BBandPass_next_aa(BBandPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *bw = ZIN(2); double a0, a1, a2, b1, b2, w0, sinw0, alpha, b0rz; double y0, y1, y2; float nextfreq, nextbw; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextbw = ZXP(bw); if ((unit->m_freq != nextfreq) || (unit->m_bw != nextbw)) { w0 = twopi * (double)nextfreq * SAMPLEDUR; sinw0 = sin(w0); alpha = sinw0 * (sinh((0.34657359027997 * (double)nextbw * w0) / sinw0)); b0rz = 1. / (1. + alpha); a0 = alpha * b0rz; a1 = 0.0f; a2 = -a0; b1 = cos(w0) * 2. * b0rz; b2 = (1. - alpha) * -b0rz; unit->m_freq = ZXP(freq); unit->m_bw = ZXP(bw); } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = nextfreq; unit->m_bw = nextbw; ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BBandPass_next_kk(BBandPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextbw = ZIN0(2); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_bw != nextbw)) { double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2, next_w0, next_alpha, next_b0rz; next_w0 = twopi * (double)nextfreq * SAMPLEDUR; next_alpha = sin(next_w0) * (sinh((0.34657359027997 * (double)nextbw * next_w0) / sin(next_w0))); next_b0rz = 1. / (1. + next_alpha); next_a0 = next_alpha * next_b0rz; next_a1 = 0.; next_a2 = -next_a0; next_b1 = cos(next_w0) * 2. * next_b0rz; next_b2 = ((1. - next_alpha) * -next_b0rz); a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta0, a0); a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta1, a1); a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta2, a2); b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb1, b1); b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb2, b2); unit->m_freq = nextfreq; unit->m_bw = nextbw; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } /* BBandStop */ struct BBandStop : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_bw; }; extern "C" { void BBandStop_next_kk(BBandStop *unit, int inNumSamples); void BBandStop_next_aa(BBandStop *unit, int inNumSamples); void BBandStop_Ctor(BBandStop* unit); } void BBandStop_Ctor(BBandStop* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate)) SETCALC(BBandStop_next_aa); else SETCALC(BBandStop_next_kk); float freq = unit->m_freq = ZIN0(1); float bw = unit->m_bw = ZIN0(2); double w0 = twopi * (double)freq * SAMPLEDUR; double sinw0 = sin(w0); double alpha = sinw0 * (sinh((0.34657359027997 * (double)bw * w0) / sinw0)); double b0rz = 1. / (1. + alpha); double b1 = unit->m_b1 = 2. * b0rz * cos(w0); unit->m_a0 = b0rz; unit->m_a1 = -b1; unit->m_a2 = b0rz; unit->m_b2 = (1. - alpha) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BBandStop_next_kk(unit, 1); POP_LOOPVALS } void BBandStop_next_aa(BBandStop *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *bw = ZIN(2); double a0, a1, a2, b1, b2, w0, sinw0, alpha, b0rz; double y0, y1, y2; float nextfreq, nextbw; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextbw = ZXP(bw); if ((unit->m_freq != nextfreq) || (unit->m_bw != nextbw)) { w0 = twopi * (double)nextfreq * SAMPLEDUR; sinw0 = sin(w0); alpha = sinw0 * (sinh((0.34657359027997 * (double)nextbw * w0) / sinw0)); b0rz = 1. / (1. + alpha); b1 = 2. * b0rz * cos(w0); a0 = b0rz; a1 = -b1; a2 = b0rz; b2 = (1. - alpha) * -b0rz; unit->m_freq = ZXP(freq); unit->m_bw = ZXP(bw); } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = nextfreq; unit->m_bw = nextbw; ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BBandStop_next_kk(BBandStop *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextbw = ZIN0(2); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_bw != nextbw)){ double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2, next_w0, next_alpha, next_b0rz; next_w0 = twopi * (double)nextfreq * SAMPLEDUR; next_alpha = sin(next_w0) * (sinh((0.34657359027997 * (double)nextbw * next_w0) / sin(next_w0))); next_b0rz = 1. / (1. + next_alpha); next_b1 = cos(next_w0) * 2. * next_b0rz; next_a0 = next_b0rz; next_a1 = -next_b1; next_a2 = next_b0rz; next_b2 = ((1. - next_alpha) * -next_b0rz); a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta0, a0); a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta1, a1); a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta2, a2); b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb1, b1); b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb2, b2); unit->m_freq = nextfreq; unit->m_bw = nextbw; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } /* BPeakEQ */ struct BPeakEQ : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_rq, m_db; }; extern "C" { void BPeakEQ_next_kkk(BPeakEQ *unit, int inNumSamples); void BPeakEQ_next_aaa(BPeakEQ *unit, int inNumSamples); void BPeakEQ_Ctor(BPeakEQ* unit); } void BPeakEQ_Ctor(BPeakEQ* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate) && (INRATE(3) == calc_FullRate)) SETCALC(BPeakEQ_next_aaa); else SETCALC(BPeakEQ_next_kkk); float freq = unit->m_freq = ZIN0(1); float rq = unit->m_rq = ZIN0(2); float db = unit->m_db = ZIN0(3); double a = pow(10., (double)db * 0.025); double w0 = twopi * (double)freq * SAMPLEDUR; double alpha = sin(w0) * 0.5 * (double)rq; double b0rz = 1. / (1. + (alpha / a)); double b1 = unit->m_b1 = 2. * b0rz * cos(w0); unit->m_a0 = (1. + (alpha * a)) * b0rz; unit->m_a1 = -b1; unit->m_a2 = (1. - (alpha * a)) * b0rz; unit->m_b2 = (1. - (alpha / a)) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BPeakEQ_next_kkk(unit, 1); POP_LOOPVALS } void BPeakEQ_next_aaa(BPeakEQ *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *rq = ZIN(2); float *db = ZIN(3); double a0, a1, a2, b1, b2, a, w0, alpha, b0rz; double y0, y1, y2; float nextfreq, nextrq, nextdb; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextrq = ZXP(rq); nextdb = ZXP(db); if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq) || (unit->m_db != nextdb)) { a = pow(10., (double)nextdb * 0.025); w0 = twopi * (double)nextfreq * SAMPLEDUR; alpha = sin(w0) * 0.5 * (double)nextrq; b0rz = 1. / (1. + (alpha / a)); b1 = 2. * b0rz * cos(w0); a0 = (1. + (alpha * a)) * b0rz; a1 = -b1; a2 = (1. - (alpha * a)) * b0rz; b2 = (1. - (alpha / a)) * -b0rz; unit->m_freq = nextfreq; unit->m_rq = nextrq; unit->m_db = nextdb; } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = ZXP(freq); unit->m_rq = ZXP(rq); unit->m_db = ZXP(db); ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BPeakEQ_next_kkk(BPeakEQ *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextrq = ZIN0(2); float nextdb = ZIN0(3); double a0, a1, a2, b1, b2, a, w0, alpha, b0rz; double y1, y2; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq) || (unit->m_db != nextdb)) { double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2; a = pow(10., (double)nextdb * 0.025); w0 = twopi * (double)nextfreq * SAMPLEDUR; alpha = sin(w0) * 0.5 * (double)nextrq; b0rz = 1. / (1. + (alpha / a)); next_b1 = 2. * b0rz * cos(w0); next_a0 = (1. + (alpha * a)) * b0rz; next_a1 = -next_b1; next_a2 = (1. - (alpha * a)) * b0rz; next_b2 = (1. - (alpha / a)) * -b0rz; a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta0, a0); a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta1, a1); a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta2, a2); b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb1, b1); b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb2, b2); unit->m_freq = nextfreq; unit->m_db = nextdb; unit->m_rq = nextrq; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } /* BAllPass */ struct BAllPass : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_rq; }; extern "C" { void BAllPass_next_kk(BAllPass *unit, int inNumSamples); void BAllPass_next_aa(BAllPass *unit, int inNumSamples); void BAllPass_Ctor(BAllPass* unit); } void BAllPass_Ctor(BAllPass* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate)) SETCALC(BAllPass_next_aa); else SETCALC(BAllPass_next_kk); float freq = unit->m_freq = ZIN0(1); float rq = unit->m_rq = ZIN0(2); double w0 = twopi * (double)freq * SAMPLEDUR; double alpha = sin(w0) * 0.5 * (double)rq; double b0rz = 1. / (1. + alpha); double a0 = unit->m_a0 = (1. - alpha) * b0rz; double b1 = unit->m_b1 = 2. * b0rz * cos(w0); unit->m_a1 = -b1; unit->m_a2 = 1.; unit->m_b2 = -a0; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BAllPass_next_kk(unit, 1); POP_LOOPVALS } void BAllPass_next_aa(BAllPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *rq = ZIN(2); double a0, a1, a2, b1, b2, w0, alpha, b0rz; double y0, y1, y2; float nextfreq, nextrq; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextrq = ZXP(rq); if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq)) { w0 = twopi * (double)nextfreq * SAMPLEDUR; alpha = sin(w0) * (double)nextrq * 0.5; b0rz = 1. / (1. + alpha); b1 = 2. * b0rz * cos(w0); a0 = (1. - alpha) * b0rz; a1 = -b1; a2 = 1.; b2 = -a0; unit->m_freq = nextfreq; unit->m_rq = nextrq; } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = ZXP(freq); unit->m_rq = ZXP(rq); ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BAllPass_next_kk(BAllPass *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextrq = ZIN0(2); double a0, a1, a2, b1, b2; double y1 = unit->m_y1; double y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_rq != nextrq)) { double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2, next_w0, next_alpha, next_b0rz; next_w0 = twopi * (double)nextfreq * SAMPLEDUR; next_alpha = sin(next_w0) * 0.5 * (double)nextrq; next_b0rz = 1. / (1. + next_alpha); next_b1 = cos(next_w0) * 2. * next_b0rz; next_a0 = (1. - next_alpha) * next_b0rz; next_a1 = -next_b1; next_a2 = 1.; next_b2 = -next_a0; a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; unit->m_freq = nextfreq; unit->m_rq = nextrq; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } /* BLowShelf */ struct BLowShelf : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_rs, m_db; }; extern "C" { void BLowShelf_next_kkk(BLowShelf *unit, int inNumSamples); void BLowShelf_next_aaa(BLowShelf *unit, int inNumSamples); void BLowShelf_Ctor(BLowShelf* unit); } void BLowShelf_Ctor(BLowShelf* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate) && (INRATE(3) == calc_FullRate)) SETCALC(BLowShelf_next_aaa); else SETCALC(BLowShelf_next_kkk); float freq = unit->m_freq = ZIN0(1); float rs = unit->m_rs = ZIN0(2); float db = unit->m_db = ZIN0(3); double a = pow(10., (double)db * 0.025); double w0 = twopi * (double)freq * SAMPLEDUR; double cosw0 = cos(w0); double sinw0 = sin(w0); double alpha = sinw0 * 0.5 * sqrt((a + (1./a)) * ((double)rs - 1.) + 2.); double i = (a + 1.) * cosw0; double j = (a - 1.) * cosw0; double k = 2. * sqrt(a) * alpha; double b0rz = 1. / ((a + 1.) + j + k); unit->m_a0 = a * (( a + 1.) - j + k) * b0rz; unit->m_a1 = 2. * a * ((a - 1.) - i) * b0rz; unit->m_a2 = a * ((a + 1.) - j - k) * b0rz; unit->m_b1 = 2. * ((a - 1.) + i) * b0rz; unit->m_b2 = ((a + 1.) + j - k) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BLowShelf_next_kkk(unit, 1); POP_LOOPVALS } void BLowShelf_next_aaa(BLowShelf *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *rs = ZIN(2); float *db = ZIN(3); double a0, a1, a2, b1, b2, a, w0, cosw0, sinw0, alpha, i, j, k, b0rz; double y0, y1, y2; float nextfreq, nextrs, nextdb; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextrs = ZXP(rs); nextdb = ZXP(db); if ((unit->m_freq != nextfreq) || (unit->m_rs != nextrs) || (unit->m_db != nextdb)) { a = pow(10., (double)nextdb * 0.025); w0 = twopi * (double)nextfreq * SAMPLEDUR; sinw0 = sin(w0); cosw0 = cos(w0); alpha = sinw0 * 0.5 * sqrt((a + (1./a)) * ((double)nextrs - 1.) + 2.); i = (a + 1.) * cosw0; j = (a - 1.) * cosw0; k = 2. * sqrt(a) * alpha; b0rz = 1. / ((a + 1.) + j + k); a0 = a * (( a + 1.) - j + k) * b0rz; a1 = 2. * a * ((a - 1.) - i) * b0rz; a2 = a * ((a + 1.) - j - k) * b0rz; b1 = 2. * ((a - 1.) + i) * b0rz; b2 = ((a + 1.) + j - k) * -b0rz; unit->m_freq = nextfreq; unit->m_rs = nextrs; unit->m_db = nextdb; } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = ZXP(freq); unit->m_rs = ZXP(rs); unit->m_db = ZXP(db); ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BLowShelf_next_kkk(BLowShelf *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextrs = ZIN0(2); float nextdb = ZIN0(3); double a0, a1, a2, b1, b2, a, w0, cosw0, sinw0, alpha, i, j, k, b0rz; double y1, y2; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_rs != nextrs) || (unit->m_db != nextdb)) { double a0slope, a1slope, a2slope, b1slope, b2slope, nexta0, nexta1, nexta2, nextb1, nextb2; a = pow(10., (double)nextdb * 0.025); w0 = twopi * (double)nextfreq * SAMPLEDUR; sinw0 = sin(w0); cosw0 = cos(w0); alpha = sinw0 * 0.5 * sqrt((a + (1./a)) * ((double)nextrs - 1.) + 2.); i = (a + 1.) * cosw0; j = (a - 1.) * cosw0; k = 2. * sqrt(a) * alpha; b0rz = 1. / ((a + 1.) + j + k); nexta0 = a * (( a + 1.) - j + k) * b0rz; nexta1 = 2. * a * ((a - 1.) - i) * b0rz; nexta2 = a * ((a + 1.) - j - k) * b0rz; nextb1 = 2. * ((a - 1.) + i) * b0rz; nextb2 = ((a + 1.) + j - k) * -b0rz; a0slope = (nexta0 - a0) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta0, a0); a1slope = (nexta1 - a1) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta1, a1); a2slope = (nexta2 - a2) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta2, a2); b1slope = (nextb1 - b1) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb1, b1); b2slope = (nextb2 - b2) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb2, b2); unit->m_freq = nextfreq; unit->m_db = nextdb; unit->m_rs = nextrs; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = nexta0; unit->m_a1 = nexta1; unit->m_a2 = nexta2; unit->m_b1 = nextb1; unit->m_b2 = nextb2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } /* BHiShelf */ struct BHiShelf : public Unit { double m_y1, m_y2, m_a0, m_a1, m_a2, m_b1, m_b2; float m_freq, m_rs, m_db; }; extern "C" { void BHiShelf_next_kkk(BHiShelf *unit, int inNumSamples); void BHiShelf_next_aaa(BHiShelf *unit, int inNumSamples); void BHiShelf_Ctor(BHiShelf* unit); } void BHiShelf_Ctor(BHiShelf* unit) { if ((INRATE(1) == calc_FullRate) && (INRATE(2) == calc_FullRate) && (INRATE(3) == calc_FullRate)) SETCALC(BHiShelf_next_aaa); else SETCALC(BHiShelf_next_kkk); float freq = unit->m_freq = ZIN0(1); float rs = unit->m_rs = ZIN0(2); float db = unit->m_db = ZIN0(3); double a = pow(10., (double)db * 0.025); double w0 = twopi * (double)freq * SAMPLEDUR; double cosw0 = cos(w0); double sinw0 = sin(w0); double alpha = sinw0 * 0.5 * sqrt((a + (1./a)) * ((double)rs - 1.) + 2.); double i = (a + 1.) * cosw0; double j = (a - 1.) * cosw0; double k = 2. * sqrt(a) * alpha; double b0rz = 1. / ((a + 1.) - j + k); unit->m_a0 = a * (( a + 1.) + j + k) * b0rz; unit->m_a1 = -2. * a * ((a - 1.) + i) * b0rz; unit->m_a2 = a * ((a + 1.) + j - k) * b0rz; unit->m_b1 = -2. * ((a - 1.) - i) * b0rz; unit->m_b2 = ((a + 1.) - j - k) * -b0rz; unit->m_y1 = 0.; unit->m_y2 = 0.; PUSH_LOOPVALS BHiShelf_next_kkk(unit, 1); POP_LOOPVALS } void BHiShelf_next_aaa(BHiShelf *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *freq = ZIN(1); float *rs = ZIN(2); float *db = ZIN(3); double a0, a1, a2, b1, b2, a, w0, cosw0, sinw0, alpha, i, j, k, b0rz; double y0, y1, y2; float nextfreq, nextrs, nextdb; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; LOOP(unit->mRate->mFilterLoops, nextfreq = ZXP(freq); nextrs = ZXP(rs); nextdb = ZXP(db); if ((unit->m_freq != nextfreq) || (unit->m_rs != nextrs) || (unit->m_db != nextdb)) { a = pow(10., (double)nextdb * 0.025); w0 = twopi * (double)nextfreq * SAMPLEDUR; sinw0 = sin(w0); cosw0 = cos(w0); alpha = sinw0 * 0.5 * sqrt((a + (1./a)) * ((double)nextrs - 1.) + 2.); i = (a + 1.) * cosw0; j = (a - 1.) * cosw0; k = 2. * sqrt(a) * alpha; b0rz = 1. / ((a + 1.) - j + k); a0 = a * (( a + 1.) + j + k) * b0rz; a1 = -2. * a * ((a - 1.) + i) * b0rz; a2 = a * ((a + 1.) + j - k) * b0rz; b1 = -2. * ((a - 1.) - i) * b0rz; b2 = ((a + 1.) - j - k) * -b0rz; unit->m_freq = ZXP(freq); unit->m_rs = ZXP(rs); unit->m_db = ZXP(db); } y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = ZXP(in) + b1 * y0 + b2 * y1; ZXP(out) = a0 * y2 + a1 * y0 + a2 * y1; y1 = ZXP(in) + b1 * y2 + b2 * y0; ZXP(out) = a0 * y1 + a1 * y2 + a2 * y0; ); LOOP(unit->mRate->mFilterRemain, y0 = ZXP(in) + b1 * y1 + b2 * y2; ZXP(out) = a0 * y0 + a1 * y1 + a2 * y2; y2 = y1; y1 = y0; unit->m_freq = ZXP(freq); unit->m_rs = ZXP(rs); unit->m_db = ZXP(db); ); unit->m_a0 = a0; unit->m_a1 = a1; unit->m_a2 = a2; unit->m_b1 = b1; unit->m_b2 = b2; unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } void BHiShelf_next_kkk(BHiShelf *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float nextfreq = ZIN0(1); float nextrs = ZIN0(2); float nextdb = ZIN0(3); double a0, a1, a2, b1, b2, a, w0, cosw0, sinw0, alpha, i, j, k, b0rz; double y1, y2; y1 = unit->m_y1; y2 = unit->m_y2; a0 = unit->m_a0; a1 = unit->m_a1; a2 = unit->m_a2; b1 = unit->m_b1; b2 = unit->m_b2; if ((unit->m_freq != nextfreq) || (unit->m_rs != nextrs) || (unit->m_db != nextdb)) { double a0slope, a1slope, a2slope, b1slope, b2slope; double next_a0, next_a1, next_a2, next_b1, next_b2; a = pow(10., (double)nextdb * 0.025); w0 = twopi * (double)nextfreq * SAMPLEDUR; sinw0 = sin(w0); cosw0 = cos(w0); alpha = sinw0 * 0.5 * sqrt((a + (1./a)) * ((double)nextrs - 1.) + 2.); i = (a + 1.) * cosw0; j = (a - 1.) * cosw0; k = 2. * sqrt(a) * alpha; b0rz = 1. / ((a + 1.) - j + k); next_a0 = a * (( a + 1.) + j + k) * b0rz; next_a1 = -2. * a * ((a - 1.) + i) * b0rz; next_a2 = a * ((a + 1.) + j - k) * b0rz; next_b1 = -2. * ((a - 1.) - i) * b0rz; next_b2 = ((a + 1.) - j - k) * -b0rz; a0slope = (next_a0 - a0) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta0, a0); a1slope = (next_a1 - a1) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta1, a1); a2slope = (next_a2 - a2) * unit->mRate->mFilterSlope; //CALCSLOPE(nexta2, a2); b1slope = (next_b1 - b1) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb1, b1); b2slope = (next_b2 - b2) * unit->mRate->mFilterSlope; //CALCSLOPE(nextb2, b2); unit->m_freq = nextfreq; unit->m_db = nextdb; unit->m_rs = nextrs; BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2, a0slope, a1slope, a2slope, b1slope, b2slope); unit->m_a0 = next_a0; unit->m_a1 = next_a1; unit->m_a2 = next_a2; unit->m_b1 = next_b1; unit->m_b2 = next_b2; } else BPerformFilterLoop(unit, out, in, y1, y2, a0, a1, a2, b1, b2); unit->m_y1 = zapgremlins(y1); unit->m_y2 = zapgremlins(y2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(Filter) { ft = inTable; DefineSimpleUnit(Ramp); DefineSimpleUnit(Lag); DefineSimpleUnit(Lag2); DefineSimpleUnit(Lag3); DefineSimpleUnit(LagUD); DefineSimpleUnit(Lag2UD); DefineSimpleUnit(Lag3UD); DefineSimpleUnit(VarLag); DefineSimpleUnit(OnePole); DefineSimpleUnit(OneZero); DefineSimpleUnit(TwoPole); DefineSimpleUnit(TwoZero); DefineSimpleUnit(Decay); DefineSimpleUnit(Decay2); DefineSimpleUnit(Flip); DefineSimpleUnit(Delay1); DefineSimpleUnit(Delay2); DefineSimpleUnit(Integrator); DefineSimpleUnit(LeakDC); DefineSimpleUnit(LPZ1); DefineSimpleUnit(HPZ1); DefineSimpleUnit(LPZ2); DefineSimpleUnit(HPZ2); DefineSimpleUnit(BPZ2); DefineSimpleUnit(BRZ2); DefineSimpleUnit(APF); DefineSimpleUnit(LPF); DefineSimpleUnit(HPF); DefineSimpleUnit(BPF); DefineSimpleUnit(BRF); DefineSimpleUnit(RLPF); DefineSimpleUnit(RHPF); DefineSimpleUnit(Slew); DefineSimpleUnit(Slope); DefineSimpleUnit(MidEQ); DefineSimpleUnit(Median); DefineSimpleUnit(Resonz); DefineSimpleUnit(Ringz); DefineSimpleUnit(Formlet); DefineSimpleUnit(FOS); DefineSimpleUnit(SOS); DefineSimpleUnit(Compander); DefineDtorUnit(Limiter); DefineDtorUnit(Normalizer); DefineSimpleUnit(Amplitude); DefineSimpleUnit(DetectSilence); DefineSimpleUnit(Hilbert); DefineSimpleUnit(FreqShift); DefineSimpleUnit(MoogFF); /* BEQSuite UGens */ DefineSimpleUnit(BLowPass); DefineSimpleUnit(BHiPass); DefineSimpleUnit(BBandPass); DefineSimpleUnit(BBandStop); DefineSimpleUnit(BPeakEQ); DefineSimpleUnit(BAllPass); DefineSimpleUnit(BLowShelf); DefineSimpleUnit(BHiShelf); } ////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/plugins/GendynUGens.cpp000644 000765 000024 00000043603 12766171724 023561 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //Gendyn UGens implemented by Nick Collins #include "SC_PlugIn.h" static InterfaceTable *ft; struct Gendy1 : public Unit // Iannis Xenakis/Marie-Helene Serra GENDYN simulation { double mPhase; float mFreqMul, mAmp, mNextAmp, mSpeed, mDur; int mMemorySize, mIndex; float* mMemoryAmp; //could hard code as 12 float* mMemoryDur; }; //following Hoffmann paper from CMJ- primary and secondary random walks struct Gendy2 : public Unit { double mPhase; float mFreqMul, mAmp, mNextAmp, mSpeed, mDur; int mMemorySize, mIndex; float* mMemoryAmp; float* mMemoryAmpStep; float* mMemoryDur; float* mMemoryDurStep; }; //Random walks as Gendy1 but works out all breakpoints per cycle and normalises time intervals to desired frequency struct Gendy3 : public Unit { double mPhase, mNextPhase, mLastPhase; float mSpeed, mFreqMul; float mAmp, mNextAmp, mInterpMult; int mMemorySize, mIndex; float* mMemoryAmp; float* mMemoryDur; double* mPhaseList; float* mAmpList; }; extern "C" { void Gendy1_next_k(Gendy1 *unit, int inNumSamples); void Gendy1_Ctor(Gendy1* unit); void Gendy1_Dtor(Gendy1* unit); void Gendy2_next_k(Gendy2 *unit, int inNumSamples); void Gendy2_Ctor(Gendy2* unit); void Gendy2_Dtor(Gendy2* unit); void Gendy3_next_k(Gendy3 *unit, int inNumSamples); void Gendy3_Ctor(Gendy3* unit); void Gendy3_Dtor(Gendy3* unit); } void Gendy1_Ctor( Gendy1* unit ) { SETCALC(Gendy1_next_k); unit->mFreqMul = unit->mRate->mSampleDur; unit->mPhase = 1.0; //should immediately decide on new target unit->mAmp = 0.0f; unit->mNextAmp = 0.0f; unit->mSpeed = 100.f; unit->mMemorySize = (int) ZIN0(8); //default is 12 //printf("memsize %d %f", unit->mMemorySize, ZIN0(8)); if(unit->mMemorySize<1) unit->mMemorySize = 1; unit->mIndex = 0; unit->mMemoryAmp = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); unit->mMemoryDur = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); RGen& rgen = *unit->mParent->mRGen; //initialise to zeroes and separations for(int i=0; imMemorySize;++i) { unit->mMemoryAmp[i] = 2*rgen.frand() - 1.0f; unit->mMemoryDur[i] = rgen.frand(); } // compute one sample of output to avoid sending garbage memory downstream to other Ctor functions // first sample of the _next output will be the current amplitude (which is 0) OUT0(0) = 0.0f; } void Gendy1_Dtor(Gendy1 *unit) { RTFree(unit->mWorld, unit->mMemoryAmp); RTFree(unit->mWorld, unit->mMemoryDur); } //called once per period so OK to work out constants in here static float Gendyn_distribution( int which, float a, float f) { float temp, c; if(a>1.f) a = 1.f; //a must be in range 0 to 1 if(a<0.0001f) a = 0.0001f; //for safety with some distributions, don't want divide by zero errors switch (which) { case 0: //LINEAR //linear break; case 1: //CAUCHY //X has a*tan((z-0.5)*pi) //I went back to first principles of the Cauchy distribution and re-integrated with a //normalisation constant //choice of 10 here is such that f=0.95 gives about 0.35 for temp, could go with 2 to make it finer c = atan(10*a); //PERHAPS CHANGE TO a=1/a; //incorrect- missed out divisor of pi in norm temp= a*tan(c*(2*pi*f - 1)); temp = (1.f/a)*tan(c*(2.f*f - 1.f)); //Cauchy distribution, C is precalculated //printf("cauchy f %f c %f temp %f out %f \n",f, c, temp, temp/10); return temp*0.1f; //(temp+100)/200; case 2: //LOGIST (ic) //X has -(log((1-z)/z)+b)/a which is not very usable as is c = 0.5f+(0.499f*a); //calculate normalisation constant c = log((1.f-c)/c); //remap into range of valid inputs to avoid infinities in the log //f= ((f-0.5)*0.499*a)+0.5; f = ((f-0.5f)*0.998f*a)+0.5f; //[0,1]->[0.001,0.999]; squashed around midpoint 0.5 by a //Xenakis calls this the LOGIST map, it's from the range [0,1] to [inf,0] where 0.5->1 //than take natural log. to avoid infinities in practise I take [0,1] -> [0.001,0.999]->[6.9,-6.9] //an interesting property is that 0.5-e is the reciprocal of 0.5+e under (1-f)/f //and hence the logs are the negative of each other temp = log((1.f-f)/f)/c; //n range [-1,1] //X also had two constants in his- I don't bother //printf("logist f %f temp %f\n", f, temp); return temp; //a*0.5*(temp+1.0); //to [0,1] case 3: //HYPERBCOS //X original a*log(tan(z*pi/2)) which is [0,1]->[0,pi/2]->[0,inf]->[-inf,inf] //unmanageable in this pure form c = tan(1.5692255f*a); //tan(0.999*a*pi*0.5); //[0, 636.6] maximum range temp = tan(1.5692255f*a*f)/c; //[0,1]->[0,1] temp = log(temp*0.999f+0.001f)*(-0.1447648f); // multiplier same as /(-6.9077553); //[0,1]->[0,1] //printf("hyperbcos f %f c %f temp %f\n", f, c, temp); return 2.f*temp-1.0f; case 4: //ARCSINE //X original a/2*(1-sin((0.5-z)*pi)) aha almost a better behaved one though [0,1]->[2,0]->[a,0] c = sin(1.5707963f*a); //sin(pi*0.5*a); //a as scaling factor of domain of sine input to use temp = sin(pi_f*(f-0.5f)*a)/c; //[-1,1] which is what I need //printf("arcsine f %f c %f temp %f\n", f, c, temp); return temp; case 5: //EXPON //X original -(log(1-z))/a [0,1]-> [1,0]-> [0,-inf]->[0,inf] c = log(1.f-(0.999f*a)); temp = log(1.f-(f*0.999f*a))/c; //printf("expon f %f c %f temp %f\n", f, c, temp); return 2.f*temp-1.f; case 6: //SINUS //X original a*sin(smp * 2*pi/44100 * b) ie depends on a second oscillator's value- //hmmm, plug this in as a I guess, will automatically accept control rate inputs then! return 2.f*a-1.f; default: break; } return 2.f*f-1.f; } void Gendy1_next_k( Gendy1 *unit, int inNumSamples ) { float *out = ZOUT(0); //distribution choices for amp and dur and constants of distribution int whichamp = (int)ZIN0(0); int whichdur = (int)ZIN0(1); float aamp = ZIN0(2); float adur = ZIN0(3); float minfreq = ZIN0(4); float maxfreq = ZIN0(5); float scaleamp = ZIN0(6); float scaledur = ZIN0(7); float rate = unit->mDur; //phase gives proportion for linear interpolation automatically double phase = unit->mPhase; float amp = unit->mAmp; float nextamp = unit->mNextAmp; float speed = unit->mSpeed; RGen& rgen = *unit->mParent->mRGen; //linear distribution 0.0 to 1.0 using rgen.frand() LOOP1(inNumSamples, float z; if (phase >= 1.0) { phase -= 1.0; int index = unit->mIndex; int num = (int)(ZIN0(9));//(unit->mMemorySize);(((int)ZIN0(9))%(unit->mMemorySize))+1; if((num>(unit->mMemorySize)) || (num<1)) num=unit->mMemorySize; //new code for indexing index = (index+1)%num; amp = nextamp; unit->mIndex = index; //Gendy dist gives value [-1,1], then use scaleamp //first term was amp before, now must check new memory slot nextamp = (unit->mMemoryAmp[index])+(scaleamp*Gendyn_distribution(whichamp, aamp,rgen.frand())); //mirroring for bounds- safe version if(nextamp>1.0f || nextamp<-1.0f) { //printf("mirroring nextamp %f ", nextamp); //to force mirroring to be sensible if(nextamp<0.0f) nextamp = nextamp+4.f; nextamp = fmod(nextamp,4.f); //printf("fmod %f ", nextamp); if(nextamp>1.0f && nextamp<3.f) nextamp = 2.f-nextamp; else if(nextamp>1.0f) nextamp = nextamp-4.f; //printf("mirrorednextamp %f \n", nextamp); }; unit->mMemoryAmp[index] = nextamp; //Gendy dist gives value [-1,1] rate= (unit->mMemoryDur[index]) + (scaledur*Gendyn_distribution(whichdur, adur, rgen.frand())); if(rate>1.0f || rate<0.0f) { if(rate<0.0) rate = rate+2.f; rate = fmod(rate,2.0f); rate = 2.f-rate; } unit->mMemoryDur[index] = rate; //printf("nextamp %f rate %f \n", nextamp, rate); //define range of speeds (say between 20 and 1000 Hz) //can have bounds as fourth and fifth inputs speed = (minfreq+((maxfreq-minfreq)*rate))*(unit->mFreqMul); //if there are 12 control points in memory, that is 12 per cycle //the speed is multiplied by 12 //(I don't store this because updating rates must remain in range [0,1] speed *= num; } //linear interpolation could be changed z = ((1.0-phase)*amp) + (phase*nextamp); phase += speed; ZXP(out) = z; ); unit->mPhase = phase; unit->mAmp = amp; unit->mNextAmp = nextamp; unit->mSpeed = speed; unit->mDur = rate; } void Gendy2_Ctor( Gendy2* unit ) { SETCALC(Gendy2_next_k); unit->mFreqMul = unit->mRate->mSampleDur; unit->mPhase = 1.0; //should immediately decide on new target unit->mAmp = 0.0f; unit->mNextAmp = 0.0f; unit->mSpeed = 100.f; unit->mMemorySize = (int) ZIN0(8); //default is 12 //printf("memsize %d %f", unit->mMemorySize, ZIN0(8)); if(unit->mMemorySize<1) unit->mMemorySize = 1; unit->mIndex = 0; unit->mMemoryAmp = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); unit->mMemoryDur = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); unit->mMemoryAmpStep = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); unit->mMemoryDurStep = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); RGen& rgen = *unit->mParent->mRGen; //initialise to zeroes and separations for(int i=0; imMemorySize;++i) { unit->mMemoryAmp[i] = 2*rgen.frand() - 1.0f; unit->mMemoryDur[i] = rgen.frand(); unit->mMemoryAmpStep[i] = 2*rgen.frand() - 1.0f; unit->mMemoryDurStep[i] = 2*rgen.frand() - 1.0f; } // compute one sample of output to avoid sending garbage memory downstream to other Ctor functions // first sample of the _next output will be the current amplitude (which is 0) OUT0(0) = 0.0f; } void Gendy2_Dtor(Gendy2 *unit) { RTFree(unit->mWorld, unit->mMemoryAmp); RTFree(unit->mWorld, unit->mMemoryDur); RTFree(unit->mWorld, unit->mMemoryAmpStep); RTFree(unit->mWorld, unit->mMemoryDurStep); } static float Gendyn_mirroring (float lower, float upper, float in) { //mirroring for bounds- safe version if(in>upper || inmDur; //phase gives proportion for linear interpolation automatically double phase = unit->mPhase; float amp = unit->mAmp; float nextamp = unit->mNextAmp; float speed = unit->mSpeed; RGen& rgen = *unit->mParent->mRGen; LOOP1(inNumSamples, float z; if (phase >= 1.0) { phase -= 1.0; int index = unit->mIndex; int num = (int)(ZIN0(9));//(unit->mMemorySize);(((int)ZIN0(9))%(unit->mMemorySize))+1; if((num>(unit->mMemorySize)) || (num<1)) num=unit->mMemorySize; //new code for indexing index = (index+1)%num; //using last amp value as seed //random values made using a lehmer number generator xenakis style float a = ZIN0(10); float c = ZIN0(11); float lehmerxen = fmod(((amp)*a)+c,1.0f); //printf("lehmer %f \n", lehmerxen); amp = nextamp; unit->mIndex = index; //Gendy dist gives value [-1,1], then use scaleamp //first term was amp before, now must check new memory slot float ampstep = (unit->mMemoryAmpStep[index])+ Gendyn_distribution(whichamp, aamp, fabs(lehmerxen)); ampstep = Gendyn_mirroring(-1.0f,1.0f,ampstep); unit->mMemoryAmpStep[index] = ampstep; nextamp = (unit->mMemoryAmp[index])+(scaleamp*ampstep); nextamp = Gendyn_mirroring(-1.0f,1.0f,nextamp); unit->mMemoryAmp[index] = nextamp; float durstep = (unit->mMemoryDurStep[index])+ Gendyn_distribution(whichdur, adur, rgen.frand()); durstep = Gendyn_mirroring(-1.0f,1.0f,durstep); unit->mMemoryDurStep[index] = durstep; rate = (unit->mMemoryDur[index])+(scaledur*durstep); rate = Gendyn_mirroring(0.0f,1.0f,rate); unit->mMemoryDur[index] = rate; //printf("nextamp %f rate %f \n", nextamp, rate); //define range of speeds (say between 20 and 1000 Hz) //can have bounds as fourth and fifth inputs speed = (minfreq+((maxfreq-minfreq)*rate))*(unit->mFreqMul); //if there are 12 control points in memory, that is 12 per cycle //the speed is multiplied by 12 //(I don't store this because updating rates must remain in range [0,1] speed *= num; } //linear interpolation could be changed z = ((1.0-phase)*amp) + (phase*nextamp); phase += speed; ZXP(out) = z; ); unit->mPhase = phase; unit->mAmp = amp; unit->mNextAmp = nextamp; unit->mSpeed = speed; unit->mDur = rate; } void Gendy3_Ctor( Gendy3* unit ) { SETCALC(Gendy3_next_k); unit->mFreqMul = unit->mRate->mSampleDur; unit->mPhase = 1.0; //should immediately decide on new target unit->mAmp = 0.0f; unit->mNextAmp = 0.0f; unit->mNextPhase = 0.0; unit->mLastPhase = 0.0; unit->mInterpMult = 1.0f; unit->mSpeed = 100.f; unit->mMemorySize = (int) ZIN0(7); if(unit->mMemorySize<1) unit->mMemorySize = 1; unit->mIndex = 0; unit->mMemoryAmp = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); unit->mMemoryDur = (float*)RTAlloc(unit->mWorld, unit->mMemorySize * sizeof(float)); //one more in amp list for guard (wrap) element unit->mAmpList = (float*)RTAlloc(unit->mWorld, (unit->mMemorySize+1) * sizeof(float)); unit->mPhaseList = (double*)RTAlloc(unit->mWorld, (unit->mMemorySize+1) * sizeof(double)); RGen& rgen = *unit->mParent->mRGen; //initialise to zeroes and separations for(int i = 0; imMemorySize;++i) { unit->mMemoryAmp[i] = 2*rgen.frand() - 1.0f; unit->mMemoryDur[i] = rgen.frand(); unit->mAmpList[i] = 2*rgen.frand() - 1.0f; unit->mPhaseList[i] = 1.0; //will be intialised immediately } unit->mMemoryAmp[0] = 0.0f; //always zeroed first BP // compute one sample of output to avoid sending garbage memory downstream to other Ctor functions // first sample of the _next output will be the current amplitude (which is 0) OUT0(0) = 0.0f; } void Gendy3_Dtor(Gendy3 *unit) { RTFree(unit->mWorld, unit->mMemoryAmp); RTFree(unit->mWorld, unit->mMemoryDur); RTFree(unit->mWorld, unit->mAmpList); RTFree(unit->mWorld, unit->mPhaseList); } void Gendy3_next_k( Gendy3 *unit, int inNumSamples ) { float *out = ZOUT(0); //distribution choices for amp and dur and constants of distribution int whichamp = (int)ZIN0(0); int whichdur = (int)ZIN0(1); float aamp = ZIN0(2); float adur = ZIN0(3); float freq = ZIN0(4); float scaleamp = ZIN0(5); float scaledur = ZIN0(6); double phase = unit->mPhase; float amp = unit->mAmp; float nextamp= unit->mNextAmp; float speed= unit->mSpeed; int index = unit->mIndex; int interpmult = (int)unit->mInterpMult; double lastphase = unit->mLastPhase; double nextphase = unit->mNextPhase; RGen& rgen = *unit->mParent->mRGen; float * amplist = unit->mAmpList; double * phaselist = unit->mPhaseList; LOOP1(inNumSamples, float z; if (phase >= 1.) { //calculate all targets for new period phase -= 1.; int num = (int)(ZIN0(8)); if((num>(unit->mMemorySize)) || (num<1)) num = unit->mMemorySize; float dursum = 0.0f; float * memoryamp = unit->mMemoryAmp; float * memorydur = unit->mMemoryDur; for(int j = 0; j0) { //first BP always stays at 0 float amp = (memoryamp[j])+ (scaleamp*Gendyn_distribution(whichamp, aamp, rgen.frand())); amp = Gendyn_mirroring(-1.0f,1.0f,amp); memoryamp[j] = amp; } float dur = (memorydur[j])+ (scaledur*Gendyn_distribution(whichdur, adur, rgen.frand())); dur = Gendyn_mirroring(0.01f,1.0f,dur); //will get normalised in a moment, don't allow zeroes memorydur[j] = dur; dursum += dur; } //normalising constant dursum = 1.f/dursum; int active = 0; //phase duration of a sample float minphase = unit->mFreqMul; speed = freq*minphase; //normalise and discard any too short (even first) for(int j = 0; j=minphase) { amplist[active] = memoryamp[j]; phaselist[active] = dur; ++active; } } //add a zero on the end at active amplist[active] = 0.0f; //guard element phaselist[active] = 2.0; //safety element //lastphase=0.0; // nextphase= phaselist[0]; // amp=amplist[0]; // nextamp=amplist[1]; // index=0; // unit->mIndex=index; // //setup to trigger next block nextphase = 0.0; nextamp = amplist[0]; index = -1; } if (phase >= nextphase) { //are we into a new region? //new code for indexing ++index; //=index+1; //%num; amp = nextamp; unit->mIndex = index; lastphase = nextphase; nextphase = lastphase+phaselist[index]; nextamp = amplist[index+1]; interpmult = (int)(1.0/(nextphase-lastphase)); } float interp = (phase-lastphase)*interpmult; //linear interpolation could be changed z = ((1.0f-interp)*amp) + (interp*nextamp); phase += speed; ZXP(out) = z; ); unit->mPhase = phase; unit->mSpeed = speed; unit->mInterpMult = interpmult; unit->mAmp = amp; unit->mNextAmp = nextamp; unit->mLastPhase = lastphase; unit->mNextPhase = nextphase; } PluginLoad(Gendyn) { ft = inTable; DefineDtorUnit(Gendy1); DefineDtorUnit(Gendy2); DefineDtorUnit(Gendy3); } SuperCollider-Source/server/plugins/GrainUGens.cpp000644 000765 000024 00000116624 12766171707 023402 0ustar00crucialstaff000000 000000 /* * JoshUGens.cpp * xSC3plugins * * Created by Josh Parmenter on 2/4/05. * Copyright 2005 __MyCompanyName__. All rights reserved. * */ /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include "function_attributes.h" static InterfaceTable *ft; const int kMaxGrains = 64; const int kMaxSynthGrains = 512; struct GrainInG { double b1, y1, y2, curamp, winPos, winInc; // envelope int counter, chan; float pan1, pan2, winType; }; struct GrainIn : public Unit { int mNumActive, m_channels, mMaxGrains; float curtrig; bool mFirst; GrainInG *mGrains; }; struct GrainSinG { double b1, y1, y2, curamp, winPos, winInc; // envelope int counter, chan; float pan1, pan2, winType; int32 oscphase; // the phase of the osc inside this grain int32 freq; // the freq of the osc inside this grain in phase inc }; struct GrainSin : public Unit { int mNumActive, m_channels, mMaxGrains; uint32 m_lomask; float curtrig; bool mFirst; double m_cpstoinc, m_radtoinc; GrainSinG *mGrains; }; struct GrainFMG { int32 coscphase, moscphase; // the phase of the osc inside this grain int32 mfreq; // the freq of the osc inside this grain in phase inc double b1, y1, y2, curamp, winPos, winInc; // envelope float deviation, carbase, pan1, pan2, winType; int counter, chan; }; struct GrainFM : public Unit { int mNumActive, m_channels, mMaxGrains; uint32 m_lomask; float curtrig; bool mFirst; double m_cpstoinc, m_radtoinc; GrainFMG *mGrains; }; struct GrainBufG { double phase, rate; double b1, y1, y2, curamp, winPos, winInc; float pan1, pan2, winType; int counter, chan, bufnum, interp; }; struct GrainBuf : public Unit { int mNumActive, m_channels, mMaxGrains; float curtrig; GrainBufG *mGrains; }; struct WarpWinGrain { double phase, rate; double winPos, winInc, b1, y1, y2, curamp; // tells the grain where to look in the winBuf for an amp value int counter, bufnum, interp; float winType; }; struct Warp1 : public Unit { float m_fbufnum; SndBuf* m_buf; int mNumActive[16]; int mNextGrain[16]; WarpWinGrain mGrains[16][kMaxGrains]; }; //////////////////////////////////////////////////////////////////////// extern "C" { void GrainIn_Ctor(GrainIn* unit); void GrainIn_Dtor(GrainIn* unit); void GrainIn_next_a(GrainIn *unit, int inNumSamples); void GrainIn_next_k(GrainIn *unit, int inNumSamples); void GrainSin_Ctor(GrainSin* unit); void GrainSin_Dtor(GrainSin* unit); void GrainSin_next_a(GrainSin *unit, int inNumSamples); void GrainSin_next_k(GrainSin *unit, int inNumSamples); void GrainFM_Ctor(GrainFM* unit); void GrainFM_Dtor(GrainFM* unit); void GrainFM_next_a(GrainFM *unit, int inNumSamples); void GrainFM_next_k(GrainFM *unit, int inNumSamples); void GrainBuf_Ctor(GrainBuf* unit); void GrainBuf_Dtor(GrainBuf* unit); void Warp1_next(Warp1 *unit, int inNumSamples); void Warp1_Ctor(Warp1* unit); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////// Granular UGens //////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// inline float GRAIN_IN_AT(Unit* unit, int index, int offset) { if (INRATE(index) == calc_FullRate) return IN(index)[offset]; if (INRATE(index) == calc_DemandRate) return DEMANDINPUT_A(index, offset + 1); return IN0(index); } template inline float grain_in_at(Unit* unit, int index, int offset) { if (full_rate) return GRAIN_IN_AT(unit, index, offset); if (INRATE(index) == calc_DemandRate) return DEMANDINPUT_A(index, offset + 1); else return IN0(index); } inline double sc_gloop(double in, double hi) { // avoid the divide if possible if (in >= hi) { in -= hi; if (in < hi) return in; } else if (in < 0.) { in += hi; if (in >= 0.) return in; } else return in; return in - hi * floor(in/hi); } #define GRAIN_BUF \ const SndBuf *buf; \ if (bufnum >= world->mNumSndBufs) { \ int localBufNum = bufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ bufnum = 0; \ buf = world->mSndBufs + bufnum; \ } \ } else { \ if (bufnum < 0) { bufnum = 0; } \ buf = world->mSndBufs + bufnum; \ } \ LOCK_SNDBUF_SHARED(buf); \ const float *bufData __attribute__((__unused__)) = buf->data; \ uint32 bufChannels __attribute__((__unused__)) = buf->channels; \ uint32 bufSamples __attribute__((__unused__)) = buf->samples; \ uint32 bufFrames = buf->frames; \ int guardFrame __attribute__((__unused__)) = bufFrames - 2; #define DECLARE_WINDOW \ double winPos, winInc, w, b1, y1, y2, y0; \ float amp; \ winPos = winInc = w = b1 = y1 = y2 = y0 = amp = 0.; \ SndBuf *window; \ const float *windowData __attribute__((__unused__)) = 0;\ uint32 windowSamples __attribute__((__unused__)) = 0; \ uint32 windowFrames __attribute__((__unused__)) = 0; \ int windowGuardFrame = 0; #define CHECK_BUF \ if (!bufData) { \ unit->mDone = true; \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } #define GET_GRAIN_WIN_RELAXED(WINTYPE) \ do { \ assert(WINTYPE < unit->mWorld->mNumSndBufs); \ window = unit->mWorld->mSndBufs + (int)WINTYPE; \ windowData = window->data; \ windowSamples = window->samples; \ windowFrames = window->frames; \ windowGuardFrame = windowFrames - 1; \ } while (0); static inline bool getGrainWin(Unit * unit, float wintype, SndBuf *& window, const float * & windowData, uint32 & windowSamples, uint32 & windowFrames, int & windowGuardFrame) { if (wintype >= unit->mWorld->mNumSndBufs) { Print("Envelope buffer out of range!\n"); return false; } assert(wintype < unit->mWorld->mNumSndBufs); if (wintype < 0) return true; // use default hann window window = unit->mWorld->mSndBufs + (int)wintype; windowData = window->data; if (!windowData) return false; windowSamples = window->samples; windowFrames = window->frames; windowGuardFrame = windowFrames - 1; return true; } #define GRAIN_LOOP_BODY_4 \ float amp = y1 * y1; \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float* table1 = bufData + iphase; \ float* table0 = table1 - 1; \ float* table2 = table1 + 1; \ float* table3 = table1 + 2; \ if (iphase == 0) { \ table0 += bufSamples; \ } else if (iphase >= guardFrame) { \ if (iphase == guardFrame) { \ table3 -= bufSamples; \ } else { \ table2 -= bufSamples; \ table3 -= bufSamples; \ } \ } \ float fracphase = phase - (double)iphase; \ float a = table0[0]; \ float b = table1[0]; \ float c = table2[0]; \ float d = table3[0]; \ float outval = amp * cubicinterp(fracphase, a, b, c, d) \ ZXP(out1) += outval; \ double y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; #define GRAIN_LOOP_BODY_2 \ float amp = y1 * y1; \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float* table1 = bufData + iphase; \ float* table2 = table1 + 1; \ if (iphase > guardFrame) { \ table2 -= bufSamples; \ } \ double fracphase = phase - (double)iphase; \ float b = table1[0]; \ float c = table2[0]; \ float outval = amp * (b + fracphase * (c - b)); \ ZXP(out1) += outval; \ double y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; #define GRAIN_LOOP_BODY_1 \ float amp = y1 * y1; \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float outval = amp * bufData[iphase]; \ ZXP(out1) += outval; \ double y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; #define BUF_GRAIN_AMP \ winPos += winInc; \ int iWinPos = (int)winPos; \ double winFrac = winPos - (double)iWinPos; \ float* winTable1 = windowData + iWinPos; \ float* winTable2 = winTable1 + 1; \ if (winPos > windowGuardFrame) { \ winTable2 -= windowSamples; \ } \ amp = lininterp(winFrac, winTable1[0], winTable2[0]); #define BUF_GRAIN_LOOP_BODY_4 \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float* table1 = bufData + iphase; \ float* table0 = table1 - 1; \ float* table2 = table1 + 1; \ float* table3 = table1 + 2; \ if (iphase == 0) { \ table0 += bufSamples; \ } else if (iphase >= guardFrame) { \ if (iphase == guardFrame) { \ table3 -= bufSamples; \ } else { \ table2 -= bufSamples; \ table3 -= bufSamples; \ } \ } \ float fracphase = phase - (double)iphase; \ float a = table0[0]; \ float b = table1[0]; \ float c = table2[0]; \ float d = table3[0]; \ float outval = amp * cubicinterp(fracphase, a, b, c, d); \ ZXP(out1) += outval; #define BUF_GRAIN_LOOP_BODY_2 \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float* table1 = bufData + iphase; \ float* table2 = table1 + 1; \ if (iphase > guardFrame) { \ table2 -= bufSamples; \ } \ float fracphase = phase - (double)iphase; \ float b = table1[0]; \ float c = table2[0]; \ float outval = amp * (b + fracphase * (c - b)); \ ZXP(out1) += outval; // amp needs to be calculated by looking up values in window #define BUF_GRAIN_LOOP_BODY_1 \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float outval = amp * bufData[iphase]; \ ZXP(out1) += outval; #define SETUP_OUT \ uint32 numOutputs = unit->mNumOutputs; \ if (numOutputs > bufChannels) { \ unit->mDone = true; \ ClearUnitOutputs(unit, inNumSamples); \ return; \ } \ float *out[16]; \ for (uint32 i=0; i 1) { \ if (numOutputs > 2) { \ pan = sc_wrap(pan * 0.5f, 0.f, 1.f); \ float cpan = numOutputs * pan + 0.5f; \ float ipan = floor(cpan); \ float panfrac = cpan - ipan; \ panangle = panfrac * pi2_f; \ grain->chan = (int)ipan; \ if (grain->chan >= (int)numOutputs) \ grain->chan -= numOutputs; \ } else { \ grain->chan = 0; \ pan = sc_clip(pan * 0.5f + 0.5f, 0.f, 1.f); \ panangle = pan * pi2_f; \ } \ pan1 = grain->pan1 = cos(panangle); \ pan2 = grain->pan2 = sin(panangle); \ } else { \ grain->chan = 0; \ pan1 = grain->pan1 = 1.; \ pan2 = grain->pan2 = 0.; \ } #define GET_GRAIN_INIT_AMP \ if(grain->winType < 0.){ \ w = pi / counter; \ b1 = grain->b1 = 2. * cos(w); \ y1 = sin(w); \ y2 = 0.; \ amp = y1 * y1; \ } else { \ amp = windowData[0]; \ winPos = grain->winPos = 0.f; \ winInc = grain->winInc = (double)windowSamples / counter; \ } #define CALC_NEXT_GRAIN_AMP_INTERNAL \ do { \ y0 = b1 * y1 - y2; \ y2 = y1; \ y1 = y0; \ amp = y1 * y1; \ } while(0) #define CALC_NEXT_GRAIN_AMP_CUSTOM \ do { \ winPos += winInc; \ int iWinPos = (int)winPos; \ double winFrac = winPos - (double)iWinPos; \ const float* winTable1 = windowData + iWinPos; \ const float* winTable2 = winTable1 + 1; \ if (!windowData) \ break; \ if (winPos > windowGuardFrame) \ winTable2 -= windowSamples; \ amp = lininterp(winFrac, winTable1[0], winTable2[0]); \ } while (0); \ if (!windowData) \ break; \ #define CALC_NEXT_GRAIN_AMP \ if(grain->winType < 0.) { \ CALC_NEXT_GRAIN_AMP_INTERNAL; \ } else { \ CALC_NEXT_GRAIN_AMP_CUSTOM; \ } #define GET_GRAIN_AMP_PARAMS \ if(grain->winType < 0.){ \ b1 = grain->b1; \ y1 = grain->y1; \ y2 = grain->y2; \ amp = grain->curamp; \ } else { \ GET_GRAIN_WIN_RELAXED(grain->winType); \ if (!windowData) break; \ winPos = grain->winPos; \ winInc = grain->winInc; \ amp = grain->curamp; \ } #define SAVE_GRAIN_AMP_PARAMS \ grain->y1 = y1; \ grain->y2 = y2; \ grain->winPos = winPos; \ grain->winInc = winInc; \ grain->curamp = amp; \ grain->counter -= nsmps; #define WRAP_CHAN(offset) \ out1 = OUT(grain->chan) + offset; \ if(numOutputs > 1) { \ if((grain->chan + 1) >= (int)numOutputs) \ out2 = OUT(0) + offset; \ else \ out2 = OUT(grain->chan + 1) + offset; \ } #define GET_PAN_PARAMS \ float pan1 = grain->pan1; \ uint32 chan1 = grain->chan; \ float *out1 = OUT(chan1); \ if(numOutputs > 1){ \ pan2 = grain->pan2; \ uint32 chan2 = chan1 + 1; \ if (chan2 >= numOutputs) chan2 = 0; \ out2 = OUT(chan2); \ } //////////////////// InGrain //////////////////// inline void GrainIn_next_play_active(GrainIn * unit, int inNumSamples) { const uint32 numOutputs = unit->mNumOutputs; float *in = IN(2); for (int i=0; i < unit->mNumActive; ) { GrainInG *grain = unit->mGrains + i; DECLARE_WINDOW GET_GRAIN_AMP_PARAMS // begin add // float pan2 = 0.f; float *out2; GET_PAN_PARAMS // end add // int nsmps = sc_min(grain->counter, inNumSamples); for (int j=0; j 1) out2[j] += outval * pan2; // end change // CALC_NEXT_GRAIN_AMP } SAVE_GRAIN_AMP_PARAMS if (grain->counter <= 0) *grain = unit->mGrains[--unit->mNumActive]; // remove grain else ++i; } } template inline void GrainIn_next_start_new(GrainIn * unit, int inNumSamples, int position) { if (unit->mNumActive+1 >= unit->mMaxGrains) { Print("Too many grains!\n"); return; } float winType = grain_in_at(unit, 4, position); DECLARE_WINDOW bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame); if (!success) return; GrainInG *grain = unit->mGrains + unit->mNumActive++; float winSize = grain_in_at(unit, 1, position); double counter = winSize * SAMPLERATE; counter = sc_max(4., counter); grain->counter = (int)counter; grain->winType = winType; GET_GRAIN_INIT_AMP const uint32 numOutputs = unit->mNumOutputs; float *in = IN(2); float *in1 = in + position; // begin add // float pan = grain_in_at(unit, 3, position); CALC_GRAIN_PAN WRAP_CHAN(position) int nsmps = sc_min(grain->counter, inNumSamples - position); for (int j=0; j 1) out2[j] += outval * pan2; // end add / change CALC_NEXT_GRAIN_AMP } SAVE_GRAIN_AMP_PARAMS if (grain->counter <= 0) *grain = unit->mGrains[--unit->mNumActive]; // remove grain } void GrainIn_next_a(GrainIn *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); //begin add // end add GrainIn_next_play_active(unit, inNumSamples); float *trig = IN(0); for (int i=0; icurtrig <= 0) && (trig[i] > 0.0)) GrainIn_next_start_new(unit, inNumSamples, i); unit->curtrig = trig[i]; } } void GrainIn_next_k(GrainIn *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); if(unit->mFirst){ unit->mFirst = false; float maxGrains = IN0(5); unit->mMaxGrains = (int)maxGrains; unit->mGrains = (GrainInG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainInG)); } GrainIn_next_play_active(unit, inNumSamples); float trig = IN0(0); if ((unit->curtrig <= 0) && (trig > 0.0)) GrainIn_next_start_new(unit, inNumSamples, 0); unit->curtrig = trig; } void GrainIn_Ctor(GrainIn *unit) { if (INRATE(0) == calc_FullRate) SETCALC(GrainIn_next_a); else SETCALC(GrainIn_next_k); unit->mFirst = true; unit->mNumActive = 0; unit->curtrig = 0.f; GrainIn_next_k(unit, 1); } void GrainIn_Dtor(GrainIn *unit) { RTFree(unit->mWorld, unit->mGrains); } inline void GrainSin_next_play_active(GrainSin * unit, int inNumSamples) { const unsigned int numOutputs = unit->mNumOutputs; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; for (int i=0; i < unit->mNumActive; ) { GrainSinG *grain = unit->mGrains + i; DECLARE_WINDOW GET_GRAIN_AMP_PARAMS // begin add // float pan2 = 0.f; float *out2; GET_PAN_PARAMS // end add // int32 thisfreq = grain->freq; int32 oscphase = grain->oscphase; int nsmps = sc_min(grain->counter, inNumSamples); for (int j=0; jm_lomask); // begin change / add // out1[j] += outval * pan1; if(numOutputs > 1) out2[j] += outval * pan2; // end change // CALC_NEXT_GRAIN_AMP oscphase += thisfreq; } SAVE_GRAIN_AMP_PARAMS grain->oscphase = oscphase; if (grain->counter <= 0) *grain = unit->mGrains[--unit->mNumActive]; // remove grain else ++i; } } template inline void GrainSin_next_start_new(GrainSin * unit, int inNumSamples, int position) { if (unit->mNumActive+1 >= unit->mMaxGrains) { Print("Too many grains!\n"); return; } float winType = grain_in_at(unit, 4, position); DECLARE_WINDOW bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame); if (!success) return; GrainSinG *grain = unit->mGrains + unit->mNumActive++; float freq = grain_in_at(unit, 2, position); float winSize = grain_in_at(unit, 1, position); int32 thisfreq = grain->freq = (int32)(unit->m_cpstoinc * freq); int32 oscphase = 0; double counter = winSize * SAMPLERATE; counter = sc_max(4., counter); grain->counter = (int)counter; grain->winType = winType; GET_GRAIN_INIT_AMP const uint32 numOutputs = unit->mNumOutputs; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; // begin add // float pan = grain_in_at(unit, 3, position); CALC_GRAIN_PAN WRAP_CHAN(position) // end add // int nsmps = sc_min(grain->counter, inNumSamples - position); for (int j=0; jm_lomask); // begin add / change out1[j] += outval * pan1; if(numOutputs > 1) out2[j] += outval * pan2; // end add / change CALC_NEXT_GRAIN_AMP oscphase += thisfreq; } grain->oscphase = oscphase; SAVE_GRAIN_AMP_PARAMS if (grain->counter <= 0) *grain = unit->mGrains[--unit->mNumActive]; // remove grain } void GrainSin_next_a(GrainSin *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); GrainSin_next_play_active(unit, inNumSamples); float *trig = IN(0); for (int i=0; icurtrig <= 0) && (trig[i] > 0.0)) GrainSin_next_start_new(unit, inNumSamples, i); unit->curtrig = trig[i]; } } void GrainSin_next_k(GrainSin *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); if(unit->mFirst){ unit->mFirst = false; float maxGrains = IN0(5); unit->mMaxGrains = (int)maxGrains; unit->mGrains = (GrainSinG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainSinG)); } GrainSin_next_play_active(unit, inNumSamples); float trig = IN0(0); if ((unit->curtrig <= 0) && (trig > 0.0)) GrainSin_next_start_new(unit, inNumSamples, 0); unit->curtrig = trig; } void GrainSin_Ctor(GrainSin *unit) { if (INRATE(0) == calc_FullRate) SETCALC(GrainSin_next_a); else SETCALC(GrainSin_next_k); int tableSizeSin = ft->mSineSize; unit->m_lomask = (tableSizeSin - 1) << 3; unit->m_radtoinc = tableSizeSin * (rtwopi * 65536.); unit->m_cpstoinc = tableSizeSin * SAMPLEDUR * 65536.; unit->curtrig = 0.f; unit->mNumActive = 0; unit->mFirst = true; GrainSin_next_k(unit, 1); } void GrainSin_Dtor(GrainSin *unit) { RTFree(unit->mWorld, unit->mGrains); } inline void GrainFM_next_play_active(GrainFM *unit, int inNumSamples) { const uint32 numOutputs = unit->mNumOutputs; // end add float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; for (int i=0; i < unit->mNumActive; ) { GrainFMG *grain = unit->mGrains + i; DECLARE_WINDOW GET_GRAIN_AMP_PARAMS int32 mfreq = grain->mfreq; int32 moscphase = grain->moscphase; int32 coscphase = grain->coscphase; float deviation = grain->deviation; float carbase = grain->carbase; // begin add // float pan2 = 0.f; float *out2; GET_PAN_PARAMS // end add // int nsmps = sc_min(grain->counter, inNumSamples); for (int j=0; jm_lomask) * deviation; float outval = amp * lookupi1(table0, table1, coscphase, unit->m_lomask); // begin change / add // out1[j] += outval * pan1; if(numOutputs > 1) out2[j] += outval * pan2; // end change // CALC_NEXT_GRAIN_AMP int32 cfreq = (int32)(unit->m_cpstoinc * (carbase + thismod)); // needs to be calced in the loop! coscphase += cfreq; moscphase += mfreq; } // need to save float carbase, int32 mfreq, float deviation grain->coscphase = coscphase; grain->moscphase = moscphase; SAVE_GRAIN_AMP_PARAMS if (grain->counter <= 0) *grain = unit->mGrains[--unit->mNumActive]; // remove grain else ++i; } } template inline void GrainFM_next_start_new(GrainFM * unit, int inNumSamples, int position) { if (unit->mNumActive+1 >= unit->mMaxGrains) { Print("Too many grains!\n"); return; } float winType = grain_in_at(unit, 6, position); DECLARE_WINDOW bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame); if (!success) return; GrainFMG *grain = unit->mGrains + unit->mNumActive++; float winSize = GRAIN_IN_AT(unit, 1, position); float carfreq = GRAIN_IN_AT(unit, 2, position); float modfreq = GRAIN_IN_AT(unit, 3, position); float index = GRAIN_IN_AT(unit, 4, position); float deviation = grain->deviation = index * modfreq; int32 mfreq = grain->mfreq = (int32)(unit->m_cpstoinc * modfreq); grain->carbase = carfreq; int32 coscphase = 0; int32 moscphase = 0; double counter = winSize * SAMPLERATE; counter = sc_max(4., counter); grain->counter = (int)counter; grain->winType = winType; //GRAIN_IN_AT(unit, 6, i); GET_GRAIN_INIT_AMP const uint32 numOutputs = unit->mNumOutputs; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; // begin add // float pan = GRAIN_IN_AT(unit, 5, position); CALC_GRAIN_PAN WRAP_CHAN(position) // end add // int nsmps = sc_min(grain->counter, inNumSamples - position); for (int j=0; jm_lomask) * deviation; float outval = amp * lookupi1(table0, table1, coscphase, unit->m_lomask); // begin add / change out1[j] += outval * pan1; if(numOutputs > 1) out2[j] += outval * pan2; // end add / change CALC_NEXT_GRAIN_AMP int32 cfreq = (int32)(unit->m_cpstoinc * (carfreq + thismod)); // needs to be calced in the loop! coscphase += cfreq; moscphase += mfreq; } // need to save float carbase, int32 mfreq, float deviation grain->coscphase = coscphase; grain->moscphase = moscphase; SAVE_GRAIN_AMP_PARAMS if (grain->counter <= 0) *grain = unit->mGrains[--unit->mNumActive]; // remove grain } void GrainFM_next_a(GrainFM *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); GrainFM_next_play_active(unit, inNumSamples); float *trig = IN(0); for (int i=0; icurtrig <= 0) && (trig[i] > 0.0)) GrainFM_next_start_new(unit, inNumSamples, i); unit->curtrig = trig[i]; } } void GrainFM_next_k(GrainFM *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); if (unit->mFirst) { unit->mFirst = false; float maxGrains = IN0(7); unit->mMaxGrains = (int)maxGrains; unit->mGrains = (GrainFMG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainFMG)); } GrainFM_next_play_active(unit, inNumSamples); float trig = IN0(0); if ((unit->curtrig <= 0) && (trig > 0.0)) GrainFM_next_start_new(unit, inNumSamples, 0); unit->curtrig = trig; } void GrainFM_Ctor(GrainFM *unit) { if (INRATE(0) == calc_FullRate) SETCALC(GrainFM_next_a); else SETCALC(GrainFM_next_k); int tableSizeSin = ft->mSineSize; unit->m_lomask = (tableSizeSin - 1) << 3; unit->m_radtoinc = tableSizeSin * (rtwopi * 65536.); unit->m_cpstoinc = tableSizeSin * SAMPLEDUR * 65536.; unit->curtrig = 0.f; unit->mNumActive = 0; unit->mFirst = true; GrainFM_next_k(unit, 1); } void GrainFM_Dtor(GrainFM *unit) { RTFree(unit->mWorld, unit->mGrains); } #define GRAIN_BUF_LOOP_BODY_4_MONO \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase; \ const float* table0 = table1 - 1; \ const float* table2 = table1 + 1; \ const float* table3 = table1 + 2; \ if (iphase == 0) { \ table0 += bufSamples; \ } else if (iphase >= guardFrame) { \ if (iphase == guardFrame) { \ table3 -= bufSamples; \ } else { \ table2 -= bufSamples; \ table3 -= bufSamples; \ } \ } \ float fracphase = phase - (double)iphase; \ float a = table0[0]; \ float b = table1[0]; \ float c = table2[0]; \ float d = table3[0]; \ float outval = amp * cubicinterp(fracphase, a, b, c, d); \ out1[j] += outval * pan1; \ #define GRAIN_BUF_LOOP_BODY_4_STEREO \ GRAIN_BUF_LOOP_BODY_4_MONO \ out2[j] += outval * pan2; #define GRAIN_BUF_LOOP_BODY_2_MONO \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase; \ const float* table2 = table1 + 1; \ if (iphase > guardFrame) { \ table2 -= bufSamples; \ } \ float fracphase = phase - (double)iphase; \ float b = table1[0]; \ float c = table2[0]; \ float outval = amp * (b + fracphase * (c - b)); \ out1[j] += outval * pan1; \ #define GRAIN_BUF_LOOP_BODY_2_STEREO \ GRAIN_BUF_LOOP_BODY_2_MONO \ out2[j] += outval * pan2; #define GRAIN_BUF_LOOP_BODY_1_MONO \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float outval = amp * bufData[iphase]; \ out1[j] += outval * pan1; #define GRAIN_BUF_LOOP_BODY_1_STEREO \ GRAIN_BUF_LOOP_BODY_1_MONO \ out2[j] += outval * pan2; #define GRAIN_BUF_PLAY_GRAIN(WINDOW) \ do {\ if (numOutputs == 1) \ { \ if (grain->interp >= 4) { \ for (int j=0; jinterp >= 2) { \ for (int j=0; jinterp >= 4) { \ for (int j=0; jinterp >= 2) { \ for (int j=0; jcounter <= 0) { *grain = unit->mGrains[--unit->mNumActive]; // remove grain return true; } else return false; } template static inline void GrainBuf_next_play_active(GrainBuf *unit, int inNumSamples) { const uint32 numOutputs = IsMono ? 1 : unit->mNumOutputs; World *world = unit->mWorld; for (int i=0; i < unit->mNumActive; ) { GrainBufG *grain = unit->mGrains + i; int bufnum = grain->bufnum; GRAIN_BUF if (!bufData || (bufChannels != 1)) { grain->counter -= inNumSamples; if (!GrainBuf_grain_cleanup(unit, grain)) ++i; continue; } double loopMax = (double)bufFrames; double rate = grain->rate; double phase = grain->phase; DECLARE_WINDOW GET_GRAIN_AMP_PARAMS // begin add // float pan2 = 0.f; float *out2; GET_PAN_PARAMS // end add // int nsmps = sc_min(grain->counter, inNumSamples); if (grain->winType < 0.) GRAIN_BUF_PLAY_GRAIN(INTERNAL); else GRAIN_BUF_PLAY_GRAIN(CUSTOM); if (GrainBuf_grain_cleanup(unit, grain)) continue; ++i; grain->phase = phase; SAVE_GRAIN_AMP_PARAMS } } template static inline void GrainBuf_next_start_new(GrainBuf *unit, int inNumSamples, int position) { World *world = unit->mWorld; if (unit->mNumActive+1 >= unit->mMaxGrains) { Print("Too many grains!\n"); return; } float winType = grain_in_at(unit, 7, position); DECLARE_WINDOW bool success = getGrainWin(unit, winType, window, windowData, windowSamples, windowFrames, windowGuardFrame); if (!success) return; GrainBufG *grain = unit->mGrains + unit->mNumActive++; int32 bufnum = grain_in_at(unit, 2, position); grain->bufnum = bufnum; GRAIN_BUF if ( (bufChannels != 1) || (!bufData) ) { GrainBuf_grain_cleanup(unit, grain); return; } float bufSampleRate = buf->samplerate; float bufRateScale = bufSampleRate * SAMPLEDUR; double loopMax = (double)bufFrames; double rate = grain->rate = grain_in_at(unit, 3, position) * bufRateScale; double phase = grain_in_at(unit, 4, position) * bufFrames; if (!sc_isfinite(phase)) { GrainBuf_grain_cleanup(unit, grain); return; } double counter = grain_in_at(unit, 1, position) * SAMPLERATE; counter = sc_max(4., counter); grain->counter = (int)counter; grain->interp = (int)grain_in_at(unit, 5, position); grain->winType = winType; GET_GRAIN_INIT_AMP const uint32 numOutputs = IsMono ? 1 : unit->mNumOutputs; // begin add // float pan = grain_in_at(unit, 6, position); CALC_GRAIN_PAN WRAP_CHAN(position) // end add // int nsmps = sc_min(grain->counter, inNumSamples - position); if (grain->winType < 0.) GRAIN_BUF_PLAY_GRAIN(INTERNAL); else GRAIN_BUF_PLAY_GRAIN(CUSTOM); grain->phase = phase; SAVE_GRAIN_AMP_PARAMS GrainBuf_grain_cleanup(unit, grain); } template static void GrainBuf_next_a(GrainBuf *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); GrainBuf_next_play_active(unit, inNumSamples); float *trig = IN(0); for (int i=0; i 0) && (unit->curtrig <=0)) GrainBuf_next_start_new(unit, inNumSamples, i); unit->curtrig = trig[i]; } } template static void GrainBuf_next_k(GrainBuf * unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); GrainBuf_next_play_active(unit, inNumSamples); float trig = IN0(0); if ((trig > 0) && (unit->curtrig <=0)) GrainBuf_next_start_new(unit, inNumSamples, 0); unit->curtrig = trig; } FLATTEN static void GrainBuf_next_k_1(GrainBuf * unit, int inNumSamples) { GrainBuf_next_k(unit, inNumSamples); } FLATTEN static void GrainBuf_next_k_2(GrainBuf * unit, int inNumSamples) { GrainBuf_next_k(unit, inNumSamples); } FLATTEN static void GrainBuf_next_a_1(GrainBuf * unit, int inNumSamples) { GrainBuf_next_a(unit, inNumSamples); } FLATTEN static void GrainBuf_next_a_2(GrainBuf * unit, int inNumSamples) { GrainBuf_next_a(unit, inNumSamples); } void GrainBuf_Ctor(GrainBuf *unit) { unit->mNumActive = 0; unit->curtrig = 0.f; float maxGrains = IN0(8); unit->mMaxGrains = (int)maxGrains; unit->mGrains = (GrainBufG*)RTAlloc(unit->mWorld, unit->mMaxGrains * sizeof(GrainBufG)); if (unit->mNumOutputs == 1) { if (INRATE(0) == calc_FullRate) SETCALC(GrainBuf_next_a_1); else SETCALC(GrainBuf_next_k_1); } else { if (INRATE(0) == calc_FullRate) SETCALC(GrainBuf_next_a_2); else SETCALC(GrainBuf_next_k_2); } (unit->mCalcFunc)(unit, 1); } void GrainBuf_Dtor(GrainBuf *unit) { RTFree(unit->mWorld, unit->mGrains); } #define BUF_GRAIN_LOOP_BODY_4_N \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase * bufChannels; \ const float* table0 = table1 - bufChannels; \ const float* table2 = table1 + bufChannels; \ const float* table3 = table2 + bufChannels; \ if (iphase == 0) { \ table0 += bufSamples; \ } else if (iphase >= guardFrame) { \ if (iphase == guardFrame) { \ table3 -= bufSamples; \ } else { \ table2 -= bufSamples; \ table3 -= bufSamples; \ } \ } \ float fracphase = phase - (double)iphase; \ float a = table0[n]; \ float b = table1[n]; \ float c = table2[n]; \ float d = table3[n]; \ float outval = amp * cubicinterp(fracphase, a, b, c, d); \ ZXP(out1) += outval; \ #define BUF_GRAIN_LOOP_BODY_2_N \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ const float* table1 = bufData + iphase * bufChannels; \ const float* table2 = table1 + bufChannels; \ if (iphase > guardFrame) { \ table2 -= bufSamples; \ } \ float fracphase = phase - (double)iphase; \ float b = table1[n]; \ float c = table2[n]; \ float outval = amp * (b + fracphase * (c - b)); \ ZXP(out1) += outval; \ // amp needs to be calculated by looking up values in window #define BUF_GRAIN_LOOP_BODY_1_N \ phase = sc_gloop(phase, loopMax); \ int32 iphase = (int32)phase; \ float outval = amp * bufData[iphase + n]; \ ZXP(out1) += outval; \ #define GET_WARP_WIN_RELAXED(WINTYPE) \ do { \ assert(WINTYPE < unit->mWorld->mNumSndBufs); \ window = unit->mWorld->mSndBufs + (int)WINTYPE; \ while (!TRY_ACQUIRE_SNDBUF_SHARED(window)) { \ RELEASE_SNDBUF_SHARED(buf); \ ACQUIRE_SNDBUF_SHARED(buf); \ } \ windowData = window->data; \ if (windowData == NULL) \ RELEASE_SNDBUF_SHARED(window); \ windowSamples = window->samples; \ windowFrames = window->frames; \ windowGuardFrame = windowFrames - 1; \ } while (0); #define GET_WARP_AMP_PARAMS \ if(grain->winType < 0.){ \ b1 = grain->b1; \ y1 = grain->y1; \ y2 = grain->y2; \ amp = grain->curamp; \ } else { \ GET_WARP_WIN_RELAXED(grain->winType); \ if (!windowData) break; \ winPos = grain->winPos; \ winInc = grain->winInc; \ amp = grain->curamp; \ } void Warp1_next(Warp1 *unit, int inNumSamples) { ClearUnitOutputs(unit, inNumSamples); GET_BUF SETUP_OUT CHECK_BUF for (uint32 n=0; n < numOutputs; n++) { int nextGrain = unit->mNextGrain[n]; for (int i=0; i < unit->mNumActive[n]; ) { WarpWinGrain *grain = unit->mGrains[n] + i; double loopMax = (double)bufFrames; double rate = grain->rate; double phase = grain->phase; DECLARE_WINDOW GET_GRAIN_AMP_PARAMS float *out1 = out[n]; int nsmps = sc_min(grain->counter, inNumSamples); if (grain->interp >= 4) { for (int j=0; jinterp >= 2) { for (int j=0; jphase = phase; SAVE_GRAIN_AMP_PARAMS if (grain->counter <= 0) *grain = unit->mGrains[n][--unit->mNumActive[n]]; // remove grain else ++i; } for (int i=0; imNumActive[n]+1 >= kMaxGrains) break; // uint32 bufnum = (uint32)GRAIN_IN_AT(unit, 0, i); // if (bufnum >= numBufs) break; float bufSampleRate = buf->samplerate; float bufRateScale = bufSampleRate * SAMPLEDUR; double loopMax = (double)bufFrames; WarpWinGrain *grain = unit->mGrains[n] + unit->mNumActive[n]++; // grain->bufnum = bufnum; float overlaps = GRAIN_IN_AT(unit, 5, i); float counter = GRAIN_IN_AT(unit, 3, i) * SAMPLERATE; double winrandamt = unit->mParent->mRGen->frand2() * (double)GRAIN_IN_AT(unit, 6, i); counter = sc_max(4., floor(counter + (counter * winrandamt))); grain->counter = (int)counter; nextGrain = (int)(counter / overlaps); unit->mNextGrain[n] = nextGrain; float rate = grain->rate = GRAIN_IN_AT(unit, 2, i) * bufRateScale; float phase = GRAIN_IN_AT(unit, 1, i) * (float)bufFrames; grain->interp = (int)GRAIN_IN_AT(unit, 7, i); float winType = grain->winType = (int)GRAIN_IN_AT(unit, 4, i); // the buffer that holds the grain shape DECLARE_WINDOW if (winType >= unit->mWorld->mNumSndBufs) { Print("Envelope buffer out of range!\n"); break; } GET_GRAIN_WIN_RELAXED(winType) if (windowData || (winType < 0.)) { GET_GRAIN_INIT_AMP float *out1 = out[n] + i; int nsmps = sc_min(grain->counter, inNumSamples - i); if (grain->interp >= 4) { for (int j=0; jinterp >= 2) { for (int j=0; jphase = phase; SAVE_GRAIN_AMP_PARAMS // end change if (grain->counter <= 0) *grain = unit->mGrains[n][--unit->mNumActive[n]]; // remove grain } } } unit->mNextGrain[n] = nextGrain; } } void Warp1_Ctor(Warp1 *unit) { SETCALC(Warp1_next); for(int i = 0; i < 16; i++){ unit->mNumActive[i] = 0; unit->mNextGrain[i] = 1; } ClearUnitOutputs(unit, 1); unit->m_fbufnum = -1e9f; } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(Grain) { ft = inTable; DefineDtorCantAliasUnit(GrainIn); DefineDtorCantAliasUnit(GrainSin); DefineDtorCantAliasUnit(GrainFM); DefineDtorCantAliasUnit(GrainBuf); DefineSimpleCantAliasUnit(Warp1); } SuperCollider-Source/server/plugins/IOUGens.cpp000644 000765 000024 00000134302 12756531745 022643 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #ifdef SC_IPHONE #include "SC_VFP11.h" #endif #ifdef SUPERNOVA #include "nova-tt/spin_lock.hpp" #include "nova-tt/rw_spinlock.hpp" #endif #ifdef NOVA_SIMD #include "simd_memory.hpp" #include "simd_mix.hpp" #include "simd_binary_arithmetic.hpp" #include "function_attributes.h" using nova::slope_argument; #endif #include static InterfaceTable *ft; ////////////////////////////////////////////////////////////////////////////////////////////////// struct IOUnit : public Unit { int32* m_busTouched; float m_fbusChannel; float *m_bus; }; struct XOut : public IOUnit { float m_xfade; }; struct OffsetOut : public IOUnit { float *m_saved; bool m_empty; }; struct AudioControl : public Unit { float *prevVal; // this will have to be a pointer later! }; const int kMaxLags = 16; struct LagControl : public IOUnit { float * m_b1; float * m_y1; }; struct LagIn : public IOUnit { float m_b1; float m_y1[kMaxLags]; }; struct LocalIn : public Unit { float *m_bus; int32 *m_busTouched; float *m_realData; }; extern "C" { void Control_Ctor(Unit *inUnit); void Control_next_k(Unit *unit, int inNumSamples); void Control_next_1(Unit *unit, int inNumSamples); void AudioControl_Ctor(AudioControl *inUnit); // void AudioControl_Dtor(AudioControl *inUnit); void AudioControl_next_k(AudioControl *unit, int inNumSamples); void AudioControl_next_1(AudioControl *unit, int inNumSamples); void TrigControl_Ctor(Unit *inUnit); void TrigControl_next_k(Unit *unit, int inNumSamples); void TrigControl_next_1(Unit *unit, int inNumSamples); void LagControl_Ctor(LagControl *inUnit); void LagControl_next_k(LagControl *unit, int inNumSamples); void LagControl_next_1(LagControl *unit, int inNumSamples); void InTrig_Ctor(IOUnit *unit); void InTrig_next_k(IOUnit *unit, int inNumSamples); void In_Ctor(IOUnit *unit); void In_next_a(IOUnit *unit, int inNumSamples); void In_next_k(IOUnit *unit, int inNumSamples); void LagIn_Ctor(LagIn *unit); void LagIn_next_0(LagIn *unit, int inNumSamples); void LagIn_next_k(LagIn *unit, int inNumSamples); void InFeedback_Ctor(IOUnit *unit); void InFeedback_next_a(IOUnit *unit, int inNumSamples); void LocalIn_Ctor(LocalIn *unit); void LocalIn_Dtor(LocalIn *unit); void LocalIn_next_a(LocalIn *unit, int inNumSamples); void LocalIn_next_k(LocalIn *unit, int inNumSamples); void Out_Ctor(IOUnit *unit); void Out_next_a(IOUnit *unit, int inNumSamples); void Out_next_k(IOUnit *unit, int inNumSamples); void XOut_Ctor(XOut *unit); void XOut_next_a(XOut *unit, int inNumSamples); void XOut_next_k(XOut *unit, int inNumSamples); void ReplaceOut_Ctor(IOUnit *unit); void ReplaceOut_next_a(IOUnit *unit, int inNumSamples); void ReplaceOut_next_k(IOUnit *unit, int inNumSamples); void OffsetOut_Ctor(OffsetOut *unit); void OffsetOut_Dtor(OffsetOut* unit); void OffsetOut_next_a(OffsetOut *unit, int inNumSamples); void LocalOut_Ctor(IOUnit *unit); void LocalOut_next_a(IOUnit *unit, int inNumSamples); void LocalOut_next_k(IOUnit *unit, int inNumSamples); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Control_next_k(Unit *unit, int inNumSamples) { uint32 numChannels = unit->mNumOutputs; float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; for (uint32 i=0; imParent->mMapControls + unit->mSpecialIndex; float *out = OUT(0); *out = **mapin; } void Control_Ctor(Unit* unit) { if (unit->mNumOutputs == 1) { SETCALC(Control_next_1); Control_next_1(unit, 1); } else { SETCALC(Control_next_k); Control_next_k(unit, 1); } } ////////////////////////////////////////////////////////////////////////////////////////////////// void AudioControl_next_k(AudioControl *unit, int inNumSamples) { uint32 numChannels = unit->mNumOutputs; float *prevVal = unit->prevVal; float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; for(uint32 i = 0; i < numChannels; ++i, mapin++){ float *out = OUT(i); int *mapRatep; int mapRate; float nextVal, curVal, valSlope; mapRatep = unit->mParent->mControlRates + unit->mSpecialIndex; mapRate = mapRatep[i]; switch (mapRate) { case 0 : { for(int j = 0; j < inNumSamples; j++){ out[j] = *mapin[0]; } } break; case 1 : { nextVal = *mapin[0]; curVal = prevVal[i]; valSlope = CALCSLOPE(nextVal, curVal); for(int j = 0; j < inNumSamples; j++){ out[j] = curVal; // should be prevVal curVal += valSlope; } unit->prevVal[i] = curVal; } break; case 2 : Copy(inNumSamples, out, *mapin); break; } } } void AudioControl_next_1(AudioControl *unit, int inNumSamples) { float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; float *out = OUT(0); int *mapRatep; int mapRate; float nextVal, curVal, valSlope; float* prevVal; prevVal = unit->prevVal; curVal = prevVal[0]; mapRatep = unit->mParent->mControlRates + unit->mSpecialIndex; mapRate = mapRatep[0]; switch (mapRate) { case 0 : { for(int i = 0; i < inNumSamples; i++){ out[i] = *mapin[0]; } } break; case 1 : { nextVal = *mapin[0]; valSlope = CALCSLOPE(nextVal, curVal); for(int i = 0; i < inNumSamples; i++){ out[i] = curVal; curVal += valSlope; } unit->prevVal[0] = curVal; } break; case 2 : Copy(inNumSamples, out, *mapin); break; } } void AudioControl_Ctor(AudioControl* unit) { unit->prevVal = (float*)RTAlloc(unit->mWorld, unit->mNumOutputs * sizeof(float)); for(int i = 0; i < unit->mNumOutputs; i++){ unit->prevVal[i] = 0.0; } if (unit->mNumOutputs == 1) { SETCALC(AudioControl_next_1); AudioControl_next_1(unit, 1); } else { SETCALC(AudioControl_next_k); AudioControl_next_k(unit, 1); } } void AudioControl_Dtor(AudioControl* unit) { RTFree(unit->mWorld, unit->prevVal); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void TrigControl_next_k(Unit *unit, int inNumSamples) { uint32 numChannels = unit->mNumOutputs; int specialIndex = unit->mSpecialIndex; Graph *parent = unit->mParent; float **mapin = parent->mMapControls + specialIndex; float *control = parent->mControls + specialIndex; float *buses = unit->mWorld->mControlBus; for (uint32 i=0; imSpecialIndex; Graph *parent = unit->mParent; float **mapin = parent->mMapControls + specialIndex; float *control = parent->mControls + specialIndex; float *out = OUT(0); // requires a bit of detective work to see what it has been mapped to. if (*mapin == control) { // read local control. *out = *control; } else { *out = **mapin; } // must zero the control even if mapped - otherwise it triggers on unmap *control = 0.f; } void TrigControl_Ctor(Unit* unit) { //Print("TrigControl_Ctor\n"); if (unit->mNumOutputs == 1) { SETCALC(TrigControl_next_1); } else { SETCALC(TrigControl_next_k); } ClearUnitOutputs(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LagControl_next_k(LagControl *unit, int inNumSamples) { uint32 numChannels = unit->mNumOutputs; float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; for (uint32 i=0; im_b1[i] * (unit->m_y1[i] - z); *out = unit->m_y1[i] = zapgremlins(x); } } void LagControl_next_1(LagControl *unit, int inNumSamples) { float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; float *out = OUT(0); float z = **mapin; float x = z + unit->m_b1[0] * (unit->m_y1[0] - z); *out = unit->m_y1[0] = zapgremlins(x); } void LagControl_Ctor(LagControl* unit) { int numChannels = unit->mNumInputs; float **mapin = unit->mParent->mMapControls + unit->mSpecialIndex; char * chunk = (char*)RTAlloc(unit->mWorld, numChannels * 2 * sizeof(float)); unit->m_y1 = (float*)chunk; unit->m_b1 = unit->m_y1 + numChannels; for (int i=0; im_y1[i] = **mapin; float lag = ZIN0(i); unit->m_b1[i] = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); } if (unit->mNumOutputs == 1) { SETCALC(LagControl_next_1); LagControl_next_1(unit, 1); } else { SETCALC(LagControl_next_k); LagControl_next_k(unit, 1); } } void LagControl_Dtor(LagControl* unit) { RTFree(unit->mWorld, unit->m_y1); } ////////////////////////////////////////////////////////////////////////////////////////////////// static inline void IO_a_update_channels(IOUnit * unit, World * world, float fbusChannel, int numChannels, int bufLength) { if (fbusChannel != unit->m_fbusChannel) { unit->m_fbusChannel = fbusChannel; int busChannel = (uint32)fbusChannel; int lastChannel = busChannel + numChannels; if (!(busChannel < 0 || lastChannel > (int)world->mNumAudioBusChannels)) { unit->m_bus = world->mAudioBus + (busChannel * bufLength); unit->m_busTouched = world->mAudioBusTouched + busChannel; } } } template static inline void IO_k_update_channels(IOUnit * unit, World * world, float fbusChannel, int numChannels) { if (fbusChannel != unit->m_fbusChannel) { unit->m_fbusChannel = fbusChannel; int busChannel = (int)fbusChannel; int lastChannel = busChannel + numChannels; if (!(busChannel < 0 || lastChannel > (int)world->mNumControlBusChannels)) { unit->m_bus = world->mControlBus + busChannel; if (UpdateTouched) unit->m_busTouched = world->mControlBusTouched + busChannel; } } } template struct AudioBusGuard { AudioBusGuard(const Unit * unit, int32 currentChannel, int32 maxChannel): unit(unit), mCurrentChannel(currentChannel), isValid(currentChannel < maxChannel) { if (isValid) lock(); } ~AudioBusGuard() { if (isValid) unlock(); } void lock() { if (LockShared) ACQUIRE_BUS_AUDIO_SHARED(mCurrentChannel); else ACQUIRE_BUS_AUDIO(mCurrentChannel); } void unlock() { if (LockShared) RELEASE_BUS_AUDIO_SHARED(mCurrentChannel); else RELEASE_BUS_AUDIO(mCurrentChannel); } const Unit * unit; const int32 mCurrentChannel; const bool isValid; }; #ifdef NOVA_SIMD FLATTEN void In_next_a_nova(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *in = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); float *out = OUT(i); if (guard.isValid && (touched[i] == bufCounter)) nova::copyvec_simd(out, in, inNumSamples); else nova::zerovec_simd(out, inNumSamples); } } FLATTEN void In_next_a_nova_64(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *in = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); float *out = OUT(i); if (guard.isValid && (touched[i] == bufCounter)) nova::copyvec_simd<64>(out, in); else nova::zerovec_simd<64>(out); } } #endif void In_next_a(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *in = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); float *out = OUT(i); if (guard.isValid && (touched[i] == bufCounter)) Copy(inNumSamples, out, in); else Fill(inNumSamples, out, 0.f); } } #ifdef IPHONE_VEC void vIn_next_a(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *in = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); float *out = OUT(i); if (guard.isValid && (touched[i] == bufCounter)) vcopy(out, in, inNumSamples); else vfill(out, 0.f, inNumSamples); } } #endif static inline float readControlBus(const float * bus, int channelIndex, int maxChannel) { if (channelIndex < maxChannel) return *bus; else return 0; } void In_next_k(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; uint32 numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; const float *in = unit->m_bus; for (uint32 i=0; iIn_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = std::numeric_limits::quiet_NaN(); if (unit->mCalcRate == calc_FullRate) { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(In_next_a_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(In_next_a_nova); else #endif SETCALC(In_next_a); unit->m_bus = world->mAudioBus; unit->m_busTouched = world->mAudioBusTouched; In_next_a(unit, 1); } else { SETCALC(In_next_k); unit->m_bus = world->mControlBus; //unit->m_busTouched = world->mControlBusTouched; In_next_k(unit, 1); } //Print("<-In_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void LagIn_next_k(LagIn *unit, int inNumSamples) { World *world = unit->mWorld; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; const float *in = unit->m_bus; float b1 = unit->m_b1; float *y1 = unit->m_y1; for (int i=0; imWorld; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; const float *in = unit->m_bus; float *y1 = unit->m_y1; for (int i=0; imWorld; unit->m_fbusChannel = -1.; float lag = ZIN0(1); unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); SETCALC(LagIn_next_k); unit->m_bus = world->mControlBus; LagIn_next_0(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void InFeedback_next_a(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *in = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); float *out = OUT(i); int diff = bufCounter - touched[i]; if (guard.isValid && (diff == 1 || diff == 0)) Copy(inNumSamples, out, in); else Fill(inNumSamples, out, 0.f); } } void InFeedback_Ctor(IOUnit* unit) { //Print("->InFeedback_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = -1.; SETCALC(InFeedback_next_a); unit->m_bus = world->mAudioBus; unit->m_busTouched = world->mAudioBusTouched; InFeedback_next_a(unit, 1); //Print("<-InFeedback_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// void InTrig_next_k(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; const float *in = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; imWorld; unit->m_fbusChannel = -1.; if (unit->mCalcRate == calc_FullRate) { SETCALC(ClearUnitOutputs); ClearUnitOutputs(unit, 1); } else { SETCALC(InTrig_next_k); unit->m_bus = world->mControlBus; unit->m_busTouched = world->mControlBusTouched; InTrig_next_k(unit, 1); } } ////////////////////////////////////////////////////////////////////////////////////////////////// void ReplaceOut_next_a(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); Copy(inNumSamples, out, in); touched[i] = bufCounter; } } } void ReplaceOut_next_k(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; float *out = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; imWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); nova::copyvec_simd(out, in, inNumSamples); touched[i] = bufCounter; } } } FLATTEN void ReplaceOut_next_a_nova_64(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); nova::copyvec_simd<64>(out, in); touched[i] = bufCounter; } } } #endif /* NOVA_SIMD */ void ReplaceOut_Ctor(IOUnit* unit) { World *world = unit->mWorld; unit->m_fbusChannel = -1.; if (unit->mCalcRate == calc_FullRate) { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(ReplaceOut_next_a_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(ReplaceOut_next_a_nova); else #endif SETCALC(ReplaceOut_next_a); unit->m_bus = world->mAudioBus; unit->m_busTouched = world->mAudioBusTouched; } else { SETCALC(ReplaceOut_next_k); unit->m_bus = world->mControlBus; unit->m_busTouched = world->mControlBusTouched; } } ////////////////////////////////////////////////////////////////////////////////////////////////// void Out_next_a(IOUnit *unit, int inNumSamples) { //Print("Out_next_a %d\n", unit->mNumInputs); World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); if (touched[i] == bufCounter) Accum(inNumSamples, out, in); else { Copy(inNumSamples, out, in); touched[i] = bufCounter; } } } } #ifdef IPHONE_VEC void vOut_next_a(IOUnit *unit, int inNumSamples) { //Print("Out_next_a %d\n", unit->mNumInputs); World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); if (touched[i] == bufCounter) { vadd(out, out, in, inNumSamples); } else { vcopy(out, in, inNumSamples); touched[i] = bufCounter; } } } } #endif #ifdef NOVA_SIMD FLATTEN void Out_next_a_nova(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); if (touched[i] == bufCounter) nova::addvec_simd(out, in, inNumSamples); else { nova::copyvec_simd(out, in, inNumSamples); touched[i] = bufCounter; } } } } FLATTEN void Out_next_a_nova_64(IOUnit *unit, int inNumSamples) { //Print("Out_next_a %d\n", unit->mNumInputs); World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+1); if (touched[i] == bufCounter) nova::addvec_simd<64>(out, in); else { nova::copyvec_simd<64>(out, in); touched[i] = bufCounter; } } } } #endif void Out_next_k(IOUnit *unit, int inNumSamples) { World *world = unit->mWorld; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; float *out = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; iOut_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = -1.; if (unit->mCalcRate == calc_FullRate) { #if defined(NOVA_SIMD) if (BUFLENGTH == 64) SETCALC(Out_next_a_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Out_next_a_nova); else SETCALC(Out_next_a); #else #ifdef IPHONE_VEC SETCALC(vOut_next_a); #else SETCALC(Out_next_a); #endif #endif unit->m_bus = world->mAudioBus; unit->m_busTouched = world->mAudioBusTouched; } else { SETCALC(Out_next_k); unit->m_bus = world->mControlBus; unit->m_busTouched = world->mControlBusTouched; } //Print("<-Out_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void XOut_next_a(XOut *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 2; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float next_xfade = ZIN0(1); float xfade0 = unit->m_xfade; float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; if (xfade0 != next_xfade) { float slope = CALCSLOPE(next_xfade, xfade0); for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float xfade = xfade0; float *in = IN(i+2); if (touched[i] == bufCounter) { LOOP1(inNumSamples, float zin = *in; float zout = *out; *out = zout + xfade * (zin - zout); //if (xxi==0) Print("x %d %d %g %g %g %g\n", bufCounter, i, zin, zout, xfade, *out); xfade += slope; ++out; ++in; ); } else { LOOP1(inNumSamples, float zin = *in; *out = xfade * zin; xfade += slope; ++out; ++in; ); touched[i] = bufCounter; } } } } else if (xfade0 == 1.f) { for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+2); Copy(inNumSamples, out, in); touched[i] = bufCounter; } } } else if (xfade0 == 0.f) { // do nothing. } else { for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+2); if (touched[i] == bufCounter) { LOOP1(inNumSamples, float zin = *in; float zout = *out; *out = zout + xfade0 * (zin - zout); ++out; ++in; ); } else { LOOP1(inNumSamples, float zin = *in; *out = xfade0 * zin; ++out; ++in; ); touched[i] = bufCounter; } } } } unit->m_xfade = next_xfade; } #ifdef NOVA_SIMD FLATTEN void XOut_next_a_nova(XOut *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 2; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); float next_xfade = ZIN0(1); float xfade0 = unit->m_xfade; float *out = unit->m_bus; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; if (xfade0 != next_xfade) { float slope = CALCSLOPE(next_xfade, xfade0); for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float xfade = xfade0; float *in = IN(i+2); if (touched[i] == bufCounter) nova::mix_vec_simd(out, out, slope_argument(1-xfade0, -slope), in, slope_argument(xfade0, slope), inNumSamples); else { nova::times_vec_simd(out, in, slope_argument(xfade, slope), inNumSamples); touched[i] = bufCounter; } } } unit->m_xfade = next_xfade; } else if (xfade0 == 1.f) { for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+2); nova::copyvec_simd(out, in, inNumSamples); touched[i] = bufCounter; } } } else if (xfade0 == 0.f) { // do nothing. } else { for (int i=0; i guard (unit, fbusChannel + i, maxChannel); if (guard.isValid) { float *in = IN(i+2); if (touched[i] == bufCounter) nova::mix_vec_simd(out, out, 1-xfade0, in, xfade0, inNumSamples); else { nova::times_vec_simd(out, in, xfade0, inNumSamples); touched[i] = bufCounter; } } } } } #endif void XOut_next_k(XOut *unit, int inNumSamples) { World *world = unit->mWorld; int numChannels = unit->mNumInputs - 2; float fbusChannel = ZIN0(0); IO_k_update_channels(unit, world, fbusChannel, numChannels); const int32 maxChannel = world->mNumControlBusChannels; const int32 firstOutputChannel = (int) fbusChannel; float xfade = ZIN0(1); float *out = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; iOut_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = -1.; unit->m_xfade = ZIN0(1); if (unit->mCalcRate == calc_FullRate) { #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(XOut_next_a_nova); #endif SETCALC(XOut_next_a); unit->m_bus = world->mAudioBus; unit->m_busTouched = world->mAudioBusTouched; } else { SETCALC(XOut_next_k); unit->m_bus = world->mControlBus; unit->m_busTouched = world->mControlBusTouched; } //Print("<-Out_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// void OffsetOut_next_a(OffsetOut *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); IO_a_update_channels(unit, world, fbusChannel, numChannels, bufLength); int32 offset = unit->mParent->mSampleOffset; int32 remain = BUFLENGTH - offset; float *out = unit->m_bus; float *saved = unit->m_saved; int32 *touched = unit->m_busTouched; const int32 bufCounter = unit->mWorld->mBufCounter; const int32 maxChannel = world->mNumAudioBusChannels; for (int i=0; i guard (unit, fbusChannel + i, maxChannel); float *in = IN(i+1); //Print("out %d %d %d %d %d\n", // i, touched[i] == bufCounter, unit->m_empty, // offset, remain); if (guard.isValid) { if (touched[i] == bufCounter) { if (unit->m_empty) { //Print("touched offset %d\n", offset); } else { Accum(offset, out, saved); } Accum(remain, out + offset, in); } else { if (unit->m_empty) { Clear(offset, out); //Print("untouched offset %d\n", offset); } else { Copy(offset, out, saved); } Copy(remain, out + offset, in); touched[i] = bufCounter; } } Copy(offset, saved, in + remain); //Print("out %d %d %d %g %g\n", i, in[0], out[0]); } unit->m_empty = false; } void OffsetOut_Ctor(OffsetOut* unit) { //Print("->Out_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = -1.; SETCALC(OffsetOut_next_a); unit->m_bus = world->mAudioBus; unit->m_busTouched = world->mAudioBusTouched; int32 offset = unit->mParent->mSampleOffset; int numChannels = unit->mNumInputs - 1; unit->m_saved = (float*)RTAlloc(unit->mWorld, offset * numChannels * sizeof(float)); unit->m_empty = true; //Print("<-Out_Ctor\n"); } void OffsetOut_Dtor(OffsetOut* unit) { // Ctor may not have run, if unit was immediately created->paused->freed! if(unit->m_saved){ World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs - 1; int32 offset = unit->mParent->mSampleOffset; int32 remain = BUFLENGTH - offset; float *out = unit->m_bus; float *saved = unit->m_saved; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; im_empty, // offset, remain); if (!unit->m_empty) { if (touched[i] == bufCounter) { Accum(offset, out, saved); } else { Copy(offset, out, saved); Clear(remain, out + offset); touched[i] = bufCounter; } } //Print("out %d %d %d %g %g\n", i, in[0], out[0]); } RTFree(unit->mWorld, unit->m_saved); } } ////////////////////////////////////////////////////////////////////////////////////////////////// void SharedIn_next_k(IOUnit *unit, int inNumSamples) { //Print("->SharedIn_next_k\n"); World *world = unit->mWorld; int numChannels = unit->mNumOutputs; float fbusChannel = ZIN0(0); if (fbusChannel != unit->m_fbusChannel) { unit->m_fbusChannel = fbusChannel; uint32 busChannel = (uint32)fbusChannel; uint32 lastChannel = busChannel + numChannels; if (!(lastChannel > world->mNumSharedControls)) { unit->m_bus = world->mSharedControls + busChannel; } } float *in = unit->m_bus; if (in) { for (int i=0; iSharedIn_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = -1.; SETCALC(SharedIn_next_k); unit->m_bus = world->mSharedControls; SharedIn_next_k(unit, 1); //Print("<-SharedIn_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void SharedOut_next_k(IOUnit *unit, int inNumSamples) { //Print("->SharedOut_next_k\n"); World *world = unit->mWorld; int numChannels = unit->mNumInputs - 1; float fbusChannel = ZIN0(0); if (fbusChannel != unit->m_fbusChannel) { unit->m_fbusChannel = fbusChannel; uint32 busChannel = (uint32)fbusChannel; uint32 lastChannel = busChannel + numChannels; if (!(lastChannel > world->mNumSharedControls)) { unit->m_bus = world->mSharedControls + busChannel; } } float *out = unit->m_bus; if (out) { for (int i=1; iSharedOut_Ctor\n"); World *world = unit->mWorld; unit->m_fbusChannel = -1.; SETCALC(SharedOut_next_k); unit->m_bus = world->mSharedControls; SharedOut_next_k(unit, 1); //Print("<-SharedOut_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LocalIn_next_a(LocalIn *unit, int inNumSamples) { World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float *in = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; imWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float *in = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; imWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumOutputs; float *in = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; i(out, in); else //nova::zerovec_simd<64>(out); Fill(inNumSamples, out, IN0(i)); } } #endif void LocalIn_next_k(LocalIn *unit, int inNumSamples) { uint32 numChannels = unit->mNumOutputs; float *in = unit->m_bus; int32 *touched = unit->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (uint32 i=0; iLocalIn_Ctor\n"); int numChannels = unit->mNumOutputs; World *world = unit->mWorld; int busDataSize = numChannels * BUFLENGTH; // align the buffer to 256 bytes so that we can use avx instructions unit->m_realData = (float*)RTAlloc(world, busDataSize * sizeof(float) + numChannels * sizeof(int32) + 32 * sizeof(float)); size_t alignment = (size_t)unit->m_realData & 31; unit->m_bus = alignment ? (float*)(size_t(unit->m_realData + 32) & ~31) : unit->m_realData; unit->m_busTouched = (int32*)(unit->m_bus + busDataSize); for (int i=0; im_busTouched[i] = -1; if (unit->mCalcRate == calc_FullRate) { if (unit->mParent->mLocalAudioBusUnit) { SETCALC(ClearUnitOutputs); ClearUnitOutputs(unit, 1); return; } unit->mParent->mLocalAudioBusUnit = unit; #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(LocalIn_next_a_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(LocalIn_next_a_nova); else #endif SETCALC(LocalIn_next_a); LocalIn_next_a(unit, 1); } else { if (unit->mParent->mLocalControlBusUnit) { SETCALC(ClearUnitOutputs); ClearUnitOutputs(unit, 1); return; } unit->mParent->mLocalControlBusUnit = unit; SETCALC(LocalIn_next_k); LocalIn_next_k(unit, 1); } //Print("<-LocalIn_Ctor\n"); } void LocalIn_Dtor(LocalIn* unit) { World *world = unit->mWorld; RTFree(world, unit->m_realData); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// void LocalOut_next_a(IOUnit *unit, int inNumSamples) { //Print("LocalOut_next_a %d\n", unit->mNumInputs); World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs; LocalIn *localIn = (LocalIn*)unit->mParent->mLocalAudioBusUnit; if (!localIn) return; float *out = localIn->m_bus; if ((out == NULL) || (numChannels != localIn->mNumOutputs)) return; int32 *touched = localIn->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; imNumInputs); World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs; LocalIn *localIn = (LocalIn*)unit->mParent->mLocalAudioBusUnit; if (!localIn) return; float *out = localIn->m_bus; if ((out == NULL) || (numChannels != localIn->mNumOutputs)) return; int32 *touched = localIn->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; imNumInputs); World *world = unit->mWorld; int bufLength = world->mBufLength; int numChannels = unit->mNumInputs; LocalIn *localIn = (LocalIn*)unit->mParent->mLocalAudioBusUnit; if (!localIn) return; float *out = localIn->m_bus; if ((out == NULL) || (numChannels != localIn->mNumOutputs)) return; int32 *touched = localIn->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; i(out, in); else { nova::copyvec_simd<64>(out, in); touched[i] = bufCounter; } //Print("LocalOut %d %g %g\n", i, in[0], out[0]); } } #endif void LocalOut_next_k(IOUnit *unit, int inNumSamples) { int numChannels = unit->mNumInputs; LocalIn *localIn = (LocalIn*)unit->mParent->mLocalControlBusUnit; if (!localIn) return; float *out = localIn->m_bus; if ((out == NULL) || (numChannels != localIn->mNumOutputs)) return; int32 *touched = localIn->m_busTouched; int32 bufCounter = unit->mWorld->mBufCounter; for (int i=0; iLocalOut_Ctor\n"); unit->m_fbusChannel = -1.; if (unit->mCalcRate == calc_FullRate) { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(LocalOut_next_a_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(LocalOut_next_a_nova); else #endif SETCALC(LocalOut_next_a); } else { SETCALC(LocalOut_next_k); } //Print("<-LocalOut_Ctor\n"); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(IO) { ft = inTable; DefineDtorUnit(OffsetOut); DefineDtorUnit(LocalIn); DefineSimpleUnit(XOut); DefineDtorUnit(LagControl); DefineDtorUnit(AudioControl); DefineUnit("Control", sizeof(Unit), (UnitCtorFunc)&Control_Ctor, 0, 0); DefineUnit("TrigControl", sizeof(Unit), (UnitCtorFunc)&TrigControl_Ctor, 0, 0); DefineUnit("ReplaceOut", sizeof(IOUnit), (UnitCtorFunc)&ReplaceOut_Ctor, 0, 0); DefineUnit("Out", sizeof(IOUnit), (UnitCtorFunc)&Out_Ctor, 0, 0); DefineUnit("LocalOut", sizeof(IOUnit), (UnitCtorFunc)&LocalOut_Ctor, 0, 0); DefineUnit("In", sizeof(IOUnit), (UnitCtorFunc)&In_Ctor, 0, 0); DefineUnit("LagIn", sizeof(IOUnit), (UnitCtorFunc)&LagIn_Ctor, 0, 0); DefineUnit("InFeedback", sizeof(IOUnit), (UnitCtorFunc)&InFeedback_Ctor, 0, 0); DefineUnit("InTrig", sizeof(IOUnit), (UnitCtorFunc)&InTrig_Ctor, 0, 0); DefineUnit("SharedOut", sizeof(IOUnit), (UnitCtorFunc)&SharedOut_Ctor, 0, 0); DefineUnit("SharedIn", sizeof(IOUnit), (UnitCtorFunc)&SharedIn_Ctor, 0, 0); } SuperCollider-Source/server/plugins/KeyTrack.cpp000644 000765 000024 00000120316 12321461511 023064 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //Nick Collins 20 Feb 2006 //revision of algorithm 22 Nov 2007 //Key tracker using weights of FFT bins. #include "ML.h" #include "FFT_UGens.h" //hard coded FFT size #define N 4096 #define NOVER2 2048 //CONVERT TO m_frameperiod to cope with different sampling rates? #define FRAMEPERIOD 0.046439909297052 //weighting parameters //4096 FFT at 44100 SR static float g_weights44100[720]= { 0.89160997732426, 0.10839002267574, 0.39160997732426, 0.10839002267574, 0.2249433106576, 0.10839002267574, 0.14160997732426, 0.10839002267574, 0.091609977324263, 0.10839002267574, 0.05827664399093, 0.10839002267574, 0.58784929938181, 0.41215070061819, 0.087849299381813, 0.41215070061819, 0.25451596604848, 0.078817367284855, 0.087849299381813, 0.16215070061819, 0.18784929938181, 0.012150700618187, 0.087849299381812, 0.078817367284855, 0.26602607158423, 0.73397392841577, 0.26602607158423, 0.23397392841577, 0.26602607158423, 0.067307261749107, 0.016026071584227, 0.23397392841577, 0.066026071584226, 0.13397392841577, 0.099359404917559, 0.067307261749107, 0.9250662388251, 0.074933761174898, 0.4250662388251, 0.074933761174898, 0.25839957215844, 0.074933761174898, 0.1750662388251, 0.074933761174898, 0.1250662388251, 0.074933761174898, 0.091732905491768, 0.074933761174898, 0.56383187935789, 0.43616812064211, 0.063831879357891, 0.43616812064211, 0.23049854602456, 0.10283478730877, 0.063831879357891, 0.18616812064211, 0.16383187935789, 0.03616812064211, 0.063831879357892, 0.10283478730877, 0.18111740708786, 0.81888259291214, 0.18111740708786, 0.31888259291214, 0.18111740708786, 0.15221592624547, 0.18111740708786, 0.068882592912141, 0.18111740708786, 0.018882592912141, 0.014450740421193, 0.15221592624547, 0.77564554804057, 0.22435445195943, 0.27564554804057, 0.22435445195943, 0.1089788813739, 0.22435445195943, 0.02564554804057, 0.22435445195943, 0.17564554804057, 0.024354451959429, 0.1089788813739, 0.057687785292764, 0.34606307757871, 0.65393692242129, 0.34606307757871, 0.15393692242129, 0.012729744245378, 0.32060358908796, 0.096063077578711, 0.15393692242129, 0.14606307757871, 0.053936922421289, 0.012729744245378, 0.15393692242129, 0.89093630414068, 0.10906369585932, 0.39093630414068, 0.10906369585932, 0.22426963747401, 0.10906369585932, 0.14093630414068, 0.10906369585932, 0.090936304140679, 0.10906369585932, 0.057602970807346, 0.10906369585932, 0.40874628442826, 0.59125371557174, 0.40874628442826, 0.091253715571737, 0.075412951094929, 0.2579203822384, 0.15874628442826, 0.091253715571737, 0.0087462844282626, 0.19125371557174, 0.075412951094929, 0.091253715571738, 0.89788375407457, 0.10211624592543, 0.39788375407457, 0.10211624592543, 0.23121708740791, 0.10211624592543, 0.14788375407457, 0.10211624592543, 0.097883754074573, 0.10211624592543, 0.06455042074124, 0.10211624592543, 0.35664375687383, 0.64335624312617, 0.35664375687383, 0.14335624312617, 0.023310423540502, 0.31002290979283, 0.10664375687383, 0.14335624312617, 0.15664375687384, 0.043356243126163, 0.023310423540502, 0.14335624312616, 0.78321995464853, 0.21678004535147, 0.28321995464853, 0.21678004535147, 0.11655328798186, 0.21678004535147, 0.033219954648526, 0.21678004535147, 0.18321995464853, 0.016780045351474, 0.11655328798186, 0.050113378684807, 0.17569859876363, 0.82430140123637, 0.17569859876363, 0.32430140123637, 0.17569859876362, 0.15763473456971, 0.17569859876363, 0.074301401236374, 0.17569859876363, 0.024301401236373, 0.0090319320969575, 0.15763473456971, 0.53205214316846, 0.46794785683154, 0.032052143168455, 0.46794785683154, 0.19871880983512, 0.13461452349821, 0.032052143168455, 0.21794785683154, 0.13205214316846, 0.067947856831543, 0.032052143168454, 0.13461452349821, 0.8501324776502, 0.1498675223498, 0.3501324776502, 0.1498675223498, 0.18346581098354, 0.1498675223498, 0.1001324776502, 0.1498675223498, 0.050132477650203, 0.1498675223498, 0.01679914431687, 0.1498675223498, 0.12766375871578, 0.87233624128422, 0.12766375871578, 0.37233624128422, 0.12766375871578, 0.20566957461755, 0.12766375871578, 0.12233624128422, 0.12766375871578, 0.072336241284219, 0.12766375871578, 0.039002907950883, 0.36223481417572, 0.63776518582428, 0.36223481417572, 0.13776518582428, 0.028901480842386, 0.30443185249095, 0.11223481417572, 0.13776518582428, 0.16223481417572, 0.037765185824279, 0.028901480842386, 0.13776518582428, 0.55129109608114, 0.44870890391886, 0.05129109608114, 0.44870890391886, 0.21795776274781, 0.11537557058553, 0.05129109608114, 0.19870890391886, 0.15129109608114, 0.048708903918859, 0.051291096081139, 0.11537557058553, 0.69212615515742, 0.30787384484258, 0.19212615515742, 0.30787384484258, 0.025459488490756, 0.30787384484258, 0.19212615515742, 0.057873844842579, 0.092126155157422, 0.10787384484258, 0.025459488490756, 0.14120717817591, 0.78187260828136, 0.21812739171864, 0.28187260828136, 0.21812739171864, 0.11520594161469, 0.21812739171864, 0.031872608281361, 0.21812739171864, 0.18187260828136, 0.018127391718639, 0.11520594161469, 0.051460725051972, 0.81749256885653, 0.18250743114347, 0.31749256885653, 0.18250743114347, 0.15082590218986, 0.18250743114348, 0.067492568856526, 0.18250743114347, 0.017492568856525, 0.18250743114347, 0.15082590218986, 0.015840764476809, 0.79576750814915, 0.20423249185085, 0.29576750814915, 0.20423249185085, 0.12910084148248, 0.20423249185085, 0.045767508149147, 0.20423249185085, 0.19576750814915, 0.0042324918508541, 0.12910084148248, 0.037565825184186, 0.71328751374767, 0.28671248625233, 0.21328751374767, 0.28671248625233, 0.046620847081009, 0.28671248625232, 0.21328751374767, 0.036712486252327, 0.11328751374767, 0.086712486252327, 0.046620847081009, 0.12004581958566, 0.56643990929705, 0.43356009070295, 0.066439909297053, 0.43356009070295, 0.23310657596372, 0.10022675736961, 0.066439909297053, 0.18356009070295, 0.16643990929705, 0.033560090702949, 0.066439909297053, 0.10022675736961, 0.35139719752725, 0.64860280247275, 0.35139719752725, 0.14860280247275, 0.018063864193915, 0.31526946913942, 0.10139719752725, 0.14860280247275, 0.15139719752725, 0.048602802472746, 0.018063864193915, 0.14860280247275, 0.06410428633691, 0.93589571366309, 0.06410428633691, 0.43589571366309, 0.064104286336909, 0.26922904699642, 0.06410428633691, 0.18589571366309, 0.064104286336914, 0.13589571366309, 0.064104286336909, 0.10256238032976, 0.70026495530041, 0.29973504469959, 0.20026495530041, 0.29973504469959, 0.03359828863374, 0.29973504469959, 0.20026495530041, 0.049735044699592, 0.10026495530041, 0.099735044699594, 0.03359828863374, 0.13306837803293, 0.25532751743156, 0.74467248256844, 0.25532751743156, 0.24467248256844, 0.25532751743157, 0.078005815901766, 0.0053275174315637, 0.24467248256844, 0.055327517431562, 0.14467248256844, 0.088660850764901, 0.078005815901766, 0.72446962835144, 0.27553037164856, 0.22446962835144, 0.27553037164856, 0.057802961684772, 0.27553037164856, 0.22446962835144, 0.025530371648557, 0.12446962835144, 0.075530371648557, 0.057802961684772, 0.1088637049819, 0.10258219216228, 0.89741780783772, 0.10258219216228, 0.39741780783772, 0.10258219216228, 0.23075114117105, 0.10258219216228, 0.14741780783772, 0.10258219216228, 0.097417807837718, 0.10258219216228, 0.064084474504388, 0.38425231031485, 0.61574768968515, 0.38425231031485, 0.11574768968515, 0.050918976981516, 0.28241435635182, 0.13425231031485, 0.11574768968515, 0.18425231031485, 0.015747689685151, 0.050918976981516, 0.11574768968515, 0.56374521656272, 0.43625478343728, 0.063745216562722, 0.43625478343728, 0.23041188322939, 0.10292145010394, 0.063745216562722, 0.18625478343728, 0.16374521656272, 0.036254783437278, 0.063745216562722, 0.10292145010394, 0.63498513771305, 0.36501486228695, 0.13498513771305, 0.36501486228695, 0.30165180437972, 0.031681528953617, 0.13498513771305, 0.11501486228695, 0.034985137713051, 0.16501486228695, 0.13498513771305, 0.031681528953617, 0.5915350162983, 0.4084649837017, 0.091535016298302, 0.4084649837017, 0.25820168296497, 0.075131650368367, 0.091535016298302, 0.1584649837017, 0.1915350162983, 0.0084649837017025, 0.091535016298299, 0.075131650368367, 0.42657502749535, 0.57342497250465, 0.42657502749535, 0.073424972504654, 0.093241694162018, 0.24009163917132, 0.17657502749535, 0.073424972504654, 0.026575027495346, 0.17342497250465, 0.093241694162018, 0.073424972504649, 0.13287981859411, 0.86712018140589, 0.13287981859411, 0.36712018140589, 0.13287981859411, 0.20045351473923, 0.13287981859411, 0.11712018140589, 0.1328798185941, 0.067120181405897, 0.13287981859411, 0.033786848072561, 0.7027943950545, 0.2972056049455, 0.2027943950545, 0.2972056049455, 0.03612772838783, 0.2972056049455, 0.2027943950545, 0.047205604945496, 0.10279439505451, 0.097205604945492, 0.03612772838783, 0.13053893827884, 0.12820857267382, 0.87179142732618, 0.12820857267382, 0.37179142732618, 0.12820857267382, 0.20512476065952, 0.12820857267382, 0.12179142732618, 0.12820857267383, 0.071791427326173, 0.12820857267382, 0.038458093992849, 0.40052991060082, 0.59947008939918, 0.40052991060082, 0.099470089399183, 0.067196577267481, 0.26613675606585, 0.15052991060082, 0.099470089399183, 0.0005299106008124, 0.19947008939919, 0.067196577267481, 0.099470089399186, 0.51065503486313, 0.48934496513687, 0.010655034863127, 0.48934496513687, 0.1773217015298, 0.15601163180353, 0.010655034863127, 0.23934496513687, 0.11065503486312, 0.089344965136877, 0.010655034863134, 0.15601163180353, 0.44893925670289, 0.55106074329711, 0.44893925670289, 0.051060743297114, 0.11560592336954, 0.21772740996379, 0.19893925670289, 0.051060743297114, 0.048939256702886, 0.15106074329711, 0.11560592336954, 0.051060743297124, 0.20516438432456, 0.79483561567544, 0.20516438432456, 0.29483561567544, 0.20516438432456, 0.12816894900878, 0.20516438432456, 0.044835615675439, 0.0051643843245643, 0.19483561567544, 0.03849771765789, 0.12816894900878, 0.7685046206297, 0.2314953793703, 0.2685046206297, 0.2314953793703, 0.10183795396303, 0.2314953793703, 0.018504620629699, 0.2314953793703, 0.1685046206297, 0.031495379370301, 0.10183795396303, 0.064828712703635, 0.12749043312544, 0.87250956687456, 0.12749043312544, 0.37250956687456, 0.12749043312544, 0.20584290020789, 0.12749043312544, 0.12250956687456, 0.12749043312544, 0.072509566874555, 0.12749043312544, 0.039176233541222, 0.2699702754261, 0.7300297245739, 0.2699702754261, 0.2300297245739, 0.2699702754261, 0.063363057907234, 0.019970275426104, 0.2300297245739, 0.069970275426101, 0.1300297245739, 0.10330360875943, 0.063363057907234, 0.1830700325966, 0.8169299674034, 0.1830700325966, 0.3169299674034, 0.1830700325966, 0.15026330073673, 0.1830700325966, 0.066929967403397, 0.18307003259659, 0.016929967403405, 0.016403365929932, 0.15026330073673, 0.85315005499069, 0.14684994500931, 0.35315005499069, 0.14684994500931, 0.18648338832404, 0.1468499450093, 0.10315005499069, 0.14684994500931, 0.053150054990692, 0.14684994500931, 0.019816721657368, 0.1468499450093, 0.26575963718821, 0.73424036281179, 0.26575963718821, 0.23424036281179, 0.26575963718821, 0.067573696145123, 0.015759637188211, 0.23424036281179, 0.065759637188205, 0.13424036281179, 0.099092970521544, 0.067573696145123, 0.40558879010901, 0.59441120989099, 0.40558879010901, 0.094411209890993, 0.07225545677566, 0.26107787655767, 0.15558879010901, 0.094411209890993, 0.0055887901090159, 0.19441120989098, 0.07225545677566, 0.094411209891007, 0.25641714534767, 0.74358285465233, 0.25641714534767, 0.24358285465233, 0.25641714534767, 0.07691618798566, 0.0064171453476689, 0.24358285465233, 0.056417145347666, 0.14358285465233, 0.089750478681007, 0.07691618798566, 0.80105982120163, 0.19894017879837, 0.30105982120163, 0.19894017879837, 0.13439315453496, 0.19894017879837, 0.051059821201633, 0.19894017879837, 0.0010598212016248, 0.19894017879838, 0.13439315453496, 0.032273512131705, 0.021310069726255, 0.97868993027375, 0.021310069726255, 0.47868993027375, 0.021310069726269, 0.31202326360706, 0.021310069726255, 0.22868993027375, 0.021310069726246, 0.17868993027375, 0.021310069726269, 0.1453565969404, 0.89787851340579, 0.10212148659421, 0.39787851340579, 0.10212148659421, 0.23121184673912, 0.10212148659421, 0.14787851340579, 0.10212148659421, 0.097878513405794, 0.10212148659421, 0.064545180072457, 0.10212148659421, 0.41032876864912, 0.58967123135088, 0.41032876864912, 0.089671231350877, 0.07699543531578, 0.25633789801755, 0.16032876864912, 0.089671231350877, 0.010328768649129, 0.18967123135087, 0.07699543531578, 0.089671231350887, 0.5370092412594, 0.4629907587406, 0.037009241259398, 0.4629907587406, 0.20367590792606, 0.12965742540727, 0.037009241259398, 0.2129907587406, 0.1370092412594, 0.062990758740602, 0.037009241259398, 0.12965742540727, 0.25498086625089, 0.74501913374911, 0.25498086625089, 0.24501913374911, 0.25498086625089, 0.078352467082444, 0.0049808662508894, 0.24501913374911, 0.054980866250889, 0.14501913374911, 0.088314199584223, 0.078352467082444, 0.53994055085221, 0.46005944914779, 0.039940550852208, 0.46005944914779, 0.20660721751887, 0.12672611581447, 0.039940550852208, 0.21005944914779, 0.1399405508522, 0.060059449147798, 0.039940550852198, 0.12672611581447, 0.36614006519321, 0.63385993480679, 0.36614006519321, 0.13385993480679, 0.032806731859864, 0.30052660147347, 0.11614006519321, 0.13385993480679, 0.16614006519319, 0.03385993480681, 0.032806731859864, 0.1338599348068, 0.70630010998138, 0.29369989001862, 0.20630010998138, 0.29369989001862, 0.039633443314737, 0.2936998900186, 0.20630010998138, 0.043699890018615, 0.10630010998138, 0.093699890018615, 0.039633443314737, 0.12703322335193 }; static int g_bins44100[720]= { 5, 6, 10, 11, 15, 16, 20, 21, 25, 26, 30, 31, 5, 6, 10, 11, 16, 17, 21, 22, 27, 28, 32, 33, 5, 6, 11, 12, 17, 18, 22, 23, 28, 29, 34, 35, 6, 7, 12, 13, 18, 19, 24, 25, 30, 31, 36, 37, 6, 7, 12, 13, 19, 20, 25, 26, 32, 33, 38, 39, 6, 7, 13, 14, 20, 21, 27, 28, 34, 35, 40, 41, 7, 8, 14, 15, 21, 22, 28, 29, 36, 37, 43, 44, 7, 8, 15, 16, 22, 23, 30, 31, 38, 39, 45, 46, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 8, 9, 17, 18, 25, 26, 34, 35, 42, 43, 51, 52, 9, 10, 18, 19, 27, 28, 36, 37, 45, 46, 54, 55, 9, 10, 19, 20, 28, 29, 38, 39, 48, 49, 57, 58, 10, 11, 20, 21, 30, 31, 40, 41, 51, 52, 61, 62, 10, 11, 21, 22, 32, 33, 43, 44, 54, 55, 64, 65, 11, 12, 22, 23, 34, 35, 45, 46, 57, 58, 68, 69, 12, 13, 24, 25, 36, 37, 48, 49, 60, 61, 72, 73, 12, 13, 25, 26, 38, 39, 51, 52, 64, 65, 77, 78, 13, 14, 27, 28, 40, 41, 54, 55, 68, 69, 81, 82, 14, 15, 28, 29, 43, 44, 57, 58, 72, 73, 86, 87, 15, 16, 30, 31, 45, 46, 61, 62, 76, 77, 91, 92, 16, 17, 32, 33, 48, 49, 64, 65, 81, 82, 97, 98, 17, 18, 34, 35, 51, 52, 68, 69, 85, 86, 103, 104, 18, 19, 36, 37, 54, 55, 72, 73, 91, 92, 109, 110, 19, 20, 38, 39, 57, 58, 77, 78, 96, 97, 115, 116, 20, 21, 40, 41, 61, 62, 81, 82, 102, 103, 122, 123, 21, 22, 43, 44, 64, 65, 86, 87, 108, 109, 129, 130, 22, 23, 45, 46, 68, 69, 91, 92, 114, 115, 137, 138, 24, 25, 48, 49, 72, 73, 97, 98, 121, 122, 145, 146, 25, 26, 51, 52, 77, 78, 102, 103, 128, 129, 154, 155, 27, 28, 54, 55, 81, 82, 109, 110, 136, 137, 163, 164, 28, 29, 57, 58, 86, 87, 115, 116, 144, 145, 173, 174, 30, 31, 61, 62, 91, 92, 122, 123, 153, 154, 183, 184, 32, 33, 64, 65, 97, 98, 129, 130, 162, 163, 194, 195, 34, 35, 68, 69, 103, 104, 137, 138, 171, 172, 206, 207, 36, 37, 72, 73, 109, 110, 145, 146, 182, 183, 218, 219, 38, 39, 77, 78, 115, 116, 154, 155, 192, 193, 231, 232, 40, 41, 81, 82, 122, 123, 163, 164, 204, 205, 245, 246, 43, 44, 86, 87, 129, 130, 173, 174, 216, 217, 259, 260, 45, 46, 91, 92, 137, 138, 183, 184, 229, 230, 275, 276, 48, 49, 97, 98, 145, 146, 194, 195, 242, 243, 291, 292, 51, 52, 102, 103, 154, 155, 205, 206, 257, 258, 308, 309, 54, 55, 109, 110, 163, 164, 218, 219, 272, 273, 327, 328, 57, 58, 115, 116, 173, 174, 231, 232, 288, 289, 346, 347, 61, 62, 122, 123, 183, 184, 244, 245, 306, 307, 367, 368, 64, 65, 129, 130, 194, 195, 259, 260, 324, 325, 389, 390, 68, 69, 137, 138, 206, 207, 274, 275, 343, 344, 412, 413, 72, 73, 145, 146, 218, 219, 291, 292, 364, 365, 436, 437, 77, 78, 154, 155, 231, 232, 308, 309, 385, 386, 462, 463, 81, 82, 163, 164, 245, 246, 326, 327, 408, 409, 490, 491, 86, 87, 173, 174, 259, 260, 346, 347, 432, 433, 519, 520, 91, 92, 183, 184, 275, 276, 366, 367, 458, 459, 550, 551, 97, 98, 194, 195, 291, 292, 388, 389, 485, 486, 583, 584, 102, 103, 205, 206, 308, 309, 411, 412, 514, 515, 617, 618, 109, 110, 218, 219, 327, 328, 436, 437, 545, 546, 654, 655, 115, 116, 231, 232, 346, 347, 462, 463, 577, 578, 693, 694, 122, 123, 244, 245, 367, 368, 489, 490, 612, 613, 734, 735, 129, 130, 259, 260, 389, 390, 518, 519, 648, 649, 778, 779, 137, 138, 274, 275, 412, 413, 549, 550, 687, 688, 824, 825, 145, 146, 291, 292, 436, 437, 582, 583, 728, 729, 873, 874, 154, 155, 308, 309, 462, 463, 617, 618, 771, 772, 925, 926 }; //4096 FFT at 48000 SR static float g_weights48000[720]= { 0.30666666666667, 0.69333333333333, 0.30666666666667, 0.19333333333333, 0.30666666666667, 0.026666666666667, 0.056666666666667, 0.19333333333333, 0.10666666666667, 0.093333333333333, 0.14, 0.026666666666667, 0.027586543807041, 0.97241345619296, 0.027586543807041, 0.47241345619296, 0.02758654380704, 0.30574678952629, 0.027586543807041, 0.22241345619296, 0.027586543807041, 0.17241345619296, 0.02758654380704, 0.13908012285963, 0.73191145326801, 0.26808854673199, 0.23191145326801, 0.26808854673199, 0.065244786601342, 0.26808854673199, 0.23191145326801, 0.018088546731992, 0.13191145326801, 0.068088546731992, 0.065244786601342, 0.10142188006533, 0.41865460692056, 0.58134539307944, 0.41865460692056, 0.081345393079437, 0.08532127358723, 0.2480120597461, 0.16865460692056, 0.081345393079437, 0.018654606920562, 0.18134539307944, 0.08532127358723, 0.081345393079437, 0.086770539160062, 0.91322946083994, 0.086770539160062, 0.41322946083994, 0.086770539160063, 0.24656279417327, 0.086770539160062, 0.16322946083994, 0.086770539160062, 0.11322946083994, 0.086770539160063, 0.079896127506604, 0.73515161776197, 0.26484838223803, 0.23515161776197, 0.26484838223803, 0.068484951095304, 0.26484838223803, 0.23515161776197, 0.014848382238029, 0.13515161776197, 0.064848382238029, 0.068484951095304, 0.098181715571363, 0.36262434726227, 0.63737565273773, 0.36262434726227, 0.13737565273773, 0.02929101392894, 0.30404231940439, 0.11262434726227, 0.13737565273773, 0.16262434726227, 0.037375652737727, 0.02929101392894, 0.13737565273773, 0.96794545252544, 0.032054547474559, 0.46794545252544, 0.032054547474559, 0.30127878585877, 0.03205454747456, 0.21794545252544, 0.032054547474559, 0.16794545252544, 0.03205454747456, 0.13461211919211, 0.03205454747456, 0.54979772942925, 0.45020227057075, 0.049797729429249, 0.45020227057075, 0.21646439609592, 0.11686893723742, 0.049797729429249, 0.20020227057075, 0.14979772942925, 0.05020227057075, 0.049797729429249, 0.11686893723742, 0.10678564881847, 0.89321435118153, 0.10678564881847, 0.39321435118153, 0.10678564881847, 0.22654768451487, 0.10678564881847, 0.14321435118153, 0.10678564881847, 0.093214351181534, 0.10678564881847, 0.059881017848201, 0.63743069905602, 0.36256930094398, 0.13743069905602, 0.36256930094398, 0.30409736572268, 0.029235967610653, 0.13743069905602, 0.11256930094398, 0.037430699056014, 0.16256930094399, 0.13743069905601, 0.029235967610653, 0.14016645162784, 0.85983354837216, 0.14016645162784, 0.35983354837216, 0.14016645162784, 0.1931668817055, 0.14016645162784, 0.10983354837216, 0.14016645162784, 0.059833548372163, 0.14016645162784, 0.02650021503883, 0.61333333333333, 0.38666666666667, 0.11333333333333, 0.38666666666667, 0.28, 0.053333333333333, 0.11333333333333, 0.13666666666667, 0.013333333333334, 0.18666666666667, 0.11333333333333, 0.053333333333333, 0.055173087614081, 0.94482691238592, 0.055173087614081, 0.44482691238592, 0.055173087614081, 0.27816024571925, 0.055173087614081, 0.19482691238592, 0.055173087614082, 0.14482691238592, 0.055173087614081, 0.11149357905259, 0.46382290653602, 0.53617709346398, 0.46382290653602, 0.036177093463982, 0.13048957320268, 0.20284376013065, 0.21382290653602, 0.036177093463982, 0.063822906536019, 0.13617709346398, 0.13048957320268, 0.036177093463982, 0.83730921384113, 0.16269078615887, 0.33730921384113, 0.16269078615887, 0.17064254717446, 0.16269078615887, 0.087309213841126, 0.16269078615887, 0.037309213841124, 0.16269078615888, 0.0039758805077928, 0.16269078615887, 0.17354107832012, 0.82645892167988, 0.17354107832012, 0.32645892167988, 0.17354107832013, 0.15979225501321, 0.17354107832012, 0.076458921679876, 0.17354107832012, 0.026458921679875, 0.0068744116534584, 0.15979225501321, 0.47030323552394, 0.52969676447606, 0.47030323552394, 0.029696764476057, 0.13696990219061, 0.19636343114272, 0.22030323552394, 0.029696764476057, 0.070303235523944, 0.12969676447606, 0.13696990219061, 0.029696764476057, 0.72524869452455, 0.27475130547545, 0.22524869452455, 0.27475130547545, 0.058582027857881, 0.27475130547545, 0.22524869452455, 0.024751305475453, 0.12524869452455, 0.074751305475453, 0.058582027857881, 0.10808463880879, 0.93589090505088, 0.064109094949119, 0.43589090505088, 0.064109094949119, 0.26922423838421, 0.06410909494912, 0.18589090505088, 0.064109094949119, 0.13589090505088, 0.06410909494912, 0.10255757171755, 0.06410909494912, 0.0995954588585, 0.9004045411415, 0.0995954588585, 0.4004045411415, 0.0995954588585, 0.23373787447483, 0.0995954588585, 0.1504045411415, 0.099595458858502, 0.1004045411415, 0.0995954588585, 0.067071207808167, 0.21357129763693, 0.78642870236307, 0.21357129763693, 0.28642870236307, 0.21357129763693, 0.1197620356964, 0.21357129763693, 0.036428702363068, 0.013571297636932, 0.18642870236307, 0.046904630970265, 0.1197620356964, 0.27486139811203, 0.72513860188797, 0.27486139811203, 0.22513860188797, 0.27486139811203, 0.058471935221306, 0.02486139811203, 0.22513860188797, 0.074861398112029, 0.12513860188797, 0.10819473144536, 0.058471935221306, 0.28033290325568, 0.71966709674432, 0.28033290325568, 0.21966709674432, 0.28033290325568, 0.053000430077657, 0.030332903255676, 0.21966709674432, 0.080332903255675, 0.11966709674433, 0.11366623658901, 0.053000430077657, 0.22666666666667, 0.77333333333333, 0.22666666666667, 0.27333333333333, 0.22666666666667, 0.10666666666667, 0.22666666666667, 0.023333333333333, 0.026666666666668, 0.17333333333333, 0.06, 0.10666666666667, 0.11034617522816, 0.88965382477184, 0.11034617522816, 0.38965382477184, 0.11034617522816, 0.22298715810517, 0.11034617522816, 0.13965382477184, 0.11034617522816, 0.089653824771835, 0.11034617522816, 0.056320491438505, 0.92764581307204, 0.072354186927964, 0.42764581307204, 0.072354186927964, 0.26097914640537, 0.072354186927965, 0.17764581307204, 0.072354186927964, 0.12764581307204, 0.072354186927961, 0.094312479738702, 0.072354186927965, 0.67461842768225, 0.32538157231775, 0.17461842768225, 0.32538157231775, 0.0079517610155856, 0.32538157231775, 0.17461842768225, 0.075381572317749, 0.074618427682248, 0.12538157231775, 0.0079517610155856, 0.15871490565108, 0.34708215664025, 0.65291784335975, 0.34708215664025, 0.15291784335975, 0.013748823306917, 0.31958451002642, 0.097082156640248, 0.15291784335975, 0.14708215664025, 0.052917843359751, 0.013748823306917, 0.15291784335975, 0.94060647104789, 0.059393528952114, 0.44060647104789, 0.059393528952114, 0.27393980438122, 0.059393528952114, 0.19060647104789, 0.059393528952114, 0.14060647104789, 0.059393528952111, 0.10727313771455, 0.059393528952114, 0.45049738904909, 0.54950261095091, 0.45049738904909, 0.049502610950906, 0.11716405571576, 0.21616927761757, 0.20049738904909, 0.049502610950906, 0.050497389049093, 0.14950261095091, 0.11716405571576, 0.049502610950905, 0.87178181010177, 0.12821818989823, 0.37178181010177, 0.12821818989823, 0.2051151434351, 0.12821818989823, 0.12178181010177, 0.12821818989823, 0.071781810101766, 0.12821818989823, 0.038448476768437, 0.12821818989823, 0.199190917717, 0.800809082283, 0.199190917717, 0.300809082283, 0.199190917717, 0.13414241561633, 0.199190917717, 0.050809082282999, 0.199190917717, 0.00080908228299563, 0.032524251050333, 0.13414241561633, 0.42714259527386, 0.57285740472614, 0.42714259527386, 0.072857404726136, 0.093809261940531, 0.2395240713928, 0.17714259527386, 0.072857404726136, 0.027142595273864, 0.17285740472614, 0.093809261940531, 0.072857404726136, 0.54972279622406, 0.45027720377594, 0.04972279622406, 0.45027720377594, 0.21638946289073, 0.1169438704426, 0.04972279622406, 0.20027720377594, 0.14972279622406, 0.050277203775937, 0.049722796224065, 0.1169438704426, 0.56066580651135, 0.43933419348865, 0.060665806511352, 0.43933419348865, 0.22733247317802, 0.10600086015531, 0.060665806511352, 0.18933419348865, 0.16066580651135, 0.039334193488651, 0.060665806511352, 0.10600086015531, 0.45333333333333, 0.54666666666667, 0.45333333333333, 0.046666666666667, 0.12, 0.21333333333333, 0.20333333333333, 0.046666666666667, 0.053333333333336, 0.14666666666666, 0.12, 0.046666666666667, 0.22069235045632, 0.77930764954368, 0.22069235045632, 0.27930764954368, 0.22069235045632, 0.11264098287701, 0.22069235045632, 0.029307649543675, 0.020692350456329, 0.17930764954367, 0.054025683789656, 0.11264098287701, 0.85529162614407, 0.14470837385593, 0.35529162614407, 0.14470837385593, 0.1886249594774, 0.14470837385593, 0.10529162614407, 0.14470837385593, 0.055291626144077, 0.14470837385592, 0.021958292810737, 0.14470837385593, 0.3492368553645, 0.6507631446355, 0.3492368553645, 0.1507631446355, 0.015903522031171, 0.31742981130216, 0.099236855364502, 0.1507631446355, 0.1492368553645, 0.050763144635505, 0.015903522031171, 0.1507631446355, 0.6941643132805, 0.3058356867195, 0.1941643132805, 0.3058356867195, 0.027497646613834, 0.3058356867195, 0.1941643132805, 0.055835686719504, 0.094164313280498, 0.1058356867195, 0.027497646613834, 0.13916902005283, 0.88121294209577, 0.11878705790423, 0.38121294209577, 0.11878705790423, 0.21454627542911, 0.11878705790423, 0.13121294209577, 0.11878705790423, 0.081212942095777, 0.11878705790422, 0.047879608762438, 0.11878705790423, 0.90099477809819, 0.099005221901812, 0.40099477809819, 0.099005221901812, 0.23432811143152, 0.09900522190181, 0.15099477809819, 0.099005221901812, 0.10099477809819, 0.099005221901814, 0.067661444764857, 0.09900522190181, 0.74356362020353, 0.25643637979647, 0.24356362020353, 0.25643637979647, 0.076896953536874, 0.25643637979646, 0.24356362020353, 0.0064363797964688, 0.14356362020353, 0.056436379796469, 0.076896953536874, 0.089769713129793, 0.398381835434, 0.601618164566, 0.398381835434, 0.101618164566, 0.065048502100666, 0.26828483123267, 0.148381835434, 0.101618164566, 0.19838183543401, 0.0016181645659913, 0.065048502100666, 0.101618164566, 0.85428519054773, 0.14571480945227, 0.35428519054773, 0.14571480945227, 0.18761852388106, 0.14571480945227, 0.10428519054773, 0.14571480945227, 0.054285190547728, 0.14571480945227, 0.020951857214394, 0.14571480945227, 0.09944559244812, 0.90055440755188, 0.09944559244812, 0.40055440755188, 0.09944559244813, 0.2338877408852, 0.09944559244812, 0.15055440755188, 0.099445592448126, 0.10055440755187, 0.09944559244813, 0.067221074218537, 0.1213316130227, 0.8786683869773, 0.1213316130227, 0.3786683869773, 0.1213316130227, 0.21200172031063, 0.1213316130227, 0.1286683869773, 0.1213316130227, 0.078668386977301, 0.1213316130227, 0.045335053643962, 0.90666666666667, 0.093333333333334, 0.40666666666667, 0.093333333333334, 0.24, 0.093333333333334, 0.15666666666667, 0.093333333333334, 0.10666666666667, 0.093333333333328, 0.073333333333333, 0.093333333333334, 0.44138470091265, 0.55861529908735, 0.44138470091265, 0.05861529908735, 0.10805136757931, 0.22528196575402, 0.19138470091265, 0.05861529908735, 0.041384700912658, 0.15861529908734, 0.10805136757931, 0.058615299087355, 0.71058325228817, 0.28941674771183, 0.21058325228817, 0.28941674771183, 0.043916585621503, 0.28941674771183, 0.21058325228817, 0.039416747711826, 0.11058325228817, 0.089416747711834, 0.043916585621503, 0.12275008104516, 0.698473710729, 0.301526289271, 0.198473710729, 0.301526289271, 0.031807044062343, 0.30152628927099, 0.198473710729, 0.051526289270996, 0.09847371072899, 0.10152628927101, 0.031807044062343, 0.13485962260432, 0.38832862656099, 0.61167137343901, 0.38832862656099, 0.11167137343901, 0.054995293227667, 0.27833804010567, 0.13832862656099, 0.11167137343901, 0.188328626561, 0.011671373439003, 0.054995293227667, 0.111671373439, 0.76242588419157, 0.23757411580843, 0.26242588419157, 0.23757411580843, 0.095759217524896, 0.23757411580844, 0.012425884191572, 0.23757411580843, 0.16242588419157, 0.037574115808434, 0.095759217524896, 0.070907449141771, 0.80198955619638, 0.19801044380362, 0.30198955619638, 0.19801044380362, 0.13532288952971, 0.19801044380362, 0.051989556196375, 0.19801044380362, 0.0019895561963722, 0.19801044380363, 0.13532288952971, 0.031343777136954, 0.48712724040706, 0.51287275959294, 0.48712724040706, 0.012872759592938, 0.15379390707375, 0.17953942625959, 0.23712724040706, 0.012872759592938, 0.087127240407062, 0.11287275959294, 0.15379390707375, 0.012872759592919, 0.796763670868, 0.203236329132, 0.296763670868, 0.203236329132, 0.13009700420133, 0.203236329132, 0.046763670868003, 0.203236329132, 0.19676367086802, 0.0032363291319825, 0.13009700420133, 0.036569662465335, 0.70857038109546, 0.29142961890454, 0.20857038109546, 0.29142961890454, 0.041903714428789, 0.29142961890454, 0.20857038109546, 0.041429618904544, 0.10857038109546, 0.091429618904544, 0.041903714428789, 0.12476295223788, 0.19889118489624, 0.80110881510376, 0.19889118489624, 0.30110881510376, 0.19889118489626, 0.13444214843707, 0.19889118489624, 0.05110881510376, 0.19889118489625, 0.0011088151037484, 0.032224518229593, 0.13444214843707, 0.24266322604541, 0.75733677395459, 0.24266322604541, 0.25733677395459, 0.24266322604541, 0.090670107287925, 0.24266322604541, 0.0073367739545915, 0.042663226045397, 0.1573367739546, 0.075996559378742, 0.090670107287925 }; static int g_bins48000[720]= { 4, 5, 9, 10, 14, 15, 18, 19, 23, 24, 28, 29, 4, 5, 9, 10, 14, 15, 19, 20, 24, 25, 29, 30, 5, 6, 10, 11, 15, 16, 21, 22, 26, 27, 31, 32, 5, 6, 11, 12, 16, 17, 22, 23, 27, 28, 33, 34, 5, 6, 11, 12, 17, 18, 23, 24, 29, 30, 35, 36, 6, 7, 12, 13, 18, 19, 25, 26, 31, 32, 37, 38, 6, 7, 13, 14, 19, 20, 26, 27, 33, 34, 39, 40, 7, 8, 14, 15, 21, 22, 28, 29, 35, 36, 42, 43, 7, 8, 14, 15, 22, 23, 29, 30, 37, 38, 44, 45, 7, 8, 15, 16, 23, 24, 31, 32, 39, 40, 47, 48, 8, 9, 16, 17, 25, 26, 33, 34, 41, 42, 50, 51, 8, 9, 17, 18, 26, 27, 35, 36, 44, 45, 53, 54, 9, 10, 18, 19, 28, 29, 37, 38, 46, 47, 56, 57, 9, 10, 19, 20, 29, 30, 39, 40, 49, 50, 59, 60, 10, 11, 21, 22, 31, 32, 42, 43, 52, 53, 63, 64, 11, 12, 22, 23, 33, 34, 44, 45, 55, 56, 66, 67, 11, 12, 23, 24, 35, 36, 47, 48, 59, 60, 70, 71, 12, 13, 25, 26, 37, 38, 50, 51, 62, 63, 75, 76, 13, 14, 26, 27, 39, 40, 53, 54, 66, 67, 79, 80, 14, 15, 28, 29, 42, 43, 56, 57, 70, 71, 84, 85, 14, 15, 29, 30, 44, 45, 59, 60, 74, 75, 89, 90, 15, 16, 31, 32, 47, 48, 63, 64, 78, 79, 94, 95, 16, 17, 33, 34, 50, 51, 66, 67, 83, 84, 100, 101, 17, 18, 35, 36, 53, 54, 70, 71, 88, 89, 106, 107, 18, 19, 37, 38, 56, 57, 75, 76, 93, 94, 112, 113, 19, 20, 39, 40, 59, 60, 79, 80, 99, 100, 119, 120, 21, 22, 42, 43, 63, 64, 84, 85, 105, 106, 126, 127, 22, 23, 44, 45, 66, 67, 89, 90, 111, 112, 133, 134, 23, 24, 47, 48, 70, 71, 94, 95, 118, 119, 141, 142, 25, 26, 50, 51, 75, 76, 100, 101, 125, 126, 150, 151, 26, 27, 53, 54, 79, 80, 106, 107, 132, 133, 159, 160, 28, 29, 56, 57, 84, 85, 112, 113, 140, 141, 168, 169, 29, 30, 59, 60, 89, 90, 119, 120, 149, 150, 178, 179, 31, 32, 63, 64, 94, 95, 126, 127, 157, 158, 189, 190, 33, 34, 66, 67, 100, 101, 133, 134, 167, 168, 200, 201, 35, 36, 70, 71, 106, 107, 141, 142, 177, 178, 212, 213, 37, 38, 75, 76, 112, 113, 150, 151, 187, 188, 225, 226, 39, 40, 79, 80, 119, 120, 159, 160, 198, 199, 238, 239, 42, 43, 84, 85, 126, 127, 168, 169, 210, 211, 252, 253, 44, 45, 89, 90, 133, 134, 178, 179, 223, 224, 267, 268, 47, 48, 94, 95, 141, 142, 189, 190, 236, 237, 283, 284, 50, 51, 100, 101, 150, 151, 200, 201, 250, 251, 300, 301, 53, 54, 106, 107, 159, 160, 212, 213, 265, 266, 318, 319, 56, 57, 112, 113, 168, 169, 225, 226, 281, 282, 337, 338, 59, 60, 119, 120, 178, 179, 238, 239, 298, 299, 357, 358, 63, 64, 126, 127, 189, 190, 252, 253, 315, 316, 378, 379, 66, 67, 133, 134, 200, 201, 267, 268, 334, 335, 401, 402, 70, 71, 141, 142, 212, 213, 283, 284, 354, 355, 425, 426, 75, 76, 150, 151, 225, 226, 300, 301, 375, 376, 450, 451, 79, 80, 159, 160, 238, 239, 318, 319, 397, 398, 477, 478, 84, 85, 168, 169, 252, 253, 337, 338, 421, 422, 505, 506, 89, 90, 178, 179, 267, 268, 357, 358, 446, 447, 535, 536, 94, 95, 189, 190, 283, 284, 378, 379, 473, 474, 567, 568, 100, 101, 200, 201, 300, 301, 400, 401, 501, 502, 601, 602, 106, 107, 212, 213, 318, 319, 424, 425, 530, 531, 637, 638, 112, 113, 225, 226, 337, 338, 450, 451, 562, 563, 675, 676, 119, 120, 238, 239, 357, 358, 476, 477, 596, 597, 715, 716, 126, 127, 252, 253, 378, 379, 505, 506, 631, 632, 757, 758, 133, 134, 267, 268, 401, 402, 535, 536, 669, 670, 802, 803, 141, 142, 283, 284, 425, 426, 567, 568, 708, 709, 850, 851 }; //Krumhansl Kessler profiles (normalised) //double g_kkminor[12] = { 0.14221523253202, 0.060211188496967, 0.079083352055718, 0.12087171422152, 0.05841383958661, 0.079308020669512, 0.057065827903842, 0.10671759155246, 0.089418108290272, 0.060435857110762, 0.075039317007414, 0.071219950572905 }; //double g_kkmajor[12] = { 0.15195022732711, 0.053362048336923, 0.083273510409189, 0.055754965302704, 0.10480976310122, 0.097870303900455, 0.060301507537688, 0.12419239052405, 0.057190715482173, 0.087580760947595, 0.054797798516391, 0.068916008614501 }; //following Izmirli; see MIREX2006 static double g_diatonicmajor[12] = { 5.0, 0.0, 3.5, 0.0, 4.5, 4.0, 0.0, 4.5, 0.0, 3.5, 0.0, 4.0}; static double g_diatonicminor[12] = { 5.0, 0.0, 3.5, 4.5, 0.0, 4.0, 0.0, 4.5, 3.5, 0.0, 0.0, 4.0}; static int g_minor[7] = {0,2,3,5,7,8,11}; static int g_major[7] = {0,2,4,5,7,9,11}; //other functions static void KeyTrack_calculatekey(KeyTrack *, uint32); void KeyTrack_Ctor(KeyTrack* unit) { unit->m_srate = unit->mWorld->mFullRate.mSampleRate; //if sample rate is 88200 or 96000, assume taking double size FFT to start with if(unit->m_srate > (44100.0*1.5)) unit->m_srate = unit->m_srate*0.5; if(((int)(unit->m_srate+0.01))==44100) { unit->m_weights = g_weights44100; unit->m_bins = g_bins44100; unit->m_frameperiod = 0.046439909297052; } else //else 48000; potentially dangerous if it isn't! Fortunately, shouldn't write any data to unknown memory { unit->m_weights = g_weights48000; unit->m_bins = g_bins48000; unit->m_frameperiod = 0.042666666666667; } //only need space for half! unit->m_FFTBuf = (float*)RTAlloc(unit->mWorld, NOVER2 * sizeof(float)); //zero chroma Clear(12, unit->m_chroma); Clear(24, unit->m_key); Clear(24, unit->m_histogram); //for(j=0;j<60;++j) { // unit->m_leaknote[j]=0.0; // } // for(j=0;j<360;++j) { // unit->m_prevphase[j]=0.0; // } //triggers //unit->m_triggerid=(int)ZIN0(1); unit->m_currentKey=0; //unit->m_frame=0; unit->mCalcFunc = (UnitCalcFunc)&KeyTrack_next; } void KeyTrack_Dtor(KeyTrack *unit) { RTFree(unit->mWorld, unit->m_FFTBuf); } void KeyTrack_next(KeyTrack *unit, int wrongNumSamples) { //int numSamples = unit->mWorld->mFullRate.mBufLength; //float *output = ZOUT(0); float fbufnum = ZIN0(0)+0.001; //next FFT bufffer ready, update //assuming at this point that buffer precalculated for any resampling if (fbufnum > -0.01f) { // && ( ZIN0(3)<0.5) //unit->m_frame= unit->m_frame+1; KeyTrack_calculatekey(unit, (uint32)fbufnum); } //always output current best key float outval= unit->m_currentKey; //control rate output ZOUT0(0)=outval; } //calculation function once FFT data ready void KeyTrack_calculatekey(KeyTrack *unit, uint32 ibufnum) { World *world = unit->mWorld; SndBuf *buf; if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; if(unit->mWorld->mVerbosity > -1){ Print("KeyTrack error: Buffer number overrun: %i\n", ibufnum); } } } else { buf = world->mSndBufs + ibufnum; } LOCK_SNDBUF(buf); //assumed in this representation ToComplexApx(buf); const float * data= buf->data; //memcpy(unit->m_FFTBuf, data, NOVER2); //to hold powers float * fftbuf= unit->m_FFTBuf; //get powers for bins //don't need to calculate past half Nyquist, because no indices involved of harmonics above 10000 Hz or so (see index data at top of file) for (int i=0; i>1 is i/2 fftbuf[i>>1] = ((data[i] * data[i]) + (data[i+1] * data[i+1])); } float * chroma= unit->m_chroma; float sum; int indexbase, index; //experimental; added leaky integration on each note; also, only add to sum if harmonic, ie not a transient float * weights = unit->m_weights; int * bins = unit->m_bins; float chromaleak= ZIN0(2); //zero for new round (should add leaky integrator here! for (int i=0;i<12;++i) chroma[i] *= chromaleak; for (int i=0;i<60;++i) { int chromaindex = (i+9)%12; //starts at A1 up to G#6 sum=0.0; indexbase= 12*i; //6 partials, 2 of each //transient sum, setting up last values too for(int j=0;j<12;++j) { //12 if 144 data points index=indexbase+j; //experimental transient detection code, not reliable //int binindex= unit->m_bins[index]-1; //SCPolar binnow= p->bin[binindex].ToPolarApx(); //float phaseadvance= (binindex+1)*(TWOPI*0.5); //k * (512/44100) * (44100/1024) //convert bin number to frequency //float power= binnow.mag * binnow.mag; //(p->bin[binindex].real)*(p->bin[binindex].real) + (p->bin[binindex].imag)*(p->bin[binindex].imag); //(p->bin[binindex].mag); //power *= power; //int phaseindex= indexbase+j; //float phasenow= binnow.phase; //0.0; //(p->bin[binindex].phase); //float prevphase = fmod(unit->m_prevphase[index]+phaseadvance,TWOPI); //float a,b,tmp; //a=phasenow; b=prevphase; //b=phasenow; a=prevphase; //if(bm_prevphase[index]= phasenow; //((p->bin[index-1].mag) * (p->bin[index-1].mag)) //printf("comparison %f %f \n",fftbuf[g_bins2[index]], power); //sum+= (unit->m_weights[index])* power; sum+= (weights[index])* (fftbuf[bins[index]]); } //transient test here too? //if(phasesum>(5*PI)){sum=0.0;} //if((i>5) && (i<15)) //printf("test phasesum %f \n", phasesum); //unit->m_leaknote[i] = (0.8*unit->m_leaknote[i]) + sum; chroma[chromaindex]+= sum; //unit->m_leaknote[i]; //sum; } float* key = unit->m_key; //major for (int i=0;i<12;++i) { sum=0.0; for (int j=0;j<7;++j) { indexbase=g_major[j]; index=(i+indexbase)%12; //sum+=(chroma[index]*g_kkmajor[indexbase]); sum+=(chroma[index]*g_diatonicmajor[indexbase]); } key[i]=sum; //10*log10(sum+1); } //minor for (int i=0;i<12;++i) { sum=0.0; for (int j=0;j<7;++j) { indexbase=g_minor[j]; index=(i+indexbase)%12; //sum+=(chroma[index]*g_kkminor[indexbase]); sum+=(chroma[index]*g_diatonicminor[indexbase]); } key[12+i]=sum; } float keyleak= ZIN0(1); //fade parameter to 0.01 for histogram in seconds, convert to FFT frames //keyleak in seconds, convert to drop time in FFT hop frames (FRAMEPERIOD) keyleak= sc_max(0.001f,keyleak/unit->m_frameperiod); //FRAMEPERIOD; //now number of frames, actual leak param is decay exponent to reach 0.01 in x seconds, ie 0.01 = leakparam ** (x/ffthopsize) //0.01 is -40dB keyleak= pow(0.01f,(1.f/keyleak)); float * histogram= unit->m_histogram; int bestkey=0; float bestscore=0.0; for (int i=0;i<24;++i) { histogram[i]= (keyleak*histogram[i])+key[i]; if(histogram[i]>bestscore) { bestscore=histogram[i]; bestkey=i; } //printf("%f ",histogram[i]); } //should find secondbest and only swap if win by a margin //printf(" best %d \n\n",bestkey); //what is winning currently? find max in histogram unit->m_currentKey=bestkey; //about 5 times per second //if((unit->m_triggerid) && ((unit->m_frame%2==0))) SendTrigger(&unit->mParent->mNode, unit->m_triggerid, bestkey); } SuperCollider-Source/server/plugins/LFUGens.cpp000644 000765 000024 00000245656 12757055125 022646 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include "SIMD_Unit.hpp" #include #include #include "function_attributes.h" #include static InterfaceTable *ft; struct Vibrato : public Unit { double mPhase, m_attackSlope, m_attackLevel; float mFreqMul, m_scaleA, m_scaleB, mFreq; int m_delay, m_attack; float trig; }; struct LFPulse : public Unit { double mPhase; float mFreqMul, mDuty; }; struct LFSaw : public Unit { double mPhase; float mFreqMul; }; struct LFPar : public Unit { double mPhase; float mFreqMul; }; struct LFCub : public Unit { double mPhase; float mFreqMul; }; struct LFTri : public Unit { double mPhase; float mFreqMul; }; struct LFGauss : public Unit { double mPhase; float mDurMul; }; struct Impulse : public Unit { double mPhase, mPhaseOffset; float mFreqMul; }; struct VarSaw : public Unit { double mPhase; float mFreqMul, mDuty, mInvDuty, mInv1Duty; }; struct SyncSaw : public Unit { double mPhase1, mPhase2; float mFreqMul; }; struct Line : public Unit { double mLevel, mSlope; float mEndLevel; int mCounter; }; struct XLine : public Unit { double mLevel, mGrowth; float mEndLevel; int mCounter; }; struct Cutoff : public Unit { double mLevel, mSlope; int mWaitCounter; }; struct LinExp : public Unit { float m_dstratio, m_rsrcrange, m_rrminuslo, m_dstlo; }; struct Clip : public Unit { float m_lo, m_hi; }; struct Wrap : public Unit { float m_lo, m_hi; }; struct Fold : public Unit { float m_lo, m_hi, m_range; }; struct Unwrap : public Unit { float m_range, m_half, m_offset, m_prev; }; struct ModDif : public Unit { float m_dif, m_mod; }; struct AmpComp : public Unit { float m_rootmul, m_exponent; }; struct AmpCompA : public Unit { double m_scale, m_offset; }; struct InRange : public Unit { // nothing }; struct InRect : public Unit { // nothing }; //struct Trapezoid : public Unit //{ // float m_leftScale, m_rightScale, m_a, m_b, m_c, m_d; //}; struct A2K : public Unit { }; struct T2K : public Unit { }; struct T2A : public Unit { float mLevel; }; struct EnvGen : public Unit { double m_a1, m_a2, m_b1, m_y1, m_y2, m_grow, m_level, m_endLevel; int m_counter, m_stage, m_shape, m_releaseNode; float m_prevGate; bool m_released; }; struct Linen : public Unit { float m_endLevel; double m_slope, m_level; int m_counter, m_stage; float m_prevGate; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void Vibrato_next(Vibrato *unit, int inNumSamples); void Vibrato_Ctor(Vibrato* unit); void LFPulse_next_a(LFPulse *unit, int inNumSamples); void LFPulse_next_k(LFPulse *unit, int inNumSamples); void LFPulse_Ctor(LFPulse* unit); void LFSaw_next_a(LFSaw *unit, int inNumSamples); void LFSaw_next_k(LFSaw *unit, int inNumSamples); void LFSaw_Ctor(LFSaw* unit); void LFTri_next_a(LFTri *unit, int inNumSamples); void LFTri_next_k(LFTri *unit, int inNumSamples); void LFTri_Ctor(LFTri* unit); void LFPar_next_a(LFPar *unit, int inNumSamples); void LFPar_next_k(LFPar *unit, int inNumSamples); void LFPar_Ctor(LFPar* unit); void LFCub_next_a(LFCub *unit, int inNumSamples); void LFCub_next_k(LFCub *unit, int inNumSamples); void LFCub_Ctor(LFCub* unit); void LFGauss_next_a(LFGauss *unit, int inNumSamples); void LFGauss_next_k(LFGauss *unit, int inNumSamples); void LFGauss_next_aa(LFGauss *unit, int inNumSamples); void LFGauss_Ctor(LFGauss* unit); void VarSaw_next_a(VarSaw *unit, int inNumSamples); void VarSaw_next_k(VarSaw *unit, int inNumSamples); void VarSaw_Ctor(VarSaw* unit); void Impulse_next_a(Impulse *unit, int inNumSamples); void Impulse_next_kk(Impulse *unit, int inNumSamples); void Impulse_next_k(Impulse *unit, int inNumSamples); void Impulse_Ctor(Impulse* unit); void SyncSaw_next_aa(SyncSaw *unit, int inNumSamples); void SyncSaw_next_ak(SyncSaw *unit, int inNumSamples); void SyncSaw_next_ka(SyncSaw *unit, int inNumSamples); void SyncSaw_next_kk(SyncSaw *unit, int inNumSamples); void SyncSaw_Ctor(SyncSaw* unit); void A2K_next(A2K *unit, int inNumSamples); void A2K_Ctor(A2K* unit); void T2K_next(T2K *unit, int inNumSamples); void T2K_Ctor(T2K* unit); void T2A_next(T2A *unit, int inNumSamples); void T2A_Ctor(T2A* unit); void Line_next(Line *unit, int inNumSamples); void Line_Ctor(Line* unit); void XLine_next(XLine *unit, int inNumSamples); void XLine_Ctor(XLine* unit); void Wrap_next_kk(Wrap *unit, int inNumSamples); void Wrap_next_ak(Wrap *unit, int inNumSamples); void Wrap_next_ka(Wrap *unit, int inNumSamples); void Wrap_next_aa(Wrap *unit, int inNumSamples); void Wrap_Ctor(Wrap* unit); void Fold_next_kk(Fold *unit, int inNumSamples); void Fold_next_ak(Fold *unit, int inNumSamples); void Fold_next_ka(Fold *unit, int inNumSamples); void Fold_next_aa(Fold *unit, int inNumSamples); void Fold_Ctor(Fold* unit); void Clip_next_kk(Clip *unit, int inNumSamples); void Clip_next_ka(Clip *unit, int inNumSamples); void Clip_next_ak(Clip *unit, int inNumSamples); void Clip_next_aa(Clip *unit, int inNumSamples); void Clip_Ctor(Clip* unit); void Unwrap_next(Unwrap* unit, int inNumSamples); void Unwrap_Ctor(Unwrap* unit); void ModDif_next_kk(ModDif *unit, int inNumSamples); void ModDif_next_ak(ModDif *unit, int inNumSamples); void ModDif_next_ka(ModDif *unit, int inNumSamples); void ModDif_next_aa(ModDif *unit, int inNumSamples); void ModDif_Ctor(ModDif* unit); void AmpComp_next(AmpComp *unit, int inNumSamples); void AmpComp_Ctor(AmpComp* unit); void AmpCompA_next(AmpCompA *unit, int inNumSamples); void AmpCompA_Ctor(AmpCompA* unit); void InRange_next(InRange *unit, int inNumSamples); void InRange_Ctor(InRange* unit); void InRect_next(InRect *unit, int inNumSamples); void InRect_Ctor(InRect* unit); void LinExp_next(LinExp *unit, int inNumSamples); void LinExp_next_kk(LinExp *unit, int inNumSamples); void LinExp_next_ak(LinExp *unit, int inNumSamples); void LinExp_next_ka(LinExp *unit, int inNumSamples); void LinExp_Ctor(LinExp* unit); void EnvGen_next_k(EnvGen *unit, int inNumSamples); void EnvGen_next_aa(EnvGen *unit, int inNumSamples); void EnvGen_next_ak(EnvGen *unit, int inNumSamples); void EnvGen_Ctor(EnvGen *unit); void Linen_next_k(Linen *unit, int inNumSamples); void Linen_Ctor(Linen *unit); } ////////////////////////////////////////////////////////////////////////////////////////////////// // in, rate, depth, rateVariation, depthVariation // 0 1 2 3 4 void Vibrato_next(Vibrato *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float curtrig = ZIN0(8); if (unit->trig <= 0.f && curtrig > 0.f){ unit->mFreqMul = 4.0 * SAMPLEDUR; unit->mPhase = 4.0 * sc_wrap(ZIN0(7), 0.f, 1.f) - 1.0; RGen& rgen = *unit->mParent->mRGen; float rate = ZIN0(1) * unit->mFreqMul; float depth = ZIN0(2); float rateVariation = ZIN0(5); float depthVariation = ZIN0(6); unit->mFreq = rate * (1.f + rateVariation * rgen.frand2()); unit->m_scaleA = depth * (1.f + depthVariation * rgen.frand2()); unit->m_scaleB = depth * (1.f + depthVariation * rgen.frand2()); unit->m_delay = (int)(ZIN0(3) * SAMPLERATE); unit->m_attack = (int)(ZIN0(4) * SAMPLERATE); unit->m_attackSlope = 1. / (double)(1 + unit->m_attack); unit->m_attackLevel = unit->m_attackSlope; } unit->trig = curtrig; double ffreq = unit->mFreq; double phase = unit->mPhase; float scaleA = unit->m_scaleA; float scaleB = unit->m_scaleB; if (unit->m_delay > 0) { int remain = sc_min(inNumSamples, unit->m_delay); unit->m_delay -= remain; inNumSamples -= remain; LOOP(remain, ZXP(out) = ZXP(in); ); if (unit->m_delay <= 0 && inNumSamples > 0) { if (unit->m_attack > 0) goto doAttack; else goto doNormal; } } else if (unit->m_attack) { doAttack: int remain = sc_min(inNumSamples, unit->m_attack); unit->m_attack -= remain; inNumSamples -= remain; double attackSlope = unit->m_attackSlope; double attackLevel = unit->m_attackLevel; LOOP(remain, if (phase < 1.f) { float z = phase; ZXP(out) = ZXP(in) * (1.f + (float)attackLevel * scaleA * (1.f - z * z)) ; } else if (phase < 3.f) { float z = phase - 2.f; ZXP(out) = ZXP(in) * (1.f + (float)attackLevel * scaleB * (z * z - 1.f)) ; } else { phase -= 4.f; float z = phase; float depth = ZIN0(2); float rateVariation = ZIN0(5); float depthVariation = ZIN0(6); float rate = ZIN0(1) * unit->mFreqMul; RGen& rgen = *unit->mParent->mRGen; ffreq = rate * (1.f + rateVariation * rgen.frand2()); scaleA = depth * (1.f + depthVariation * rgen.frand2()); scaleB = depth * (1.f + depthVariation * rgen.frand2()); ZXP(out) = ZXP(in) * (1.f + (float)attackLevel * scaleA * (1.f - z * z)) ; } phase += ffreq; attackLevel += attackSlope; ); unit->m_attackLevel = attackLevel; if (unit->m_attack <= 0 && inNumSamples > 0) goto doNormal; } else { doNormal: LOOP1(inNumSamples, if (phase < 1.f) { float z = phase; ZXP(out) = ZXP(in) * (1.f + scaleA * (1.f - z * z)) ; } else if (phase < 3.f) { float z = phase - 2.f; ZXP(out) = ZXP(in) * (1.f + scaleB * (z * z - 1.f)) ; } else { phase -= 4.f; float z = phase; float depth = ZIN0(2); float rateVariation = ZIN0(5); float depthVariation = ZIN0(6); float rate = ZIN0(1) * unit->mFreqMul; RGen& rgen = *unit->mParent->mRGen; ffreq = rate * (1.f + rateVariation * rgen.frand2()); scaleA = depth * (1.f + depthVariation * rgen.frand2()); scaleB = depth * (1.f + depthVariation * rgen.frand2()); ZXP(out) = ZXP(in) * (1.f + scaleA * (1.f - z * z)) ; } phase += ffreq; ); } unit->mPhase = phase; unit->mFreq = ffreq; unit->m_scaleA = scaleA; unit->m_scaleB = scaleB; } void Vibrato_Ctor(Vibrato* unit) { unit->mFreqMul = 4.0 * SAMPLEDUR; unit->mPhase = 4.0 * sc_wrap(ZIN0(7), 0.f, 1.f) - 1.0; RGen& rgen = *unit->mParent->mRGen; float rate = ZIN0(1) * unit->mFreqMul; float depth = ZIN0(2); float rateVariation = ZIN0(5); float depthVariation = ZIN0(6); unit->mFreq = rate * (1.f + rateVariation * rgen.frand2()); unit->m_scaleA = depth * (1.f + depthVariation * rgen.frand2()); unit->m_scaleB = depth * (1.f + depthVariation * rgen.frand2()); unit->m_delay = (int)(ZIN0(3) * SAMPLERATE); unit->m_attack = (int)(ZIN0(4) * SAMPLERATE); unit->m_attackSlope = 1. / (double)(1 + unit->m_attack); unit->m_attackLevel = unit->m_attackSlope; unit->trig = 0.0f; SETCALC(Vibrato_next); Vibrato_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFPulse_next_a(LFPulse *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float nextDuty = ZIN0(2); float duty = unit->mDuty; float freqmul = unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z; if (phase >= 1.f) { phase -= 1.f; duty = unit->mDuty = nextDuty; // output at least one sample from the opposite polarity z = duty <= 0.5f ? 1.f : 0.f; } else { z = phase < duty ? 1.f : 0.f; } phase += ZXP(freq) * freqmul; ZXP(out) = z; ); unit->mPhase = phase; } void LFPulse_next_k(LFPulse *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; float nextDuty = ZIN0(2); float duty = unit->mDuty; double phase = unit->mPhase; LOOP1(inNumSamples, float z; if (phase >= 1.f) { phase -= 1.f; duty = unit->mDuty = nextDuty; // output at least one sample from the opposite polarity z = duty <= 0.5f ? 1.f : 0.f; } else { z = phase < duty ? 1.f : 0.f; } phase += freq; ZXP(out) = z; ); unit->mPhase = phase; } void LFPulse_Ctor(LFPulse* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LFPulse_next_a); } else { SETCALC(LFPulse_next_k); } unit->mFreqMul = unit->mRate->mSampleDur; unit->mPhase = ZIN0(1); unit->mDuty = ZIN0(2); LFPulse_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFSaw_next_a(LFSaw *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float freqmul = unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z = phase; // out must be written last for in place operation phase += ZXP(freq) * freqmul; if (phase >= 1.f) phase -= 2.f; else if (phase <= -1.f) phase += 2.f; ZXP(out) = z; ); unit->mPhase = phase; } void LFSaw_next_k(LFSaw *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; double phase = unit->mPhase; if (freq >= 0.f) { LOOP1(inNumSamples, ZXP(out) = phase; phase += freq; if (phase >= 1.f) phase -= 2.f; ); } else { LOOP1(inNumSamples, ZXP(out) = phase; phase += freq; if (phase <= -1.f) phase += 2.f; ); } unit->mPhase = phase; } void LFSaw_Ctor(LFSaw* unit) { if (INRATE(0) == calc_FullRate) SETCALC(LFSaw_next_a); else SETCALC(LFSaw_next_k); unit->mFreqMul = 2.0 * unit->mRate->mSampleDur; unit->mPhase = ZIN0(1); LFSaw_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFPar_next_a(LFPar *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float freqmul = unit->mFreqMul; double phase = unit->mPhase; float z, y; LOOP1(inNumSamples, if (phase < 1.f) { z = phase; y = 1.f - z*z; } else if (phase < 3.f) { z = phase - 2.f; y = z*z - 1.f; } else { phase -= 4.f; z = phase; y = 1.f - z*z; } // Note: the following two lines were originally one, but seems to compile wrong on mac float phaseadd = ZXP(freq); phase += phaseadd * freqmul; ZXP(out) = y; ); unit->mPhase = phase; } void LFPar_next_k(LFPar *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, if (phase < 1.f) { float z = phase; ZXP(out) = 1.f - z*z; } else if (phase < 3.f) { float z = phase - 2.f; ZXP(out) = z*z - 1.f; } else { phase -= 4.f; float z = phase; ZXP(out) = 1.f - z*z; } phase += freq; ); unit->mPhase = phase; } void LFPar_Ctor(LFPar* unit) { if (INRATE(0) == calc_FullRate) SETCALC(LFPar_next_a); else SETCALC(LFPar_next_k); unit->mFreqMul = 4.0 * unit->mRate->mSampleDur; unit->mPhase = ZIN0(1); LFPar_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFCub_next_a(LFCub *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float freqmul = unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z; if (phase < 1.f) { z = phase; } else if (phase < 2.f) { z = 2.f - phase; } else { phase -= 2.f; z = phase; } float phaseadd = ZXP(freq); phase += phaseadd * freqmul; ZXP(out) = z * z * (6.f - 4.f * z) - 1.f; ); unit->mPhase = phase; } void LFCub_next_k(LFCub *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z; if (phase < 1.f) { z = phase; } else if (phase < 2.f) { z = 2.f - phase; } else { phase -= 2.f; z = phase; } ZXP(out) = z * z * (6.f - 4.f * z) - 1.f; phase += freq; ); unit->mPhase = phase; } void LFCub_Ctor(LFCub* unit) { if (INRATE(0) == calc_FullRate) SETCALC(LFCub_next_a); else SETCALC(LFCub_next_k); unit->mFreqMul = 2.0 * unit->mRate->mSampleDur; unit->mPhase = ZIN0(1) + 0.5; LFCub_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFTri_next_a(LFTri *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float freqmul = unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z = phase > 1.f ? 2.f - phase : phase; phase += ZXP(freq) * freqmul; if (phase >= 3.f) phase -= 4.f; ZXP(out) = z; ); unit->mPhase = phase; } void LFTri_next_k(LFTri *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z = phase > 1.f ? 2.f - phase : phase; phase += freq; if (phase >= 3.f) phase -= 4.f; ZXP(out) = z; ); unit->mPhase = phase; } void LFTri_Ctor(LFTri* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LFTri_next_a); } else { SETCALC(LFTri_next_k); } unit->mFreqMul = 4.0 * unit->mRate->mSampleDur; unit->mPhase = ZIN0(1); LFTri_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void LFGauss_next_k(LFGauss *unit, int inNumSamples) { float *out = ZOUT(0); float dur = ZIN0(0); float c = ZIN0(1); float b = ZIN0(2); float loop = ZIN0(3); // offset phase by b double x = unit->mPhase - b; // for a full cycle from -1 to 1 in duration, double the step. float step = 2.f / (dur * unit->mRate->mSampleRate); // calculate exponent only once per loop float factor = -1.f / (2.f * c * c); LOOP1(inNumSamples, if (x > 1.f) { if(loop) { x -= 2.f; } else { DoneAction(ZIN0(4), unit); } } ZXP(out) = exp(x * x * factor); x += step; ); unit->mPhase = x + b; } void LFGauss_next_a(LFGauss *unit, int inNumSamples) { float *out = ZOUT(0); float *dur = ZIN(0); float c = ZIN0(1); float b = ZIN0(2); float loop = ZIN0(3); float sr = unit->mRate->mSampleRate; // offset phase by b double x = unit->mPhase - b; float factor = -1.f / (2.f * c * c); LOOP1(inNumSamples, if (x > 1.f) { if(loop) { x -= 2.f; } else { DoneAction(ZIN0(4), unit); } } // for a full cycle from -1 to 1 in duration, double the step. float step = 2.f / (ZXP(dur) * sr); ZXP(out) = exp(x * x * factor); x += step; ); unit->mPhase = x + b; } void LFGauss_next_aa(LFGauss *unit, int inNumSamples) { float *out = ZOUT(0); float *dur = ZIN(0); float *c = ZIN(1); float b = ZIN0(2); float loop = ZIN0(3); float sr = unit->mRate->mSampleRate; // offset phase by b double x = unit->mPhase - b; LOOP1(inNumSamples, if (x > 1.f) { if(loop) { x -= 2.f; } else { DoneAction(ZIN0(4), unit); } } // for a full cycle from -1 to 1 in duration, double the step. float step = 2.f / (ZXP(dur) * sr); float cval = ZXP(c); float factor = -1.f / (2.f * cval * cval); ZXP(out) = exp(x * x * factor); x += step; ); unit->mPhase = x + b; } void LFGauss_Ctor(LFGauss* unit) { if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) { SETCALC(LFGauss_next_aa); } else { SETCALC(LFGauss_next_a); } } else { SETCALC(LFGauss_next_k); } unit->mPhase = -1.0; //LFGauss_next_k(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Impulse_next_a(Impulse *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float freqmul = unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z; if (phase >= 1.f) { phase -= 1.f; z = 1.f; } else { z = 0.f; } phase += ZXP(freq) * freqmul; ZXP(out) = z; ); unit->mPhase = phase; } /* phase mod - jrh 03 */ void Impulse_next_ak(Impulse *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); double phaseOffset = ZIN0(1); float freqmul = unit->mFreqMul; double phase = unit->mPhase; double prev_phaseOffset = unit->mPhaseOffset; double phaseSlope = CALCSLOPE(phaseOffset, prev_phaseOffset); phase += prev_phaseOffset; LOOP1(inNumSamples, float z; phase += phaseSlope; if (phase >= 1.f) { phase -= 1.f; z = 1.f; } else { z = 0.f; } phase += ZXP(freq) * freqmul; ZXP(out) = z; ); unit->mPhase = phase - phaseOffset; unit->mPhaseOffset = phaseOffset; } void Impulse_next_kk(Impulse *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; double phaseOffset = ZIN0(1); double phase = unit->mPhase; double prev_phaseOffset = unit->mPhaseOffset; double phaseSlope = CALCSLOPE(phaseOffset, prev_phaseOffset); phase += prev_phaseOffset; LOOP1(inNumSamples, float z; phase += phaseSlope; if (phase >= 1.f) { phase -= 1.f; z = 1.f; } else { z = 0.f; } phase += freq; ZXP(out) = z; ); unit->mPhase = phase - phaseOffset; unit->mPhaseOffset = phaseOffset; } void Impulse_next_k(Impulse *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, float z; if (phase >= 1.f) { phase -= 1.f; z = 1.f; } else { z = 0.f; } phase += freq; ZXP(out) = z; ); unit->mPhase = phase; } void Impulse_Ctor(Impulse* unit) { unit->mPhase = ZIN0(1); if (INRATE(0) == calc_FullRate) { if(INRATE(1) != calc_ScalarRate) { SETCALC(Impulse_next_ak); unit->mPhase = 1.f; } else { SETCALC(Impulse_next_a); } } else { if(INRATE(1) != calc_ScalarRate) { SETCALC(Impulse_next_kk); unit->mPhase = 1.f; } else { SETCALC(Impulse_next_k); } } unit->mPhaseOffset = 0.f; unit->mFreqMul = unit->mRate->mSampleDur; if (unit->mPhase == 0.f) unit->mPhase = 1.f; ZOUT0(0) = 0.f; } ////////////////////////////////////////////////////////////////////////////////////////////////// void VarSaw_next_a(VarSaw *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float nextDuty = ZIN0(2); float duty = unit->mDuty; float invduty = unit->mInvDuty; float inv1duty = unit->mInv1Duty; float freqmul = unit->mFreqMul; double phase = unit->mPhase; LOOP1(inNumSamples, if (phase >= 1.f) { phase -= 1.f; duty = unit->mDuty = sc_clip(nextDuty, 0.001, 0.999); invduty = unit->mInvDuty = 2.f / duty; inv1duty = unit->mInv1Duty = 2.f / (1.f - duty); } float z = phase < duty ? phase * invduty : (1.f - phase) * inv1duty; phase += ZXP(freq) * freqmul; ZXP(out) = z - 1.f; ); unit->mPhase = phase; } void VarSaw_next_k(VarSaw *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0) * unit->mFreqMul; float nextDuty = ZIN0(2); float duty = unit->mDuty; float invduty = unit->mInvDuty; float inv1duty = unit->mInv1Duty; double phase = unit->mPhase; LOOP1(inNumSamples, if (phase >= 1.f) { phase -= 1.f; duty = unit->mDuty = sc_clip(nextDuty, 0.001, 0.999); invduty = unit->mInvDuty = 2.f / duty; inv1duty = unit->mInv1Duty = 2.f / (1.f - duty); } float z = phase < duty ? phase * invduty : (1.f - phase) * inv1duty; phase += freq; ZXP(out) = z - 1.f; ); unit->mPhase = phase; } void VarSaw_Ctor(VarSaw* unit) { if (INRATE(0) == calc_FullRate) { SETCALC(VarSaw_next_a); } else { SETCALC(VarSaw_next_k); } unit->mFreqMul = unit->mRate->mSampleDur; unit->mPhase = ZIN0(1); float duty = ZIN0(2); duty = unit->mDuty = sc_clip(duty, 0.001, 0.999); unit->mInvDuty = 2.f / duty; unit->mInv1Duty = 2.f / (1.f - duty); ZOUT0(0) = 0.f; } ////////////////////////////////////////////////////////////////////////////////////////////////// void SyncSaw_next_aa(SyncSaw *unit, int inNumSamples) { float freqmul = unit->mFreqMul; float *out = ZOUT(0); float *freq1 = ZIN(0); float *freq2 = ZIN(1); double phase1 = unit->mPhase1; double phase2 = unit->mPhase2; LOOP1(inNumSamples, float freq1x = ZXP(freq1) * freqmul; float freq2x = ZXP(freq2) * freqmul; float z = phase2; phase2 += freq2x; if (phase2 >= 1.f) phase2 -= 2.f; phase1 += freq1x; if (phase1 >= 1.f) { phase1 -= 2.f; phase2 = (phase1 + 1.f) * freq2x / freq1x - 1.f; } ZXP(out) = z; ); unit->mPhase1 = phase1; unit->mPhase2 = phase2; } void SyncSaw_next_ak(SyncSaw *unit, int inNumSamples) { float freqmul = unit->mFreqMul; float *out = ZOUT(0); float *freq1 = ZIN(0); float freq2x = ZIN0(1) * freqmul; double phase1 = unit->mPhase1; double phase2 = unit->mPhase2; LOOP1(inNumSamples, float freq1x = ZXP(freq1) * freqmul; float z = phase2; phase2 += freq2x; if (phase2 >= 1.f) phase2 -= 2.f; phase1 += freq1x; if (phase1 >= 1.f) { phase1 -= 2.f; phase2 = (phase1 + 1.f) * freq2x / freq1x - 1.f; } ZXP(out) = z; ); unit->mPhase1 = phase1; unit->mPhase2 = phase2; } void SyncSaw_next_ka(SyncSaw *unit, int inNumSamples) { float freqmul = unit->mFreqMul; float *out = ZOUT(0); float freq1x = ZIN0(0) * freqmul; float *freq2 = ZIN(1); double phase1 = unit->mPhase1; double phase2 = unit->mPhase2; LOOP1(inNumSamples, float freq2x = ZXP(freq2) * freqmul; float z = phase2; phase2 += freq2x; if (phase2 >= 1.f) phase2 -= 2.f; phase1 += freq1x; if (phase1 >= 1.f) { phase1 -= 2.f; phase2 = (phase1 + 1.f) * freq2x / freq1x - 1.f; } ZXP(out) = z; ); unit->mPhase1 = phase1; unit->mPhase2 = phase2; } void SyncSaw_next_kk(SyncSaw *unit, int inNumSamples) { float *out = ZOUT(0); float freq1x = ZIN0(0) * unit->mFreqMul; float freq2x = ZIN0(1) * unit->mFreqMul; double phase1 = unit->mPhase1; double phase2 = unit->mPhase2; LOOP1(inNumSamples, float z = phase2; phase2 += freq2x; if (phase2 >= 1.f) phase2 -= 2.f; phase1 += freq1x; if (phase1 >= 1.f) { phase1 -= 2.f; phase2 = (phase1 + 1.f) * freq2x / freq1x - 1.f; } ZXP(out) = z; ); unit->mPhase1 = phase1; unit->mPhase2 = phase2; } void SyncSaw_Ctor(SyncSaw* unit) { if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) { SETCALC(SyncSaw_next_aa); } else { SETCALC(SyncSaw_next_ak); } } else { if (INRATE(1) == calc_FullRate) { SETCALC(SyncSaw_next_ka); } else { SETCALC(SyncSaw_next_kk); } } unit->mFreqMul = 2.0 * unit->mRate->mSampleDur; unit->mPhase1 = 0.; unit->mPhase2 = 0.; SyncSaw_next_kk(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// struct K2A: SIMD_Unit { ControlRateInput<0> mLevel; K2A(void) { mLevel.init(this); if (inRate(0) == calc_ScalarRate) set_unrolled_calc_function, &K2A::next_i, &K2A::next_i >(); else set_unrolled_calc_function, &K2A::next_k, &K2A::next_k >(); } template void next_k(int inNumSamples) { if (mLevel.changed(this)) slope_vec(out(0), mLevel.slope(this), inNumSamples); else next_i(inNumSamples); } template void next_i(int inNumSamples) { set_vec(out(0), mLevel, inNumSamples); } }; ////////////////////////////////////////////////////////////////////////////////////////////////// void A2K_next(A2K *unit, int inNumSamples) { ZOUT0(0) = ZIN0(0); // return first sample in block } void A2K_Ctor(A2K* unit) { SETCALC(A2K_next); A2K_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void T2K_next(T2K *unit, int inNumSamples) { float out = 0.f, val; float *in = ZIN(0); int n = unit->mWorld->mBufLength; LOOP1(n, val = ZXP(in); if(val>out) out=val; ); ZOUT0(0) = out; } void T2K_Ctor(T2K* unit) { SETCALC(T2K_next); ZOUT0(0) = ZIN0(0); } ////////////////////////////////////////////////////////////////////////////////////////////////// static inline void T2A_write_trigger(T2A * unit, float level) { float *out = OUT(0); int offset = (int) IN0(1); out[offset] = level; } void T2A_next(T2A *unit, int inNumSamples) { float level = IN0(0); ZClear(inNumSamples, ZOUT(0)); if((unit->mLevel <= 0.f && level > 0.f)) T2A_write_trigger(unit, level); unit->mLevel = level; } #ifdef NOVA_SIMD FLATTEN void T2A_next_nova(T2A *unit, int inNumSamples) { float level = IN0(0); nova::zerovec_simd(OUT(0), inNumSamples); if((unit->mLevel <= 0.f && level > 0.f)) T2A_write_trigger(unit, level); unit->mLevel = level; } FLATTEN void T2A_next_nova_64(T2A *unit, int inNumSamples) { float level = IN0(0); nova::zerovec_simd<64>(OUT(0)); if((unit->mLevel <= 0.f && level > 0.f)) T2A_write_trigger(unit, level); unit->mLevel = level; } #endif void T2A_Ctor(T2A* unit) { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(T2A_next_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(T2A_next_nova); else #endif SETCALC(T2A_next); T2A_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// struct DC: SIMD_Unit { float value; DC(void) { value = in0(0); if (value == 0) set_unrolled_calc_function, &DC::next_i, &DC::next_i >(); else set_unrolled_calc_function, &DC::next_i, &DC::next_i >(); } template void next_i(int inNumSamples) { if (isZero) zero_vec(out(0), inNumSamples); else set_vec(out(0), value, inNumSamples); } }; ////////////////////////////////////////////////////////////////////////////////////////////////// static inline void Line_next_loop(Line * unit, int & counter, int remain, double & level) { float *out = ZOUT(0); double slope = unit->mSlope; do { if (counter==0) { int nsmps = remain; remain = 0; float endlevel = unit->mEndLevel; LOOP(nsmps, ZXP(out) = endlevel; ); } else { int nsmps = sc_min(remain, counter); counter -= nsmps; remain -= nsmps; LOOP(nsmps, ZXP(out) = level; level += slope; ); if (counter == 0) { unit->mDone = true; int doneAction = (int)ZIN0(3); DoneAction(doneAction, unit); } } } while (remain); } void Line_next(Line *unit, int inNumSamples) { double level = unit->mLevel; int counter = unit->mCounter; Line_next_loop(unit, counter, inNumSamples, level); unit->mCounter = counter; unit->mLevel = level; } #ifdef NOVA_SIMD FLATTEN void Line_next_nova(Line *unit, int inNumSamples) { double level = unit->mLevel; int counter = unit->mCounter; if (counter == 0) { nova::setvec_simd(OUT(0), unit->mEndLevel, inNumSamples); return; } if (counter > inNumSamples) { double slope = unit->mSlope; nova::set_slope_vec_simd(OUT(0), (float)level, (float)slope, inNumSamples); unit->mLevel = level + inNumSamples * slope; unit->mCounter = counter - inNumSamples; return; } Line_next_loop(unit, counter, inNumSamples, level); unit->mCounter = counter; unit->mLevel = level; } FLATTEN void Line_next_nova_64(Line *unit, int inNumSamples) { double level = unit->mLevel; int counter = unit->mCounter; if (counter == 0) { nova::setvec_simd<64>(OUT(0), unit->mEndLevel); return; } if (counter > inNumSamples) { double slope = unit->mSlope; nova::set_slope_vec_simd(OUT(0), (float)level, (float)slope, 64); unit->mLevel = level + inNumSamples * slope; unit->mCounter = counter - inNumSamples; return; } Line_next_loop(unit, counter, inNumSamples, level); unit->mCounter = counter; unit->mLevel = level; } #endif void Line_Ctor(Line* unit) { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(Line_next_nova); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Line_next_nova); else #endif SETCALC(Line_next); double start = ZIN0(0); double end = ZIN0(1); double dur = ZIN0(2); int counter = (int)(dur * unit->mRate->mSampleRate + .5f); unit->mCounter = sc_max(1, counter); if(counter == 0){ unit->mLevel = end; unit->mSlope = 0.; } else { unit->mLevel = start; unit->mSlope = (end - start) / unit->mCounter; unit->mLevel += unit->mSlope; } unit->mEndLevel = end; ZOUT0(0) = unit->mLevel; } ////////////////////////////////////////////////////////////////////////////////////////////////// static inline void Xline_next_loop(XLine * unit, int & counter, int remain, double & level) { float *out = ZOUT(0); double grow = unit->mGrowth; do { if (counter==0) { int nsmps = remain; remain = 0; LOOP(nsmps, ZXP(out) = level; ); } else { int nsmps = sc_min(remain, counter); counter -= nsmps; remain -= nsmps; LOOP(nsmps, ZXP(out) = level; level *= grow; ); if (counter == 0) { level = unit->mEndLevel; unit->mDone = true; int doneAction = (int)ZIN0(3); DoneAction(doneAction, unit); } } } while (remain); } void XLine_next(XLine *unit, int inNumSamples) { double level = unit->mLevel; int counter = unit->mCounter; Xline_next_loop(unit, counter, inNumSamples, level); unit->mCounter = counter; unit->mLevel = level; } #ifdef NOVA_SIMD FLATTEN void XLine_next_nova(XLine *unit, int inNumSamples) { double level = unit->mLevel; int counter = unit->mCounter; if (counter == 0) { nova::setvec_simd(OUT(0), (float)level, inNumSamples); return; } if (counter > inNumSamples) { double grow = unit->mGrowth; nova::set_exp_vec_simd(OUT(0), (float)level, (float)grow, inNumSamples); level *= sc_powi(grow, inNumSamples); counter -= inNumSamples; } else Xline_next_loop(unit, counter, inNumSamples, level); unit->mCounter = counter; unit->mLevel = level; } FLATTEN void XLine_next_nova_64(XLine *unit, int inNumSamples) { double level = unit->mLevel; int counter = unit->mCounter; if (counter == 0) { nova::setvec_simd<64>(OUT(0), (float)level); return; } if (counter > 64) { double grow = unit->mGrowth; nova::set_exp_vec_simd(OUT(0), (float)level, (float)grow, 64); level *= sc_powi(grow, inNumSamples); counter -= inNumSamples; } else Xline_next_loop(unit, counter, inNumSamples, level); unit->mCounter = counter; unit->mLevel = level; } #endif void XLine_Ctor(XLine* unit) { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(XLine_next_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(XLine_next_nova); else #endif SETCALC(XLine_next); double start = ZIN0(0); double end = ZIN0(1); double dur = ZIN0(2); int counter = (int)(dur * unit->mRate->mSampleRate + .5f); unit->mEndLevel = end; if (counter == 0) { ZOUT0(0) = end; unit->mLevel = end; unit->mCounter = 0; unit->mGrowth = 0; } else { ZOUT0(0) = start; unit->mCounter = counter; unit->mGrowth = pow(end / start, 1.0 / counter); unit->mLevel = start * unit->mGrowth; } } ////////////////////////////////////////////////////////////////////////////////////////////////// /* void Wrap_next(Wrap* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lo = unit->m_lo; float hi = unit->m_hi; float range = unit->m_range; LOOP1(inNumSamples, ZXP(out) = sc_wrap(ZXP(in), lo, hi, range); ); } void Wrap_Ctor(Wrap* unit) { SETCALC(Wrap_next); unit->m_lo = ZIN0(1); unit->m_hi = ZIN0(2); if (unit->m_lo > unit->m_hi) { float temp = unit->m_lo; unit->m_lo = unit->m_hi; unit->m_hi = temp; } unit->m_range = unit->m_hi - unit->m_lo; Wrap_next(unit, 1); } */ void Wrap_next_kk(Wrap* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_lo = ZIN0(1); float next_hi = ZIN0(2); float lo = unit->m_lo; float lo_slope = CALCSLOPE(next_lo, lo); float hi = unit->m_hi; float hi_slope = CALCSLOPE(next_hi, hi); LOOP1(inNumSamples, float range = hi - lo; ZXP(out) = sc_wrap(ZXP(in), lo, hi, range); lo += lo_slope; hi += hi_slope; ); unit->m_lo = lo; unit->m_hi = hi; } void Wrap_next_ka(Wrap* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_lo = ZIN0(1); float *hi = ZIN(2); float lo = unit->m_lo; float lo_slope = CALCSLOPE(next_lo, lo); LOOP1(inNumSamples, float curhi = ZXP(hi); ZXP(out) = sc_wrap(ZXP(in), lo, curhi, curhi - lo); lo += lo_slope; ); unit->m_lo = lo; } void Wrap_next_ak(Wrap* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *lo = ZIN(1); float next_hi = ZIN0(2); float hi = unit->m_hi; float hi_slope = CALCSLOPE(next_hi, hi); LOOP1(inNumSamples, float curlo = ZXP(lo); ZXP(out) = sc_wrap(ZXP(in), curlo, hi, hi - curlo); hi += hi_slope; ); unit->m_hi = hi; } void Wrap_next_aa(Wrap* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *lo = ZIN(1); float *hi = ZIN(2); LOOP1(inNumSamples, float curhi = ZXP(hi); float curlo = ZXP(lo); ZXP(out) = sc_wrap(ZXP(in), curlo, curhi, curhi - curlo); ); } void Wrap_Ctor(Wrap* unit) { if(BUFLENGTH == 1) { // _aa? Well, yes - that calc func doesn't interpolate // and interpolation is not needed for kr (1 sample/block) SETCALC(Wrap_next_aa); } else { if(INRATE(1) == calc_FullRate) { if(INRATE(2) == calc_FullRate) SETCALC(Wrap_next_aa); else SETCALC(Wrap_next_ak); } else { if(INRATE(2) == calc_FullRate) SETCALC(Wrap_next_ka); else SETCALC(Wrap_next_kk); } } unit->m_lo = ZIN0(1); unit->m_hi = ZIN0(2); Wrap_next_kk(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// /* void Fold_next(Fold* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lo = unit->m_lo; float hi = unit->m_hi; float range = unit->m_range; float range2 = unit->m_range2; LOOP1(inNumSamples, ZXP(out) = sc_fold(ZXP(in), lo, hi, range, range2); ); } void Fold_Ctor(Fold* unit) { SETCALC(Fold_next); unit->m_lo = ZIN0(1); unit->m_hi = ZIN0(2); if (unit->m_lo > unit->m_hi) { float temp = unit->m_lo; unit->m_lo = unit->m_hi; unit->m_hi = temp; } unit->m_range = unit->m_hi - unit->m_lo; unit->m_range2 = 2.f * unit->m_range; Fold_next(unit, 1); } */ void Fold_next_kk(Fold* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_lo = ZIN0(1); float next_hi = ZIN0(2); float lo = unit->m_lo; float lo_slope = CALCSLOPE(next_lo, lo); float hi = unit->m_hi; float hi_slope = CALCSLOPE(next_hi, hi); LOOP1(inNumSamples, float range = hi - lo; float range2 = range * 2.f; ZXP(out) = sc_fold(ZXP(in), lo, hi, range, range2); lo += lo_slope; hi += hi_slope; ); unit->m_lo = lo; unit->m_hi = hi; } void Fold_next_ka(Fold* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_lo = ZIN0(1); float *hi = ZIN(2); float lo = unit->m_lo; float lo_slope = CALCSLOPE(next_lo, lo); LOOP1(inNumSamples, float curhi = ZXP(hi); float range = curhi - lo; float range2 = range * 2.f; ZXP(out) = sc_fold(ZXP(in), lo, curhi, range, range2); lo += lo_slope; ); unit->m_lo = lo; } void Fold_next_ak(Fold* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *lo = ZIN(1); float next_hi = ZIN0(2); float hi = unit->m_hi; float hi_slope = CALCSLOPE(next_hi, hi); LOOP1(inNumSamples, float curlo = ZXP(lo); float range = hi - curlo; float range2 = range * 2.f; ZXP(out) = sc_fold(ZXP(in), curlo, hi, range, range2); hi += hi_slope; ); unit->m_hi = hi; } void Fold_next_aa(Fold* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *lo = ZIN(1); float *hi = ZIN(2); LOOP1(inNumSamples, float curhi = ZXP(hi); float curlo = ZXP(lo); float range = curhi - curlo; float range2 = range * 2.0; ZXP(out) = sc_fold(ZXP(in), curlo, curhi, range, range2); ); } void Fold_Ctor(Fold* unit) { if(BUFLENGTH == 1) { // _aa? Well, yes - that calc func doesn't interpolate // and interpolation is not needed for kr (1 sample/block) SETCALC(Fold_next_aa); } else { if(INRATE(1) == calc_FullRate) { if(INRATE(2) == calc_FullRate) SETCALC(Fold_next_aa); else SETCALC(Fold_next_ak); } else { if(INRATE(2) == calc_FullRate) SETCALC(Fold_next_ka); else SETCALC(Fold_next_kk); } } unit->m_lo = ZIN0(1); unit->m_hi = ZIN0(2); Fold_next_kk(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Clip_next_ii(Clip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lo = unit->m_lo; float hi = unit->m_hi; LOOP1(inNumSamples, ZXP(out) = sc_clip(ZXP(in), lo, hi); ); } void Clip_next_kk(Clip* unit, int inNumSamples) { float next_lo = ZIN0(1); float next_hi = ZIN0(2); float lo = unit->m_lo; float hi = unit->m_hi; if (lo == next_lo && hi == next_hi) { Clip_next_ii(unit, inNumSamples); return; } float *out = ZOUT(0); float *in = ZIN(0); float lo_slope = CALCSLOPE(next_lo, lo); float hi_slope = CALCSLOPE(next_hi, hi); LOOP1(inNumSamples, ZXP(out) = sc_clip(ZXP(in), lo, hi); lo += lo_slope; hi += hi_slope; ); unit->m_lo = lo; unit->m_hi = hi; } void Clip_next_ka(Clip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_lo = ZIN0(1); float *hi = ZIN(2); float lo = unit->m_lo; float lo_slope = CALCSLOPE(next_lo, lo); LOOP1(inNumSamples, ZXP(out) = sc_clip(ZXP(in), lo, ZXP(hi)); lo += lo_slope; ); unit->m_lo = lo; } void Clip_next_ak(Clip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *lo = ZIN(1); float next_hi = ZIN0(2); float hi = unit->m_hi; float hi_slope = CALCSLOPE(next_hi, hi); LOOP1(inNumSamples, ZXP(out) = sc_clip(ZXP(in), ZXP(lo), hi); hi += hi_slope; ); unit->m_hi = hi; } void Clip_next_aa(Clip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *lo = ZIN(1); float *hi = ZIN(2); LOOP1(inNumSamples, ZXP(out) = sc_clip(ZXP(in), ZXP(lo), ZXP(hi)); ); } void Clip_next_k(Clip* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lo = ZIN0(1); float hi = ZIN0(2); ZXP(out) = sc_clip(ZXP(in), lo, hi); } #ifdef NOVA_SIMD void Clip_next_nova_ii(Clip* unit, int inNumSamples) { float lo = unit->m_lo; float hi = unit->m_hi; nova::clip_vec_simd(OUT(0), IN(0), lo, hi, inNumSamples); } void Clip_next_nova_ki(Clip* unit, int inNumSamples) { float next_lo = ZIN0(1); float lo = unit->m_lo; float hi = unit->m_hi; if (lo == next_lo) { Clip_next_nova_ii(unit, inNumSamples); return; } float lo_slope = CALCSLOPE(next_lo, lo); nova::clip_vec_simd(OUT(0), IN(0), slope_argument(lo, lo_slope), hi, inNumSamples); unit->m_lo = next_lo; } void Clip_next_nova_ik(Clip* unit, int inNumSamples) { float next_hi = ZIN0(2); float lo = unit->m_lo; float hi = unit->m_hi; if (hi == next_hi) { Clip_next_nova_ii(unit, inNumSamples); return; } float hi_slope = CALCSLOPE(next_hi, hi); nova::clip_vec_simd(OUT(0), IN(0), lo, slope_argument(hi, hi_slope), inNumSamples); unit->m_hi = next_hi; } void Clip_next_nova_kk(Clip* unit, int inNumSamples) { float next_lo = ZIN0(1); float next_hi = ZIN0(2); float lo = unit->m_lo; float hi = unit->m_hi; if (lo == next_lo && hi == next_hi) { Clip_next_nova_ii(unit, inNumSamples); return; } if (lo == next_lo) { Clip_next_nova_ik(unit, inNumSamples); return; } if (hi == next_hi) { Clip_next_nova_ki(unit, inNumSamples); return; } float lo_slope = CALCSLOPE(next_lo, lo); float hi_slope = CALCSLOPE(next_hi, hi); nova::clip_vec_simd(OUT(0), IN(0), slope_argument(lo, lo_slope), slope_argument(hi, hi_slope), inNumSamples); unit->m_lo = next_lo; unit->m_hi = next_hi; } void Clip_next_nova_ai(Clip* unit, int inNumSamples) { float hi = unit->m_hi; nova::clip_vec_simd(OUT(0), IN(0), IN(1), hi, inNumSamples); } void Clip_next_nova_ak(Clip* unit, int inNumSamples) { float next_hi = ZIN0(2); float hi = unit->m_hi; if (hi == next_hi) { Clip_next_nova_ai(unit, inNumSamples); return; } float hi_slope = CALCSLOPE(next_hi, hi); nova::clip_vec_simd(OUT(0), IN(0), IN(1), slope_argument(hi, hi_slope), inNumSamples); unit->m_hi = next_hi; } void Clip_next_nova_ia(Clip* unit, int inNumSamples) { float lo = unit->m_lo; nova::clip_vec_simd(OUT(0), IN(0), lo, IN(2), inNumSamples); } void Clip_next_nova_ka(Clip* unit, int inNumSamples) { float next_lo = ZIN0(1); float lo = unit->m_lo; if (lo == next_lo) { Clip_next_nova_ia(unit, inNumSamples); return; } float lo_slope = CALCSLOPE(next_lo, lo); nova::clip_vec_simd(OUT(0), IN(0), slope_argument(lo, lo_slope), IN(2), inNumSamples); unit->m_lo = next_lo; } void Clip_next_nova_aa(Clip* unit, int inNumSamples) { nova::clip_vec_simd(OUT(0), IN(0), IN(1), IN(2), inNumSamples); } #endif typedef void (*ClipCalcFunc)(Clip*, int); static ClipCalcFunc Clip_SelectCalc(Clip * unit) { if(BUFLENGTH == 1) return Clip_next_k; int loRate = INRATE(1); int hiRate = INRATE(2); #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) { switch (loRate) { case calc_FullRate: switch (hiRate) { case calc_FullRate: return Clip_next_nova_aa; case calc_BufRate: return Clip_next_nova_ak; case calc_ScalarRate: return Clip_next_nova_ai; } break; case calc_BufRate: switch (hiRate) { case calc_FullRate: return Clip_next_nova_ka; case calc_BufRate: return Clip_next_nova_kk; case calc_ScalarRate: return Clip_next_nova_ki; } break; case calc_ScalarRate: switch (hiRate) { case calc_FullRate: return Clip_next_nova_ia; case calc_BufRate: return Clip_next_nova_ik; case calc_ScalarRate: return Clip_next_nova_ii; } break; } } #endif if (loRate == calc_FullRate && hiRate == calc_FullRate) return Clip_next_aa; if (loRate == calc_ScalarRate && hiRate == calc_ScalarRate) return Clip_next_ii; if (loRate == calc_FullRate && hiRate != calc_FullRate) return Clip_next_ak; if (loRate != calc_FullRate && hiRate == calc_FullRate) return Clip_next_ak; return Clip_next_kk; } void Clip_Ctor(Clip* unit) { ClipCalcFunc fn = Clip_SelectCalc(unit); unit->mCalcFunc = (UnitCalcFunc)fn; unit->m_lo = ZIN0(1); unit->m_hi = ZIN0(2); Clip_next_ii(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void Unwrap_next(Unwrap* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float range = unit->m_range; float half = unit->m_half; float prev = unit->m_prev; float offset = unit->m_offset; LOOP1(inNumSamples, float zin = ZXP(in); float diff = zin - prev; if (fabs(diff) > half) { if (zin < prev) offset += range; else offset -= range; } ZXP(out) = zin + offset; prev = zin; ); unit->m_prev = prev; unit->m_offset = offset; } void Unwrap_Ctor(Unwrap* unit) { SETCALC(Unwrap_next); float in = ZIN0(0); float lo = ZIN0(1); float hi = ZIN0(2); if (lo > hi) { float temp = lo; lo = hi; hi = temp; } unit->m_range = fabs(hi - lo); unit->m_half = unit->m_range * 0.5f; if (in < lo || in >= hi) unit->m_offset = floor((lo - in)/unit->m_range) * unit->m_range; else unit->m_offset = 0.f; Unwrap_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void ModDif_next_kk(ModDif* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_dif = ZIN0(1); float next_mod = ZIN0(2); float dif = unit->m_dif; float dif_slope = CALCSLOPE(next_dif, dif); float mod = unit->m_mod; float mod_slope = CALCSLOPE(next_mod, mod); LOOP1(inNumSamples, float inval = ZXP(in); float diff = std::fmod(std::abs(inval - dif), mod); float modhalf = mod * 0.5; ZXP(out) = modhalf - std::fabs(diff - modhalf); dif += dif_slope; mod += mod_slope; ); unit->m_dif = dif; unit->m_mod = mod; } void ModDif_next_ka(ModDif* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float next_dif = ZIN0(1); float *mod = ZIN(2); float dif = unit->m_dif; float dif_slope = CALCSLOPE(next_dif, dif); LOOP1(inNumSamples, float inval = ZXP(in); float curmod = ZXP(mod); float diff = std::fmod(std::abs(inval - dif), curmod); float modhalf = curmod * 0.5; ZXP(out) = modhalf - std::abs(diff - modhalf); dif += dif_slope; ); unit->m_dif = dif; } void ModDif_next_ak(ModDif* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *dif = ZIN(1); float next_mod = ZIN0(2); float mod = unit->m_mod; float mod_slope = CALCSLOPE(next_mod, mod); LOOP1(inNumSamples, float inval = ZXP(in); float diff = std::fmod(std::abs(inval - ZXP(dif)), mod); float modhalf = mod * 0.5; ZXP(out) = modhalf - std::abs(diff - modhalf); mod += mod_slope; ); unit->m_mod = mod; } void ModDif_next_aa(ModDif* unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *dif = ZIN(1); float *mod = ZIN(2); LOOP1(inNumSamples, float inval = ZXP(in); float curmod = ZXP(mod); float diff = std::fmod(std::abs(inval - ZXP(dif)), curmod); float modhalf = curmod * 0.5; ZXP(out) = modhalf - std::abs(diff - modhalf); ); } void ModDif_Ctor(ModDif* unit) { if(BUFLENGTH == 1) { // _aa? Well, yes - that calc func doesn't interpolate // and interpolation is not needed for kr (1 sample/block) SETCALC(ModDif_next_aa); } else { if(INRATE(1) == calc_FullRate) { if(INRATE(2) == calc_FullRate) SETCALC(ModDif_next_aa); else SETCALC(ModDif_next_ak); } else { if(INRATE(2) == calc_FullRate) SETCALC(ModDif_next_ka); else SETCALC(ModDif_next_kk); } } unit->m_dif = ZIN0(1); unit->m_mod = ZIN0(2); ModDif_next_kk(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void AmpComp_next(AmpComp *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float rootmul = unit->m_rootmul; float xb = unit->m_exponent; LOOP1(inNumSamples, float xa = ZXP(freq); ZXP(out) = xa >= 0.f ? pow(xa, xb) * rootmul : -pow(-xa, xb) * rootmul; ); } void AmpComp_next_kk(AmpComp *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); float root = ZIN0(1); float xb = ZIN0(2); LOOP1(inNumSamples, float xa = root / ZXP(freq); ZXP(out) = xa >= 0.f ? pow(xa, xb) : -pow(-xa, xb); ); } void AmpComp_Ctor(AmpComp* unit) { if(INRATE(1) != calc_ScalarRate || INRATE(2) != calc_ScalarRate) { SETCALC(AmpComp_next_kk); } else { float exp = ZIN0(2); unit->m_rootmul = pow(ZIN0(1), exp); unit->m_exponent = -1.f * exp; SETCALC(AmpComp_next); } AmpComp_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// const double AMPCOMP_K = 3.5041384 * 10e15; const double AMPCOMP_C1 = 20.598997 * 20.598997; const double AMPCOMP_C2 = 107.65265 * 107.65265; const double AMPCOMP_C3 = 737.86223 * 737.86223; const double AMPCOMP_C4 = 12194.217 * 12194.217; const double AMPCOMP_MINLEVEL = -0.1575371167435; double AmpCompA_calcLevel(double freq) { double r = freq * freq; double level = (AMPCOMP_K * r * r * r * r); double n1 = AMPCOMP_C1 + r; double n2 = AMPCOMP_C4 + r; level = level / ( n1 * n1 * (AMPCOMP_C2 + r) * (AMPCOMP_C3 + r) * n2 * n2 ); level = 1. - sqrt(level); return level; } void AmpCompA_next(AmpCompA *unit, int inNumSamples) { float *out = ZOUT(0); float *freq = ZIN(0); double scale = unit->m_scale; double offset = unit->m_offset; LOOP1(inNumSamples, ZXP(out) = AmpCompA_calcLevel(ZXP(freq)) * scale + offset; ); } void AmpCompA_Ctor(AmpCompA* unit) { double rootFreq = ZIN0(1); double rootLevel = AmpCompA_calcLevel(rootFreq); float minLevel = ZIN0(2); unit->m_scale = (ZIN0(3) - minLevel) / (rootLevel - AMPCOMP_MINLEVEL); unit->m_offset = minLevel - unit->m_scale * AMPCOMP_MINLEVEL; SETCALC(AmpCompA_next); AmpCompA_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void InRange_next(InRange *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lo = ZIN0(1); float hi = ZIN0(2); LOOP1(inNumSamples, float zin = ZXP(in); ZXP(out) = zin >= lo && zin <= hi ? 1.f : 0.f; ); } void InRange_Ctor(InRange* unit) { SETCALC(InRange_next); InRange_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void InRect_next(InRect* unit, int inNumSamples) { float *out = ZOUT(0); float *inx = ZIN(0); float *iny = ZIN(1); float left = ZIN0(2); float top = ZIN0(3); float right = ZIN0(4); float bottom = ZIN0(5); LOOP1(inNumSamples, float x = ZXP(inx); float y = ZXP(iny); ZXP(out) = x >= left && x <= right && y >= top && y <= bottom ? 1.f : 0.f; ); } void InRect_Ctor(InRect* unit) { SETCALC(InRect_next); InRect_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LinExp_next(LinExp *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float dstlo = unit->m_dstlo; float dstratio = unit->m_dstratio; float rsrcrange = unit->m_rsrcrange; float rrminuslo = unit->m_rrminuslo; LOOP1(inNumSamples, ZXP(out) = dstlo * pow(dstratio, ZXP(in) * rsrcrange + rrminuslo); ); } #ifdef NOVA_SIMD static inline void LinExp_next_nova_loop(float * out, const float * in, int inNumSamples, nova::vec dstlo, nova::vec dstratio, nova::vec rsrcrange, nova::vec rrminuslo) { const int vecSize = nova::vec::size; int unroll = inNumSamples / (2*vecSize); do { nova::vec val0, val1; val0.load_aligned(in); val1.load_aligned(in + vecSize); val0 = dstlo * pow(dstratio, val0 * rsrcrange + rrminuslo); val1 = dstlo * pow(dstratio, val1 * rsrcrange + rrminuslo); val0.store_aligned(out); val1.store_aligned(out + vecSize); in += 2*vecSize; out += 2*vecSize; } while (--unroll); } FLATTEN static void LinExp_next_nova(LinExp *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); LinExp_next_nova_loop(out, in, inNumSamples, unit->m_dstlo, unit->m_dstratio, unit->m_rsrcrange, unit->m_rrminuslo); } FLATTEN static void LinExp_next_nova_kk(LinExp *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); float srclo = ZIN0(1); float srchi = ZIN0(2); float dstlo = ZIN0(3); float dsthi = ZIN0(4); float dstratio = dsthi/dstlo; float rsrcrange = sc_reciprocal(srchi - srclo); float rrminuslo = rsrcrange * -srclo; LinExp_next_nova_loop(out, in, inNumSamples, dstlo, dstratio, rsrcrange, rrminuslo); } #endif void LinExp_next_kk(LinExp *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float srclo = ZIN0(1); float srchi = ZIN0(2); float dstlo = ZIN0(3); float dsthi = ZIN0(4); float dstratio = dsthi * sc_reciprocal(dstlo); float rsrcrange = sc_reciprocal(srchi - srclo); float rrminuslo = rsrcrange * -srclo; LOOP1(inNumSamples, ZXP(out) = dstlo * pow(dstratio, ZXP(in) * rsrcrange + rrminuslo); ); } void LinExp_next_aa(LinExp *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *srclo = ZIN(1); float *srchi = ZIN(2); float *dstlo = ZIN(3); float *dsthi = ZIN(4); LOOP1(inNumSamples, float zdsthi = ZXP(dsthi); float zdstlo = ZXP(dstlo); float zsrchi = ZXP(srchi); float zsrclo = ZXP(srclo); float dstratio = zdsthi/zdstlo; float rsrcrange = sc_reciprocal(zsrchi - zsrclo); float rrminuslo = rsrcrange * -zsrclo; ZXP(out) = zdstlo * pow(dstratio, ZXP(in) * rsrcrange + rrminuslo); ); } void LinExp_next_ak(LinExp *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *srclo = ZIN(1); float *srchi = ZIN(2); float dstlo = ZIN0(3); float dsthi = ZIN0(4); float dstratio = dsthi/dstlo; LOOP1(inNumSamples, float zsrchi = ZXP(srchi); float zsrclo = ZXP(srclo); float rsrcrange = sc_reciprocal(zsrchi - zsrclo); float rrminuslo = rsrcrange * -zsrclo; ZXP(out) = dstlo * pow(dstratio, ZXP(in) * rsrcrange + rrminuslo); ); } void LinExp_next_ka(LinExp *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float srclo = ZIN0(1); float srchi = ZIN0(2); float *dstlo = ZIN(3); float *dsthi = ZIN(4); float rsrcrange = sc_reciprocal(srchi - srclo); float rrminuslo = rsrcrange * -srclo; LOOP1(inNumSamples, float zdsthi = ZXP(dsthi); float zdstlo = ZXP(dstlo); float dstratio = zdsthi/zdstlo; ZXP(out) = zdstlo * pow(dstratio, ZXP(in) * rsrcrange + rrminuslo); ); } static void LinExp_SetCalc(LinExp* unit) { if(INRATE(1) == calc_FullRate || INRATE(2) == calc_FullRate) { if(INRATE(3) == calc_FullRate || INRATE(4) == calc_FullRate) { SETCALC(LinExp_next_aa); return; } else { SETCALC(LinExp_next_ak); return; } } else { if(INRATE(3) == calc_FullRate || INRATE(4) == calc_FullRate) { SETCALC(LinExp_next_ka); return; } } bool allScalar = true; for(int i = 1; i<5; i++) { if(INRATE(i) != calc_ScalarRate) { allScalar = false; break; } }; #ifdef NOVA_SIMD if ((BUFLENGTH % (2*nova::vec::size)) == 0) if (allScalar) SETCALC(LinExp_next_nova); else SETCALC(LinExp_next_nova_kk); else #endif if (allScalar) SETCALC(LinExp_next); else SETCALC(LinExp_next_kk); if (!allScalar) return; float srclo = ZIN0(1); float srchi = ZIN0(2); float dstlo = ZIN0(3); float dsthi = ZIN0(4); unit->m_dstlo = dstlo; unit->m_dstratio = dsthi/dstlo; unit->m_rsrcrange = sc_reciprocal(srchi - srclo); unit->m_rrminuslo = unit->m_rsrcrange * -srclo; } void LinExp_Ctor(LinExp* unit) { LinExp_SetCalc(unit); float srclo = ZIN0(1); float srchi = ZIN0(2); float dstlo = ZIN0(3); float dsthi = ZIN0(4); unit->m_dstlo = dstlo; unit->m_dstratio = dsthi/dstlo; unit->m_rsrcrange = 1. / (srchi - srclo); unit->m_rrminuslo = unit->m_rsrcrange * -srclo; LinExp_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// enum { kEnvGen_gate, kEnvGen_levelScale, kEnvGen_levelBias, kEnvGen_timeScale, kEnvGen_doneAction, kEnvGen_initLevel, kEnvGen_numStages, kEnvGen_releaseNode, kEnvGen_loopNode, // 'kEnvGen_nodeOffset' must always be last // if you need to add an arg, put it before this one kEnvGen_nodeOffset }; enum { shape_Step, shape_Linear, shape_Exponential, shape_Sine, shape_Welch, shape_Curve, shape_Squared, shape_Cubed, shape_Hold, shape_Sustain = 9999 }; #ifdef NOVA_SIMD void EnvGen_next_ak_nova(EnvGen *unit, int inNumSamples); #endif #define ENVGEN_NOT_STARTED 1000000000 void EnvGen_Ctor(EnvGen *unit) { //Print("EnvGen_Ctor A\n"); if (unit->mCalcRate == calc_FullRate) { if (INRATE(0) == calc_FullRate) { SETCALC(EnvGen_next_aa); } else { #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(EnvGen_next_ak_nova); else #endif SETCALC(EnvGen_next_ak); } } else { SETCALC(EnvGen_next_k); } // gate = 1.0, levelScale = 1.0, levelBias = 0.0, timeScale // level0, numstages, releaseNode, loopNode, // [level, dur, shape, curve] unit->m_endLevel = unit->m_level = ZIN0(kEnvGen_initLevel) * ZIN0(kEnvGen_levelScale) + ZIN0(kEnvGen_levelBias); unit->m_counter = 0; unit->m_stage = ENVGEN_NOT_STARTED; unit->m_shape = shape_Hold; unit->m_prevGate = 0.f; unit->m_released = false; unit->m_releaseNode = (int)ZIN0(kEnvGen_releaseNode); float** envPtr = unit->mInBuf + kEnvGen_nodeOffset; const int initialShape = (int32)*envPtr[2]; if (initialShape == shape_Hold) unit->m_level = *envPtr[0]; // we start at the end level; EnvGen_next_k(unit, 1); } static bool check_gate(EnvGen * unit, float prevGate, float gate, int & counter, double level, int counterOffset = 0) { if (prevGate <= 0.f && gate > 0.f) { unit->m_stage = -1; unit->m_released = false; unit->mDone = false; counter = counterOffset; return false; } else if (gate <= -1.f && prevGate > -1.f && !unit->m_released) { // cutoff int numstages = (int)ZIN0(kEnvGen_numStages); float dur = -gate - 1.f; counter = (int32)(dur * SAMPLERATE); counter = sc_max(1, counter) + counterOffset; unit->m_stage = numstages; unit->m_shape = shape_Linear; // first ZIN0 gets the last envelope node's level, then apply levelScale and levelBias unit->m_endLevel = ZIN0(unit->mNumInputs - 4) * ZIN0(kEnvGen_levelScale) + ZIN0(kEnvGen_levelBias); unit->m_grow = (unit->m_endLevel - level) / counter; unit->m_released = true; return false; } else if (prevGate > 0.f && gate <= 0.f && unit->m_releaseNode >= 0 && !unit->m_released) { counter = counterOffset; unit->m_stage = unit->m_releaseNode - 1; unit->m_released = true; return false; } return true; } static inline bool check_gate_ar(EnvGen * unit, int i, float & prevGate, float *& gatein, int &nsmps, int & counter, double level) { const float gate = ZXP(gatein); const bool result = check_gate(unit, prevGate, gate, counter, level, i); if (!result) { --gatein; nsmps = i; } prevGate = gate; return result; } static inline bool EnvGen_nextSegment(EnvGen * unit, int & counter, double & level) { //if (unit->m_stage == ENVGEN_NOT_STARTED) { return true; } // this fixes doneAction 14, but breaks with EnvGen_next_aa //Print("stage %d rel %d\n", unit->m_stage, (int)ZIN0(kEnvGen_releaseNode)); int numstages = (int)ZIN0(kEnvGen_numStages); //Print("stage %d numstages %d\n", unit->m_stage, numstages); if (unit->m_stage+1 >= numstages) { // num stages //Print("stage+1 > num stages\n"); counter = INT_MAX; unit->m_shape = 0; level = unit->m_endLevel; unit->mDone = true; int doneAction = (int)ZIN0(kEnvGen_doneAction); DoneAction(doneAction, unit); } else if (unit->m_stage+1 == (int)ZIN0(kEnvGen_releaseNode) && !unit->m_released) { // sustain stage int loopNode = (int)ZIN0(kEnvGen_loopNode); if (loopNode >= 0 && loopNode < numstages) { unit->m_stage = loopNode; goto initSegment; } else { counter = INT_MAX; unit->m_shape = shape_Sustain; level = unit->m_endLevel; } //Print("sustain\n"); } else { unit->m_stage++; initSegment: //Print("stage %d\n", unit->m_stage); //Print("initSegment\n"); //out = unit->m_level; int stageOffset = (unit->m_stage << 2) + kEnvGen_nodeOffset; if (stageOffset + 4 > unit->mNumInputs) { // oops. Print("envelope went past end of inputs.\n"); ClearUnitOutputs(unit, 1); NodeEnd(&unit->mParent->mNode); return false; } float previousEndLevel = unit->m_endLevel; float** envPtr = unit->mInBuf + stageOffset; double endLevel = *envPtr[0] * ZIN0(kEnvGen_levelScale) + ZIN0(kEnvGen_levelBias); // scale levels double dur = *envPtr[1] * ZIN0(kEnvGen_timeScale); unit->m_shape = (int32)*envPtr[2]; double curve = *envPtr[3]; unit->m_endLevel = endLevel; counter = (int32)(dur * SAMPLERATE); counter = sc_max(1, counter); //Print("stageOffset %d level %g endLevel %g dur %g shape %d curve %g\n", stageOffset, level, endLevel, dur, unit->m_shape, curve); //Print("SAMPLERATE %g\n", SAMPLERATE); if (counter == 1) unit->m_shape = 1; // shape_Linear //Print("new counter = %d shape = %d\n", counter, unit->m_shape); switch (unit->m_shape) { case shape_Step : { level = endLevel; } break; case shape_Hold : { level = previousEndLevel; } break; case shape_Linear : { unit->m_grow = (endLevel - level) / counter; //Print("grow %g\n", unit->m_grow); } break; case shape_Exponential : { unit->m_grow = pow(endLevel / level, 1.0 / counter); } break; case shape_Sine : { double w = pi / counter; unit->m_a2 = (endLevel + level) * 0.5; unit->m_b1 = 2. * cos(w); unit->m_y1 = (endLevel - level) * 0.5; unit->m_y2 = unit->m_y1 * sin(pi * 0.5 - w); level = unit->m_a2 - unit->m_y1; } break; case shape_Welch : { double w = (pi * 0.5) / counter; unit->m_b1 = 2. * cos(w); if (endLevel >= level) { unit->m_a2 = level; unit->m_y1 = 0.; unit->m_y2 = -sin(w) * (endLevel - level); } else { unit->m_a2 = endLevel; unit->m_y1 = level - endLevel; unit->m_y2 = cos(w) * (level - endLevel); } level = unit->m_a2 + unit->m_y1; } break; case shape_Curve : { if (fabs(curve) < 0.001) { unit->m_shape = 1; // shape_Linear unit->m_grow = (endLevel - level) / counter; } else { double a1 = (endLevel - level) / (1.0 - exp(curve)); unit->m_a2 = level + a1; unit->m_b1 = a1; unit->m_grow = exp(curve / counter); } } break; case shape_Squared : { unit->m_y1 = sqrt(level); unit->m_y2 = sqrt(endLevel); unit->m_grow = (unit->m_y2 - unit->m_y1) / counter; } break; case shape_Cubed : { unit->m_y1 = pow(level, 1.0/3.0);//0.33333333); unit->m_y2 = pow(endLevel, 1.0/3.0); unit->m_grow = (unit->m_y2 - unit->m_y1) / counter; } break; } } return true; } template static inline void EnvGen_perform(EnvGen * unit, float *& out, double & level, int & nsmps, GateCheck const & gateCheck) { switch (unit->m_shape) { case shape_Step : case shape_Hold : { for (int i=0; im_grow; for (int i=0; im_grow; for (int i=0; im_a2; double b1 = unit->m_b1; double y2 = unit->m_y2; double y1 = unit->m_y1; for (int i=0; im_y1 = y1; unit->m_y2 = y2; } break; case shape_Welch : { double a2 = unit->m_a2; double b1 = unit->m_b1; double y2 = unit->m_y2; double y1 = unit->m_y1; for (int i=0; im_y1 = y1; unit->m_y2 = y2; } break; case shape_Curve : { double a2 = unit->m_a2; double b1 = unit->m_b1; double grow = unit->m_grow; for (int i=0; im_b1 = b1; } break; case shape_Squared : { double grow = unit->m_grow; double y1 = unit->m_y1; for (int i=0; im_y1 = y1; } break; case shape_Cubed : { double grow = unit->m_grow; double y1 = unit->m_y1; for (int i=0; im_y1 = y1; } break; case shape_Sustain : { for (int i=0; i( unit, out, level, nsmps, [](int i) { return true;}); } void EnvGen_next_k(EnvGen *unit, int inNumSamples) { float gate = ZIN0(kEnvGen_gate); //Print("->EnvGen_next_k gate %g\n", gate); int counter = unit->m_counter; double level = unit->m_level; check_gate(unit, unit->m_prevGate, gate, counter, level); unit->m_prevGate = gate; // gate = 1.0, levelScale = 1.0, levelBias = 0.0, timeScale // level0, numstages, releaseNode, loopNode, // [level, dur, shape, curve] if (counter <= 0) { bool success = EnvGen_nextSegment( unit, counter, level ); if (!success) return; } float *out = ZOUT(0); EnvGen_perform( unit, out, level, 1 ); //Print("x %d %d %d %g\n", unit->m_stage, counter, unit->m_shape, *out); unit->m_level = level; unit->m_counter = counter - 1; } void EnvGen_next_ak(EnvGen *unit, int inNumSamples) { float *out = ZOUT(0); float gate = ZIN0(kEnvGen_gate); int counter = unit->m_counter; double level = unit->m_level; check_gate(unit, unit->m_prevGate, gate, counter, level); unit->m_prevGate = gate; int remain = inNumSamples; while (remain) { if (counter <= 0) { bool success = EnvGen_nextSegment( unit, counter, level ); if (!success) return; } int nsmps = sc_min(remain, counter); EnvGen_perform( unit, out, level, nsmps ); remain -= nsmps; counter -= nsmps; } //Print("x %d %d %d %g\n", unit->m_stage, counter, unit->m_shape, ZOUT0(0)); unit->m_level = level; unit->m_counter = counter; } #ifdef NOVA_SIMD FLATTEN void EnvGen_next_ak_nova(EnvGen *unit, int inNumSamples) { float *out = ZOUT(0); float gate = ZIN0(kEnvGen_gate); int counter = unit->m_counter; double level = unit->m_level; check_gate(unit, unit->m_prevGate, gate, counter, level); unit->m_prevGate = gate; int remain = inNumSamples; if (counter > inNumSamples) { switch (unit->m_shape) { case shape_Step : case shape_Hold : case shape_Sustain : nova::setvec_simd(OUT(0), (float)level, inNumSamples); remain = 0; counter -= inNumSamples; break; case shape_Linear : { double slope = unit->m_grow; nova::set_slope_vec_simd(OUT(0), (float)level, (float)slope, inNumSamples); level += inNumSamples * slope; remain = 0; counter -= inNumSamples; } break; case shape_Exponential : { double grow = unit->m_grow; nova::set_exp_vec_simd(OUT(0), (float)level, (float)grow, inNumSamples); level *= sc_powi(grow, inNumSamples); remain = 0; counter -= inNumSamples; } break; } } while (remain) { if (counter <= 0) { bool success = EnvGen_nextSegment( unit, counter, level ); if (!success) return; } int nsmps = sc_min(remain, counter); EnvGen_perform( unit, out, level, nsmps ); remain -= nsmps; counter -= nsmps; } //Print("x %d %d %d %g\n", unit->m_stage, counter, unit->m_shape, ZOUT0(0)); unit->m_level = level; unit->m_counter = counter; } #endif void EnvGen_next_aa(EnvGen *unit, int inNumSamples) { float *out = ZOUT(0); float *gatein = ZIN(kEnvGen_gate); int counter = unit->m_counter; double level = unit->m_level; float gate = unit->m_prevGate; int remain = inNumSamples; while (remain) { if (counter <= 0) { bool success = EnvGen_nextSegment( unit, counter, level ); if (!success) return; } int nsmps = sc_min(remain, counter); EnvGen_perform( unit, out, level, nsmps, [&](int i) { return check_gate_ar( unit, i, gate, gatein, nsmps, counter, level ); } ); remain -= nsmps; counter -= nsmps; } unit->m_level = level; unit->m_counter = counter; unit->m_prevGate = gate; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Linen_Ctor(Linen *unit) { // gate attack level release SETCALC(Linen_next_k); unit->m_level = 0.f; unit->m_stage = 4; unit->m_prevGate = 0.f; if(ZIN0(0) <= -1.f) { unit->m_stage = 1; } // early release Linen_next_k(unit, 1); } void Linen_next_k(Linen *unit, int inNumSamples) { float gate = ZIN0(0); float *out = OUT(0); if (unit->m_prevGate <= 0.f && gate > 0.f) { unit->mDone = false; unit->m_stage = 0; float attackTime = ZIN0(1); float susLevel = ZIN0(2); int counter = (int)(attackTime * SAMPLERATE); counter = sc_max(1, counter); unit->m_slope = (susLevel - unit->m_level) / counter; unit->m_counter = counter; } switch (unit->m_stage) { case 0 : case 2 : *out = unit->m_level; unit->m_level += unit->m_slope; if (--unit->m_counter == 0) unit->m_stage++; break; case 1 : *out = unit->m_level; if (gate <= -1.f) { // cutoff unit->m_stage = 2; float releaseTime = -gate - 1.f; int counter = (int)(releaseTime * SAMPLERATE); counter = sc_max(1, counter); unit->m_slope = -unit->m_level / counter; unit->m_counter = counter; } else if (gate <= 0.f) { unit->m_stage = 2; float releaseTime = ZIN0(3); int counter = (int)(releaseTime * SAMPLERATE); counter = sc_max(1, counter); unit->m_slope = -unit->m_level / counter; unit->m_counter = counter; //Print("release %d %d\n", unit->mParent->mNode.mID, counter); } break; case 3 : { *out = 0.f; //Print("done %d\n", unit->mParent->mNode.mID); unit->mDone = true; unit->m_stage++; int doneAction = (int)ZIN0(4); DoneAction(doneAction, unit); } break; case 4 : *out = 0.f; break; } unit->m_prevGate = gate; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void EnvFill(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { if (buf->channels != 1) return; int size = buf->samples; int byteSize = size * sizeof(float); float *data = (float*)malloc(byteSize); double level = msg->getf(); int numStages = msg->geti(); /*int releaseNode =*/ msg->geti(); // ignored /*int loopNode =*/ msg->geti(); // ignored double pos = 0.; int32 index = 0; int32 remain = size; for (int j=0; j < numStages; ++j) { double endLevel = msg->getf(); double dur = msg->getf(); int shape = msg->geti(); double curve = msg->getf(); int32 ipos = (int32)pos; double smpdur = dur * size; int32 nsmps = (int32)smpdur - ipos; nsmps = sc_min(nsmps, remain); switch (shape) { case shape_Step : { level = endLevel; for (int i=0; i= level) { a2 = level; y1 = 0.; y2 = -sin(w) * (endLevel - level); } else { a2 = endLevel; y1 = level - endLevel; y2 = cos(w) * (level - endLevel); } level = a2 + y1; for (int i=0; idata, data, byteSize); free(data); } //////////////////// Add IEnvGen 06/06/2007 ///////////////////////////////// struct IEnvGen : public Unit { float m_level, m_offset; float m_startpoint, m_numvals, m_pointin; float* m_envvals; }; extern "C" { void IEnvGen_next_a(IEnvGen *unit, int inNumSamples); void IEnvGen_next_k(IEnvGen *unit, int inNumSamples); void IEnvGen_Ctor(IEnvGen* unit); void IEnvGen_Dtor(IEnvGen* unit); } #define GET_ENV_VAL \ switch (shape) \ { \ case shape_Step : \ level = unit->m_level = endLevel; \ break; \ case shape_Hold : \ level = unit->m_level; \ unit->m_level = endLevel; \ break; \ case shape_Linear : \ default: \ level = unit->m_level = pos * (endLevel - begLevel) + begLevel; \ break; \ case shape_Exponential : \ level = unit->m_level = begLevel * pow(endLevel / begLevel, pos); \ break; \ case shape_Sine : \ level = unit->m_level = begLevel + (endLevel - begLevel) * (-cos(pi * pos) * 0.5 + 0.5); \ break; \ case shape_Welch : \ { \ if (begLevel < endLevel) \ level = unit->m_level = begLevel + (endLevel - begLevel) * sin(pi2 * pos); \ else \ level = unit->m_level = endLevel - (endLevel - begLevel) * sin(pi2 - pi2 * pos); \ break; \ } \ case shape_Curve : \ if (fabs((float)curve) < 0.0001) { \ level = unit->m_level = pos * (endLevel - begLevel) + begLevel; \ } else { \ double denom = 1. - exp((float)curve); \ double numer = 1. - exp((float)(pos * curve)); \ level = unit->m_level = begLevel + (endLevel - begLevel) * (numer/denom); \ } \ break; \ case shape_Squared : \ { \ double sqrtBegLevel = sqrt(begLevel); \ double sqrtEndLevel = sqrt(endLevel); \ double sqrtLevel = pos * (sqrtEndLevel - sqrtBegLevel) + sqrtBegLevel; \ level = unit->m_level = sqrtLevel * sqrtLevel; \ break; \ } \ case shape_Cubed : \ { \ double cbrtBegLevel = pow(begLevel, 0.3333333f); \ double cbrtEndLevel = pow(endLevel, 0.3333333f); \ double cbrtLevel = pos * (cbrtEndLevel - cbrtBegLevel) + cbrtBegLevel; \ level = unit->m_level = cbrtLevel * cbrtLevel * cbrtLevel; \ break; \ } \ } void IEnvGen_Ctor(IEnvGen *unit) { if (INRATE(0) == calc_FullRate) { SETCALC(IEnvGen_next_a); } else { SETCALC(IEnvGen_next_k); } // pointer, offset // initlevel, numstages, totaldur, // [dur, shape, curve, level] * numvals int numStages = (int)IN0(3); int numvals = numStages * 4; // initlevel + (levels, dur, shape, curves) * stages float offset = unit->m_offset = IN0(1); float point = unit->m_pointin = IN0(0) - offset; unit->m_envvals = (float*)RTAlloc(unit->mWorld, (int)(numvals + 1.) * sizeof(float)); unit->m_envvals[0] = IN0(2); // Print("offset of and initial values %3,3f, %3.3f\n", offset, unit->m_envvals[0]); // fill m_envvals with the values; for (int i = 1; i <= numvals; i++) { unit->m_envvals[i] = IN0(4 + i); // Print("val for: %d, %3.3f\n", i, unit->m_envvals[i]); } // float out = OUT0(0); float totalDur = IN0(4); float level = 0.f; float newtime = 0.f; int stage = 0; float seglen = 0.f; if (point >= totalDur) { unit->m_level = level = unit->m_envvals[numStages * 4]; // grab the last value } else { if (point <= 0.0) { unit->m_level = level = unit->m_envvals[0]; } else { float segpos = point; // determine which segment the current time pointer needs calculated for(int j = 0; point >= newtime; j++) { seglen = unit->m_envvals[(j * 4) + 1]; newtime += seglen; segpos -= seglen; stage = j; } segpos = segpos + seglen; float begLevel = unit->m_envvals[(stage * 4)]; int shape = (int)unit->m_envvals[(stage * 4) + 2]; int curve = (int)unit->m_envvals[(stage * 4) + 3]; float endLevel = unit->m_envvals[(stage * 4) + 4]; float pos = (segpos / seglen); GET_ENV_VAL } } OUT0(0) = level; } void IEnvGen_Dtor(IEnvGen *unit) { RTFree(unit->mWorld, unit->m_envvals); } void IEnvGen_next_a(IEnvGen *unit, int inNumSamples) { float* out = OUT(0); float level = unit->m_level; float* pointin = IN(0); float offset = unit->m_offset; int numStages = (int)IN0(3); float point; // = unit->m_pointin; float totalDur = IN0(4); int stagemul; // pointer, offset // level0, numstages, totaldur, // [initval, [dur, shape, curve, level] * N ] for( int i = 0; i < inNumSamples; i++) { if (pointin[i] == unit->m_pointin){ out[i] = level; } else { unit->m_pointin = point = sc_max(pointin[i] - offset, 0.0); float newtime = 0.f; int stage = 0; float seglen = 0.f; if (point >= totalDur) { unit->m_level = level = unit->m_envvals[numStages * 4]; // grab the last value } else { if (point <= 0.0) { unit->m_level = level = unit->m_envvals[0]; } else { float segpos = point; // determine which segment the current time pointer needs for(int j = 0; point >= newtime; j++) { seglen = unit->m_envvals[(j * 4) + 1]; newtime += seglen; segpos -= seglen; stage = j; } stagemul = stage * 4; segpos = segpos + seglen; float begLevel = unit->m_envvals[stagemul]; int shape = (int)unit->m_envvals[stagemul + 2]; int curve = (int)unit->m_envvals[stagemul + 3]; float endLevel = unit->m_envvals[stagemul + 4]; float pos = (segpos / seglen); GET_ENV_VAL } } out[i] = level; } } } void IEnvGen_next_k(IEnvGen *unit, int inNumSamples) { float* out = OUT(0); float level = unit->m_level; float pointin = IN0(0); float offset = unit->m_offset; int numStages = (int)IN0(3); float point; // = unit->m_pointin; float totalDur = IN0(4); int stagemul; // pointer, offset // level0, numstages, totaldur, // [initval, [dur, shape, curve, level] * N ] for( int i = 0; i < inNumSamples; i++) { if (pointin == unit->m_pointin){ out[i] = level; } else { unit->m_pointin = point = sc_max(pointin - offset, 0.0); float newtime = 0.f; int stage = 0; float seglen = 0.f; if (point >= totalDur) { unit->m_level = level = unit->m_envvals[numStages * 4]; // grab the last value } else { if (point <= 0.0) { unit->m_level = level = unit->m_envvals[0]; } else { float segpos = point; // determine which segment the current time pointer needs for(int j = 0; point >= newtime; j++) { seglen = unit->m_envvals[(j * 4) + 1]; newtime += seglen; segpos -= seglen; stage = j; } stagemul = stage * 4; segpos = segpos + seglen; float begLevel = unit->m_envvals[stagemul]; int shape = (int)unit->m_envvals[stagemul + 2]; int curve = (int)unit->m_envvals[stagemul + 3]; float endLevel = unit->m_envvals[stagemul + 4]; float pos = (segpos / seglen); GET_ENV_VAL } } out[i] = level; } } } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(LF) { ft = inTable; DefineSimpleUnit(Vibrato); DefineSimpleUnit(LFPulse); DefineSimpleUnit(LFSaw); DefineSimpleUnit(LFPar); DefineSimpleUnit(LFCub); DefineSimpleUnit(LFTri); DefineSimpleUnit(LFGauss); DefineSimpleUnit(Impulse); DefineSimpleUnit(VarSaw); DefineSimpleUnit(SyncSaw); registerUnit( ft, "K2A" ); DefineSimpleUnit(A2K); DefineSimpleUnit(T2K); DefineSimpleUnit(T2A); registerUnit( ft, "DC" ); DefineSimpleUnit(Line); DefineSimpleUnit(XLine); DefineSimpleUnit(Wrap); DefineSimpleUnit(Fold); DefineSimpleUnit(Clip); DefineSimpleUnit(Unwrap); DefineSimpleUnit(ModDif); DefineSimpleUnit(AmpComp); DefineSimpleUnit(AmpCompA); DefineSimpleUnit(InRange); DefineSimpleUnit(InRect); DefineSimpleUnit(LinExp); DefineSimpleUnit(EnvGen); DefineSimpleUnit(Linen); DefineBufGen("env", EnvFill); DefineDtorUnit(IEnvGen); } SuperCollider-Source/server/plugins/Loudness.cpp000644 000765 000024 00000023646 12321461511 023153 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //Nick Collins 8 Nov 2007 //loudness model #include "ML.h" //perhaps need to have sampling rate choice here: but then, double rate, double fft size, only use bottom 1024 again as useful spectrum in human hearing range! So should just work? int eqlbandbins[43]= {1,2,3,4,5,6,7,8,9,11,13,15,17,19,22,25,28,32,36,41,46,52,58,65,73,82,92,103,116,129,144,161,180,201,225,251,280,312,348,388,433,483,513}; int eqlbandsizes[42]= {1,1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,4,4,5,5,6,6,7,8,9,10,11,13,13,15,17,19,21,24,26,29,32,36,40,45,50,29}; //was 30 float contours[42][11]= {{ 47.88, 59.68, 68.55, 75.48, 81.71, 87.54, 93.24, 98.84,104.44,109.94,115.31},{ 29.04, 41.78, 51.98, 60.18, 67.51, 74.54, 81.34, 87.97, 94.61,101.21,107.74},{ 20.72, 32.83, 43.44, 52.18, 60.24, 67.89, 75.34, 82.70, 89.97, 97.23,104.49},{ 15.87, 27.14, 37.84, 46.94, 55.44, 63.57, 71.51, 79.34, 87.14, 94.97,102.37},{ 12.64, 23.24, 33.91, 43.27, 52.07, 60.57, 68.87, 77.10, 85.24, 93.44,100.90},{ 10.31, 20.43, 31.03, 40.54, 49.59, 58.33, 66.89, 75.43, 83.89, 92.34,100.80},{ 8.51, 18.23, 28.83, 38.41, 47.65, 56.59, 65.42, 74.16, 82.89, 91.61,100.33},{ 7.14, 16.55, 27.11, 36.79, 46.16, 55.27, 64.29, 73.24, 82.15, 91.06, 99.97},{ 5.52, 14.58, 25.07, 34.88, 44.40, 53.73, 62.95, 72.18, 81.31, 90.44, 99.57},{ 3.98, 12.69, 23.10, 32.99, 42.69, 52.27, 61.66, 71.15, 80.54, 89.93, 99.31},{ 2.99, 11.43, 21.76, 31.73, 41.49, 51.22, 60.88, 70.51, 80.11, 89.70, 99.30},{ 2.35, 10.58, 20.83, 30.86, 40.68, 50.51, 60.33, 70.08, 79.83, 89.58, 99.32},{ 2.05, 10.12, 20.27, 30.35, 40.22, 50.10, 59.97, 69.82, 79.67, 89.52, 99.38},{ 2.00, 9.93, 20.00, 30.07, 40.00, 49.93, 59.87, 69.80, 79.73, 89.67, 99.60},{ 2.19, 10.00, 20.00, 30.00, 40.00, 50.00, 59.99, 69.99, 79.98, 89.98, 99.97},{ 2.71, 10.56, 20.61, 30.71, 40.76, 50.81, 60.86, 70.96, 81.01, 91.06,101.17},{ 3.11, 11.05, 21.19, 31.41, 41.53, 51.64, 61.75, 71.95, 82.05, 92.15,102.33},{ 2.39, 10.69, 21.14, 31.52, 41.73, 51.95, 62.11, 72.31, 82.46, 92.56,102.59},{ 1.50, 10.11, 20.82, 31.32, 41.62, 51.92, 62.12, 72.32, 82.52, 92.63,102.56},{ -0.17, 8.50, 19.27, 29.77, 40.07, 50.37, 60.57, 70.77, 80.97, 91.13,101.23},{ -1.80, 6.96, 17.77, 28.29, 38.61, 48.91, 59.13, 69.33, 79.53, 89.71, 99.86},{ -3.42, 5.49, 16.36, 26.94, 37.31, 47.61, 57.88, 68.08, 78.28, 88.41, 98.39},{ -4.73, 4.38, 15.34, 25.99, 36.39, 46.71, 57.01, 67.21, 77.41, 87.51, 97.41},{ -5.73, 3.63, 14.74, 25.48, 35.88, 46.26, 56.56, 66.76, 76.96, 87.06, 96.96},{ -6.24, 3.33, 14.59, 25.39, 35.84, 46.22, 56.52, 66.72, 76.92, 87.04, 97.00},{ -6.09, 3.62, 15.03, 25.83, 36.37, 46.70, 57.00, 67.20, 77.40, 87.57, 97.68},{ -5.32, 4.44, 15.90, 26.70, 37.28, 47.60, 57.90, 68.10, 78.30, 88.52, 98.78},{ -3.49, 6.17, 17.52, 28.32, 38.85, 49.22, 59.52, 69.72, 79.92, 90.20,100.61},{ -0.81, 8.58, 19.73, 30.44, 40.90, 51.24, 61.52, 71.69, 81.87, 92.15,102.63},{ 2.91, 11.82, 22.64, 33.17, 43.53, 53.73, 63.96, 74.09, 84.22, 94.45,104.89},{ 6.68, 15.19, 25.71, 36.03, 46.25, 56.31, 66.45, 76.49, 86.54, 96.72,107.15},{ 10.43, 18.65, 28.94, 39.02, 49.01, 58.98, 68.93, 78.78, 88.69, 98.83,109.36},{ 13.56, 21.65, 31.78, 41.68, 51.45, 61.31, 71.07, 80.73, 90.48,100.51,111.01},{ 14.36, 22.91, 33.19, 43.09, 52.71, 62.37, 71.92, 81.38, 90.88,100.56,110.56},{ 15.06, 23.90, 34.23, 44.05, 53.48, 62.90, 72.21, 81.43, 90.65, 99.93,109.34},{ 15.36, 23.90, 33.89, 43.31, 52.40, 61.42, 70.29, 79.18, 88.00, 96.69,105.17},{ 15.60, 23.90, 33.60, 42.70, 51.50, 60.20, 68.70, 77.30, 85.80, 94.00,101.70},{ 15.60, 23.90, 33.60, 42.70, 51.50, 60.20, 68.70, 77.30, 85.80, 94.00,101.70},{ 15.60, 23.90, 33.60, 42.70, 51.50, 60.20, 68.70, 77.30, 85.80, 94.00,101.70},{ 15.60, 23.90, 33.60, 42.70, 51.50, 60.20, 68.70, 77.30, 85.80, 94.00,101.70},{ 15.60, 23.90, 33.60, 42.70, 51.50, 60.20, 68.70, 77.30, 85.80, 94.00,101.70},{ 15.60, 23.90, 33.60, 42.70, 51.50, 60.20, 68.70, 77.30, 85.80, 94.00,101.70}}; double phons[11]={2,10,20,30,40,50,60,70,80,90,100}; //other functions static void Loudness_dofft(Loudness *, uint32); void Loudness_Ctor(Loudness* unit) { //may want to check sampling rate here! unit->m_numbands= 42; unit->m_ERBbands = (float*)RTAlloc(unit->mWorld, unit->m_numbands * sizeof(float)); Clear(unit->m_numbands, unit->m_ERBbands); unit->m_sones=0; //unit->m_phontotal=0; unit->mCalcFunc = (UnitCalcFunc)&Loudness_next; Loudness_next(unit, 1); } void Loudness_Dtor(Loudness *unit) { RTFree(unit->mWorld, unit->m_ERBbands); } void Loudness_next(Loudness *unit, int wrongNumSamples) { float fbufnum = ZIN0(0); //next FFT bufffer ready, update //assuming at this point that buffer precalculated for any resampling if (fbufnum > -0.01f) Loudness_dofft(unit, (uint32)fbufnum); //always output sones //float outval= unit->m_sones; //printf("sones %f phontotal %f \n",outval, unit->m_phontotal); //control rate output ZOUT0(0)=unit->m_sones; } //temporal masking over ERB bands: peaks take a while to decay //spectral masking over which bins summed as contributors for ERB bands; spreading activation function actually implies that the overall power is greater from spread? //masking not triangular but slanted towards masking higher frequency content (ie, lower freq bins mask upper) //for true MP3 style compression would have to see if each FFT bin was noise like or sine like (transient measure on instantaneous frequency for example), and use the appropriate masking curve //efficiency is preferred here //thus can calculate squared powers as you go? cheapest if only have effect of spectral masking above, covering a fixed number of bins? but then, frequency biased loudness based on ERB band centre frequency! //calculation function once FFT data ready void Loudness_dofft(Loudness *unit, uint32 ibufnum) { World *world = unit->mWorld; //if (ibufnum >= world->mNumSndBufs) ibufnum = 0; SndBuf *buf; // = world->mSndBufs + ibufnum; //int numbins = buf->samples - 2 >> 1; //support LocalBuf if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; } } else { buf = world->mSndBufs + ibufnum; } LOCK_SNDBUF(buf); float * data= buf->data; float loudsum=0.0; float smask= ZIN0(1); float tmask= ZIN0(2); for (int k=0; km_numbands; ++k){ int bandstart=eqlbandbins[k]; //int bandend=eqlbandbins[k+1]; int bandsize= eqlbandsizes[k]; int bandend= bandstart+bandsize; float bsum=0.0; float real, imag, power; int index; float lastpower=0.0; for (int h=bandstart; hbsum) bsum=power; bsum= bsum+power; } //store recips of bandsizes? //why average? surely just take max or sum is better! //bsum= bsum/bandsize; //into dB, avoid log of 0 //float db= 10*log10((bsum*10000000)+0.001); //float db= 10*log10((bsum*32382)+0.001); //empricially derived 32382*2.348 float db= 10*log10((bsum*76032.936f)+0.001f); //correct multipler until you get loudness output of 1! //correcting for power of three combination //bsum=bsum+0.001; //4.8810017610244 = log10(76032.936) //float db= 10*((0.33334*log10(bsum)) + 4.8810017610244); //correct multipler until you get loudness output of 1! //printf("bsum %f db %f \n",bsum,db); //convert via contour if(dbcontours[k][10]) db=phons[10]; else { float prop=0.0; int j; for (j=1; j<11; ++j) { if(dbm_ERBbands[k] = sc_max(db, (unit->m_ERBbands[k]) - tmask); //printf("db %f erbband %f \n",db, unit->m_ERBbands[k]); //must sum as intensities, not dbs once corrected, pow used to be other way around //loudsum+= ((pow(10, 0.1*unit->m_ERBbands[k])-0.001)*0.0000308813538386); // loudsum+= ((pow(10, 0.1*unit->m_ERBbands[k])-0.001)); //multiplier not needed since invert below; can trust no overflow? } //total excitation, correct back to dB scale in phons //float phontotal= 10*log10((loudsum*32382)+0.001); float phontotal= 10*log10((loudsum)+0.001); //didn't use divisor above, so no need to restore here //unit->m_phontotal= phontotal; //now to sones: /* from Praat: Excitation.c Sones = 2 ** ((Phones - 40) / 10) */ unit->m_sones= pow (2.f, (phontotal - 40) / 10); //printf("phontotal %f sones %f \n",phontotal, unit->m_sones); //about 5 times per second //if((unit->m_triggerid) && ((unit->m_frame%2==0))) SendTrigger(&unit->mParent->mNode, unit->m_triggerid, bestkey); } SuperCollider-Source/server/plugins/MFCC.cpp000644 000765 000024 00000170007 12321461511 022061 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //This MFCC UGen combines work by Dan Stowell (influenced also by Jamie Bullock's work on libxtract) and independent work by Nick Collins //Mel scale based frequency warping of spectrum, powers combined discrete cosine transform (DCT-II) via brute force calculation //see academic refs, wikipedia and http://www.fftw.org/fftw3_doc/Real-even_002fodd-DFTs-_0028cosine_002fsine-transforms_0029.html#Real-even_002fodd-DFTs-_0028cosine_002fsine-transforms_0029 #include "ML.h" #include "FFT_UGens.h" //The plugin could be generalised to pass alternative scale data (corresponding to Barks, ERBs and different FFT sizes etc) via a buffer //For the moment, the data below is used and only 1024 FFT supported. For the associated Mel scale spacing generation code see the bottom of the MFCC help file int g_startbin44100[42]= { 0, 2, 4, 5, 7, 9, 11, 13, 15, 17, 20, 23, 26, 29, 33, 36, 41, 45, 50, 55, 60, 66, 73, 80, 87, 96, 104, 114, 124, 135, 147, 159, 173, 188, 204, 221, 240, 260, 282, 305, 330, 357 }; //int g_endbin44100[42]= { 2, 3, 5, 7, 9, 11, 13, 15, 18, 21, 24, 27, 31, 34, 39, 43, 48, 53, 58, 64, 71, 78, 85, 94, 102, 112, 122, 133, 145, 157, 171, 186, 202, 219, 238, 258, 280, 303, 328, 355, 385, 416 }; //efficiency trick; one above actual endbin, allows for loop to test only < and not <= int g_endbin44100[42]= {3, 4, 6, 8, 10, 12, 14, 16, 19, 22, 25, 28, 32, 35, 40, 44, 49, 54, 59, 65, 72, 79, 86, 95, 103, 113, 123, 134, 146, 158, 172, 187, 203, 220, 239, 259, 281, 304, 329, 356, 386, 417 }; int g_cumulindex44100[43]= { 0, 3, 5, 7, 10, 13, 16, 19, 22, 26, 31, 36, 41, 47, 53, 60, 68, 76, 85, 94, 104, 116, 129, 142, 157, 173, 190, 209, 229, 251, 274, 299, 327, 357, 389, 424, 462, 503, 547, 594, 645, 701, 760 }; float g_melbandweights44100[761]= { 0.5, 1, 0.5, 0.5, 1, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.75, 0.5, 0.25, 0.25, 0.5, 0.75, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.75, 0.5, 0.25, 0.25, 0.5, 0.75, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.83333333333333, 0.66666666666667, 0.5, 0.33333333333333, 0.16666666666667, 0.16666666666667, 0.33333333333333, 0.5, 0.66666666666667, 0.83333333333333, 1, 0.85714285714286, 0.71428571428571, 0.57142857142857, 0.42857142857143, 0.28571428571429, 0.14285714285714, 0.14285714285714, 0.28571428571429, 0.42857142857143, 0.57142857142857, 0.71428571428571, 0.85714285714286, 1, 0.85714285714286, 0.71428571428571, 0.57142857142857, 0.42857142857143, 0.28571428571429, 0.14285714285714, 0.14285714285714, 0.28571428571429, 0.42857142857143, 0.57142857142857, 0.71428571428571, 0.85714285714286, 1, 0.85714285714286, 0.71428571428571, 0.57142857142857, 0.42857142857143, 0.28571428571429, 0.14285714285714, 0.14285714285714, 0.28571428571429, 0.42857142857143, 0.57142857142857, 0.71428571428571, 0.85714285714286, 1, 0.88888888888889, 0.77777777777778, 0.66666666666667, 0.55555555555556, 0.44444444444444, 0.33333333333333, 0.22222222222222, 0.11111111111111, 0.11111111111111, 0.22222222222222, 0.33333333333333, 0.44444444444444, 0.55555555555556, 0.66666666666667, 0.77777777777778, 0.88888888888889, 1, 0.875, 0.75, 0.625, 0.5, 0.375, 0.25, 0.125, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 0.90909090909091, 0.81818181818182, 0.72727272727273, 0.63636363636364, 0.54545454545455, 0.45454545454545, 0.36363636363636, 0.27272727272727, 0.18181818181818, 0.090909090909091, 0.090909090909091, 0.18181818181818, 0.27272727272727, 0.36363636363636, 0.45454545454545, 0.54545454545455, 0.63636363636364, 0.72727272727273, 0.81818181818182, 0.90909090909091, 1, 0.91666666666667, 0.83333333333333, 0.75, 0.66666666666667, 0.58333333333333, 0.5, 0.41666666666667, 0.33333333333333, 0.25, 0.16666666666667, 0.083333333333333, 0.083333333333333, 0.16666666666667, 0.25, 0.33333333333333, 0.41666666666667, 0.5, 0.58333333333333, 0.66666666666667, 0.75, 0.83333333333333, 0.91666666666667, 1, 0.91666666666667, 0.83333333333333, 0.75, 0.66666666666667, 0.58333333333333, 0.5, 0.41666666666667, 0.33333333333333, 0.25, 0.16666666666667, 0.083333333333333, 0.083333333333333, 0.16666666666667, 0.25, 0.33333333333333, 0.41666666666667, 0.5, 0.58333333333333, 0.66666666666667, 0.75, 0.83333333333333, 0.91666666666667, 1, 0.92857142857143, 0.85714285714286, 0.78571428571429, 0.71428571428571, 0.64285714285714, 0.57142857142857, 0.5, 0.42857142857143, 0.35714285714286, 0.28571428571429, 0.21428571428571, 0.14285714285714, 0.071428571428572, 0.071428571428571, 0.14285714285714, 0.21428571428571, 0.28571428571429, 0.35714285714286, 0.42857142857143, 0.5, 0.57142857142857, 0.64285714285714, 0.71428571428571, 0.78571428571429, 0.85714285714286, 0.92857142857143, 1, 0.93333333333333, 0.86666666666667, 0.8, 0.73333333333333, 0.66666666666667, 0.6, 0.53333333333333, 0.46666666666667, 0.4, 0.33333333333333, 0.26666666666667, 0.2, 0.13333333333333, 0.066666666666667, 0.066666666666667, 0.13333333333333, 0.2, 0.26666666666667, 0.33333333333333, 0.4, 0.46666666666667, 0.53333333333333, 0.6, 0.66666666666667, 0.73333333333333, 0.8, 0.86666666666667, 0.93333333333333, 1, 0.9375, 0.875, 0.8125, 0.75, 0.6875, 0.625, 0.5625, 0.5, 0.4375, 0.375, 0.3125, 0.25, 0.1875, 0.125, 0.0625, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, 0.5625, 0.625, 0.6875, 0.75, 0.8125, 0.875, 0.9375, 1, 0.94117647058824, 0.88235294117647, 0.82352941176471, 0.76470588235294, 0.70588235294118, 0.64705882352941, 0.58823529411765, 0.52941176470588, 0.47058823529412, 0.41176470588235, 0.35294117647059, 0.29411764705882, 0.23529411764706, 0.17647058823529, 0.11764705882353, 0.058823529411765, 0.058823529411765, 0.11764705882353, 0.17647058823529, 0.23529411764706, 0.29411764705882, 0.35294117647059, 0.41176470588235, 0.47058823529412, 0.52941176470588, 0.58823529411765, 0.64705882352941, 0.70588235294118, 0.76470588235294, 0.82352941176471, 0.88235294117647, 0.94117647058824, 1, 0.94736842105263, 0.89473684210526, 0.84210526315789, 0.78947368421053, 0.73684210526316, 0.68421052631579, 0.63157894736842, 0.57894736842105, 0.52631578947368, 0.47368421052632, 0.42105263157895, 0.36842105263158, 0.31578947368421, 0.26315789473684, 0.21052631578947, 0.15789473684211, 0.10526315789474, 0.052631578947369, 0.052631578947368, 0.10526315789474, 0.15789473684211, 0.21052631578947, 0.26315789473684, 0.31578947368421, 0.36842105263158, 0.42105263157895, 0.47368421052632, 0.52631578947368, 0.57894736842105, 0.63157894736842, 0.68421052631579, 0.73684210526316, 0.78947368421053, 0.84210526315789, 0.89473684210526, 0.94736842105263, 1, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.25, 0.2, 0.15, 0.1, 0.05, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 0.95454545454545, 0.90909090909091, 0.86363636363636, 0.81818181818182, 0.77272727272727, 0.72727272727273, 0.68181818181818, 0.63636363636364, 0.59090909090909, 0.54545454545455, 0.5, 0.45454545454545, 0.40909090909091, 0.36363636363636, 0.31818181818182, 0.27272727272727, 0.22727272727273, 0.18181818181818, 0.13636363636364, 0.090909090909091, 0.045454545454545, 0.045454545454545, 0.090909090909091, 0.13636363636364, 0.18181818181818, 0.22727272727273, 0.27272727272727, 0.31818181818182, 0.36363636363636, 0.40909090909091, 0.45454545454545, 0.5, 0.54545454545455, 0.59090909090909, 0.63636363636364, 0.68181818181818, 0.72727272727273, 0.77272727272727, 0.81818181818182, 0.86363636363636, 0.90909090909091, 0.95454545454545, 1, 0.95652173913043, 0.91304347826087, 0.8695652173913, 0.82608695652174, 0.78260869565217, 0.73913043478261, 0.69565217391304, 0.65217391304348, 0.60869565217391, 0.56521739130435, 0.52173913043478, 0.47826086956522, 0.43478260869565, 0.39130434782609, 0.34782608695652, 0.30434782608696, 0.26086956521739, 0.21739130434783, 0.17391304347826, 0.1304347826087, 0.08695652173913, 0.043478260869565, 0.043478260869565, 0.08695652173913, 0.1304347826087, 0.17391304347826, 0.21739130434783, 0.26086956521739, 0.30434782608696, 0.34782608695652, 0.39130434782609, 0.43478260869565, 0.47826086956522, 0.52173913043478, 0.56521739130435, 0.60869565217391, 0.65217391304348, 0.69565217391304, 0.73913043478261, 0.78260869565217, 0.82608695652174, 0.8695652173913, 0.91304347826087, 0.95652173913043, 1, 0.96, 0.92, 0.88, 0.84, 0.8, 0.76, 0.72, 0.68, 0.64, 0.6, 0.56, 0.52, 0.48, 0.44, 0.4, 0.36, 0.32, 0.28, 0.24, 0.2, 0.16, 0.12, 0.08, 0.04, 0.04, 0.08, 0.12, 0.16, 0.2, 0.24, 0.28, 0.32, 0.36, 0.4, 0.44, 0.48, 0.52, 0.56, 0.6, 0.64, 0.68, 0.72, 0.76, 0.8, 0.84, 0.88, 0.92, 0.96, 1, 0.96296296296296, 0.92592592592593, 0.88888888888889, 0.85185185185185, 0.81481481481481, 0.77777777777778, 0.74074074074074, 0.7037037037037, 0.66666666666667, 0.62962962962963, 0.59259259259259, 0.55555555555556, 0.51851851851852, 0.48148148148148, 0.44444444444444, 0.40740740740741, 0.37037037037037, 0.33333333333333, 0.2962962962963, 0.25925925925926, 0.22222222222222, 0.18518518518519, 0.14814814814815, 0.11111111111111, 0.074074074074074, 0.037037037037037, 0.037037037037037, 0.074074074074074, 0.11111111111111, 0.14814814814815, 0.18518518518519, 0.22222222222222, 0.25925925925926, 0.2962962962963, 0.33333333333333, 0.37037037037037, 0.40740740740741, 0.44444444444444, 0.48148148148148, 0.51851851851852, 0.55555555555556, 0.59259259259259, 0.62962962962963, 0.66666666666667, 0.7037037037037, 0.74074074074074, 0.77777777777778, 0.81481481481481, 0.85185185185185, 0.88888888888889, 0.92592592592593, 0.96296296296296, 1, 0.96666666666667, 0.93333333333333, 0.9, 0.86666666666667, 0.83333333333333, 0.8, 0.76666666666667, 0.73333333333333, 0.7, 0.66666666666667, 0.63333333333333, 0.6, 0.56666666666667, 0.53333333333333, 0.5, 0.46666666666667, 0.43333333333333, 0.4, 0.36666666666667, 0.33333333333333, 0.3, 0.26666666666667, 0.23333333333333, 0.2, 0.16666666666667, 0.13333333333333, 0.1, 0.066666666666667, 0.033333333333333, 0.033333333333333, 0.066666666666667, 0.1, 0.13333333333333, 0.16666666666667, 0.2, 0.23333333333333, 0.26666666666667, 0.3, 0.33333333333333, 0.36666666666667, 0.4, 0.43333333333333, 0.46666666666667, 0.5, 0.53333333333333, 0.56666666666667, 0.6, 0.63333333333333, 0.66666666666667, 0.7, 0.73333333333333, 0.76666666666667, 0.8, 0.83333333333333, 0.86666666666667, 0.9, 0.93333333333333, 0.96666666666667, 1, 0.96774193548387, 0.93548387096774, 0.90322580645161, 0.87096774193548, 0.83870967741935, 0.80645161290323, 0.7741935483871, 0.74193548387097, 0.70967741935484, 0.67741935483871, 0.64516129032258, 0.61290322580645, 0.58064516129032, 0.54838709677419, 0.51612903225806, 0.48387096774194, 0.45161290322581, 0.41935483870968, 0.38709677419355, 0.35483870967742, 0.32258064516129, 0.29032258064516, 0.25806451612903, 0.2258064516129, 0.19354838709677, 0.16129032258065, 0.12903225806452, 0.096774193548387, 0.064516129032258, 0.032258064516129 }; int g_startbin48000[42]= { 0, 2, 4, 5, 6, 8, 10, 12, 14, 16, 18, 21, 24, 27, 30, 34, 37, 41, 46, 51, 56, 61, 67, 73, 80, 88, 96, 104, 114, 124, 135, 147, 159, 173, 188, 203, 220, 239, 259, 280, 304, 328 }; //int g_endbin48000[42]= { 2, 3, 4, 6, 8, 10, 12, 14, 16, 19, 22, 25, 28, 32, 35, 39, 44, 49, 54, 59, 65, 71, 78, 86, 94, 102, 112, 122, 133, 145, 157, 171, 186, 201, 218, 237, 257, 278, 302, 326, 353, 383 }; //with efficiency trick int g_endbin48000[42]= { 3, 4, 5, 7, 9, 11, 13, 15, 17, 20, 23, 26, 29, 33, 36, 40, 45, 50, 55, 60, 66, 72, 79, 87, 95, 103, 113, 123, 134, 146, 158, 172, 187, 202, 219, 238, 258, 279, 303, 327, 354, 384 }; int g_cumulindex48000[43]= { 0, 3, 5, 6, 8, 11, 14, 17, 20, 23, 27, 32, 37, 42, 48, 54, 60, 68, 77, 86, 95, 105, 116, 128, 142, 157, 172, 189, 208, 228, 250, 273, 298, 326, 355, 386, 421, 459, 499, 543, 590, 640, 695 }; float g_melbandweights48000[761]= { 0.5, 1, 0.5, 0.5, 1, 1, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.5, 0.5, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.75, 0.5, 0.25, 0.25, 0.5, 0.75, 1, 0.66666666666667, 0.33333333333333, 0.33333333333333, 0.66666666666667, 1, 0.75, 0.5, 0.25, 0.25, 0.5, 0.75, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.8, 0.6, 0.4, 0.2, 0.2, 0.4, 0.6, 0.8, 1, 0.83333333333333, 0.66666666666667, 0.5, 0.33333333333333, 0.16666666666667, 0.16666666666667, 0.33333333333333, 0.5, 0.66666666666667, 0.83333333333333, 1, 0.83333333333333, 0.66666666666667, 0.5, 0.33333333333333, 0.16666666666667, 0.16666666666667, 0.33333333333333, 0.5, 0.66666666666667, 0.83333333333333, 1, 0.85714285714286, 0.71428571428571, 0.57142857142857, 0.42857142857143, 0.28571428571429, 0.14285714285714, 0.14285714285714, 0.28571428571429, 0.42857142857143, 0.57142857142857, 0.71428571428571, 0.85714285714286, 1, 0.875, 0.75, 0.625, 0.5, 0.375, 0.25, 0.125, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 0.875, 0.75, 0.625, 0.5, 0.375, 0.25, 0.125, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 0.875, 0.75, 0.625, 0.5, 0.375, 0.25, 0.125, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 0.90909090909091, 0.81818181818182, 0.72727272727273, 0.63636363636364, 0.54545454545455, 0.45454545454545, 0.36363636363636, 0.27272727272727, 0.18181818181818, 0.090909090909091, 0.090909090909091, 0.18181818181818, 0.27272727272727, 0.36363636363636, 0.45454545454545, 0.54545454545455, 0.63636363636364, 0.72727272727273, 0.81818181818182, 0.90909090909091, 1, 0.91666666666667, 0.83333333333333, 0.75, 0.66666666666667, 0.58333333333333, 0.5, 0.41666666666667, 0.33333333333333, 0.25, 0.16666666666667, 0.083333333333333, 0.083333333333333, 0.16666666666667, 0.25, 0.33333333333333, 0.41666666666667, 0.5, 0.58333333333333, 0.66666666666667, 0.75, 0.83333333333333, 0.91666666666667, 1, 0.91666666666667, 0.83333333333333, 0.75, 0.66666666666667, 0.58333333333333, 0.5, 0.41666666666667, 0.33333333333333, 0.25, 0.16666666666667, 0.083333333333333, 0.083333333333333, 0.16666666666667, 0.25, 0.33333333333333, 0.41666666666667, 0.5, 0.58333333333333, 0.66666666666667, 0.75, 0.83333333333333, 0.91666666666667, 1, 0.92857142857143, 0.85714285714286, 0.78571428571429, 0.71428571428571, 0.64285714285714, 0.57142857142857, 0.5, 0.42857142857143, 0.35714285714286, 0.28571428571429, 0.21428571428571, 0.14285714285714, 0.071428571428572, 0.071428571428571, 0.14285714285714, 0.21428571428571, 0.28571428571429, 0.35714285714286, 0.42857142857143, 0.5, 0.57142857142857, 0.64285714285714, 0.71428571428571, 0.78571428571429, 0.85714285714286, 0.92857142857143, 1, 0.93333333333333, 0.86666666666667, 0.8, 0.73333333333333, 0.66666666666667, 0.6, 0.53333333333333, 0.46666666666667, 0.4, 0.33333333333333, 0.26666666666667, 0.2, 0.13333333333333, 0.066666666666667, 0.066666666666667, 0.13333333333333, 0.2, 0.26666666666667, 0.33333333333333, 0.4, 0.46666666666667, 0.53333333333333, 0.6, 0.66666666666667, 0.73333333333333, 0.8, 0.86666666666667, 0.93333333333333, 1, 0.93333333333333, 0.86666666666667, 0.8, 0.73333333333333, 0.66666666666667, 0.6, 0.53333333333333, 0.46666666666667, 0.4, 0.33333333333333, 0.26666666666667, 0.2, 0.13333333333333, 0.066666666666667, 0.066666666666667, 0.13333333333333, 0.2, 0.26666666666667, 0.33333333333333, 0.4, 0.46666666666667, 0.53333333333333, 0.6, 0.66666666666667, 0.73333333333333, 0.8, 0.86666666666667, 0.93333333333333, 1, 0.94117647058824, 0.88235294117647, 0.82352941176471, 0.76470588235294, 0.70588235294118, 0.64705882352941, 0.58823529411765, 0.52941176470588, 0.47058823529412, 0.41176470588235, 0.35294117647059, 0.29411764705882, 0.23529411764706, 0.17647058823529, 0.11764705882353, 0.058823529411765, 0.058823529411765, 0.11764705882353, 0.17647058823529, 0.23529411764706, 0.29411764705882, 0.35294117647059, 0.41176470588235, 0.47058823529412, 0.52941176470588, 0.58823529411765, 0.64705882352941, 0.70588235294118, 0.76470588235294, 0.82352941176471, 0.88235294117647, 0.94117647058824, 1, 0.94736842105263, 0.89473684210526, 0.84210526315789, 0.78947368421053, 0.73684210526316, 0.68421052631579, 0.63157894736842, 0.57894736842105, 0.52631578947368, 0.47368421052632, 0.42105263157895, 0.36842105263158, 0.31578947368421, 0.26315789473684, 0.21052631578947, 0.15789473684211, 0.10526315789474, 0.052631578947369, 0.052631578947368, 0.10526315789474, 0.15789473684211, 0.21052631578947, 0.26315789473684, 0.31578947368421, 0.36842105263158, 0.42105263157895, 0.47368421052632, 0.52631578947368, 0.57894736842105, 0.63157894736842, 0.68421052631579, 0.73684210526316, 0.78947368421053, 0.84210526315789, 0.89473684210526, 0.94736842105263, 1, 0.95, 0.9, 0.85, 0.8, 0.75, 0.7, 0.65, 0.6, 0.55, 0.5, 0.45, 0.4, 0.35, 0.3, 0.25, 0.2, 0.15, 0.1, 0.05, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1, 0.95238095238095, 0.9047619047619, 0.85714285714286, 0.80952380952381, 0.76190476190476, 0.71428571428571, 0.66666666666667, 0.61904761904762, 0.57142857142857, 0.52380952380952, 0.47619047619048, 0.42857142857143, 0.38095238095238, 0.33333333333333, 0.28571428571429, 0.23809523809524, 0.19047619047619, 0.14285714285714, 0.095238095238095, 0.047619047619048, 0.047619047619048, 0.095238095238095, 0.14285714285714, 0.19047619047619, 0.23809523809524, 0.28571428571429, 0.33333333333333, 0.38095238095238, 0.42857142857143, 0.47619047619048, 0.52380952380952, 0.57142857142857, 0.61904761904762, 0.66666666666667, 0.71428571428571, 0.76190476190476, 0.80952380952381, 0.85714285714286, 0.9047619047619, 0.95238095238095, 1, 0.95833333333333, 0.91666666666667, 0.875, 0.83333333333333, 0.79166666666667, 0.75, 0.70833333333333, 0.66666666666667, 0.625, 0.58333333333333, 0.54166666666667, 0.5, 0.45833333333333, 0.41666666666667, 0.375, 0.33333333333333, 0.29166666666667, 0.25, 0.20833333333333, 0.16666666666667, 0.125, 0.083333333333333, 0.041666666666667, 0.041666666666667, 0.083333333333333, 0.125, 0.16666666666667, 0.20833333333333, 0.25, 0.29166666666667, 0.33333333333333, 0.375, 0.41666666666667, 0.45833333333333, 0.5, 0.54166666666667, 0.58333333333333, 0.625, 0.66666666666667, 0.70833333333333, 0.75, 0.79166666666667, 0.83333333333333, 0.875, 0.91666666666667, 0.95833333333333, 1, 0.95833333333333, 0.91666666666667, 0.875, 0.83333333333333, 0.79166666666667, 0.75, 0.70833333333333, 0.66666666666667, 0.625, 0.58333333333333, 0.54166666666667, 0.5, 0.45833333333333, 0.41666666666667, 0.375, 0.33333333333333, 0.29166666666667, 0.25, 0.20833333333333, 0.16666666666667, 0.125, 0.083333333333333, 0.041666666666667, 0.041666666666667, 0.083333333333333, 0.125, 0.16666666666667, 0.20833333333333, 0.25, 0.29166666666667, 0.33333333333333, 0.375, 0.41666666666667, 0.45833333333333, 0.5, 0.54166666666667, 0.58333333333333, 0.625, 0.66666666666667, 0.70833333333333, 0.75, 0.79166666666667, 0.83333333333333, 0.875, 0.91666666666667, 0.95833333333333, 1, 0.96296296296296, 0.92592592592593, 0.88888888888889, 0.85185185185185, 0.81481481481481, 0.77777777777778, 0.74074074074074, 0.7037037037037, 0.66666666666667, 0.62962962962963, 0.59259259259259, 0.55555555555556, 0.51851851851852, 0.48148148148148, 0.44444444444444, 0.40740740740741, 0.37037037037037, 0.33333333333333, 0.2962962962963, 0.25925925925926, 0.22222222222222, 0.18518518518519, 0.14814814814815, 0.11111111111111, 0.074074074074074, 0.037037037037037, 0.037037037037037, 0.074074074074074, 0.11111111111111, 0.14814814814815, 0.18518518518519, 0.22222222222222, 0.25925925925926, 0.2962962962963, 0.33333333333333, 0.37037037037037, 0.40740740740741, 0.44444444444444, 0.48148148148148, 0.51851851851852, 0.55555555555556, 0.59259259259259, 0.62962962962963, 0.66666666666667, 0.7037037037037, 0.74074074074074, 0.77777777777778, 0.81481481481481, 0.85185185185185, 0.88888888888889, 0.92592592592593, 0.96296296296296, 1, 0.96666666666667, 0.93333333333333, 0.9, 0.86666666666667, 0.83333333333333, 0.8, 0.76666666666667, 0.73333333333333, 0.7, 0.66666666666667, 0.63333333333333, 0.6, 0.56666666666667, 0.53333333333333, 0.5, 0.46666666666667, 0.43333333333333, 0.4, 0.36666666666667, 0.33333333333333, 0.3, 0.26666666666667, 0.23333333333333, 0.2, 0.16666666666667, 0.13333333333333, 0.1, 0.066666666666667, 0.033333333333333 }; //generated in SC using: //a= Array.fill(42, {|i| cos(pi/42.0*((0..41)+0.5)*(i+1))}); //Post << a.flatten << nl; //up to 42 coefficients, each with 42 multipliers for each of 42 bands float dct[1764]= {0.9993007047884, 0.99371220989324, 0.98256647323329, 0.96592582628907, 0.94388333030837, 0.91656225586998, 0.88411539350461, 0.84672419922828, 0.80459777976667, 0.75797172314545, 0.70710678118655, 0.65228741127812, 0.5938201855735, 0.53203207651534, 0.46726862827306, 0.39989202431974, 0.33027906195517, 0.25881904510252, 0.18591160716291, 0.11196447610331, 0.037391194276326, -0.037391194276326, -0.11196447610331, -0.18591160716291, -0.25881904510252, -0.33027906195517, -0.39989202431974, -0.46726862827306, -0.53203207651534, -0.5938201855735, -0.65228741127812, -0.70710678118655, -0.75797172314545, -0.80459777976667, -0.84672419922828, -0.88411539350461, -0.91656225586998, -0.94388333030837, -0.96592582628907, -0.98256647323329, -0.99371220989324, -0.9993007047884, 0.99720379718118, 0.97492791218182, 0.9308737486442, 0.86602540378444, 0.78183148246803, 0.68017273777092, 0.56332005806362, 0.43388373911756, 0.2947551744109, 0.14904226617617, 6.1232339957368e-17, -0.14904226617617, -0.2947551744109, -0.43388373911756, -0.56332005806362, -0.68017273777092, -0.78183148246803, -0.86602540378444, -0.9308737486442, -0.97492791218182, -0.99720379718118, -0.99720379718118, -0.97492791218182, -0.9308737486442, -0.86602540378444, -0.78183148246803, -0.68017273777092, -0.56332005806362, -0.43388373911756, -0.2947551744109, -0.14904226617617, -1.836970198721e-16, 0.14904226617617, 0.2947551744109, 0.43388373911756, 0.56332005806362, 0.68017273777092, 0.78183148246803, 0.86602540378444, 0.9308737486442, 0.97492791218182, 0.99720379718118, 0.99371220989324, 0.94388333030837, 0.84672419922828, 0.70710678118655, 0.53203207651534, 0.33027906195517, 0.11196447610331, -0.11196447610331, -0.33027906195517, -0.53203207651534, -0.70710678118655, -0.84672419922828, -0.94388333030837, -0.99371220989324, -0.99371220989324, -0.94388333030837, -0.84672419922828, -0.70710678118655, -0.53203207651534, -0.33027906195517, -0.11196447610331, 0.11196447610331, 0.33027906195517, 0.53203207651534, 0.70710678118655, 0.84672419922828, 0.94388333030837, 0.99371220989324, 0.99371220989324, 0.94388333030837, 0.84672419922828, 0.70710678118655, 0.53203207651534, 0.33027906195517, 0.11196447610331, -0.11196447610331, -0.33027906195517, -0.53203207651534, -0.70710678118655, -0.84672419922828, -0.94388333030837, -0.99371220989324, 0.98883082622513, 0.90096886790242, 0.73305187182983, 0.5, 0.22252093395631, -0.074730093586424, -0.3653410243664, -0.62348980185873, -0.82623877431599, -0.95557280578614, -1, -0.95557280578614, -0.82623877431599, -0.62348980185873, -0.36534102436639, -0.074730093586424, 0.22252093395631, 0.5, 0.73305187182983, 0.90096886790242, 0.98883082622513, 0.98883082622513, 0.90096886790242, 0.73305187182983, 0.5, 0.22252093395631, -0.074730093586424, -0.3653410243664, -0.62348980185873, -0.826238774316, -0.95557280578614, -1, -0.95557280578614, -0.82623877431599, -0.62348980185873, -0.36534102436639, -0.074730093586424, 0.22252093395631, 0.5, 0.73305187182983, 0.90096886790242, 0.98883082622513, 0.98256647323329, 0.84672419922828, 0.5938201855735, 0.25881904510252, -0.11196447610331, -0.46726862827306, -0.75797172314545, -0.94388333030837, -0.9993007047884, -0.91656225586998, -0.70710678118655, -0.39989202431974, -0.037391194276326, 0.33027906195517, 0.65228741127812, 0.88411539350461, 0.99371220989324, 0.96592582628907, 0.80459777976667, 0.53203207651534, 0.18591160716291, -0.18591160716291, -0.53203207651534, -0.80459777976667, -0.96592582628907, -0.99371220989324, -0.88411539350461, -0.65228741127812, -0.33027906195517, 0.037391194276327, 0.39989202431974, 0.70710678118655, 0.91656225586998, 0.9993007047884, 0.94388333030837, 0.75797172314545, 0.46726862827306, 0.11196447610331, -0.25881904510252, -0.5938201855735, -0.84672419922828, -0.98256647323329, 0.97492791218182, 0.78183148246803, 0.43388373911756, -1.6081226496766e-16, -0.43388373911756, -0.78183148246803, -0.97492791218182, -0.97492791218182, -0.78183148246803, -0.43388373911756, -1.836970198721e-16, 0.43388373911756, 0.78183148246803, 0.97492791218182, 0.97492791218182, 0.78183148246803, 0.43388373911756, 3.0616169978684e-16, -0.43388373911756, -0.78183148246803, -0.97492791218182, -0.97492791218182, -0.78183148246803, -0.43388373911756, 1.3477304596987e-15, 0.43388373911756, 0.78183148246803, 0.97492791218182, 0.97492791218182, 0.78183148246803, 0.43388373911756, 5.5109105961631e-16, -0.43388373911756, -0.78183148246803, -0.97492791218182, -0.97492791218182, -0.78183148246803, -0.43388373911756, 1.1028010998692e-15, 0.43388373911756, 0.78183148246803, 0.97492791218182, 0.96592582628907, 0.70710678118655, 0.25881904510252, -0.25881904510252, -0.70710678118655, -0.96592582628907, -0.96592582628907, -0.70710678118655, -0.25881904510252, 0.25881904510252, 0.70710678118655, 0.96592582628907, 0.96592582628907, 0.70710678118655, 0.25881904510252, -0.25881904510252, -0.70710678118655, -0.96592582628907, -0.96592582628907, -0.70710678118655, -0.25881904510252, 0.25881904510252, 0.70710678118655, 0.96592582628907, 0.96592582628907, 0.70710678118655, 0.25881904510252, -0.25881904510252, -0.70710678118655, -0.96592582628907, -0.96592582628907, -0.70710678118655, -0.25881904510252, 0.25881904510252, 0.70710678118655, 0.96592582628907, 0.96592582628907, 0.70710678118655, 0.25881904510252, -0.25881904510252, -0.70710678118655, -0.96592582628907, 0.95557280578614, 0.62348980185873, 0.074730093586424, -0.5, -0.90096886790242, -0.98883082622513, -0.73305187182983, -0.22252093395631, 0.3653410243664, 0.82623877431599, 1, 0.82623877431599, 0.3653410243664, -0.22252093395631, -0.73305187182983, -0.98883082622513, -0.90096886790242, -0.5, 0.074730093586425, 0.62348980185873, 0.95557280578614, 0.95557280578614, 0.62348980185873, 0.074730093586424, -0.5, -0.90096886790242, -0.98883082622513, -0.73305187182983, -0.22252093395632, 0.3653410243664, 0.826238774316, 1, 0.82623877431599, 0.36534102436639, -0.22252093395631, -0.73305187182983, -0.98883082622513, -0.90096886790242, -0.5, 0.074730093586425, 0.62348980185873, 0.95557280578614, 0.94388333030837, 0.53203207651534, -0.11196447610331, -0.70710678118655, -0.99371220989324, -0.84672419922828, -0.33027906195517, 0.33027906195517, 0.84672419922828, 0.99371220989324, 0.70710678118655, 0.11196447610331, -0.53203207651534, -0.94388333030837, -0.94388333030837, -0.53203207651534, 0.11196447610331, 0.70710678118655, 0.99371220989324, 0.84672419922828, 0.33027906195517, -0.33027906195517, -0.84672419922828, -0.99371220989324, -0.70710678118655, -0.11196447610331, 0.53203207651534, 0.94388333030837, 0.94388333030837, 0.53203207651534, -0.11196447610331, -0.70710678118655, -0.99371220989324, -0.84672419922828, -0.33027906195517, 0.33027906195517, 0.84672419922828, 0.99371220989324, 0.70710678118655, 0.11196447610331, -0.53203207651534, -0.94388333030837, 0.9308737486442, 0.43388373911756, -0.2947551744109, -0.86602540378444, -0.97492791218182, -0.56332005806362, 0.14904226617617, 0.78183148246803, 0.99720379718118, 0.68017273777092, 3.0616169978684e-16, -0.68017273777092, -0.99720379718118, -0.78183148246803, -0.14904226617617, 0.56332005806362, 0.97492791218182, 0.86602540378444, 0.2947551744109, -0.43388373911756, -0.9308737486442, -0.9308737486442, -0.43388373911756, 0.2947551744109, 0.86602540378444, 0.97492791218182, 0.56332005806362, -0.14904226617617, -0.78183148246803, -0.99720379718118, -0.68017273777092, -2.6948419387608e-15, 0.68017273777092, 0.99720379718118, 0.78183148246803, 0.14904226617617, -0.56332005806362, -0.97492791218182, -0.86602540378444, -0.2947551744109, 0.43388373911756, 0.9308737486442, 0.91656225586998, 0.33027906195517, -0.46726862827306, -0.96592582628907, -0.84672419922828, -0.18591160716291, 0.5938201855735, 0.99371220989324, 0.75797172314545, 0.037391194276326, -0.70710678118655, -0.9993007047884, -0.65228741127812, 0.11196447610331, 0.80459777976667, 0.98256647323329, 0.53203207651534, -0.25881904510252, -0.88411539350461, -0.94388333030837, -0.39989202431974, 0.39989202431974, 0.94388333030837, 0.88411539350461, 0.25881904510252, -0.53203207651534, -0.98256647323329, -0.80459777976667, -0.11196447610331, 0.65228741127812, 0.9993007047884, 0.70710678118655, -0.03739119427633, -0.75797172314545, -0.99371220989324, -0.5938201855735, 0.18591160716291, 0.84672419922828, 0.96592582628907, 0.46726862827306, -0.33027906195517, -0.91656225586998, 0.90096886790242, 0.22252093395631, -0.62348980185873, -1, -0.62348980185873, 0.22252093395631, 0.90096886790242, 0.90096886790242, 0.22252093395631, -0.62348980185873, -1, -0.62348980185873, 0.22252093395631, 0.90096886790242, 0.90096886790242, 0.22252093395631, -0.62348980185873, -1, -0.62348980185873, 0.22252093395631, 0.90096886790242, 0.90096886790242, 0.22252093395632, -0.62348980185873, -1, -0.62348980185873, 0.22252093395631, 0.90096886790242, 0.90096886790242, 0.22252093395631, -0.62348980185874, -1, -0.62348980185873, 0.22252093395632, 0.90096886790242, 0.90096886790242, 0.22252093395631, -0.62348980185874, -1, -0.62348980185873, 0.22252093395631, 0.90096886790242, 0.88411539350461, 0.11196447610331, -0.75797172314545, -0.96592582628907, -0.33027906195517, 0.5938201855735, 0.9993007047884, 0.53203207651534, -0.39989202431974, -0.98256647323329, -0.70710678118655, 0.18591160716291, 0.91656225586998, 0.84672419922828, 0.037391194276326, -0.80459777976667, -0.94388333030837, -0.25881904510252, 0.65228741127812, 0.99371220989324, 0.46726862827306, -0.46726862827306, -0.99371220989324, -0.65228741127812, 0.25881904510252, 0.94388333030837, 0.80459777976667, -0.037391194276326, -0.84672419922828, -0.91656225586998, -0.18591160716291, 0.70710678118655, 0.98256647323329, 0.39989202431974, -0.53203207651534, -0.9993007047884, -0.5938201855735, 0.33027906195516, 0.96592582628907, 0.75797172314545, -0.1119644761033, -0.88411539350461, 0.86602540378444, 6.1232339957368e-17, -0.86602540378444, -0.86602540378444, -1.836970198721e-16, 0.86602540378444, 0.86602540378444, 3.0616169978684e-16, -0.86602540378444, -0.86602540378444, -4.2862637970157e-16, 0.86602540378444, 0.86602540378444, 5.5109105961631e-16, -0.86602540378444, -0.86602540378444, -2.4499125789313e-15, 0.86602540378444, 0.86602540378444, -9.8033641995447e-16, -0.86602540378444, -0.86602540378444, -2.6948419387608e-15, 0.86602540378444, 0.86602540378444, -7.35407060125e-16, -0.86602540378444, -0.86602540378444, -2.9397712985902e-15, 0.86602540378444, 0.86602540378444, -4.9047770029553e-16, -0.86602540378444, -0.86602540378444, -3.1847006584197e-15, 0.86602540378444, 0.86602540378444, -2.4554834046606e-16, -0.86602540378444, -0.86602540378444, -3.4296300182492e-15, 0.86602540378444, 0.84672419922828, -0.11196447610331, -0.94388333030837, -0.70710678118655, 0.33027906195517, 0.99371220989324, 0.53203207651534, -0.53203207651534, -0.99371220989324, -0.33027906195517, 0.70710678118655, 0.94388333030837, 0.11196447610331, -0.84672419922828, -0.84672419922828, 0.11196447610331, 0.94388333030837, 0.70710678118655, -0.33027906195517, -0.99371220989324, -0.53203207651534, 0.53203207651534, 0.99371220989324, 0.33027906195517, -0.70710678118655, -0.94388333030837, -0.11196447610331, 0.84672419922828, 0.84672419922829, -0.11196447610331, -0.94388333030837, -0.70710678118655, 0.33027906195517, 0.99371220989324, 0.53203207651534, -0.53203207651534, -0.99371220989324, -0.33027906195517, 0.70710678118655, 0.94388333030837, 0.11196447610331, -0.84672419922829, 0.82623877431599, -0.22252093395631, -0.98883082622513, -0.5, 0.62348980185873, 0.95557280578614, 0.074730093586424, -0.90096886790242, -0.73305187182983, 0.3653410243664, 1, 0.36534102436639, -0.73305187182983, -0.90096886790242, 0.074730093586425, 0.95557280578614, 0.62348980185873, -0.5, -0.98883082622513, -0.22252093395632, 0.826238774316, 0.82623877431599, -0.22252093395631, -0.98883082622513, -0.5, 0.62348980185874, 0.95557280578614, 0.074730093586423, -0.90096886790242, -0.73305187182982, 0.3653410243664, 1, 0.36534102436639, -0.73305187182983, -0.90096886790242, 0.074730093586427, 0.95557280578614, 0.62348980185873, -0.5, -0.98883082622513, -0.22252093395632, 0.826238774316, 0.80459777976667, -0.33027906195517, -0.9993007047884, -0.25881904510252, 0.84672419922828, 0.75797172314545, -0.39989202431974, -0.99371220989324, -0.18591160716291, 0.88411539350461, 0.70710678118655, -0.46726862827306, -0.98256647323329, -0.11196447610331, 0.91656225586998, 0.65228741127812, -0.53203207651534, -0.96592582628907, -0.037391194276324, 0.94388333030837, 0.5938201855735, -0.5938201855735, -0.94388333030837, 0.037391194276326, 0.96592582628907, 0.53203207651534, -0.65228741127812, -0.91656225586998, 0.11196447610331, 0.98256647323329, 0.46726862827306, -0.70710678118655, -0.88411539350461, 0.18591160716291, 0.99371220989324, 0.39989202431973, -0.75797172314546, -0.84672419922828, 0.25881904510253, 0.9993007047884, 0.33027906195517, -0.80459777976667, 0.78183148246803, -0.43388373911756, -0.97492791218182, 7.0448139982802e-16, 0.97492791218182, 0.43388373911756, -0.78183148246803, -0.78183148246803, 0.43388373911756, 0.97492791218182, 5.5109105961631e-16, -0.97492791218182, -0.43388373911756, 0.78183148246803, 0.78183148246803, -0.43388373911756, -0.97492791218182, 8.5787174003974e-16, 0.97492791218182, 0.43388373911756, -0.78183148246803, -0.78183148246803, 0.43388373911756, 0.97492791218182, -4.9047770029553e-16, -0.97492791218182, -0.43388373911756, 0.78183148246803, 0.78183148246803, -0.43388373911756, -0.97492791218182, -3.4296300182492e-15, 0.97492791218182, 0.43388373911755, -0.78183148246803, -0.78183148246803, 0.43388373911756, 0.97492791218182, -6.8611169784081e-15, -0.97492791218182, -0.43388373911756, 0.78183148246803, 0.75797172314545, -0.53203207651534, -0.91656225586998, 0.25881904510252, 0.99371220989324, 0.037391194276326, -0.98256647323329, -0.33027906195517, 0.88411539350461, 0.5938201855735, -0.70710678118655, -0.80459777976667, 0.46726862827306, 0.94388333030837, -0.18591160716291, -0.9993007047884, -0.11196447610331, 0.96592582628907, 0.39989202431974, -0.84672419922828, -0.65228741127812, 0.65228741127812, 0.84672419922829, -0.39989202431974, -0.96592582628907, 0.11196447610331, 0.9993007047884, 0.18591160716292, -0.94388333030837, -0.46726862827306, 0.80459777976667, 0.70710678118655, -0.59382018557351, -0.88411539350461, 0.33027906195516, 0.98256647323329, -0.037391194276329, -0.99371220989324, -0.25881904510252, 0.91656225586998, 0.53203207651534, -0.75797172314546, 0.73305187182983, -0.62348980185873, -0.82623877431599, 0.5, 0.90096886790242, -0.3653410243664, -0.95557280578614, 0.22252093395631, 0.98883082622513, -0.074730093586425, -1, -0.074730093586423, 0.98883082622513, 0.22252093395632, -0.95557280578614, -0.36534102436639, 0.90096886790242, 0.5, -0.82623877431599, -0.62348980185873, 0.73305187182983, 0.73305187182983, -0.62348980185874, -0.826238774316, 0.5, 0.90096886790242, -0.36534102436639, -0.95557280578614, 0.22252093395632, 0.98883082622513, -0.074730093586424, -1, -0.07473009358642, 0.98883082622513, 0.22252093395631, -0.95557280578614, -0.3653410243664, 0.90096886790242, 0.5, -0.82623877431599, -0.62348980185873, 0.73305187182983, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118655, 0.70710678118655, 0.70710678118655, -0.70710678118655, -0.70710678118654, 0.70710678118655, 0.70710678118655, -0.70710678118655, 0.68017273777092, -0.78183148246803, -0.56332005806362, 0.86602540378444, 0.43388373911756, -0.9308737486442, -0.2947551744109, 0.97492791218182, 0.14904226617617, -0.99720379718118, -2.4499125789313e-15, 0.99720379718118, -0.14904226617617, -0.97492791218182, 0.29475517441091, 0.9308737486442, -0.43388373911756, -0.86602540378444, 0.56332005806362, 0.78183148246803, -0.68017273777092, -0.68017273777092, 0.78183148246803, 0.56332005806362, -0.86602540378444, -0.43388373911756, 0.9308737486442, 0.2947551744109, -0.97492791218182, -0.14904226617617, 0.99720379718118, 2.4431037919288e-16, -0.99720379718118, 0.14904226617618, 0.97492791218182, -0.29475517441091, -0.9308737486442, 0.43388373911756, 0.86602540378444, -0.56332005806362, -0.78183148246803, 0.68017273777092, 0.65228741127812, -0.84672419922828, -0.39989202431974, 0.96592582628907, 0.11196447610331, -0.9993007047884, 0.18591160716291, 0.94388333030837, -0.46726862827306, -0.80459777976667, 0.70710678118655, 0.5938201855735, -0.88411539350461, -0.33027906195517, 0.98256647323329, 0.037391194276325, -0.99371220989324, 0.25881904510252, 0.91656225586998, -0.53203207651534, -0.75797172314545, 0.75797172314545, 0.53203207651534, -0.91656225586998, -0.25881904510252, 0.99371220989324, -0.037391194276329, -0.98256647323329, 0.33027906195516, 0.88411539350461, -0.5938201855735, -0.70710678118655, 0.80459777976667, 0.46726862827306, -0.94388333030837, -0.18591160716291, 0.9993007047884, -0.11196447610331, -0.96592582628907, 0.39989202431974, 0.84672419922829, -0.65228741127812, 0.62348980185873, -0.90096886790242, -0.22252093395631, 1, -0.22252093395631, -0.90096886790242, 0.62348980185873, 0.62348980185873, -0.90096886790242, -0.22252093395632, 1, -0.22252093395631, -0.90096886790242, 0.62348980185873, 0.62348980185873, -0.90096886790242, -0.22252093395632, 1, -0.22252093395632, -0.90096886790242, 0.62348980185873, 0.62348980185873, -0.90096886790242, -0.22252093395632, 1, -0.22252093395632, -0.90096886790242, 0.62348980185874, 0.62348980185874, -0.90096886790242, -0.22252093395631, 1, -0.22252093395632, -0.90096886790242, 0.62348980185873, 0.62348980185873, -0.90096886790242, -0.22252093395631, 1, -0.22252093395632, -0.90096886790242, 0.62348980185874, 0.5938201855735, -0.94388333030837, -0.037391194276326, 0.96592582628907, -0.53203207651534, -0.65228741127812, 0.91656225586998, 0.11196447610331, -0.98256647323329, 0.46726862827306, 0.70710678118655, -0.88411539350461, -0.18591160716292, 0.99371220989324, -0.39989202431974, -0.75797172314545, 0.84672419922828, 0.25881904510252, -0.9993007047884, 0.33027906195516, 0.80459777976667, -0.80459777976667, -0.33027906195517, 0.9993007047884, -0.25881904510252, -0.84672419922828, 0.75797172314545, 0.39989202431974, -0.99371220989324, 0.18591160716292, 0.88411539350461, -0.70710678118655, -0.46726862827306, 0.98256647323329, -0.11196447610331, -0.91656225586997, 0.65228741127812, 0.53203207651534, -0.96592582628907, 0.037391194276331, 0.94388333030837, -0.59382018557351, 0.56332005806362, -0.97492791218182, 0.14904226617617, 0.86602540378444, -0.78183148246803, -0.2947551744109, 0.99720379718118, -0.43388373911756, -0.68017273777092, 0.9308737486442, -9.8033641995447e-16, -0.9308737486442, 0.68017273777092, 0.43388373911756, -0.99720379718118, 0.29475517441091, 0.78183148246803, -0.86602540378444, -0.14904226617617, 0.97492791218182, -0.56332005806362, -0.56332005806362, 0.97492791218182, -0.14904226617617, -0.86602540378444, 0.78183148246803, 0.2947551744109, -0.99720379718118, 0.43388373911756, 0.68017273777092, -0.93087374864421, -4.1644180977376e-15, 0.9308737486442, -0.68017273777092, -0.43388373911756, 0.99720379718118, -0.2947551744109, -0.78183148246803, 0.86602540378444, 0.14904226617617, -0.97492791218183, 0.56332005806363, 0.53203207651534, -0.99371220989324, 0.33027906195517, 0.70710678118655, -0.94388333030837, 0.11196447610331, 0.84672419922828, -0.84672419922828, -0.11196447610331, 0.94388333030837, -0.70710678118655, -0.33027906195517, 0.99371220989324, -0.53203207651534, -0.53203207651534, 0.99371220989324, -0.33027906195517, -0.70710678118655, 0.94388333030837, -0.1119644761033, -0.84672419922828, 0.84672419922828, 0.11196447610331, -0.94388333030837, 0.70710678118655, 0.33027906195516, -0.99371220989324, 0.53203207651534, 0.53203207651534, -0.99371220989324, 0.33027906195517, 0.70710678118655, -0.94388333030837, 0.11196447610331, 0.84672419922829, -0.84672419922829, -0.1119644761033, 0.94388333030837, -0.70710678118655, -0.33027906195517, 0.99371220989324, -0.53203207651534, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.50000000000001, 0.5, -1, 0.50000000000001, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.5, -1, 0.5, 0.46726862827306, -0.99371220989324, 0.65228741127812, 0.25881904510252, -0.94388333030837, 0.80459777976667, 0.037391194276326, -0.84672419922829, 0.91656225586998, -0.18591160716291, -0.70710678118655, 0.98256647323329, -0.39989202431974, -0.53203207651534, 0.9993007047884, -0.59382018557351, -0.33027906195517, 0.96592582628907, -0.75797172314546, -0.11196447610331, 0.88411539350461, -0.88411539350461, 0.11196447610331, 0.75797172314545, -0.96592582628907, 0.33027906195517, 0.5938201855735, -0.9993007047884, 0.53203207651533, 0.39989202431974, -0.98256647323329, 0.70710678118654, 0.1859116071629, -0.91656225586998, 0.84672419922828, -0.037391194276335, -0.80459777976667, 0.94388333030837, -0.25881904510253, -0.65228741127812, 0.99371220989324, -0.46726862827307, 0.43388373911756, -0.97492791218182, 0.78183148246803, -5.8201671991329e-16, -0.78183148246803, 0.97492791218182, -0.43388373911756, -0.43388373911756, 0.97492791218182, -0.78183148246803, -2.6948419387608e-15, 0.78183148246803, -0.97492791218182, 0.43388373911756, 0.43388373911755, -0.97492791218182, 0.78183148246803, -2.4554834046606e-16, -0.78183148246803, 0.97492791218182, -0.43388373911756, -0.43388373911756, 0.97492791218182, -0.78183148246803, 3.1859386196929e-15, 0.78183148246803, -0.97492791218182, 0.43388373911756, 0.43388373911756, -0.97492791218182, 0.78183148246803, 9.7909845868129e-16, -0.78183148246802, 0.97492791218182, -0.43388373911756, -0.43388373911756, 0.97492791218182, -0.78183148246802, 1.9612918205455e-15, 0.78183148246803, -0.97492791218182, 0.43388373911756, 0.39989202431974, -0.94388333030837, 0.88411539350461, -0.25881904510252, -0.53203207651534, 0.98256647323329, -0.80459777976667, 0.11196447610331, 0.65228741127812, -0.9993007047884, 0.70710678118655, 0.037391194276325, -0.75797172314545, 0.99371220989324, -0.5938201855735, -0.18591160716291, 0.84672419922829, -0.96592582628907, 0.46726862827306, 0.33027906195517, -0.91656225586998, 0.91656225586998, -0.33027906195517, -0.46726862827306, 0.96592582628907, -0.84672419922829, 0.18591160716291, 0.5938201855735, -0.99371220989324, 0.75797172314545, -0.037391194276328, -0.70710678118655, 0.9993007047884, -0.65228741127812, -0.11196447610331, 0.80459777976667, -0.98256647323329, 0.53203207651533, 0.25881904510251, -0.88411539350461, 0.94388333030837, -0.39989202431975, 0.36534102436639, -0.90096886790242, 0.95557280578614, -0.5, -0.22252093395631, 0.82623877431599, -0.98883082622513, 0.62348980185873, 0.074730093586423, -0.73305187182983, 1, -0.73305187182983, 0.074730093586424, 0.62348980185873, -0.98883082622513, 0.826238774316, -0.22252093395631, -0.5, 0.95557280578614, -0.90096886790242, 0.3653410243664, 0.36534102436639, -0.90096886790242, 0.95557280578614, -0.5, -0.22252093395631, 0.82623877431599, -0.98883082622513, 0.62348980185873, 0.074730093586418, -0.73305187182983, 1, -0.73305187182983, 0.074730093586426, 0.62348980185874, -0.98883082622513, 0.826238774316, -0.22252093395631, -0.49999999999999, 0.95557280578614, -0.90096886790242, 0.3653410243664, 0.33027906195517, -0.84672419922828, 0.99371220989324, -0.70710678118655, 0.11196447610331, 0.53203207651534, -0.94388333030837, 0.94388333030837, -0.53203207651534, -0.11196447610331, 0.70710678118655, -0.99371220989324, 0.84672419922828, -0.33027906195517, -0.33027906195516, 0.84672419922828, -0.99371220989324, 0.70710678118655, -0.11196447610331, -0.53203207651534, 0.94388333030837, -0.94388333030837, 0.53203207651533, 0.11196447610331, -0.70710678118654, 0.99371220989324, -0.84672419922828, 0.33027906195516, 0.33027906195517, -0.84672419922828, 0.99371220989324, -0.70710678118655, 0.11196447610331, 0.53203207651533, -0.94388333030837, 0.94388333030837, -0.53203207651533, -0.11196447610331, 0.70710678118655, -0.99371220989324, 0.84672419922828, -0.33027906195517, 0.2947551744109, -0.78183148246803, 0.99720379718118, -0.86602540378444, 0.43388373911756, 0.14904226617617, -0.68017273777092, 0.97492791218182, -0.93087374864421, 0.56332005806362, -7.35407060125e-16, -0.56332005806362, 0.9308737486442, -0.97492791218182, 0.68017273777092, -0.14904226617618, -0.43388373911756, 0.86602540378444, -0.99720379718118, 0.78183148246803, -0.2947551744109, -0.2947551744109, 0.78183148246803, -0.99720379718118, 0.86602540378444, -0.43388373911756, -0.14904226617618, 0.68017273777092, -0.97492791218182, 0.93087374864421, -0.56332005806362, -4.899206177226e-15, 0.56332005806362, -0.93087374864421, 0.97492791218182, -0.68017273777093, 0.14904226617618, 0.43388373911756, -0.86602540378443, 0.99720379718118, -0.78183148246803, 0.29475517441091, 0.25881904510252, -0.70710678118655, 0.96592582628907, -0.96592582628907, 0.70710678118655, -0.25881904510252, -0.25881904510252, 0.70710678118655, -0.96592582628907, 0.96592582628907, -0.70710678118655, 0.25881904510252, 0.25881904510252, -0.70710678118655, 0.96592582628907, -0.96592582628907, 0.70710678118655, -0.25881904510252, -0.25881904510252, 0.70710678118655, -0.96592582628907, 0.96592582628907, -0.70710678118655, 0.25881904510252, 0.25881904510252, -0.70710678118655, 0.96592582628907, -0.96592582628907, 0.70710678118655, -0.25881904510252, -0.25881904510252, 0.70710678118655, -0.96592582628907, 0.96592582628907, -0.70710678118655, 0.25881904510252, 0.25881904510252, -0.70710678118655, 0.96592582628907, -0.96592582628907, 0.70710678118654, -0.25881904510253, 0.22252093395631, -0.62348980185873, 0.90096886790242, -1, 0.90096886790242, -0.62348980185873, 0.22252093395631, 0.22252093395632, -0.62348980185873, 0.90096886790242, -1, 0.90096886790242, -0.62348980185874, 0.22252093395631, 0.22252093395631, -0.62348980185873, 0.90096886790242, -1, 0.90096886790242, -0.62348980185873, 0.22252093395632, 0.22252093395631, -0.62348980185873, 0.90096886790242, -1, 0.90096886790242, -0.62348980185873, 0.22252093395632, 0.22252093395631, -0.62348980185873, 0.90096886790242, -1, 0.90096886790242, -0.62348980185874, 0.22252093395631, 0.22252093395631, -0.62348980185873, 0.90096886790242, -1, 0.90096886790242, -0.62348980185873, 0.22252093395632, 0.18591160716291, -0.53203207651534, 0.80459777976667, -0.96592582628907, 0.99371220989324, -0.88411539350461, 0.65228741127812, -0.33027906195517, -0.037391194276324, 0.39989202431974, -0.70710678118655, 0.91656225586998, -0.9993007047884, 0.94388333030837, -0.75797172314546, 0.46726862827306, -0.1119644761033, -0.25881904510252, 0.5938201855735, -0.84672419922828, 0.98256647323329, -0.98256647323329, 0.84672419922828, -0.59382018557351, 0.25881904510252, 0.1119644761033, -0.46726862827306, 0.75797172314545, -0.94388333030837, 0.9993007047884, -0.91656225586998, 0.70710678118655, -0.39989202431975, 0.037391194276323, 0.33027906195517, -0.65228741127811, 0.88411539350461, -0.99371220989324, 0.96592582628907, -0.80459777976667, 0.53203207651533, -0.18591160716292, 0.14904226617617, -0.43388373911756, 0.68017273777092, -0.86602540378444, 0.97492791218182, -0.99720379718118, 0.93087374864421, -0.78183148246803, 0.56332005806362, -0.29475517441091, -2.9397712985902e-15, 0.2947551744109, -0.56332005806362, 0.78183148246803, -0.9308737486442, 0.99720379718118, -0.97492791218182, 0.86602540378444, -0.68017273777092, 0.43388373911756, -0.14904226617617, -0.14904226617617, 0.43388373911756, -0.68017273777092, 0.86602540378443, -0.97492791218182, 0.99720379718118, -0.9308737486442, 0.78183148246803, -0.56332005806363, 0.2947551744109, 8.8193138957707e-15, -0.29475517441089, 0.56332005806362, -0.78183148246803, 0.9308737486442, -0.99720379718118, 0.97492791218182, -0.86602540378444, 0.68017273777092, -0.43388373911756, 0.14904226617618, 0.11196447610331, -0.33027906195517, 0.53203207651534, -0.70710678118655, 0.84672419922828, -0.94388333030837, 0.99371220989324, -0.99371220989324, 0.94388333030837, -0.84672419922828, 0.70710678118655, -0.53203207651534, 0.33027906195516, -0.1119644761033, -0.11196447610331, 0.33027906195516, -0.53203207651534, 0.70710678118655, -0.84672419922828, 0.94388333030837, -0.99371220989324, 0.99371220989324, -0.94388333030837, 0.84672419922828, -0.70710678118654, 0.53203207651534, -0.33027906195517, 0.11196447610331, 0.1119644761033, -0.33027906195517, 0.53203207651534, -0.70710678118655, 0.84672419922828, -0.94388333030837, 0.99371220989324, -0.99371220989324, 0.94388333030837, -0.84672419922828, 0.70710678118656, -0.53203207651533, 0.33027906195516, -0.11196447610331, 0.074730093586424, -0.22252093395631, 0.36534102436639, -0.5, 0.62348980185873, -0.73305187182983, 0.82623877431599, -0.90096886790242, 0.95557280578614, -0.98883082622513, 1, -0.98883082622513, 0.95557280578614, -0.90096886790242, 0.826238774316, -0.73305187182983, 0.62348980185873, -0.5, 0.3653410243664, -0.22252093395631, 0.074730093586427, 0.074730093586424, -0.22252093395631, 0.3653410243664, -0.5, 0.62348980185873, -0.73305187182983, 0.826238774316, -0.90096886790242, 0.95557280578614, -0.98883082622513, 1, -0.98883082622513, 0.95557280578614, -0.90096886790242, 0.826238774316, -0.73305187182983, 0.62348980185872, -0.50000000000001, 0.36534102436639, -0.22252093395632, 0.074730093586431, 0.037391194276326, -0.11196447610331, 0.18591160716291, -0.25881904510252, 0.33027906195517, -0.39989202431974, 0.46726862827306, -0.53203207651534, 0.5938201855735, -0.65228741127812, 0.70710678118655, -0.75797172314545, 0.80459777976667, -0.84672419922828, 0.88411539350461, -0.91656225586998, 0.94388333030837, -0.96592582628907, 0.98256647323329, -0.99371220989324, 0.9993007047884, -0.9993007047884, 0.99371220989324, -0.98256647323329, 0.96592582628907, -0.94388333030837, 0.91656225586997, -0.88411539350461, 0.84672419922828, -0.80459777976668, 0.75797172314545, -0.70710678118654, 0.65228741127813, -0.5938201855735, 0.53203207651534, -0.46726862827307, 0.39989202431975, -0.33027906195516, 0.25881904510252, -0.18591160716291, 0.1119644761033, -0.037391194276333, 6.1232339957368e-17, -1.836970198721e-16, -5.8201671991329e-16, 1.3477304596987e-15, 5.5109105961631e-16, 1.1028010998692e-15, -9.8033641995447e-16, -2.6948419387608e-15, -7.35407060125e-16, 6.1294238021026e-16, -4.9047770029553e-16, 3.9207266991813e-15, -2.4554834046606e-16, -3.4296300182492e-15, -6.1898063658838e-19, 3.4308679795224e-15, 2.4431037919288e-16, 3.1859386196929e-15, -6.6161876185786e-15, -4.1644180977376e-15, -6.3712582587492e-15, 9.8015072576349e-15, 9.7909845868129e-16, 2.4511505402045e-15, -5.8813995390902e-15, 9.311648537976e-15, 1.4689571783402e-15, 1.9612918205455e-15, 8.8193138957707e-15, 8.8217898183171e-15, 1.9588158979992e-15, 1.4714331008866e-15, -4.9016820997724e-15, 8.3319310986581e-15, 2.4486746176581e-15, 1.519242909643e-14, -4.4118233801134e-15, -6.3687823362028e-15, -1.1272321377885e-14, 4.9171566156871e-16, 1.0288890054748e-14, 7.3522136593402e-15 }; //other functions static void MFCC_dofft(MFCC *, uint32); static float MFCC_prepareMel(MFCC *, float *); //float MFCC_prepareERB(MFCC *, float *); void MFCC_Ctor(MFCC* unit) { //may want to check sampling rate here! unit->m_srate = unit->mWorld->mFullRate.mSampleRate; //if sample rate is 88200 or 96000, assume taking double size FFT to start with if(unit->m_srate > (44100.0*1.5)) unit->m_srate = unit->m_srate*0.5; if(((int)(unit->m_srate+0.01))==44100) { unit->m_startbin= g_startbin44100; unit->m_endbin= g_endbin44100; unit->m_cumulindex= g_cumulindex44100; unit->m_bandweights= g_melbandweights44100; } else //else 48000; potentially dangerous if it isn't! Fortunately, shouldn't write any data to unknown memory { unit->m_startbin= g_startbin48000; unit->m_endbin= g_endbin48000; unit->m_cumulindex= g_cumulindex48000; unit->m_bandweights= g_melbandweights48000; } //fixed for now unit->m_numbands= 42; unit->m_bands = (float*)RTAlloc(unit->mWorld, unit->m_numbands * sizeof(float)); Clear(unit->m_numbands, unit->m_bands); unit->m_numcoefficients= (int)ZIN0(1); //range checks if(unit->m_numcoefficients<1){unit->m_numcoefficients=1;} if(unit->m_numcoefficients>42){unit->m_numcoefficients=42;} unit->m_mfcc = (float*)RTAlloc(unit->mWorld, unit->m_numcoefficients * sizeof(float)); Clear(unit->m_numcoefficients, unit->m_mfcc); for (int j=0; jm_numcoefficients; ++j) ZOUT0(j) = 0.f; unit->mCalcFunc = (UnitCalcFunc)&MFCC_next; } void MFCC_Dtor(MFCC *unit) { if(unit->m_mfcc) RTFree(unit->mWorld, unit->m_mfcc); if(unit->m_bands) RTFree(unit->mWorld, unit->m_bands); } void MFCC_next(MFCC *unit, int wrongNumSamples) { float fbufnum = ZIN0(0); //next FFT bufffer ready, update //assuming at this point that buffer precalculated for any resampling if (fbufnum> -0.01f) MFCC_dofft(unit, (uint32)fbufnum); //always output sones //float outval= unit->m_sones; //printf("sones %f phontotal %f \n",outval, unit->m_phontotal); //number of outputs depends on numcoefficients //control rate output //ZOUT0(0)=unit->m_sones; for (int k=0; km_numcoefficients; ++k) ZOUT0(k)= unit->m_mfcc[k]; } //calculation function once FFT data ready void MFCC_dofft(MFCC *unit, uint32 ibufnum) { World *world = unit->mWorld; SndBuf *buf; if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; } } else { buf = world->mSndBufs + ibufnum; } LOCK_SNDBUF(buf); //int numbins = buf->samples - 2 >> 1; //assumed in this representation ToComplexApx(buf); float * data= buf->data; float mult= MFCC_prepareMel(unit, data); //MFCC_prepareERB float * pbands= unit->m_bands; //now use cosine basis for transform; approximates principal components, compresses information into a smaller number of bands //FFT is actually more expensive here, easiest just to calculate the basis decomposition straight off //hard coded 42 = max num bands because this is how the indexing in the dct source is set up for (int k=0; km_numcoefficients; ++k){ float sum=0.0; int base= k*42; for (int j=0; jm_numbands; ++j) { int index= base+j; //sum+= (0.5*dct[index]+0.5)*pbands[j]; sum+= (dct[index])*pbands[j]; } //could also divide by numcoefficients, but left off for compatibility between MFCCs extracted in different ways unit->m_mfcc[k]= 0.25f*((sum*mult)+1.0f); //0.5*(0.5*(sum*mult)+0.5); } } float MFCC_prepareMel(MFCC * unit, float * data) { float * pbands= unit->m_bands; int * startbin= unit->m_startbin; int * endbin= unit->m_endbin; int * cumulindex= unit->m_cumulindex; float * weights= unit->m_bandweights; for (int k=0; km_numbands; ++k){ int bandstart = startbin[k]; int bandend = endbin[k]; //p1 = endbin[k]+1; float bsum=0.f; float real, imag, power; int index, index2; //float lastpower=0.0; index2= cumulindex[k] - bandstart; for (int j=bandstart; j < bandend; ++j) { index = j+j; real= data[index]; imag= data[index+1]; if(j==0) power= real*real; //sc_abs(real); //dc else power = real*real + imag*imag; //sqrt((real*real) + (imag*imag)); float multiplier = weights[index2 + j]; //[cumulindex[k] + (j-bandstart)] bsum += (power*multiplier); } //either keep as double to preserve the small value //pbands[k] = 10.f * (sc_log10((bsum< 1e-42? 1e-42: bsum)) + 5.f); //or make sure value works as a float: //pbands[k] = 10.f * (sc_log10((bsum< 1e-20f? 1e-20f: bsum)) + 5.f); //want to avoid negative values, dynamic range roughly around 11 powers of ten (110dB) //pbands[k] = 10.f * (std::log10((bsum< 1e-5f? 1e-5f: bsum)) + 5.f); pbands[k] = 10.f * (std::log10(sc_max(1e-5f, bsum)) +5.f); } //float mult= 0.01; //(1.0/((float)unit->m_numcoefficients)); //0.01*(1.0/((float)unit->m_numcoefficients)); return 0.01f; } //Original draft for EFCC //temporal masking over ERB bands: peaks take a while to decay //spectral masking over which bins summed as contributors for ERB bands; spreading activation function actually implies that the overall power is greater from spread? //masking not triangular but slanted towards masking higher frequency content (ie, lower freq bins mask upper) // //for true MP3 style compression would have to see if each FFT bin was noise like or sine like (transient measure on instantaneous frequency for example), and use the appropriate masking curve //efficiency is preferred here // //thus can calculate squared powers as you go? cheapest if only have effect of spectral masking above, covering a fixed number of bins? but then, frequency biased loudness based on ERB band centre frequency! //float MFCC_prepareERB(MFCC * unit, float * data) { // //int j,k; // // float * pbands= unit->m_bands; // // for (k=0; km_numbands; ++k){ // // int bandstart=eqlbandbins[k]; // //int bandend=eqlbandbins[k+1]; // int bandsize= eqlbandsizes[k]; // int bandend= bandstart+bandsize; // // float bsum=0.0; // float real, imag, power; // int index; // //float lastpower=0.0; // // for (j=bandstart; jcontours[k][10]) db=phons[10]; // else { // // float prop=0.0; // // for (j=1; j<11; ++j) { // if(dbm_bands[k]) - tmask); // // } // // // //now use cosine basis for transform; approximates principal components, compresses information into a smaller number of bands // //FFT is actually more expensive here, easiest just to calculate the basis decomposition straight off // float mult= 0.01*(1.0/((float)unit->m_numcoefficients)); // // return mult; //} // SuperCollider-Source/server/plugins/ML.cpp000644 000765 000024 00000002370 12321461511 021656 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //machine listening plug-ins adapted for SuperCollider core #include "ML.h" #include "FFT_UGens.h" InterfaceTable *ft; PluginLoad(ML_UGens) { ft = inTable; DefineDtorCantAliasUnit(BeatTrack); DefineDtorUnit(Loudness); DefineDtorUnit(KeyTrack); DefineDtorUnit(MFCC); DefineDtorUnit(Onsets); DefineDtorCantAliasUnit(BeatTrack2); DefineSimpleUnit(SpecFlatness); DefineDtorUnit(SpecPcile); DefineSimpleUnit(SpecCentroid); } SuperCollider-Source/server/plugins/ML.h000644 000765 000024 00000007062 12321461511 021326 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" //global data //helpful constants //#define PI 3.1415926535898f //#define TWOPI 6.28318530717952646f extern InterfaceTable *ft; //shared data extern int eqlbandbins[43]; extern int eqlbandsizes[42]; extern float contours[42][11]; extern double phons[11]; //#include "KeyTrack.h" #include "BeatTrack.h" //#include "Loudness.h" #include "Onsets.h" //#include "MFCC.h" #include "BeatTrack2.h" struct Loudness : Unit { //FFT data int m_numbands; float * m_ERBbands; //float m_phontotal; //final output float m_sones; }; struct KeyTrack : Unit { //FFT data float * m_FFTBuf; //coping with different sampling rates float m_srate; //use as a flag to check sample rate is correct float * m_weights; //will point to the sample rate specific data int * m_bins; float m_frameperiod; //counter //uint32 m_frame; //experimental transient avoidance //float m_prevphase[720]; //60*12 //float m_leaknote[60]; float m_chroma[12]; float m_key[24]; float m_histogram[24]; //key histogram //float m_keyleak; //fade parameter for histogram //int m_triggerid; int m_currentKey; }; struct MFCC : Unit { //MFCC int m_numcoefficients; float * m_mfcc; //ERB int m_numbands; float * m_bands; //sampling rate specific data float m_srate; int * m_startbin; int * m_endbin; int * m_cumulindex; float * m_bandweights; }; ////////////////////////////////////////////////////////////////////////////////////////////////// struct FFTAnalyser_Unit : Unit { float outval; // Not always used: multipliers which convert from bin indices to freq vals, and vice versa. // See also the macros for deriving these. float m_bintofreq /* , m_freqtobin */; float m_halfnyq_over_numbinsp2; }; struct FFTAnalyser_OutOfPlace : FFTAnalyser_Unit { int m_numbins; float *m_tempbuf; }; struct SpecFlatness : FFTAnalyser_Unit { double m_oneovern; }; struct SpecPcile : FFTAnalyser_OutOfPlace { bool m_interpolate; }; struct SpecCentroid : FFTAnalyser_Unit { }; extern "C" { //required interface functions void Loudness_next(Loudness *unit, int wrongNumSamples); void Loudness_Ctor(Loudness *unit); void Loudness_Dtor(Loudness *unit); void KeyTrack_next(KeyTrack *unit, int wrongNumSamples); void KeyTrack_Ctor(KeyTrack *unit); void KeyTrack_Dtor(KeyTrack *unit); void MFCC_next(MFCC *unit, int wrongNumSamples); void MFCC_Ctor(MFCC *unit); void MFCC_Dtor(MFCC *unit); void SpecFlatness_Ctor(SpecFlatness *unit); void SpecFlatness_next(SpecFlatness *unit, int inNumSamples); // void SpecPcile_Ctor(SpecPcile *unit); void SpecPcile_next(SpecPcile *unit, int inNumSamples); void SpecPcile_Dtor(SpecPcile *unit); // void SpecCentroid_Ctor(SpecCentroid *unit); void SpecCentroid_next(SpecCentroid *unit, int inNumSamples); } SuperCollider-Source/server/plugins/ML_SpecStats.cpp000644 000765 000024 00000021124 12321461511 023645 0ustar00crucialstaff000000 000000 /* Spectral statistics UGens for SuperCollider, by Dan Stowell. Copyright (c) Dan Stowell 2006-2007. Now part of SuperCollider 3, (c) James McCartney. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include "SCComplex.h" #include "FFT_UGens.h" #include "ML.h" ////////////////////////////////////////////////////////////////////////////////////////////////// /* struct FFTAnalyser_Unit : Unit { float outval; // Not always used: multipliers which convert from bin indices to freq vals, and vice versa. // See also the macros for deriving these. float m_bintofreq; // , m_freqtobin; }; struct FFTAnalyser_OutOfPlace : FFTAnalyser_Unit { int m_numbins; float *m_tempbuf; }; struct SpecFlatness : FFTAnalyser_Unit { }; struct SpecPcile : FFTAnalyser_OutOfPlace { bool m_interpolate; }; struct SpecCentroid : FFTAnalyser_Unit { }; */ ////////////////////////////////////////////////////////////////////////////////////////////////// // for operation on one buffer // just like PV_GET_BUF except it outputs unit->outval rather than -1 when FFT not triggered #define FFTAnalyser_GET_BUF \ float fbufnum = ZIN0(0); \ if (fbufnum < 0.f) { ZOUT0(0) = unit->outval; return; } \ ZOUT0(0) = fbufnum; \ uint32 ibufnum = (uint32)fbufnum; \ World *world = unit->mWorld; \ SndBuf *buf; \ if (!(ibufnum < world->mNumSndBufs)) { \ int localBufNum = ibufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(!(localBufNum > parent->localBufNum)) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ buf = world->mSndBufs; \ } \ } else { \ buf = world->mSndBufs + ibufnum; \ } \ LOCK_SNDBUF(buf); \ int numbins = (buf->samples - 2) >> 1; // Copied from FFT_UGens.cpp #define GET_BINTOFREQ \ if(unit->m_bintofreq==0.f){ \ unit->m_bintofreq = world->mFullRate.mSampleRate / buf->samples; \ } \ float bintofreq = unit->m_bintofreq; /* #define GET_FREQTOBIN \ if(unit->m_freqtobin==0.f){ \ unit->m_freqtobin = buf->samples / world->mFullRate.mSampleRate; \ } \ float freqtobin = unit->m_freqtobin; */ ////////////////////////////////////////////////////////////////////////////////////////////////// /* extern "C" { void SpecFlatness_Ctor(SpecFlatness *unit); void SpecFlatness_next(SpecFlatness *unit, int inNumSamples); void SpecPcile_Ctor(SpecPcile *unit); void SpecPcile_next(SpecPcile *unit, int inNumSamples); void SpecPcile_Dtor(SpecPcile *unit); void SpecCentroid_Ctor(SpecCentroid *unit); void SpecCentroid_next(SpecCentroid *unit, int inNumSamples); } */ /* SCPolarBuf* ToPolarApx(SndBuf *buf) { if (buf->coord == coord_Complex) { SCComplexBuf* p = (SCComplexBuf*)buf->data; int numbins = buf->samples - 2 >> 1; for (int i=0; ibin[i].ToPolarApxInPlace(); } buf->coord = coord_Polar; } return (SCPolarBuf*)buf->data; } SCComplexBuf* ToComplexApx(SndBuf *buf) { if (buf->coord == coord_Polar) { SCPolarBuf* p = (SCPolarBuf*)buf->data; int numbins = buf->samples - 2 >> 1; for (int i=0; ibin[i].ToComplexApxInPlace(); } buf->coord = coord_Complex; } return (SCComplexBuf*)buf->data; } InterfaceTable *ft; void init_SCComplex(InterfaceTable *inTable); */ ////////////////////////////////////////////////////////////////////////////////////////////////// void SpecFlatness_Ctor(SpecFlatness *unit) { SETCALC(SpecFlatness_next); ZOUT0(0) = unit->outval = 0.; unit->m_oneovern = 0.; } void SpecFlatness_next(SpecFlatness *unit, int inNumSamples) { FFTAnalyser_GET_BUF if(unit->m_oneovern == 0.) unit->m_oneovern = 1./(numbins + 2); SCComplexBuf *p = ToComplexApx(buf); // Spectral Flatness Measure is geometric mean divided by arithmetic mean. // // In order to calculate geom mean without hitting the precision limit, // we use the trick of converting to log, taking the average, then converting back from log. double geommean = std::log(sc_abs(p->dc)) + std::log(sc_abs(p->nyq)); double mean = sc_abs(p->dc) + sc_abs(p->nyq); for (int i=0; ibin[i].real); float iabs = (p->bin[i].imag); float amp = std::sqrt((rabs*rabs) + (iabs*iabs)); if(amp != 0.f) { // zeroes lead to NaNs geommean += std::log(amp); mean += amp; } } double oneovern = unit->m_oneovern; geommean = exp(geommean * oneovern); // Average and then convert back to linear mean *= oneovern; // Store the val for output in future calls unit->outval = (mean==0.f ? 0.8f : (geommean / mean)); // Note: for silence the value is undefined. // Here, for silence we instead output an empirical value based on very quiet white noise. ZOUT0(0) = unit->outval; } //////////////////////////////////////////////////////////////////////////////////// void SpecPcile_Ctor(SpecPcile *unit) { SETCALC(SpecPcile_next); unit->m_interpolate = ZIN0(2) > 0.f; ZOUT0(0) = unit->outval = 0.; unit->m_tempbuf = 0; } void SpecPcile_next(SpecPcile *unit, int inNumSamples) { FFTAnalyser_GET_BUF // Used to be MAKE_TEMP_BUF but we can handle it more cleanly in this specific case: if (!unit->m_tempbuf) { unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float)); unit->m_numbins = numbins; unit->m_halfnyq_over_numbinsp2 = ((float)unit->mWorld->mSampleRate) * 0.5f / (float)(numbins+2); } else if (numbins != unit->m_numbins) return; // Percentile value as a fraction. eg: 0.5 == 50-percentile (median). float fraction = ZIN0(1); bool interpolate = unit->m_interpolate; // The magnitudes in *p will be converted to cumulative sum values and stored in *q temporarily SCComplexBuf *p = ToComplexApx(buf); float *q = (float*)unit->m_tempbuf; float cumul = sc_abs(p->dc); for (int i=0; ibin[i].real; float imag = p->bin[i].imag; cumul += std::sqrt(real*real + imag*imag); // A convenient place to store the mag values... q[i] = cumul; } cumul += sc_abs(p->nyq); float target = cumul * fraction; // The target cumul value, stored somewhere in q float bestposition = 0; // May be linear-interpolated between bins, but not implemented yet // NB If nothing beats the target (e.g. if fraction is -1) zero Hz is returned float binpos; for(int i=0; ibin[i].real, i); if(!(q[i] < target)){ // this is a ">=" comparison, done more efficiently as "!(<)" if(interpolate && i!=0) { binpos = ((float)i) + 1.f - (q[i] - target) / (q[i] - q[i-1]); } else { binpos = ((float)i) + 1.f; } bestposition = binpos * unit->m_halfnyq_over_numbinsp2; //Print("Target %g beaten by %g (at position %i), equating to freq %g\n", // target, p->bin[i].real, i, bestposition); break; } } // Store the val for output in future calls unit->outval = bestposition; ZOUT0(0) = unit->outval; } void SpecPcile_Dtor(SpecPcile *unit) { if(unit->m_tempbuf) RTFree(unit->mWorld, unit->m_tempbuf); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void SpecCentroid_Ctor(SpecCentroid *unit) { SETCALC(SpecCentroid_next); ZOUT0(0) = unit->outval = 0.; unit->m_bintofreq = 0.f; } void SpecCentroid_next(SpecCentroid *unit, int inNumSamples) { FFTAnalyser_GET_BUF SCPolarBuf *p = ToPolarApx(buf); GET_BINTOFREQ double num = sc_abs(p->nyq) * (numbins+1); double denom = sc_abs(p->nyq); for (int i=0; ibin[i].mag) * (i+1); denom += sc_abs(p->bin[i].mag); } ZOUT0(0) = unit->outval = denom == 0.0 ? 0.f : (float) (bintofreq * num/denom); } ////////////////////////////////////////////////////////////////////////////////////////////////// /* void load(InterfaceTable *inTable) { ft= inTable; //(*ft->fDefineUnit)("SpecFlatness", sizeof(FFTAnalyser_Unit), (UnitCtorFunc)&SpecFlatness_Ctor, 0, 0); //(*ft->fDefineUnit)("SpecPcile", sizeof(SpecPcile_Unit), (UnitCtorFunc)&SpecPcile_Ctor, (UnitDtorFunc)&SpecPcile_Dtor, 0); DefineSimpleUnit(SpecFlatness); DefineDtorUnit(SpecPcile); DefineSimpleUnit(SpecCentroid); } */ SuperCollider-Source/server/plugins/MulAddUGens.cpp000644 000765 000024 00000036525 12756531745 023512 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.hpp" #include "SIMD_Unit.hpp" static InterfaceTable *ft; namespace { struct MulAdd: SIMD_Unit { ControlRateInput<1> mMul; ControlRateInput<2> mAdd; #define MULADD_CALCFUNC(METHOD_NAME) \ do { \ set_unrolled_calc_function, \ &MulAdd::METHOD_NAME, \ &MulAdd::METHOD_NAME >(); \ return; \ } while (0) MulAdd(void) { mMul.init(this); mAdd.init(this); if (mCalcRate != calc_FullRate) { set_calc_function(); return; } assert(inRate(0) == calc_FullRate); switch (inRate(1)) { case calc_FullRate: switch (inRate(2)) { case calc_FullRate: MULADD_CALCFUNC(next_aa); case calc_BufRate: MULADD_CALCFUNC(next_ak); case calc_ScalarRate: if (mAdd == 0.f) MULADD_CALCFUNC(next_a0); else MULADD_CALCFUNC(next_ai); default: assert(false); } case calc_BufRate: switch (inRate(2)) { case calc_FullRate: MULADD_CALCFUNC(next_ka); case calc_BufRate: MULADD_CALCFUNC(next_kk); case calc_ScalarRate: if (mAdd == 0.f) MULADD_CALCFUNC(next_k0); else MULADD_CALCFUNC(next_ki); default: assert(false); } case calc_ScalarRate: switch (inRate(2)) { case calc_FullRate: if (mMul == 1.0) MULADD_CALCFUNC(next_1a); else if (mMul == 0.f) MULADD_CALCFUNC(next_0a); else MULADD_CALCFUNC(next_ia); case calc_BufRate: if (mMul == 1.0) MULADD_CALCFUNC(next_1k); else if (mMul == 0.f) MULADD_CALCFUNC(next_0k); else MULADD_CALCFUNC(next_ik); case calc_ScalarRate: if (mMul == 1.0) { if (mAdd == 0) MULADD_CALCFUNC(next_10); else MULADD_CALCFUNC(next_1i); } else if (mMul == 0.f) { if (mAdd == 0.f) MULADD_CALCFUNC(next_00); else MULADD_CALCFUNC(next_0i); } else { if (mAdd == 0.f) MULADD_CALCFUNC(next_i0); else MULADD_CALCFUNC(next_ii); } default: assert(false); } default: assert(false); } } inline bool mulChanged(void) const { return mMul.changed(this); } inline bool addChanged(void) const { return mAdd.changed(this); } #if __cplusplus <= 199711L nova::detail::scalar_ramp_argument mulSlope(void) #else decltype(nova::slope_argument(0.f, 0.f)) mulSlope(void) #endif { return mMul.slope(this); } #if __cplusplus <= 199711L nova::detail::scalar_ramp_argument addSlope(void) #else decltype(nova::slope_argument(0.f, 0.f)) addSlope(void) #endif { return mAdd.slope(this); } void next_scalar(int inNumSamples) { out0(0) = (in0(0) * in0(1)) + in0(2); } template void next_aa(int inNumSamples) { muladd(out(0), in(0), in(1), in(2), inNumSamples); } template void next_ak(int inNumSamples) { if (addChanged()) muladd(out(0), in(0), in(1), addSlope(), inNumSamples); else { if (mAdd == 0.f) times_vec(out(0), in(0), in(1), inNumSamples); else next_ai(inNumSamples); } } template void next_ai(int inNumSamples) { muladd(out(0), in(0), in(1), mAdd, inNumSamples); } template void next_ka(int inNumSamples) { if (mulChanged()) muladd(out(0), in(0), mulSlope(), in(2), inNumSamples); else next_ia(inNumSamples); } template void next_kk(int inNumSamples) { if (addChanged()) { if (mulChanged()) muladd(out(0), in(0), mulSlope(), addSlope(), inNumSamples); else { if (mMul == 0) slope_vec(out(0), addSlope(), inNumSamples); else if (mMul == 1.f) plus_vec(out(0), in(0), addSlope(), inNumSamples); else muladd(out(0), in(0), mMul, addSlope(), inNumSamples); } } else next_ki(inNumSamples); } template void next_ki(int inNumSamples) { if (mulChanged()) muladd(out(0), in(0), mulSlope(), mAdd, inNumSamples); else next_ii(inNumSamples); } template void next_ia(int inNumSamples) { if (mMul == 0) next_0a(inNumSamples); else if (mMul == 1.0) next_1a(inNumSamples); else muladd(out(0), in(0), mMul, in(2), inNumSamples); } template void next_ik(int inNumSamples) { if (addChanged()) { if (mMul == 0.f) slope_vec(out(0), addSlope(), inNumSamples); else if (mMul == 1.f) plus_vec(out(0), in(0), addSlope(), inNumSamples); else muladd(out(0), in(0), mMul, addSlope(), inNumSamples); } else next_ii(inNumSamples); } template void next_ii(int inNumSamples) { if (mMul == 0) next_0i(inNumSamples); else if (mMul == 1.f) { next_1i(inNumSamples); } else { if (mAdd == 0) times_vec(out(0), in(0), mMul, inNumSamples); else muladd(out(0), in(0), mMul, mAdd, inNumSamples); } } template void next_1a(int inNumSamples) { plus_vec(out(0), in(0), in(2), inNumSamples); } template void next_1k(int inNumSamples) { if (addChanged()) plus_vec(out(0), in(0), addSlope(), inNumSamples); else next_1i(inNumSamples); } template void next_1i(int inNumSamples) { if (mAdd == 0) copy_vec(out(0), in(0), inNumSamples); else plus_vec(out(0), in(0), mAdd, inNumSamples); } template void next_0a(int inNumSamples) { copy_vec(out(0), in(2), inNumSamples); } template void next_0k(int inNumSamples) { if (addChanged()) slope_vec(out(0), addSlope(), inNumSamples); else next_0i(inNumSamples); } template void next_0i(int inNumSamples) { set_vec(out(0), mAdd, inNumSamples); } template void next_a0(int inNumSamples) { times_vec(out(0), in(0), in(1), inNumSamples); } template void next_k0(int inNumSamples) { if (mulChanged()) times_vec(out(0), in(0), mulSlope(), inNumSamples); else next_ik(inNumSamples); } template void next_i0(int inNumSamples) { if (mMul == 0.f) next_00(inNumSamples); else if (mMul == 1.f) next_10(inNumSamples); else times_vec(out(0), in(0), mMul, inNumSamples); } template void next_10(int inNumSamples) { copy_vec(out(0), in(0), inNumSamples); } template void next_00(int inNumSamples) { set_vec(out(0), 0.f, inNumSamples); } }; struct Sum3: SIMD_Unit { ControlRateInput<1> in1; ControlRateInput<2> in2; Sum3(void) { in1.init(this); in2.init(this); if (mCalcRate != calc_FullRate) { set_calc_function(); return; } assert(inRate(0) == calc_FullRate); switch (inRate(1)) { case calc_FullRate: switch (inRate(2)) { case calc_FullRate: set_vector_calc_function, &Sum3::next_aaa >(); return; case calc_BufRate: set_vector_calc_function, &Sum3::next_aak >(); return; case calc_ScalarRate: set_vector_calc_function, &Sum3::next_aai >(); return; default: assert(false); } case calc_BufRate: switch (inRate(2)) { case calc_BufRate: set_vector_calc_function, &Sum3::next_akk >(); return; case calc_ScalarRate: set_vector_calc_function, &Sum3::next_aki >(); return; default: assert(false); } case calc_ScalarRate: assert (inRate(2) == calc_ScalarRate); set_vector_calc_function, &Sum3::next_aii >(); return; default: assert(false); } } template static void sum_vec(float * out, Arg1 const & arg1, Arg2 const & arg2, Arg3 const & arg3, int inNumSamples) { if (SIMD) nova::sum_vec_simd(out, arg1, arg2, arg3, inNumSamples); else nova::sum_vec(out, arg1, arg2, arg3, inNumSamples); } void next_scalar(int inNumSamples) { out0(0) = in0(0) + in0(1) + in0(2); } template void next_aaa(int inNumSamples) { sum_vec(out(0), in(0), in(1), in(2), inNumSamples); } template void next_aak(int inNumSamples) { if (in2.changed(this)) sum_vec(out(0), in(0), in(1), in2.slope(this), inNumSamples); else next_aai(inNumSamples); } template void next_aai(int inNumSamples) { sum_vec(out(0), in(0), in(1), in2, inNumSamples); } template void next_aki(int inNumSamples) { if (in1.changed(this)) sum_vec(out(0), in(0), in1.slope(this), in2, inNumSamples); else next_aii(inNumSamples); } template void next_akk(int inNumSamples) { if (in2.changed(this)) { if (in1.changed(this)) sum_vec(out(0), in(0), in1.slope(this), in2.slope(this), inNumSamples); else sum_vec(out(0), in(0), in1, in2.slope(this), inNumSamples); } else next_aki(inNumSamples); } template void next_aii(int inNumSamples) { sum_vec(out(0), in(0), in0(1), in0(2), inNumSamples); } }; struct Sum4: SIMD_Unit { ControlRateInput<1> in1; ControlRateInput<2> in2; ControlRateInput<3> in3; Sum4(void) { in1.init(this); in2.init(this); in3.init(this); if (mCalcRate != calc_FullRate) { set_calc_function(); return; } assert(inRate(0) == calc_FullRate); switch (inRate(1)) { case calc_FullRate: switch (inRate(2)) { case calc_FullRate: switch (inRate(3)) { case calc_FullRate: set_vector_calc_function, &Sum4::next_aaaa >(); return; case calc_BufRate: set_vector_calc_function, &Sum4::next_aaak >(); return; case calc_ScalarRate: set_vector_calc_function, &Sum4::next_aaai >(); return; default: assert(false); } case calc_BufRate: switch (inRate(3)) { case calc_BufRate: set_vector_calc_function, &Sum4::next_aakk >(); return; case calc_ScalarRate: set_vector_calc_function, &Sum4::next_aaki >(); return; default: assert(false); } case calc_ScalarRate: switch (inRate(3)) { case calc_ScalarRate: set_vector_calc_function, &Sum4::next_aaii >(); return; default: assert(false); } } case calc_BufRate: switch (inRate(2)) { case calc_BufRate: switch (inRate(3)) { case calc_BufRate: set_vector_calc_function, &Sum4::next_akkk >(); return; case calc_ScalarRate: set_vector_calc_function, &Sum4::next_akki >(); return; default: assert(false); } case calc_ScalarRate: switch (inRate(3)) { case calc_ScalarRate: set_vector_calc_function, &Sum4::next_akii >(); return; default: assert(false); } } case calc_ScalarRate: switch (inRate(2)) { case calc_ScalarRate: switch (inRate(3)) { case calc_ScalarRate: set_vector_calc_function, &Sum4::next_aiii >(); return; default: assert(false); } default: assert(false); } default: assert(false); } } void next_scalar(int inNumSamples) { out0(0) = in0(0) + in0(1) + in0(2) + in0(3); } template static void sum_vec(float * out, Arg1 const & arg1, Arg2 const & arg2, Arg3 const & arg3, Arg4 const & arg4, int inNumSamples) { if (SIMD) nova::sum_vec_simd(out, arg1, arg2, arg3, arg4, inNumSamples); else nova::sum_vec(out, arg1, arg2, arg3, arg4, inNumSamples); } template void next_aaaa(int inNumSamples) { sum_vec(out(0), in(0), in(1), in(2), in(3), inNumSamples); } template void next_aaak(int inNumSamples) { if (in3.changed(this)) sum_vec(out(0), in(0), in(1), in(2), in3.slope(this), inNumSamples); else next_aaai(inNumSamples); } template void next_aaai(int inNumSamples) { sum_vec(out(0), in(0), in(1), in(2), in3, inNumSamples); } template void next_aakk(int inNumSamples) { if (in3.changed(this)) { if (in2.changed(this)) sum_vec(out(0), in(0), in(1), in2.slope(this), in3.slope(this), inNumSamples); else sum_vec(out(0), in(0), in(1), in2, in3.slope(this), inNumSamples); } else next_aaki(inNumSamples); } template void next_aaki(int inNumSamples) { if (in2.changed(this)) sum_vec(out(0), in(0), in(1), in2.slope(this), in3, inNumSamples); else next_aaii(inNumSamples); } template void next_aaii(int inNumSamples) { sum_vec(out(0), in(0), in(1), in2, in3, inNumSamples); } template void next_akkk(int inNumSamples) { if (in3.changed(this)) { if (in2.changed(this)) { if (in1.changed(this)) sum_vec(out(0), in(0), in1.slope(this), in2.slope(this), in3.slope(this), inNumSamples); else sum_vec(out(0), in(0), in1, in2.slope(this), in3.slope(this), inNumSamples); } else { if (in1.changed(this)) sum_vec(out(0), in(0), in1.slope(this), in2, in3.slope(this), inNumSamples); else sum_vec(out(0), in(0), in1, in2, in3.slope(this), inNumSamples); } } else next_akki(inNumSamples); } template void next_akki(int inNumSamples) { if (in2.changed(this)) { if (in1.changed(this)) sum_vec(out(0), in(0), in1.slope(this), in2.slope(this), in3, inNumSamples); else sum_vec(out(0), in(0), in1, in2.slope(this), in3, inNumSamples); } else next_akii(inNumSamples); } template void next_akii(int inNumSamples) { if (in1.changed(this)) sum_vec(out(0), in(0), in1.slope(this), in2, in3, inNumSamples); else next_aiii(inNumSamples); } template void next_aiii(int inNumSamples) { sum_vec(out(0), in(0), in1, in2, in3, inNumSamples); } }; } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(MulAdd) { ft = inTable; registerUnit(ft, "MulAdd" ); registerUnit(ft, "Sum3" ); registerUnit(ft, "Sum4" ); } SuperCollider-Source/server/plugins/NoiseUGens.cpp000644 000765 000024 00000067736 12524671173 023422 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" static InterfaceTable *ft; struct WhiteNoise : public Unit { }; struct ClipNoise : public Unit { }; struct BrownNoise : public Unit { float mLevel; }; struct PinkNoise : public Unit { uint32 mDice[16]; int32 mTotal; }; struct Dust : public Unit { float m_density, m_thresh, m_scale; }; struct Dust2 : public Unit { float m_density, m_thresh, m_scale; }; struct GrayNoise : public Unit { int32 mCounter; }; struct Crackle : public Unit { double m_y1, m_y2; }; struct Logistic : public Unit { double m_y1; int mCounter; }; struct Hasher : public Unit { }; struct MantissaMask : public Unit { }; struct IRand : public Unit { }; struct Rand : public Unit { }; struct TRand : public Unit { float m_trig, m_value; }; struct TIRand : public Unit { float m_trig, m_value; }; struct TExpRand : public Unit { float m_trig, m_value; }; struct NRand : public Unit { }; struct LinRand : public Unit { }; struct ExpRand : public Unit { }; struct CoinGate : public Unit { float m_trig; }; struct LFClipNoise : public Unit { float mLevel; int mCounter; }; struct LFNoise0 : public Unit { float mLevel; int mCounter; }; struct LFNoise1 : public Unit { float mLevel, mSlope; int mCounter; }; struct LFNoise2 : public Unit { float mLevel, mSlope, mCurve; float m_nextvalue, m_nextmidpt; int mCounter; }; struct RandSeed : public Unit { float m_trig; }; struct RandID : public Unit { float m_id; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void WhiteNoise_next(WhiteNoise *unit, int inNumSamples); void WhiteNoise_Ctor(WhiteNoise* unit); void GrayNoise_next(GrayNoise *unit, int inNumSamples); void GrayNoise_Ctor(GrayNoise* unit); void ClipNoise_next(ClipNoise *unit, int inNumSamples); void ClipNoise_Ctor(ClipNoise* unit); void PinkNoise_next(PinkNoise *unit, int inNumSamples); void PinkNoise_Ctor(PinkNoise* unit); void BrownNoise_next(BrownNoise *unit, int inNumSamples); void BrownNoise_Ctor(BrownNoise* unit); void Dust_next(Dust *unit, int inNumSamples); void Dust_Ctor(Dust *unit); void Dust2_next(Dust2 *unit, int inNumSamples); void Dust2_Ctor(Dust2 *unit); void Crackle_next(Crackle *unit, int inNumSamples); void Crackle_Ctor(Crackle *unit); void Hasher_next(Hasher *unit, int inNumSamples); void Hasher_Ctor(Hasher *unit); void MantissaMask_next(MantissaMask *unit, int inNumSamples); void MantissaMask_Ctor(MantissaMask *unit); void IRand_Ctor(IRand *unit); void Rand_Ctor(Rand *unit); void LinRand_Ctor(LinRand* unit); void NRand_Ctor(NRand* unit); void ExpRand_Ctor(ExpRand *unit); void CoinGate_Ctor(CoinGate *unit); void CoinGate_next_k(CoinGate *unit, int inNumSamples); void CoinGate_next(CoinGate *unit, int inNumSamples); void TIRand_next_a(TIRand *unit, int inNumSamples); void TIRand_next_k(TIRand *unit, int inNumSamples); void TIRand_Ctor(TIRand *unit); void TRand_next_a(TRand *unit, int inNumSamples); void TRand_next_k(TRand *unit, int inNumSamples); void TRand_Ctor(TRand *unit); void TExpRand_next_a(TExpRand *unit, int inNumSamples); void TExpRand_next_k(TExpRand *unit, int inNumSamples); void TExpRand_Ctor(TExpRand *unit); void Logistic_next_1(Logistic *unit, int inNumSamples); void Logistic_next_k(Logistic *unit, int inNumSamples); void Logistic_Ctor(Logistic *unit); void LFClipNoise_next(LFClipNoise *unit, int inNumSamples); void LFClipNoise_Ctor(LFClipNoise *unit); void LFNoise0_next(LFNoise0 *unit, int inNumSamples); void LFNoise0_Ctor(LFNoise0 *unit); void LFNoise1_next(LFNoise1 *unit, int inNumSamples); void LFNoise1_Ctor(LFNoise1 *unit); void LFNoise2_next(LFNoise2 *unit, int inNumSamples); void LFNoise2_Ctor(LFNoise2 *unit); void RandSeed_next(RandSeed *unit, int inNumSamples); void RandSeed_next_k(RandSeed *unit, int inNumSamples); void RandSeed_Ctor(RandSeed *unit); void RandID_next(RandID *unit, int inNumSamples); void RandID_Ctor(RandID *unit); } ////////////////////////////////////////////////////////////////////////////////////////////////// void ClipNoise_next(ClipNoise *unit, int inNumSamples) { float *out = ZOUT(0); RGET LOOP1(inNumSamples, ZXP(out) = fcoin(s1, s2, s3); ); RPUT } void ClipNoise_Ctor(ClipNoise* unit) { SETCALC(ClipNoise_next); ClipNoise_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void GrayNoise_next(GrayNoise *unit, int inNumSamples) { float *out = ZOUT(0); RGET int counter = unit->mCounter; LOOP1(inNumSamples, counter ^= 1L << (trand(s1,s2,s3) & 31); ZXP(out) = counter * 4.65661287308e-10f; ); unit->mCounter = counter; RPUT } void GrayNoise_Ctor(GrayNoise* unit) { SETCALC(GrayNoise_next); unit->mCounter = 0; GrayNoise_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void WhiteNoise_next(WhiteNoise *unit, int inNumSamples) { float *out = ZOUT(0); RGET LOOP1(inNumSamples, ZXP(out) = frand2(s1, s2, s3); ); RPUT } void WhiteNoise_Ctor(WhiteNoise* unit) { SETCALC(WhiteNoise_next); WhiteNoise_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void PinkNoise_next(PinkNoise *unit, int inNumSamples) { float *out = ZOUT(0); RGET uint32 total = unit->mTotal; uint32 *dice = unit->mDice; LOOP1(inNumSamples, uint32 counter = trand(s1,s2,s3); // Magnus Jonsson's suggestion. uint32 newrand = counter >> 13; int k = (CTZ(counter)) & 15; uint32 prevrand = dice[k]; dice[k] = newrand; total += (newrand - prevrand); newrand = trand(s1,s2,s3) >> 13; elem32 val; // ensure write before read val.u = (total + newrand) | 0x40000000; ZXP(out) = val.f - 3.0f; counter ++; ); unit->mTotal = total; RPUT } void PinkNoise_Ctor(PinkNoise* unit) { SETCALC(PinkNoise_next); RGET uint32 *dice = unit->mDice; int32 total = 0; for (int i=0; i<16; ++i) { uint32 newrand = trand(s1,s2,s3) >> 13; total += newrand; dice[i] = newrand; } unit->mTotal = total; RPUT PinkNoise_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BrownNoise_next(BrownNoise *unit, int inNumSamples) { float *out = ZOUT(0); RGET float z = unit->mLevel; LOOP1(inNumSamples, z += frand8(s1, s2, s3); if (z > 1.f) z = 2.f - z; else if (z < -1.f) z = -2.f - z; ZXP(out) = z; ); unit->mLevel = z; RPUT } void BrownNoise_Ctor(BrownNoise* unit) { SETCALC(BrownNoise_next); unit->mLevel = unit->mParent->mRGen->frand2(); ZOUT0(0) = unit->mLevel; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Dust_Ctor(Dust *unit) { SETCALC(Dust_next); unit->m_density = 0.f; unit->m_scale = 0.f; unit->m_thresh = 0.f; Dust_next(unit, 1); } void Dust_next(Dust *unit, int inNumSamples) { float *out = ZOUT(0); float density = ZIN0(0); float thresh, scale; RGET if (density != unit->m_density) { thresh = unit->m_thresh = density * unit->mRate->mSampleDur; scale = unit->m_scale = thresh > 0.f ? 1.f / thresh : 0.f; unit->m_density = density; } else { thresh = unit->m_thresh; scale = unit->m_scale; } LOOP1(inNumSamples, float z = frand(s1,s2,s3); if (z < thresh) ZXP(out) = z * scale; else ZXP(out) = 0.f; ); RPUT } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Dust2_Ctor(Dust2 *unit) { SETCALC(Dust2_next); unit->m_density = 0.f; unit->m_scale = 0.f; unit->m_thresh = 0.f; Dust2_next(unit, 1); } void Dust2_next(Dust2 *unit, int inNumSamples) { float *out = ZOUT(0); float density = ZIN0(0); float thresh, scale; RGET if (density != unit->m_density) { thresh = unit->m_thresh = density * unit->mRate->mSampleDur; scale = unit->m_scale = thresh > 0.f ? 2.f / thresh : 0.f; unit->m_density = density; } else { thresh = unit->m_thresh; scale = unit->m_scale; } LOOP1(inNumSamples, float z = frand(s1,s2,s3); if (z < thresh) ZXP(out) = z * scale - 1.f; else ZXP(out) = 0.f; ); RPUT } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Crackle_next(Crackle *unit, int inNumSamples) { float *out = ZOUT(0); float paramf = ZIN0(0); float y1 = unit->m_y1; float y2 = unit->m_y2; float y0; LOOP1(inNumSamples, ZXP(out) = y0 = fabs(y1 * paramf - y2 - 0.05f); y2 = y1; y1 = y0; ); unit->m_y1 = y1; unit->m_y2 = y2; } void Crackle_Ctor(Crackle* unit) { SETCALC(Crackle_next); unit->m_y1 = unit->mParent->mRGen->drand(); unit->m_y2 = 0.f; Crackle_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Logistic_next_1(Logistic *unit, int inNumSamples) { float *out = ZOUT(0); double paramf = ZIN0(0); double y1 = unit->m_y1; LOOP1(inNumSamples, ZXP(out) = y1 = paramf * y1 * (1.0 - y1); // chaotic equation ); unit->m_y1 = y1; } void Logistic_next_k(Logistic *unit, int inNumSamples) { float *out = ZOUT(0); double paramf = ZIN0(0); float freq = ZIN0(1); double y1 = unit->m_y1; int32 counter = unit->mCounter; long remain = inNumSamples; do { if (counter<=0) { counter = (int32)(unit->mRate->mSampleRate / sc_max(freq, .001f)); counter = sc_max(1, counter); y1 = paramf * y1 * (1.0 - y1); // chaotic equation } long nsmps = sc_min(counter, remain); counter -= nsmps; remain -= nsmps; LOOP(nsmps, ZXP(out) = y1;); } while (remain); unit->m_y1 = y1; unit->mCounter = counter; } void Logistic_Ctor(Logistic* unit) { if (INRATE(0) == calc_ScalarRate && ZIN0(1) >= unit->mRate->mSampleRate) SETCALC(Logistic_next_1); else SETCALC(Logistic_next_k); unit->m_y1 = ZIN0(2); unit->mCounter = 0; Logistic_next_1(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Rand_Ctor(Rand* unit) { float lo = ZIN0(0); float hi = ZIN0(1); float range = hi - lo; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = rgen.frand() * range + lo; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void TRand_next_k(TRand* unit, int inNumSamples) { float trig = ZIN0(2); if (trig > 0.f && unit->m_trig <= 0.f) { float lo = ZIN0(0); float hi = ZIN0(1); float range = hi - lo; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = unit->m_value = rgen.frand() * range + lo; } else { ZOUT0(0) = unit->m_value; } unit->m_trig = trig; } void TRand_next_a(TRand* unit, int inNumSamples) { float lo = ZIN0(0); float hi = ZIN0(1); float *trig = ZIN(2); float prev = unit->m_trig; float *out = ZOUT(0); float outval = unit->m_value; float next; LOOP1(inNumSamples, next = ZXP(trig); if (next > 0.f && prev <= 0.f) { float range = hi - lo; RGen& rgen = *unit->mParent->mRGen; ZXP(out) = outval = rgen.frand() * range + lo; } else { ZXP(out) = outval; }; prev = next; ) unit->m_trig = next; unit->m_value = outval; } void TRand_next_aa(TRand* unit, int inNumSamples) { float *lo = ZIN(0); float *hi = ZIN(1); float *trig = ZIN(2); float prev = unit->m_trig; float *out = ZOUT(0); float outval = unit->m_value; float next; LOOP1(inNumSamples, next = ZXP(trig); if (next > 0.f && prev <= 0.f) { float loval = ZXP(lo); float range = ZXP(hi) - loval; RGen& rgen = *unit->mParent->mRGen; ZXP(out) = outval = rgen.frand() * range + loval; } else { ZXP(out) = outval; }; prev = next; ) unit->m_trig = next; unit->m_value = outval; } void TRand_Ctor(TRand* unit) { float lo = ZIN0(0); float hi = ZIN0(1); float range = hi - lo; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = unit->m_value = rgen.frand() * range + lo; if(unit->mCalcRate == calc_FullRate) { if(INRATE(0) == calc_FullRate) { SETCALC(TRand_next_aa); } else { SETCALC(TRand_next_a); } } else { SETCALC(TRand_next_k); } unit->m_trig = ZIN0(2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void TExpRand_next_k(TExpRand* unit, int inNumSamples) { float trig = ZIN0(2); if (trig > 0.f && unit->m_trig <= 0.f) { float lo = ZIN0(0); float hi = ZIN0(1); float ratio = hi / lo; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = unit->m_value = pow(ratio, rgen.frand()) * lo; } else { ZOUT0(0) = unit->m_value; } unit->m_trig = trig; } void TExpRand_next_a(TExpRand* unit, int inNumSamples) { float lo = ZIN0(0); float hi = ZIN0(1); float *trig = ZIN(2); float prev = unit->m_trig; float *out = ZOUT(0); float outval = unit->m_value; float next; LOOP1(inNumSamples, next = ZXP(trig); if (next > 0.f && prev <= 0.f) { float ratio = hi / lo; RGen& rgen = *unit->mParent->mRGen; ZXP(out) = outval = pow(ratio, rgen.frand()) * lo; } else { ZXP(out) = outval; } ) unit->m_trig = next; unit->m_value = outval; } void TExpRand_next_aa(TExpRand* unit, int inNumSamples) { float *lo = ZIN(0); float *hi = ZIN(1); float *trig = ZIN(2); float prev = unit->m_trig; float *out = ZOUT(0); float outval = unit->m_value; float next; LOOP1(inNumSamples, next = ZXP(trig); if (next > 0.f && prev <= 0.f) { float loval = ZXP(lo); float ratio = ZXP(hi) / loval; RGen& rgen = *unit->mParent->mRGen; ZXP(out) = outval = pow(ratio, rgen.frand()) * loval; } else { ZXP(out) = outval; } ) unit->m_trig = next; unit->m_value = outval; } void TExpRand_Ctor(TExpRand* unit) { float lo = ZIN0(0); float hi = ZIN0(1); float ratio = hi / lo; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = unit->m_value = pow(ratio, rgen.frand()) * lo; if(unit->mCalcRate == calc_FullRate) { if(INRATE(0) == calc_FullRate) { SETCALC(TExpRand_next_aa); } else { SETCALC(TExpRand_next_a); } } else { SETCALC(TExpRand_next_k); } unit->m_trig = ZIN0(2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void IRand_Ctor(IRand* unit) { int lo = (int)ZIN0(0); int hi = (int)ZIN0(1); int range = hi - lo + 1; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = (float)(rgen.irand(range) + lo); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void TIRand_next_k(TIRand* unit, int inNumSamples) { float trig = ZIN0(2); if (trig > 0.f && unit->m_trig <= 0.f) { int lo = (int)ZIN0(0); int hi = (int)ZIN0(1); int range = hi - lo + 1; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = unit->m_value = (float)(rgen.irand(range) + lo); } else { ZOUT0(0) = unit->m_value; } unit->m_trig = trig; } void TIRand_next_a(TIRand* unit, int inNumSamples) { int lo = (int)ZIN0(0); int hi = (int)ZIN0(1); float *trig = ZIN(2); float prev = unit->m_trig; float *out = ZOUT(0); float outval = unit->m_value; float next; LOOP1(inNumSamples, next = ZXP(trig); if (next > 0.f && prev <= 0.f) { int range = hi - lo + 1; RGen& rgen = *unit->mParent->mRGen; ZXP(out) = outval = (float)(rgen.irand(range) + lo); } else { ZXP(out) = outval; } ) unit->m_trig = next; unit->m_value = outval; } void TIRand_next_aa(TIRand* unit, int inNumSamples) { float *lo = ZIN(0); float *hi = ZIN(1); float *trig = ZIN(2); float prev = unit->m_trig; float *out = ZOUT(0); float outval = unit->m_value; float next; LOOP1(inNumSamples, next = ZXP(trig); if (next > 0.f && prev <= 0.f) { int loval = (int)ZXP(lo); int range = (int)ZXP(hi) - loval + 1; RGen& rgen = *unit->mParent->mRGen; ZXP(out) = outval = (float)(rgen.irand(range) + loval); } else { ZXP(out) = outval; } ) unit->m_trig = next; unit->m_value = outval; } void TIRand_Ctor(TIRand* unit) { int lo = (int)ZIN0(0); int hi = (int)ZIN0(1); int range = hi - lo + 1; RGen& rgen = *unit->mParent->mRGen; ZOUT0(0) = unit->m_value = (float)(rgen.irand(range) + lo); if(unit->mCalcRate == calc_FullRate) { if(INRATE(0) == calc_FullRate) { SETCALC(TIRand_next_aa); } else { SETCALC(TIRand_next_a); } } else { SETCALC(TIRand_next_k); } unit->m_trig = ZIN0(2); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void CoinGate_Ctor(CoinGate* unit) { if (unit->mCalcRate == calc_FullRate) { SETCALC(CoinGate_next); } else { SETCALC(CoinGate_next_k); } unit->m_trig = ZIN0(1); } void CoinGate_next_k(CoinGate* unit, int inNumSamples) { float trig = ZIN0(1); float level = 0.f; RGen& rgen = *unit->mParent->mRGen; if (trig > 0.f && unit->m_trig <= 0.f) { if(rgen.frand() < ZIN0(0)) { level = trig; } } ZOUT0(0) = level; unit->m_trig = trig; } void CoinGate_next(CoinGate* unit, int inNumSamples) { float *trig = ZIN(1); float *out = ZOUT(0); float prevtrig = unit->m_trig; float probability = ZIN0(0); RGen& rgen = *unit->mParent->mRGen; LOOP1(inNumSamples, float curtrig = ZXP(trig); float level = 0.f; if (prevtrig <= 0.f && curtrig > 0.f) { if(rgen.frand() < probability) { level = curtrig; } else { level = 0.f; } } prevtrig = curtrig; ZXP(out) = level; ) unit->m_trig = prevtrig; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void RandSeed_Ctor(RandSeed* unit) { unit->m_trig = 0.; if(unit->mCalcRate == calc_FullRate){ SETCALC(RandSeed_next); } else { SETCALC(RandSeed_next_k); } RandSeed_next(unit, 1); } void RandSeed_next_k(RandSeed* unit, int inNumSamples) { float trig = ZIN0(0); if (trig > 0.f && unit->m_trig <= 0.f) { RGen& rgen = *unit->mParent->mRGen; int seed = (int)DEMANDINPUT_A(1, inNumSamples); rgen.init(seed); } unit->m_trig = trig; ZOUT0(0) = 0.f; } void RandSeed_next(RandSeed* unit, int inNumSamples) { float *trig = ZIN(0); float *out = ZOUT(0); float prevtrig = unit->m_trig; float curtrig; LOOP1(inNumSamples, curtrig = ZXP(trig); if (curtrig > 0.f && prevtrig <= 0.f) { RGen& rgen = *unit->mParent->mRGen; int seed = (int)DEMANDINPUT_A(1, inNumSamples); rgen.init(seed); } prevtrig = curtrig; ZXP(out) = 0.f; ) unit->m_trig = curtrig; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void RandID_Ctor(RandID* unit) { unit->m_id = -1.; SETCALC(RandID_next); RandID_next(unit, 1); } void RandID_next(RandID* unit, int inNumSamples) { float id = ZIN0(0); if (id != unit->m_id) { unit->m_id = id; uint32 iid = (uint32)id; if (iid < unit->mWorld->mNumRGens) { unit->mParent->mRGen = unit->mWorld->mRGen + iid; } } ZOUT0(0) = 0.f; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LinRand_Ctor(LinRand* unit) { float lo = ZIN0(0); float hi = ZIN0(1); int n = (int)ZIN0(2); float range = hi - lo; RGen& rgen = *unit->mParent->mRGen; float a, b; a = rgen.frand(); b = rgen.frand(); if (n <= 0) { ZOUT0(0) = sc_min(a, b) * range + lo; } else { ZOUT0(0) = sc_max(a, b) * range + lo; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void NRand_Ctor(NRand* unit) { float lo = ZIN0(0); float hi = ZIN0(1); int n = (int)ZIN0(2); float range = hi - lo; RGen& rgen = *unit->mParent->mRGen; float sum = 0; for (int i=0; imParent->mRGen->frand()) * lo; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Hasher_next(Hasher *unit, int inNumSamples) { int32 *in = (int32*)ZIN(0); float *out = ZOUT(0); LOOP1(inNumSamples, union { float f; int i; } u; int z = ZXP(in); u.i = 0x40000000 | ((uint32)Hash(z) >> 9); ZXP(out) = u.f - 3.f; ); } void Hasher_Ctor(Hasher* unit) { SETCALC(Hasher_next); Hasher_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void MantissaMask_next(MantissaMask *unit, int inNumSamples) { int32 *in = (int32*)ZIN(0); int32 bits = (int32)ZIN0(1); int32 *out = (int32*)ZOUT(0); int32 mask = -1 << (23 - bits); LOOP1(inNumSamples, ZXP(out) = mask & ZXP(in); ); } void MantissaMask_Ctor(MantissaMask* unit) { SETCALC(MantissaMask_next); MantissaMask_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LFClipNoise_next(LFClipNoise *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float level = unit->mLevel; int32 counter = unit->mCounter; RGET int remain = inNumSamples; do { if (counter<=0) { counter = (int)(unit->mRate->mSampleRate / sc_max(freq, .001f)); counter = sc_max(1, counter); level = fcoin(s1,s2,s3); } int nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; LOOP(nsmps, ZXP(out) = level;); } while (remain); unit->mLevel = level; unit->mCounter = counter; RPUT } void LFClipNoise_Ctor(LFClipNoise* unit) { SETCALC(LFClipNoise_next); unit->mCounter = 0; unit->mLevel = 0.f; LFClipNoise_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LFNoise0_next(LFNoise0 *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float level = unit->mLevel; int32 counter = unit->mCounter; RGET int remain = inNumSamples; do { if (counter<=0) { counter = (int32)(unit->mRate->mSampleRate / sc_max(freq, .001f)); counter = sc_max(1, counter); level = frand2(s1,s2,s3); } int nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; LOOP(nsmps, ZXP(out) = level;); } while (remain); unit->mLevel = level; unit->mCounter = counter; RPUT } void LFNoise0_next_1(LFNoise0 *unit, int inNumSamples) { assert(inNumSamples == 1); float freq = ZIN0(0); float level = unit->mLevel; int32 counter = unit->mCounter; if (counter<=0) { counter = (int32)(unit->mRate->mSampleRate / sc_max(freq, .001f)); counter = sc_max(1, counter); RGET level = frand2(s1,s2,s3); unit->mLevel = level; RPUT } ZOUT0(0) = level; counter -= 1; unit->mCounter = counter; } void LFNoise0_Ctor(LFNoise0* unit) { if (BUFLENGTH == 1) SETCALC(LFNoise0_next_1); else SETCALC(LFNoise0_next); unit->mCounter = 0; unit->mLevel = 0.f; LFNoise0_next_1(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LFNoise1_next(LFNoise1 *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float level = unit->mLevel; float slope = unit->mSlope; int32 counter = unit->mCounter; RGET int remain = inNumSamples; do { if (counter<=0) { counter = (int32)(unit->mRate->mSampleRate / sc_max(freq, .001f)); counter = sc_max(1, counter); float nextlevel = frand2(s1,s2,s3); slope = (nextlevel - level) / counter; } int nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; LOOP(nsmps, ZXP(out) = level; level += slope;); } while (remain); unit->mLevel = level; unit->mSlope = slope; unit->mCounter = counter; RPUT } void LFNoise1_Ctor(LFNoise1* unit) { SETCALC(LFNoise1_next); unit->mCounter = 0; unit->mLevel = unit->mParent->mRGen->frand2(); unit->mSlope = 0.f; LFNoise1_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LFNoise2_next(LFNoise2 *unit, int inNumSamples) { float *out = ZOUT(0); float freq = ZIN0(0); float level = unit->mLevel; float slope = unit->mSlope; float curve = unit->mCurve; int counter = unit->mCounter; RGET int remain = inNumSamples; do { if (counter<=0) { float value = unit->m_nextvalue; unit->m_nextvalue = frand2(s1,s2,s3); level = unit->m_nextmidpt; unit->m_nextmidpt = (unit->m_nextvalue + value) * .5; counter = (int32)(unit->mRate->mSampleRate / sc_max(freq, .001f)); counter = sc_max(2, counter); float fseglen = (float)counter; curve = 2.f * (unit->m_nextmidpt - level - fseglen * slope) / (fseglen * fseglen + fseglen); } int nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; LOOP(nsmps, ZXP(out) = level; slope += curve; level += slope; ); } while (remain); unit->mLevel = level; unit->mSlope = slope; unit->mCurve = curve; unit->mCounter = counter; RPUT } void LFNoise2_Ctor(LFNoise2* unit) { SETCALC(LFNoise2_next); unit->mCounter = 0; unit->mSlope = 0.f; unit->mLevel = 0.f; unit->m_nextvalue = unit->mParent->mRGen->frand2(); unit->m_nextmidpt = unit->m_nextvalue * .5f; LFNoise2_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void WrapBufRd_next0(Unit *unit, int inNumSamples); void WrapBufRd_next0(Unit *unit, int inNumSamples) { int bufnum = (int)ZIN0(0); float *pos = ZIN(1); const SndBuf *buf = unit->mWorld->mSndBufs + bufnum; int numchan = buf->channels; LOCK_SNDBUF_SHARED(buf); if (numchan != unit->mNumOutputs) { ClearUnitOutputs(unit, inNumSamples); return; } const float *data = buf->data; int numframes = buf->frames; float *out[16]; for (int i=0; imWorld->mSndBufs + bufnum; LOCK_SNDBUF_SHARED(buf); int numchan = buf->channels; if (numchan != unit->mNumOutputs) { ClearUnitOutputs(unit, inNumSamples); return; } const float *data = buf->data; int numframes = buf->frames; int maxframe = numframes - 2; float *out[16]; for (int i=0; ioutval rather than -1 when FFT not triggered #define Onsets_GET_BUF \ float fbufnum = ZIN0(0); \ if (fbufnum < 0.f) { ZOUT0(0) = unit->outval; return; } \ ZOUT0(0) = fbufnum; \ uint32 ibufnum = (uint32)fbufnum; \ World *world = unit->mWorld; \ SndBuf *buf; \ if (ibufnum >= world->mNumSndBufs) { \ int localBufNum = ibufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ buf = world->mSndBufs; \ } \ } else { \ buf = world->mSndBufs + ibufnum; \ } \ LOCK_SNDBUF(buf); \ ////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void Onsets_Ctor(Onsets *unit) { if(ZIN0(8)>0) SETCALC(Onsets_next_rawodf); else SETCALC(Onsets_next); unit->m_needsinit = true; unit->m_ods = (OnsetsDS*) RTAlloc(unit->mWorld, sizeof(OnsetsDS) ); ZOUT0(0) = unit->outval = 0.f; } void Onsets_next(Onsets *unit, int inNumSamples) { Onsets_GET_BUF // In practice, making the polar conversion here in SC is more efficient because SC provides a lookup table method. SCPolarBuf *p = ToPolarApx(buf); OnsetsDS *ods = unit->m_ods; int odftype = (int)ZIN0(2); float relaxtime = ZIN0(3); int medspan = (int)ZIN0(6); if(unit->m_needsinit){ // Init happens here because we need to be sure about FFT size. unit->m_odsdata = (float*) RTAlloc(unit->mWorld, onsetsds_memneeded(odftype, buf->samples, medspan) ); onsetsds_init(ods, unit->m_odsdata, ODS_FFT_SC3_POLAR, odftype, buf->samples, medspan, FULLRATE); onsetsds_setrelax(ods, relaxtime, buf->samples>>1); unit->m_needsinit = false; } // Here is the best place to set parameters - after init is ensured // These are "painless" to set: ods->thresh = ZIN0(1); ods->floor = ZIN0(4); ods->mingap = (int)ZIN0(5); ods->whtype = (int)ZIN0(7); // Now to process unit->outval = onsetsds_process(ods, (float*) p); ZOUT0(0) = unit->outval; } void Onsets_next_rawodf(Onsets *unit, int inNumSamples) { Onsets_GET_BUF // In practice, making the polar conversion here in SC is more efficient because SC provides a lookup table method. SCPolarBuf *p = ToPolarApx(buf); OnsetsDS *ods = unit->m_ods; int odftype = (int)ZIN0(2); float relaxtime = ZIN0(3); int medspan = (int)ZIN0(6); if(unit->m_needsinit){ // Init happens here because we need to be sure about FFT size. unit->m_odsdata = (float*) RTAlloc(unit->mWorld, onsetsds_memneeded(odftype, buf->samples, medspan) ); onsetsds_init(ods, unit->m_odsdata, ODS_FFT_SC3_POLAR, odftype, buf->samples, medspan, FULLRATE); onsetsds_setrelax(ods, relaxtime, buf->samples>>1); unit->m_needsinit = false; } // Here is the best place to set parameters - after init is ensured // These are "painless" to set: ods->thresh = ZIN0(1); ods->floor = ZIN0(4); ods->mingap = (int)ZIN0(5); ods->whtype = (int)ZIN0(7); // Now to process onsetsds_process(ods, (float*) p); // But we want the ODF, not the triggers, for this special mode... //unit->outval = ods->odfvalpost; unit->outval = ods->odfvals[0]; ZOUT0(0) = unit->outval; } void Onsets_Dtor(Onsets *unit) { if(!unit->m_needsinit){ RTFree(unit->mWorld, unit->m_odsdata); } RTFree(unit->mWorld, unit->m_ods); } SuperCollider-Source/server/plugins/Onsets.h000644 000765 000024 00000002450 12321461511 022265 0ustar00crucialstaff000000 000000 /* Onset detector for SuperCollider Copyright (c) 2007 Dan Stowell. All rights reserved. http://onsetsds.sourceforge.net Now part of: SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "onsetsds.h" struct Onsets : Unit { float outval; float *m_odsdata; OnsetsDS *m_ods; bool m_needsinit; }; extern "C" { void Onsets_Ctor(Onsets *unit); void Onsets_next(Onsets *unit, int inNumSamples); void Onsets_next_rawodf(Onsets *unit, int inNumSamples); void Onsets_Dtor(Onsets *unit); } SuperCollider-Source/server/plugins/onsetsds.c000644 000765 000024 00000036750 12450771573 022700 0ustar00crucialstaff000000 000000 /* OnsetsDS - real time musical onset detection library. Copyright (c) 2007 Dan Stowell. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "onsetsds.h" #define ODS_DEBUG_POST_CSV 0 #ifdef _MSC_VER // msvc doesn't support c99 #define hypotf _hypotf #define inline /* inline */ #endif static inline float onsetsds_phase_rewrap(float phase){ return (phase>MINUSPI && phase> 1) - 1; // No of bins, not counting DC/nyq switch(odftype){ case ODS_ODF_POWER: case ODS_ODF_MAGSUM: // No old FFT frames needed, easy: return (medspan+medspan + fftsize + numbins + 2) * sizeof(float); case ODS_ODF_COMPLEX: case ODS_ODF_RCOMPLEX: return (medspan+medspan + fftsize + numbins + 2 // For each bin (NOT dc/nyq) we store mag, phase and d_phase + numbins + numbins + numbins ) * sizeof(float); case ODS_ODF_PHASE: case ODS_ODF_WPHASE: return (medspan+medspan + fftsize + numbins + 2 // For each bin (NOT dc/nyq) we store phase and d_phase + numbins + numbins ) * sizeof(float); case ODS_ODF_MKL: return (medspan+medspan + fftsize + numbins + 2 // For each bin (NOT dc/nyq) we store mag + numbins ) * sizeof(float); break; } return -1; //bleh } void onsetsds_init(OnsetsDS *ods, float *odsdata, int fftformat, int odftype, size_t fftsize, unsigned int medspan, float srate){ int numbins, realnumbins; // The main pointer to the processing area - other pointers will indicate areas within this ods->data = odsdata; // Set all vals in processing area to zero memset(odsdata, 0, onsetsds_memneeded(odftype, fftsize, medspan)); ods->srate = srate; numbins = (fftsize >> 1) - 1; // No of bins, not counting DC/nyq realnumbins = numbins + 2; // Also point the other pointers to the right places ods->curr = (OdsPolarBuf*) odsdata; ods->psp = odsdata + fftsize; ods->odfvals = odsdata + fftsize + realnumbins; ods->sortbuf = odsdata + fftsize + realnumbins + medspan; ods->other = odsdata + fftsize + realnumbins + medspan + medspan; // Default settings for Adaptive Whitening, user can set own values after init onsetsds_setrelax(ods, 1.f, fftsize>>1); ods->floor = 0.1; switch(odftype){ case ODS_ODF_POWER: ods->odfparam = 0.01; // "powthresh" in SC code ods->normfactor = 2560.f / (realnumbins * fftsize); break; case ODS_ODF_MAGSUM: ods->odfparam = 0.01; // "powthresh" in SC code ods->normfactor = 113.137085f / (realnumbins * sqrt(fftsize)); break; case ODS_ODF_COMPLEX: ods->odfparam = 0.01; // "powthresh" in SC code ods->normfactor = 231.70475f / pow(fftsize, 1.5);// / fftsize; break; case ODS_ODF_RCOMPLEX: ods->odfparam = 0.01; // "powthresh" in SC code ods->normfactor = 231.70475f / pow(fftsize, 1.5);// / fftsize; break; case ODS_ODF_PHASE: ods->odfparam = 0.01; // "powthresh" in SC code ods->normfactor = 5.12f / fftsize;// / fftsize; break; case ODS_ODF_WPHASE: ods->odfparam = 0.0001; // "powthresh" in SC code. For WPHASE it's kind of superfluous. ods->normfactor = 115.852375f / pow(fftsize, 1.5);// / fftsize; break; case ODS_ODF_MKL: ods->odfparam = 0.01; // EPSILON parameter. Brossier recommends 1e-6 but I (ICMC 2007) found larger vals (e.g 0.01) to work better ods->normfactor = 7.68f * 0.25f / fftsize; break; default: printf("onsetsds_init ERROR: \"odftype\" is not a recognised value\n"); } ods->odfvalpost = 0.f; ods->odfvalpostprev = 0.f; ods->thresh = 0.5f; ods->logmags = false; ods->odftype = odftype; ods->whtype = ODS_WH_ADAPT_MAX1; ods->fftformat = fftformat; ods->whiten = (odftype != ODS_ODF_MKL); // Deactivate whitening for MKL by default ods->detected = false; ods->med_odd = (medspan & 1) != 0; ods->medspan = medspan; ods->mingap = 0; ods->gapleft = 0; ods->fftsize = fftsize; ods->numbins = numbins; //printf("End of _init: normfactor is %g\n", ods->normfactor); } bool onsetsds_process(OnsetsDS* ods, float* fftbuf){ onsetsds_loadframe(ods, fftbuf); onsetsds_whiten(ods); onsetsds_odf(ods); onsetsds_detect(ods); return ods->detected; } void onsetsds_setrelax(OnsetsDS* ods, float time, size_t hopsize){ ods->relaxtime = time; ods->relaxcoef = (time == 0.0f) ? 0.0f : exp((ods_log1 * hopsize)/(time * ods->srate)); } void onsetsds_loadframe(OnsetsDS* ods, float* fftbuf){ float *pos, *pos2, imag, real; int i; switch(ods->fftformat){ case ODS_FFT_SC3_POLAR: // The format is the same! dc, nyq, mag[1], phase[1], ... memcpy(ods->curr, fftbuf, ods->fftsize * sizeof(float)); break; case ODS_FFT_SC3_COMPLEX: ods->curr->dc = fftbuf[0]; ods->curr->nyq = fftbuf[1]; // Then convert cartesian to polar: pos = fftbuf + 2; for(i=0; i< (ods->numbins << 1); i += 2){ real = pos[i]; imag = pos[i+1]; // Plus 1 rather than increment; seems to avoid LSU reject on my PPC ods->curr->bin[i].mag = hypotf(imag, real); ods->curr->bin[i].phase = atan2f(imag, real); } break; case ODS_FFT_FFTW3_HC: ods->curr->dc = fftbuf[0]; ods->curr->nyq = fftbuf[ods->fftsize>>1]; // Then convert cartesian to polar: // (Starting positions: real and imag for bin 1) pos = fftbuf + 1; pos2 = fftbuf + ods->fftsize - 1; for(i=0; inumbins; i++){ real = *(pos++); imag = *(pos2--); ods->curr->bin[i].mag = hypotf(imag, real); ods->curr->bin[i].phase = atan2f(imag, real); } break; case ODS_FFT_FFTW3_R2C: ods->curr->dc = fftbuf[0]; ods->curr->nyq = fftbuf[ods->fftsize]; // Then convert cartesian to polar: pos = fftbuf + 2; for(i=0; inumbins; i++){ real = *(pos++); imag = *(pos++); ods->curr->bin[i].mag = hypotf(imag, real); ods->curr->bin[i].phase = atan2f(imag, real); } break; } // Conversion to log-domain magnitudes, including re-scaling to aim back at the zero-to-one range. // Not well tested yet. if(ods->logmags){ for(i=0; inumbins; i++){ ods->curr->bin[i].mag = (log(ods_max(ods->curr->bin[i].mag, ODS_LOG_LOWER_LIMIT)) - ODS_LOGOF_LOG_LOWER_LIMIT) * ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT; } ods->curr->dc = (log(ods_max(ods_abs(ods->curr->dc ), ODS_LOG_LOWER_LIMIT)) - ODS_LOGOF_LOG_LOWER_LIMIT) * ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT; ods->curr->nyq = (log(ods_max(ods_abs(ods->curr->nyq), ODS_LOG_LOWER_LIMIT)) - ODS_LOGOF_LOG_LOWER_LIMIT) * ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT; } } void onsetsds_whiten(OnsetsDS* ods){ float val,oldval, relaxcoef, floor; int numbins, i; OdsPolarBuf *curr; float *psp; float *pspp1; // Offset by 1, avoids quite a lot of "+1"s in the following code if(ods->whtype == ODS_WH_NONE){ //printf("onsetsds_whiten(): ODS_WH_NONE, skipping\n"); return; } // NB: Apart from the above, ods->whtype is currently IGNORED and only one mode is used. relaxcoef = ods->relaxcoef; numbins = ods->numbins; curr = ods->curr; psp = ods->psp; pspp1 = psp + 1; floor = ods->floor; //printf("onsetsds_whiten: relaxcoef=%g, relaxtime=%g, floor=%g\n", relaxcoef, ods->relaxtime, floor); ////////////////////// For each bin, update the record of the peak value ///////////////////// val = fabs(curr->dc); // Grab current magnitude oldval = psp[0]; // If it beats the amplitude stored then that's our new amplitude; // otherwise our new amplitude is a decayed version of the old one if(val < oldval) { val = val + (oldval - val) * relaxcoef; } psp[0] = val; // Store the "amplitude trace" back val = fabs(curr->nyq); oldval = pspp1[numbins]; if(val < oldval) { val = val + (oldval - val) * relaxcoef; } pspp1[numbins] = val; for(i=0; ibin[i].mag); oldval = pspp1[i]; if(val < oldval) { val = val + (oldval - val) * relaxcoef; } pspp1[i] = val; } //////////////////////////// Now for each bin, rescale the current magnitude //////////////////////////// curr->dc /= ods_max(floor, psp[0]); curr->nyq /= ods_max(floor, pspp1[numbins]); for(i=0; ibin[i].mag /= ods_max(floor, pspp1[i]); } } void onsetsds_odf(OnsetsDS* ods){ int numbins = ods->numbins; OdsPolarBuf *curr = ods->curr; float* val = ods->odfvals; int i, tbpointer; float deviation, diff, curmag; double totdev; float predmag, predphase, yesterphase, yesterphasediff; float yestermag; bool rectify = true; // Here we shunt the "old" ODF values down one place memcpy(val + 1, val, (ods->medspan - 1)*sizeof(float)); // Now calculate a new value and store in ods->odfvals[0] switch(ods->odftype){ case ODS_ODF_POWER: *val = (curr->nyq * curr->nyq) + (curr->dc * curr->dc); for(i=0; ibin[i].mag * curr->bin[i].mag; } break; case ODS_ODF_MAGSUM: *val = ods_abs(curr->nyq) + ods_abs(curr->dc); for(i=0; ibin[i].mag); } break; case ODS_ODF_COMPLEX: rectify = false; // ...and then drop through to: case ODS_ODF_RCOMPLEX: // Note: "other" buf is stored in this format: mag[0],phase[0],d_phase[0],mag[1],phase[1],d_phase[1], ... // Iterate through, calculating the deviation from expected value. totdev = 0.0; tbpointer = 0; for (i=0; ibin[i].mag); // Predict mag as yestermag predmag = ods->other[tbpointer++]; yesterphase = ods->other[tbpointer++]; yesterphasediff = ods->other[tbpointer++]; // Thresholding as Brossier did - discard (ignore) bin's deviation if bin's power is minimal if(curmag > ods->odfparam) { // If rectifying, ignore decreasing bins if((!rectify) || !(curmag < predmag)){ // Predict phase as yesterval + yesterfirstdiff predphase = yesterphase + yesterphasediff; // Here temporarily using the "deviation" var to store the phase difference // so that the rewrap macro can use it more efficiently deviation = predphase - curr->bin[i].phase; // Deviation is Euclidean distance between predicted and actual. // In polar coords: sqrt(r1^2 + r2^2 - r1r2 cos (theta1 - theta2)) deviation = sqrtf(predmag * predmag + curmag * curmag - predmag * curmag * cosf(onsetsds_phase_rewrap(deviation)) ); totdev += deviation; } } } // totdev will be the output, but first we need to fill tempbuf with today's values, ready for tomorrow. tbpointer = 0; for (i=0; iother[tbpointer++] = ods_abs(curr->bin[i].mag); // Storing mag diff = curr->bin[i].phase - ods->other[tbpointer]; // Retrieving yesterphase from buf ods->other[tbpointer++] = curr->bin[i].phase; // Storing phase // Wrap onto +-PI range diff = onsetsds_phase_rewrap(diff); ods->other[tbpointer++] = diff; // Storing first diff to buf } *val = (float)totdev; break; case ODS_ODF_PHASE: rectify = false; // So, actually, "rectify" means "useweighting" in this context // ...and then drop through to: case ODS_ODF_WPHASE: // Note: "other" buf is stored in this format: phase[0],d_phase[0],phase[1],d_phase[1], ... // Iterate through, calculating the deviation from expected value. totdev = 0.0; tbpointer = 0; for (i=0; ibin[i].mag) > ods->odfparam) { // Deviation is the *second difference* of the phase, which is calc'ed as curval - yesterval - yesterfirstdiff deviation = curr->bin[i].phase - ods->other[tbpointer] - ods->other[tbpointer+1]; tbpointer += 2; // Wrap onto +-PI range deviation = onsetsds_phase_rewrap(deviation); if(rectify){ // "rectify" meaning "useweighting"... totdev += fabs(deviation * ods_abs(curr->bin[i].mag)); } else { totdev += fabs(deviation); } } } // totdev will be the output, but first we need to fill tempbuf with today's values, ready for tomorrow. tbpointer = 0; for (i=0; ibin[i].phase - ods->other[tbpointer]; // Retrieving yesterphase from buf ods->other[tbpointer++] = curr->bin[i].phase; // Storing phase // Wrap onto +-PI range diff = onsetsds_phase_rewrap(diff); ods->other[tbpointer++] = diff; // Storing first diff to buf } *val = (float)totdev; break; case ODS_ODF_MKL: // Iterate through, calculating the Modified Kullback-Liebler distance totdev = 0.0; tbpointer = 0; for (i=0; ibin[i].mag); yestermag = ods->other[tbpointer]; // Here's the main implementation of Brossier's MKL eq'n (eqn 2.9 from his thesis): deviation = ods_abs(curmag) / (ods_abs(yestermag) + ods->odfparam); totdev += log(1.f + deviation); // Store the mag as yestermag ods->other[tbpointer++] = curmag; } *val = (float)totdev; break; } #if ODS_DEBUG_POST_CSV printf("%g,", *val); printf("%g,", ods->odfvals[0] * ods->normfactor); #endif ods->odfvals[0] *= ods->normfactor; } // End of ODF function void SelectionSort(float *array, int length); void SelectionSort(float *array, int length) { // Algo is simply based on http://en.wikibooks.org/wiki/Algorithm_implementation/Sorting/Selection_sort int max, i; float temp; while(length > 0) { max = 0; for(i = 1; i < length; i++) if(array[i] > array[max]) max = i; temp = array[length-1]; array[length-1] = array[max]; array[max] = temp; length--; } } void onsetsds_detect(OnsetsDS* ods){ float* sortbuf = ods->sortbuf; int medspan = ods->medspan; // Shift the yesterval to its rightful place ods->odfvalpostprev = ods->odfvalpost; ///////// MEDIAN REMOVAL //////////// // Copy odfvals to sortbuf memcpy(sortbuf, ods->odfvals, medspan * sizeof(float)); // Sort sortbuf SelectionSort(sortbuf, medspan); // Subtract the middlest value === the median if(ods->med_odd){ ods->odfvalpost = ods->odfvals[0] - sortbuf[(medspan - 1) >> 1]; }else{ ods->odfvalpost = ods->odfvals[0] - ((sortbuf[medspan >> 1] + sortbuf[(medspan >> 1) - 1]) * 0.5f); } // Detection not allowed if we're too close to a previous detection. if(ods->gapleft != 0) { ods->gapleft--; ods->detected = false; } else { // Now do the detection. ods->detected = (ods->odfvalpost > ods->thresh) && (ods->odfvalpostprev <= ods->thresh); if(ods->detected){ ods->gapleft = ods->mingap; } } #if ODS_DEBUG_POST_CSV printf("%g\n", ods->odfvalpost); #endif } SuperCollider-Source/server/plugins/onsetsds.h000644 000765 000024 00000024667 12321461511 022672 0ustar00crucialstaff000000 000000 /* OnsetsDS - real time musical onset detection library. Copyright (c) 2007 Dan Stowell. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** \file */ #ifndef _OnsetsDS_ #define _OnsetsDS_ #ifdef __cplusplus extern "C" { #endif #include #include #include #include //////////////////////////////////////////////////////////////////////////////// // Macros and consts //log(0.1) #define ods_log1 -2.30258509 #define PI 3.1415926535898f #define MINUSPI -3.1415926535898f #define TWOPI 6.28318530717952646f #define INV_TWOPI 0.1591549430919f #define ods_abs(a) ((a)<0? -(a) : (a)) #define ods_max(a,b) (((a) > (b)) ? (a) : (b)) #define ods_min(a,b) (((a) < (b)) ? (a) : (b)) #define ODS_LOG_LOWER_LIMIT 2e-42 #define ODS_LOGOF_LOG_LOWER_LIMIT -96.0154267 #define ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT 0.010414993 //////////////////////////////////////////////////////////////////////////////// // Constants /** * Types of incoming FFT data format. OnsetsDS needs to know where the FFT * data comes from in order to interpret it correctly. */ enum onsetsds_fft_types { ODS_FFT_SC3_COMPLEX, ///< SuperCollider, cartesian co-ords ("SCComplexBuf") - NB it's more efficient to provide polar data from SC ODS_FFT_SC3_POLAR, ///< SuperCollider, polar co-ords ("SCPolarBuf") ODS_FFT_FFTW3_HC, ///< FFTW "halfcomplex" format ODS_FFT_FFTW3_R2C ///< FFTW regular format, typically produced using real-to-complex transform }; /** * Types of onset detection function */ enum onsetsds_odf_types { ODS_ODF_POWER, ///< Power ODS_ODF_MAGSUM, ///< Sum of magnitudes ODS_ODF_COMPLEX, ///< Complex-domain deviation ODS_ODF_RCOMPLEX, ///< Complex-domain deviation, rectified (only increases counted) ODS_ODF_PHASE, ///< Phase deviation ODS_ODF_WPHASE, ///< Weighted phase deviation ODS_ODF_MKL ///< Modified Kullback-Liebler deviation }; /** * Types of whitening - may not all be implemented yet. */ enum onsetsds_wh_types { ODS_WH_NONE, ///< No whitening - onsetsds_whiten() becomes a no-op ODS_WH_ADAPT_MAX1, ///< Adaptive whitening - tracks recent-peak-magnitude in each bin, normalises that to 1 ODS_WH_NORMMAX, ///< Simple normalisation - each frame is normalised (independent of others) so largest magnitude becomes 1. Not implemented. ODS_WH_NORMMEAN ///< Simple normalisation - each frame is normalised (independent of others) so mean magnitude becomes 1. Not implemented. }; //////////////////////////////////////////////////////////////////////////////// // Structs typedef struct OdsPolarBin { float mag, phase; } OdsPolarBin; typedef struct OdsPolarBuf { float dc, nyq; OdsPolarBin bin[1]; } OdsPolarBuf; /// The main data structure for the onset detection routine typedef struct OnsetsDS { /// "data" is a pointer to the memory that must be EXTERNALLY allocated. /// Other pointers will point to locations within this memory. float *data, *psp, ///< Peak Spectral Profile - size is numbins+2, data is stored in order dc through to nyquist *odfvals, // odfvals[0] will be the current val, odfvals[1] prev, etc *sortbuf, // Used to calculate the median *other; // Typically stores data about the previous frame OdsPolarBuf* curr; // Current FFT frame, as polar float srate, ///< The sampling rate of the input audio. Set by onsetsds_init() // Adaptive whitening params relaxtime, ///< Do NOT set this directly. Use onsetsds_setrelax() which will also update relaxcoef. relaxcoef, ///< Relaxation coefficient (memory coefficient). See also onsetsds_setrelax() floor, ///< floor - the lowest value that a PSP magnitude can take. /// A parameter for the ODF. For most this is a magnitude threshold for a single bin to be considered; /// but for #ODS_ODF_MKL it is the "epsilon" parameter. odfparam, /// Value used internally to scale ODF value according to the FFT frame size. Automatically set by onsetsds_init() normfactor, // ODF val after median processing odfvalpost, // Previous val is needed for threshold-crossing detection odfvalpostprev, /// Threshold (of ODF value, after median processing) for detection. /// Values between 0 and 1 are expected, but outside this range may /// sometimes be appropriate too. thresh; int odftype, ///< Choose from #onsetsds_odf_types whtype, ///< Choose from #onsetsds_wh_types fftformat; ///< Choose from #onsetsds_fft_types bool whiten, ///< Whether to apply whitening - onsetsds_init() decides this on your behalf detected,///< Output val - true if onset detected in curr frame /** NOT YET USED: Whether to convert magnitudes to log domain before processing. This is done as follows: Magnitudes below a log-lower-limit threshold (ODS_LOG_LOWER_LIMIT) are pushed up to that threshold (to avoid log(0) infinity problems), then the log is taken. The values are re-scaled to a similar range as the linear-domain values (assumed to lie between zero and approximately one) by subtracting log(ODS_LOG_LOWER_LIMIT) and then dividing by abs(log(ODS_LOG_LOWER_LIMIT)). */ logmags, med_odd; ///< Whether median span is odd or not (used internally) unsigned int /// Number of frames used in median calculation medspan, /// Size of enforced gap between detections, measured in FFT frames. mingap, gapleft; size_t fftsize, numbins; // numbins is the count not including DC/nyq } OnsetsDS; //////////////////////////////////////////////////////////////////////////////// // Function prototypes /** * \defgroup MainUserFuncs Main user functions */ //@{ /** * Determine how many bytes of memory must be allocated (e.g. using malloc) to * accompany the OnsetsDS struct, operating using the specified settings (used to * store part-processed FFT data etc). The user must * call this, and then allocate the memory, BEFORE calling onsetsds_init(). * @param odftype Which onset detection function (ODF) you'll be using, chosen from #onsetsds_odf_types * @param fftsize Size of FFT: 512 is recommended. * @param medspan The number of past frames that will be used for median calculation during triggering */ size_t onsetsds_memneeded (int odftype, size_t fftsize, unsigned int medspan); /** * Initialise the OnsetsDS struct and its associated memory, ready to detect * onsets using the specified settings. Must be called before any call to * onsetsds_process(). * * Note: you can change the onset detection function type in mid-operation * by calling onsetsds_init() again, but because memory will be reset this * will behave as if starting from scratch (rather than being aware of the past * few frames of sound). Do not attempt to change the * onset detection function in a more hacky way (e.g. fiddling with the struct) * because memory is set up differently for each of the different ODFs. * @param ods An instance of the OnsetsDS struct * @param odsdata A pointer to the memory allocated, size given by onsetsds_memneeded(). * @param fftformat Which format of FFT data is to be expected, chosen from #onsetsds_fft_types * @param odftype Which onset detection function (ODF) you'll be using, chosen from #onsetsds_odf_types * @param fftsize Size of FFT: 512 or 1024 is recommended. * @param medspan The number of past frames that will be used for median calculation during triggering * @param srate The sampling rate of the input audio */ void onsetsds_init(OnsetsDS* ods, float* odsdata, int fftformat, int odftype, size_t fftsize, unsigned int medspan, float srate); /** * Process a single FFT data frame in the audio signal. Note that processing * assumes that each call to onsetsds_process() is on a subsequent frame in * the same audio stream - to handle multiple streams you must use separate * OnsetsDS structs and memory! * * This function's main purpose is to call some of the library's other functions, * in the expected sequence. */ bool onsetsds_process(OnsetsDS* ods, float* fftbuf); //@} //////////////////////////////////////////////////////////////////////////////// // Function prototypes less commonly called by users /** * \defgroup LessCommonFuncs Other useful functions */ //@{ /** * Set the "memory coefficient" indirectly via the time for the * memory to decay by 60 dB. * @param ods The OnsetsDS * @param time The time in seconds * @param hopsize The FFT frame hopsize (typically this will be half the FFT frame size) */ void onsetsds_setrelax(OnsetsDS* ods, float time, size_t hopsize); //@} //////////////////////////////////////////////////////////////////////////////// // Function prototypes not typically called by users /** * \defgroup OtherFuncs Other functions, not typically called by users */ //@{ /** * Load the current frame of FFT data into the OnsetsDS struct. * * Not typically called directly by users since onsetsds_process() calls this. */ void onsetsds_loadframe(OnsetsDS* ods, float* fftbuf); /** * Apply adaptive whitening to the FFT data in the OnsetsDS struct. * * Not typically called directly by users since onsetsds_process() calls this. */ void onsetsds_whiten(OnsetsDS* ods); /** * Calculate the Onset Detection Function (includes scaling ODF outputs to * similar range) * * Not typically called directly by users since onsetsds_process() calls this. */ void onsetsds_odf(OnsetsDS* ods); /** * Detects salient peaks in Onset Detection Function by removing the median, * then thresholding. Afterwards, the member ods.detected will indicate whether * or not an onset was detected. * * Not typically called directly by users since onsetsds_process() calls this. */ void onsetsds_detect(OnsetsDS* ods); //@} //////////////////////////////////////////////////////////////////////////////// #ifdef __cplusplus } #endif #endif SuperCollider-Source/server/plugins/OscUGens.cpp000644 000765 000024 00000302276 12766171707 023066 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include "function_attributes.h" #include #include static InterfaceTable *ft; struct BufUnit : public Unit { SndBuf *m_buf; float m_fbufnum; }; struct TableLookup : public BufUnit { double m_cpstoinc, m_radtoinc; int32 mTableSize; int32 m_lomask; }; struct DegreeToKey : public BufUnit { int32 mPrevIndex; float mPrevKey; int32 mOctave; }; struct Select : public Unit { }; struct TWindex : public Unit { int32 m_prevIndex; float m_trig; }; struct Index : public BufUnit { }; struct IndexL : public BufUnit { }; struct WrapIndex : public BufUnit { }; struct FoldIndex : public BufUnit { }; struct IndexInBetween : public BufUnit { }; struct DetectIndex : public BufUnit { float mPrev; float mPrevIn; }; struct Shaper : public BufUnit { float mOffset; float mPrevIn; }; struct FSinOsc : public Unit { double m_b1, m_y1, m_y2, m_freq; }; struct PSinGrain : public Unit { double m_b1, m_y1, m_y2; double m_level, m_slope, m_curve; int32 mCounter; }; struct Osc : public TableLookup { int32 m_phase; float m_phasein; }; struct SinOsc : public TableLookup { int32 m_phase; float m_phasein; }; struct SinOscFB : public TableLookup { int32 m_phase; float m_prevout, m_feedback; }; struct OscN : public TableLookup { int32 m_phase; float m_phasein; }; struct COsc : public TableLookup { int32 m_phase1, m_phase2; }; struct VOsc : public Unit { double m_cpstoinc, m_radtoinc; int32 mTableSize; int32 m_lomask; int32 m_phase, m_phaseoffset; float m_phasein, m_bufpos; }; struct VOsc3 : public Unit { double m_cpstoinc; int32 mTableSize; int32 m_lomask; int32 m_phase1, m_phase2, m_phase3; float m_bufpos; }; struct Formant : public Unit { int32 m_phase1, m_phase2, m_phase3; double m_cpstoinc; }; struct Blip : public Unit { int32 m_phase, m_numharm, m_N; float m_freqin, m_scale; double m_cpstoinc; }; struct Saw : public Unit { int32 m_phase, m_N; float m_freqin, m_scale, m_y1; double m_cpstoinc; }; struct Pulse : public Unit { int32 m_phase, m_phaseoff, m_N; float m_freqin, m_scale, m_y1; double m_cpstoinc; }; struct Klang : public Unit { float *m_coefs; int32 m_numpartials; }; struct Klank : public Unit { float *m_coefs; float *m_buf; float m_x1, m_x2; int32 m_numpartials; }; #define xlomask8 0x000003FC #define xlomask9 0x000007FC #define xlomask10 0x00000FFC #define xlomask11 0x00001FFC #define xlomask12 0x00003FFC #define xlomask13 0x00007FFC #define xlomask8i 0x000007F8 #define xlomask9i 0x00000FF8 #define xlomask10i 0x00001FF8 #define xlomask11i 0x00003FF8 #define xlomask12i 0x00007FF8 #define xlomask13i 0x0000FFF8 #define onecyc13 0x20000000 ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void DegreeToKey_Ctor(DegreeToKey *unit); void DegreeToKey_next_1(DegreeToKey *unit, int inNumSamples); void DegreeToKey_next_k(DegreeToKey *unit, int inNumSamples); void DegreeToKey_next_a(DegreeToKey *unit, int inNumSamples); void Select_Ctor(Select *unit); void Select_next_1(Select *unit, int inNumSamples); void Select_next_k(Select *unit, int inNumSamples); void Select_next_a(Select *unit, int inNumSamples); void TWindex_Ctor(TWindex *unit); void TWindex_next_k(TWindex *unit, int inNumSamples); void TWindex_next_ak(TWindex *unit, int inNumSamples); void Index_Ctor(Index *unit); void Index_next_1(Index *unit, int inNumSamples); void Index_next_k(Index *unit, int inNumSamples); void Index_next_a(Index *unit, int inNumSamples); void IndexL_Ctor(IndexL *unit); void IndexL_next_1(IndexL *unit, int inNumSamples); void IndexL_next_k(IndexL *unit, int inNumSamples); void IndexL_next_a(IndexL *unit, int inNumSamples); void FoldIndex_Ctor(FoldIndex *unit); void FoldIndex_next_1(FoldIndex *unit, int inNumSamples); void FoldIndex_next_k(FoldIndex *unit, int inNumSamples); void FoldIndex_next_a(FoldIndex *unit, int inNumSamples); void WrapIndex_Ctor(WrapIndex *unit); void WrapIndex_next_1(WrapIndex *unit, int inNumSamples); void WrapIndex_next_k(WrapIndex *unit, int inNumSamples); void WrapIndex_next_a(WrapIndex *unit, int inNumSamples); void Shaper_Ctor(Shaper *unit); void Shaper_next_1(Shaper *unit, int inNumSamples); void Shaper_next_k(Shaper *unit, int inNumSamples); void Shaper_next_a(Shaper *unit, int inNumSamples); void DetectIndex_Ctor(DetectIndex *unit); void DetectIndex_next_1(DetectIndex *unit, int inNumSamples); void DetectIndex_next_k(DetectIndex *unit, int inNumSamples); void DetectIndex_next_a(DetectIndex *unit, int inNumSamples); void IndexInBetween_Ctor(IndexInBetween *unit); void IndexInBetween_next_1(IndexInBetween *unit, int inNumSamples); void IndexInBetween_next_k(IndexInBetween *unit, int inNumSamples); void IndexInBetween_next_a(IndexInBetween *unit, int inNumSamples); void FSinOsc_Ctor(FSinOsc *unit); void FSinOsc_next(FSinOsc *unit, int inNumSamples); void FSinOsc_next_i(FSinOsc *unit, int inNumSamples); void PSinGrain_Ctor(PSinGrain *unit); void PSinGrain_next(PSinGrain *unit, int inNumSamples); void SinOsc_Ctor(SinOsc *unit); void SinOsc_next_ikk(SinOsc *unit, int inNumSamples); void SinOsc_next_ika(SinOsc *unit, int inNumSamples); void SinOsc_next_iak(SinOsc *unit, int inNumSamples); void SinOsc_next_iaa(SinOsc *unit, int inNumSamples); void Osc_Ctor(Osc *unit); void Osc_next_ikk(Osc *unit, int inNumSamples); void Osc_next_ika(Osc *unit, int inNumSamples); void Osc_next_iak(Osc *unit, int inNumSamples); void Osc_next_iaa(Osc *unit, int inNumSamples); void OscN_Ctor(OscN *unit); void OscN_next_nkk(OscN *unit, int inNumSamples); void OscN_next_nka(OscN *unit, int inNumSamples); void OscN_next_nak(OscN *unit, int inNumSamples); void OscN_next_naa(OscN *unit, int inNumSamples); void COsc_Ctor(COsc *unit); void COsc_next(COsc *unit, int inNumSamples); void VOsc_Ctor(VOsc *unit); void VOsc_next_ikk(VOsc *unit, int inNumSamples); void VOsc_next_ika(VOsc *unit, int inNumSamples); void VOsc3_Ctor(VOsc3 *unit); void VOsc3_next_ik(VOsc3 *unit, int inNumSamples); void Formant_Ctor(Formant *unit); void Formant_next(Formant *unit, int inNumSamples); void Blip_Ctor(Blip *unit); void Blip_next(Blip *unit, int inNumSamples); void Saw_Ctor(Saw *unit); void Saw_next(Saw *unit, int inNumSamples); void Pulse_Ctor(Pulse *unit); void Pulse_next(Pulse *unit, int inNumSamples); void Klang_Dtor(Klang *unit); void Klang_Ctor(Klang *unit); void Klang_next(Klang *unit, int inNumSamples); void Klank_Dtor(Klank *unit); void Klank_Ctor(Klank *unit); void Klank_next(Klank *unit, int inNumSamples); } ////////////////////////////////////////////////////////////////////////////////////////////////// force_inline bool UnitGetTable(BufUnit * unit, int inNumSamples, const SndBuf * & buf, const float * & bufData, int & tableSize) { float fbufnum = ZIN0(0); if (fbufnum != unit->m_fbufnum) { uint32 bufnum = (uint32)fbufnum; World *world = unit->mWorld; if (bufnum >= world->mNumSndBufs) { uint32 localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) unit->m_buf = parent->mLocalSndBufs + localBufNum; else { bufnum = 0; unit->m_buf = world->mSndBufs + bufnum; } } else unit->m_buf = world->mSndBufs + bufnum; unit->m_fbufnum = fbufnum; } buf = unit->m_buf; if(!buf) { ClearUnitOutputs(unit, inNumSamples); return false; } bufData = buf->data; if (!bufData) { ClearUnitOutputs(unit, inNumSamples); return false; } tableSize = buf->samples; return true; } #define GET_TABLE \ const SndBuf * buf; \ const float * bufData; \ int tableSize; \ do { \ bool tableValid = UnitGetTable(unit, inNumSamples, buf, bufData, tableSize); \ if (!tableValid) return; \ } while (0); static inline bool verify_wavetable(Unit * unit, const char * name, int tableSize, int inNumSamples) { // phase computation is not precise for large wavetables. if (tableSize > 131072) { if (unit->mWorld->mVerbosity >= -1) Print("Warning: wave table too big (%s)\n", name); ClearUnitOutputs(unit, inNumSamples); return false; } if (!ISPOWEROFTWO(tableSize)) { if (unit->mWorld->mVerbosity >= -1) Print("Warning: size of wavetable not a power of two (%s)\n", name); ClearUnitOutputs(unit, inNumSamples); return false; } return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////// /* void TableLookup_SetTable(TableLookup* unit, int32 inSize, float* inTable) { unit->mTable0 = inTable; unit->mTable1 = inTable + 1; unit->mTableSize = inSize; unit->mMaxIndex = unit->mTableSize - 1; unit->mFMaxIndex = unit->mMaxIndex; unit->m_radtoinc = unit->mTableSize * (rtwopi * 65536.); unit->m_cpstoinc = unit->mTableSize * SAMPLEDUR * 65536.; //Print("TableLookup_SetTable unit->m_radtoinc %g %d %g\n", m_radtoinc, unit->mTableSize, rtwopi); } */ //////////////////////////////////////////////////////////////////////////////////////////////////////// void DegreeToKey_Ctor(DegreeToKey *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(DegreeToKey_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(DegreeToKey_next_a); } else { SETCALC(DegreeToKey_next_k); } unit->mOctave = (int32)ZIN0(2); unit->mPrevIndex = std::numeric_limits::max(); unit->mPrevKey = 0.; DegreeToKey_next_1(unit, 1); } void DegreeToKey_next_1(DegreeToKey *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; int32 key, oct; int32 octave = unit->mOctave; float val; int32 index = (int32)floor(ZIN0(1)); if (index == unit->mPrevIndex) { val = unit->mPrevKey; } else if (index < 0) { unit->mPrevIndex = index; key = tableSize + index % tableSize; oct = (index + 1) / tableSize - 1; val = unit->mPrevKey = table[key] + octave * oct; } else if (index > maxindex) { unit->mPrevIndex = index; key = index % tableSize; oct = index / tableSize; val = unit->mPrevKey = table[key] + octave * oct; } else { unit->mPrevIndex = index; val = unit->mPrevKey = table[index]; } ZOUT0(0) = val; } void DegreeToKey_next_k(DegreeToKey *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); int32 key, oct; float octave = unit->mOctave; float val; int32 index = (int32)floor(ZIN0(1)); if (index == unit->mPrevIndex) { val = unit->mPrevKey; } else if (index < 0) { unit->mPrevIndex = index; key = tableSize + index % tableSize; oct = (index + 1) / tableSize - 1; val = unit->mPrevKey = table[key] + octave * oct; } else if (index > maxindex) { unit->mPrevIndex = index; key = index % tableSize; oct = index / tableSize; val = unit->mPrevKey = table[key] + octave * oct; } else { unit->mPrevIndex = index; val = unit->mPrevKey = table[index]; } LOOP1(inNumSamples, ZXP(out) = val; ); } void DegreeToKey_next_a(DegreeToKey *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); int32 previndex = unit->mPrevIndex; float prevkey = unit->mPrevKey; int32 key, oct; float octave = unit->mOctave; LOOP1(inNumSamples, int32 index = (int32)floor(ZXP(in)); if (index == previndex) { ZXP(out) = prevkey; } else if (index < 0) { previndex = index; key = tableSize + index % tableSize; oct = (index + 1) / tableSize - 1; ZXP(out) = prevkey = table[key] + octave * oct; } else if (index > maxindex) { previndex = index; key = index % tableSize; oct = index / tableSize; ZXP(out) = prevkey = table[key] + octave * oct; } else { previndex = index; ZXP(out) = prevkey = table[index]; } ); unit->mPrevIndex = previndex; unit->mPrevKey = prevkey; } //////////////////////////////////////////////////////////////////////////////////// void Select_Ctor(Select *unit) { if (BUFLENGTH == 1) { SETCALC(Select_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(Select_next_a); } else { SETCALC(Select_next_k); } Select_next_1(unit, 1); } void Select_next_1(Select *unit, int inNumSamples) { int32 maxindex = unit->mNumInputs - 1; int32 index = (int32)ZIN0(0) + 1; index = sc_clip(index, 1, maxindex); ZOUT0(0) = ZIN0(index); } void Select_next_k(Select *unit, int inNumSamples) { int32 maxindex = unit->mNumInputs - 1; int32 index = (int32)ZIN0(0) + 1; index = sc_clip(index, 1, maxindex); float *out = OUT(0); float *in = IN(index); Copy(inNumSamples, out, in); } void Select_next_a(Select *unit, int inNumSamples) { int32 maxindex = unit->mNumInputs - 1; float *out = ZOUT(0); float *in0 = ZIN(0); float **in = unit->mInBuf; for (int i=0; im_prevIndex = 0; unit->m_trig = -1.f; // make it trigger the first time TWindex_next_k(unit, 1); } void TWindex_next_k(TWindex *unit, int inNumSamples) { int maxindex = unit->mNumInputs; int32 index = maxindex; float sum = 0.f; float maxSum = 0.f; float normalize = ZIN0(1); // switch normalisation on or off float trig = ZIN0(0); float *out = ZOUT(0); if (trig > 0.f && unit->m_trig <= 0.f) { if(normalize == 1) { for (int32 k=2; kmParent->mRGen; float max = maxSum * rgen.frand(); for (int32 k=2; k= max) { index = k - 2; break; } } unit->m_prevIndex = index; } else { index = unit->m_prevIndex; } LOOP1(inNumSamples, ZXP(out) = index; ) unit->m_trig = trig; } void TWindex_next_ak(TWindex *unit, int inNumSamples) { int maxindex = unit->mNumInputs; int32 index = maxindex; float sum = 0.f; float maxSum = 0.f; float normalize = ZIN0(1);//switch normalisation on or off float *trig = ZIN(0); float *out = ZOUT(0); float curtrig; if(normalize == 1) { for (int32 k=2; kmParent->mRGen; LOOP1(inNumSamples, curtrig = ZXP(trig); if (curtrig > 0.f && unit->m_trig <= 0.f) { float max = maxSum * rgen.frand(); for (int32 k=2; k= max) { index = k - 2; break; } } unit->m_prevIndex = index; } else index = unit->m_prevIndex; ZXP(out) = index; unit->m_trig = curtrig; ) } //////////////////////////////////////////////////////////////////////////////////// void Index_Ctor(Index *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(Index_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(Index_next_a); } else { SETCALC(Index_next_k); } Index_next_1(unit, 1); } void Index_next_1(Index *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; int32 index = (int32)ZIN0(1); index = sc_clip(index, 0, maxindex); ZOUT0(0) = table[index]; } void Index_next_k(Index *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); int32 index = (int32)ZIN0(1); index = sc_clip(index, 0, maxindex); float val = table[index]; LOOP1(inNumSamples, ZXP(out) = val; ); } void Index_next_a(Index *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); LOOP1(inNumSamples, int32 index = (int32)ZXP(in); index = sc_clip(index, 0, maxindex); ZXP(out) = table[index]; ); } //////////////////////////////////////////////////////////////////////////////////// void IndexL_Ctor(IndexL *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(IndexL_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(IndexL_next_a); } else { SETCALC(IndexL_next_k); } IndexL_next_1(unit, 1); } void IndexL_next_1(IndexL *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float findex = ZIN0(1); float frac = sc_frac(findex); int32 index = (int32)findex; index = sc_clip(index, 0, maxindex); float a = table[index]; float b = table[sc_clip(index + 1, 0, maxindex)]; ZOUT0(0) = lininterp(frac, a, b); } void IndexL_next_k(IndexL *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float findex = ZIN0(1); float frac = sc_frac(findex); int32 index = (int32)findex; index = sc_clip(index, 0, maxindex); float a = table[index]; float b = table[sc_clip(index + 1, 0, maxindex)]; float val = lininterp(frac, a, b); LOOP1(inNumSamples, ZXP(out) = val; ); } void IndexL_next_a(IndexL *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); LOOP1(inNumSamples, float findex = ZXP(in); float frac = sc_frac(findex); int32 i1 = sc_clip((int32)findex, 0, maxindex); int32 i2 = sc_clip(i1 + 1, 0, maxindex); float a = table[i1]; float b = table[i2]; ZXP(out) = lininterp(frac, a, b); ); } //////////////////////////////////////////////////////////////////////////////////// void FoldIndex_Ctor(FoldIndex *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(FoldIndex_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(FoldIndex_next_a); } else { SETCALC(FoldIndex_next_k); } FoldIndex_next_1(unit, 1); } void FoldIndex_next_1(FoldIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; int32 index = (int32)ZIN0(1); index = sc_fold(index, 0, maxindex); ZOUT0(0) = table[index]; } void FoldIndex_next_k(FoldIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; int32 index = (int32)ZIN0(1); float *out = ZOUT(0); index = sc_fold(index, 0, maxindex); float val = table[index]; LOOP1(inNumSamples, ZXP(out) = val; ); } void FoldIndex_next_a(FoldIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); LOOP1(inNumSamples, int32 index = (int32)ZXP(in); index = sc_fold(index, 0, maxindex); ZXP(out) = table[index]; ); } //////////////////////////////////////////////////////////////////////////////////// void WrapIndex_Ctor(WrapIndex *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(WrapIndex_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(WrapIndex_next_a); } else { SETCALC(WrapIndex_next_k); } WrapIndex_next_1(unit, 1); } void WrapIndex_next_1(WrapIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; int32 index = (int32)floor(ZIN0(1)); index = sc_wrap(index, 0, maxindex); ZOUT0(0) = table[index]; } void WrapIndex_next_k(WrapIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); int32 index = (int32)ZIN0(1); index = sc_wrap(index, 0, maxindex); float val = table[index]; LOOP1(inNumSamples, ZXP(out) = val; ); } void WrapIndex_next_a(WrapIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); LOOP1(inNumSamples, int32 index = (int32)ZXP(in); index = sc_wrap(index, 0, maxindex); ZXP(out) = table[index]; ); } //////////////////////////////////////////////////////////////////////////////////// static float IndexInBetween_FindIndex(const float* table, float in, int32 maxindex) { for(int32 i = 0; i <= maxindex; i++) { if(table[i] > in) { if(i == 0) { return 0.f; } else { return ((in - table[i - 1]) / (table[i] - table[i - 1]) + i - 1); } } } return (float)maxindex; } void IndexInBetween_Ctor(IndexInBetween *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(IndexInBetween_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(IndexInBetween_next_a); } else { SETCALC(IndexInBetween_next_k); } IndexInBetween_next_1(unit, 1); } void IndexInBetween_next_1(IndexInBetween *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float in = ZIN0(1); ZOUT0(0) = IndexInBetween_FindIndex(table, in, maxindex); } void IndexInBetween_next_k(IndexInBetween *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float in = ZIN0(1); float val = IndexInBetween_FindIndex(table, in, maxindex); LOOP1(inNumSamples, ZXP(out) = val; ); } void IndexInBetween_next_a(IndexInBetween *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); LOOP1(inNumSamples, ZXP(out) = IndexInBetween_FindIndex(table, ZXP(in), maxindex); ); } //////////////////////////////////////////////////////////////////////////////////// static int32 DetectIndex_FindIndex(const float* table, float in, int32 maxindex) { int32 index; for(index = 0; index <= maxindex; index+=1) { if(table[index] == in) { return index; } } return -1; } void DetectIndex_Ctor(DetectIndex *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(DetectIndex_next_1); } else if (INRATE(0) == calc_FullRate) { SETCALC(DetectIndex_next_a); } else { SETCALC(DetectIndex_next_k); } unit->mPrev = -1.f; DetectIndex_next_1(unit, 1); } void DetectIndex_next_1(DetectIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float in = ZIN0(1); int32 index; if(in == unit->mPrevIn) { index = (int32)unit->mPrev; } else { index = DetectIndex_FindIndex(table, in, maxindex); unit->mPrev = index; unit->mPrevIn = in; } ZOUT0(0) = (float)index; } void DetectIndex_next_k(DetectIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float in = ZIN0(1); int32 index; float val; if(in == unit->mPrevIn) { index = (int32)unit->mPrev; } else { index = DetectIndex_FindIndex(table, in, maxindex); unit->mPrev = index; unit->mPrevIn = in; }; val = (float)index; LOOP1(inNumSamples, ZXP(out) = val; ); } void DetectIndex_next_a(DetectIndex *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; int32 maxindex = tableSize - 1; float *out = ZOUT(0); float *in = ZIN(1); float prev = unit->mPrevIn; int32 prevIndex = (int32)unit->mPrev; float inval; LOOP1(inNumSamples, inval = ZXP(in); if(inval != prev) { prevIndex = DetectIndex_FindIndex(table, inval, maxindex); } prev = inval; ZXP(out) = (float)prevIndex; ); unit->mPrev = prevIndex; unit->mPrevIn = inval; } //////////////////////////////////////////////////////////////////////////////////// void Shaper_Ctor(Shaper *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); if (BUFLENGTH == 1) { SETCALC(Shaper_next_1); } else if (INRATE(1) == calc_FullRate) { SETCALC(Shaper_next_a); } else { SETCALC(Shaper_next_k); } unit->mPrevIn = ZIN0(0); Shaper_next_1(unit, 1); } float force_inline ShaperPerform(const float * table0, const float * table1, float in, float offset, float fmaxindex) { float findex = offset + in * offset; findex = sc_clip(findex, 0.f, fmaxindex); int32 index = (int32)findex; float pfrac = findex - (index - 1); index <<= 3; float val1 = *(const float*)((const char*)table0 + index); float val2 = *(const float*)((const char*)table1 + index); float val = val1 + val2 * pfrac; return val; } void Shaper_next_1(Shaper *unit, int inNumSamples) { // get table GET_TABLE const float *table0 = bufData; const float *table1 = table0 + 1; float fmaxindex = (float)(tableSize>>1) - 0.001; float offset = tableSize * 0.25; ZOUT0(0) = ShaperPerform(table0, table1, ZIN0(1), offset, fmaxindex); } void Shaper_next_k(Shaper *unit, int inNumSamples) { // get table GET_TABLE const float *table0 = bufData; const float *table1 = table0 + 1; float fmaxindex = (float)(tableSize>>1) - 0.001; float offset = tableSize * 0.25; float *out = ZOUT(0); float fin = ZIN0(1); if (fin == unit->mPrevIn) { LOOP1(inNumSamples, ZXP(out) = ShaperPerform(table0, table1, fin, offset, fmaxindex); ); } else { float phaseinc = (fin - unit->mPrevIn) * offset; unit->mPrevIn = fin; LOOP1(inNumSamples, ZXP(out) = ShaperPerform(table0, table1, fin, offset, fmaxindex); fin += phaseinc; ); } } void Shaper_next_a(Shaper *unit, int inNumSamples) { // get table GET_TABLE const float *table0 = bufData; const float *table1 = table0 + 1; float fmaxindex = (float)(tableSize>>1) - 0.001; float offset = tableSize * 0.25; float *out = ZOUT(0); const float *in = ZIN(1); LOOP1(inNumSamples, float fin = ZXP(in); ZXP(out) = ShaperPerform(table0, table1, fin, offset, fmaxindex); ); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void FSinOsc_Ctor(FSinOsc *unit) { if (INRATE(0) == calc_ScalarRate) SETCALC(FSinOsc_next_i); else SETCALC(FSinOsc_next); unit->m_freq = ZIN0(0); float iphase = ZIN0(1); float w = unit->m_freq * unit->mRate->mRadiansPerSample; unit->m_b1 = 2. * cos(w); unit->m_y1 = sin(iphase); unit->m_y2 = sin(iphase - w); ZOUT0(0) = unit->m_y1; } void FSinOsc_next(FSinOsc *unit, int inNumSamples) { float *out = ZOUT(0); double freq = ZIN0(0); double b1; if (freq != unit->m_freq) { unit->m_freq = freq; double w = freq * unit->mRate->mRadiansPerSample; unit->m_b1 = b1 = 2.f * cos(w); } else { b1 = unit->m_b1; } double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; //Print("y %g %g b1 %g\n", y1, y2, b1); //Print("%d %d\n", unit->mRate->mFilterLoops, unit->mRate->mFilterRemain); LOOP(unit->mRate->mFilterLoops, ZXP(out) = y0 = b1 * y1 - y2; ZXP(out) = y2 = b1 * y0 - y1; ZXP(out) = y1 = b1 * y2 - y0; ); LOOP(unit->mRate->mFilterRemain, ZXP(out) = y0 = b1 * y1 - y2; y2 = y1; y1 = y0; ); //Print("y %g %g b1 %g\n", y1, y2, b1); unit->m_y1 = y1; unit->m_y2 = y2; } void FSinOsc_next_i(FSinOsc *unit, int inNumSamples) { float * __restrict__ out = ZOUT(0); double b1 = unit->m_b1; double y0; double y1 = unit->m_y1; double y2 = unit->m_y2; //Print("y %g %g b1 %g\n", y1, y2, b1); //Print("%d %d\n", unit->mRate->mFilterLoops, unit->mRate->mFilterRemain); LOOP(unit->mRate->mFilterLoops, y0 = b1 * y1 - y2; y2 = b1 * y0 - y1; y1 = b1 * y2 - y0; ZXP(out) = y0; ZXP(out) = y2; ZXP(out) = y1; ); LOOP(unit->mRate->mFilterRemain, ZXP(out) = y0 = b1 * y1 - y2; y2 = y1; y1 = y0; ); //Print("y %g %g b1 %g\n", y1, y2, b1); unit->m_y1 = y1; unit->m_y2 = y2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void PSinGrain_Ctor(PSinGrain *unit) { SETCALC(PSinGrain_next); float freq = ZIN0(0); float dur = ZIN0(1); float amp = ZIN0(2); float w = freq * unit->mRate->mRadiansPerSample; float sdur = SAMPLERATE * dur; float rdur = 1.f / sdur; float rdur2 = rdur * rdur; unit->m_level = 0.f; unit->m_slope = 4.0 * (rdur - rdur2); // ampslope unit->m_curve = -8.0 * rdur2; // ampcurve unit->mCounter = (int32)(sdur + .5); /* calc feedback param and initial conditions */ unit->m_b1 = 2. * cos(w); unit->m_y1 = 0.f; unit->m_y2 = -sin(w) * amp; ZOUT0(0) = 0.f; } void PSinGrain_next(PSinGrain *unit, int inNumSamples) { float *out = ZOUT(0); float y0; float y1 = unit->m_y1; float y2 = unit->m_y2; float b1 = unit->m_b1; float level = unit->m_level; float slope = unit->m_slope; float curve = unit->m_curve; int32 counter = unit->mCounter; int32 remain = inNumSamples; int32 nsmps; do { if (counter<=0) { nsmps = remain; remain = 0; LOOP(nsmps, ZXP(out) = 0.f;); // can't use Clear bcs might not be aligned } else { nsmps = sc_min(remain, counter); remain -= nsmps; counter -= nsmps; if (nsmps == inNumSamples) { nsmps = unit->mRate->mFilterLoops; LOOP(nsmps, y0 = b1 * y1 - y2; ZXP(out) = y0 * level; level += slope; slope += curve; y2 = b1 * y0 - y1; ZXP(out) = y2 * level; level += slope; slope += curve; y1 = b1 * y2 - y0; ZXP(out) = y1 * level; level += slope; slope += curve; ); nsmps = unit->mRate->mFilterRemain; LOOP(nsmps, y0 = b1 * y1 - y2; y2 = y1; y1 = y0; ZXP(out) = y0 * level; level += slope; slope += curve; ); } else { LOOP(nsmps, y0 = b1 * y1 - y2; y2 = y1; y1 = y0; ZXP(out) = y0 * level; level += slope; slope += curve; ); } if (counter == 0) { NodeEnd(&unit->mParent->mNode); } } } while (remain>0); unit->m_level = level; unit->m_slope = slope; unit->m_y1 = y1; unit->m_y2 = y2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// template force_inline void Osc_ikk_perform(OscType *unit, const float * table0, const float * table1, int inNumSamples) { float *out = ZOUT(0); float freqin = ZIN0(FreqInputIndex); float phasein = ZIN0(FreqInputIndex + 1); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; int32 freq = (int32)(unit->m_cpstoinc * freqin); int32 phaseinc = freq + (int32)(CALCSLOPE(phasein, unit->m_phasein) * unit->m_radtoinc); unit->m_phasein = phasein; LOOP1(inNumSamples, ZXP(out) = lookupi1(table0, table1, phase, lomask); phase += phaseinc; ); unit->m_phase = phase; } void SinOsc_next_ikk(SinOsc *unit, int inNumSamples) { float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; Osc_ikk_perform(unit, table0, table1, inNumSamples); } template force_inline void Osc_ika_perform(OscType *unit, const float * table0, const float * table1, int inNumSamples) { float *out = ZOUT(0); float freqin = ZIN0(FreqInputIndex); float *phasein = ZIN(FreqInputIndex + 1); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; int32 freq = (int32)(unit->m_cpstoinc * freqin); float radtoinc = unit->m_radtoinc; LOOP1(inNumSamples, int32 phaseoffset = phase + (int32)(radtoinc * ZXP(phasein)); ZXP(out) = lookupi1(table0, table1, phaseoffset, lomask); phase += freq; ); unit->m_phase = phase; } void SinOsc_next_ika(SinOsc *unit, int inNumSamples) { const float *table0 = ft->mSineWavetable; const float *table1 = table0 + 1; Osc_ika_perform(unit, table0, table1, inNumSamples); } template force_inline void Osc_iaa_perform(OscType * unit, const float * table0, const float * table1, int inNumSamples) { float *out = ZOUT(0); float *freqin = ZIN(FreqInputIndex); float *phasein = ZIN(FreqInputIndex + 1); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; float cpstoinc = unit->m_cpstoinc; float radtoinc = unit->m_radtoinc; LOOP1(inNumSamples, float phaseIn = ZXP(phasein); float freqIn = ZXP(freqin); int32 phaseoffset = phase + (int32)(radtoinc * phaseIn); float z = lookupi1(table0, table1, phaseoffset, lomask); phase += (int32)(cpstoinc * freqIn); ZXP(out) = z; ); unit->m_phase = phase; } void SinOsc_next_iaa(SinOsc *unit, int inNumSamples) { const float *table0 = ft->mSineWavetable; const float *table1 = table0 + 1; Osc_iaa_perform(unit, table0, table1, inNumSamples); } template force_inline void Osc_iak_perform(OscType *unit, const float * table0, const float * table1, int inNumSamples) { float *out = ZOUT(0); float *freqin = ZIN(FreqInputIndex); float phasein = ZIN0(FreqInputIndex + 1); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; float cpstoinc = unit->m_cpstoinc; float radtoinc = unit->m_radtoinc; float phasemod = unit->m_phasein; if (phasein != phasemod) { float phaseslope = CALCSLOPE(phasein, phasemod); LOOP1(inNumSamples, int32 pphase = phase + (int32)(radtoinc * phasemod); phasemod += phaseslope; float z = lookupi1(table0, table1, pphase, lomask); phase += (int32)(cpstoinc * ZXP(freqin)); ZXP(out) = z; ); } else { LOOP1(inNumSamples, int32 pphase = phase + (int32)(radtoinc * phasemod); float z = lookupi1(table0, table1, pphase, lomask); phase += (int32)(cpstoinc * ZXP(freqin)); ZXP(out) = z; ); } unit->m_phase = phase; unit->m_phasein = phasein; } void SinOsc_next_iak(SinOsc *unit, int inNumSamples) { float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; Osc_iak_perform(unit, table0, table1, inNumSamples); } template force_inline void Osc_iai_perform(OscType *unit, const float * table0, const float * table1, int inNumSamples) { float *out = ZOUT(0); float *freqin = ZIN(FreqInputIndex); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; float cpstoinc = unit->m_cpstoinc; float radtoinc = unit->m_radtoinc; float phasemod = unit->m_phasein; LOOP1(inNumSamples, int32 pphase = phase + (int32)(radtoinc * phasemod); float z = lookupi1(table0, table1, pphase, lomask); phase += (int32)(cpstoinc * ZXP(freqin)); ZXP(out) = z; ); unit->m_phase = phase; } void SinOsc_next_iai(SinOsc *unit, int inNumSamples) { float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; Osc_iai_perform(unit, table0, table1, inNumSamples); } void SinOsc_Ctor(SinOsc *unit) { int tableSize2 = ft->mSineSize; unit->m_phasein = ZIN0(1); unit->m_radtoinc = tableSize2 * (rtwopi * 65536.); unit->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.; unit->m_lomask = (tableSize2 - 1) << 3; if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) SETCALC(SinOsc_next_iaa); else if (INRATE(1) == calc_BufRate) SETCALC(SinOsc_next_iak); else SETCALC(SinOsc_next_iai); unit->m_phase = 0; } else { if (INRATE(1) == calc_FullRate) { //Print("next_ika\n"); SETCALC(SinOsc_next_ika); unit->m_phase = 0; } else { SETCALC(SinOsc_next_ikk); unit->m_phase = (int32)(unit->m_phasein * unit->m_radtoinc); } } SinOsc_next_ikk(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////!!! void SinOscFB_next_kk(SinOscFB *unit, int inNumSamples) { float *out = ZOUT(0); float freqin = ZIN0(0); float feedback = unit->m_feedback; float nextFeedback = ZIN0(1) * unit->m_radtoinc; float *table0 = ft->mSineWavetable; float *table1 = table0 + 1; int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; float prevout = unit->m_prevout; float feedback_slope = CALCSLOPE(nextFeedback, feedback); int32 freq = (int32)(unit->m_cpstoinc * freqin); LooP(inNumSamples) { prevout = lookupi1(table0, table1, phase + (int32)(feedback * prevout), lomask); ZXP(out) = prevout; phase += freq; feedback += feedback_slope; } unit->m_phase = phase; unit->m_prevout = prevout; unit->m_feedback = feedback; } void SinOscFB_Ctor(SinOscFB *unit) { //Print("next_ik\n"); SETCALC(SinOscFB_next_kk); int tableSize2 = ft->mSineSize; unit->m_lomask = (tableSize2 - 1) << 3; unit->m_radtoinc = tableSize2 * (rtwopi * 65536.); unit->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.; unit->m_prevout = 0.; unit->m_feedback = ZIN0(1) * unit->m_radtoinc; unit->m_phase = 0; SinOscFB_next_kk(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void Osc_Ctor(Osc *unit) { unit->mTableSize = -1; float fbufnum = ZIN0(0); uint32 bufnum = (uint32)fbufnum; World *world = unit->mWorld; SndBuf *buf; if (bufnum >= world->mNumSndBufs) { int localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = unit->m_buf = parent->mLocalSndBufs + localBufNum; } else { buf = unit->m_buf = world->mSndBufs; } } else { buf = unit->m_buf = world->mSndBufs + bufnum; } int tableSize = buf->samples; int tableSize2 = tableSize >> 1; unit->m_radtoinc = tableSize2 * (rtwopi * 65536.); // Osc, OscN, PMOsc unit->m_phasein = ZIN0(2); if (INRATE(1) == calc_FullRate) { if (INRATE(2) == calc_FullRate) { //Print("next_iaa\n"); SETCALC(Osc_next_iaa); unit->m_phase = 0; } else { //Print("next_iak\n"); SETCALC(Osc_next_iak); unit->m_phase = 0; } } else { if (INRATE(2) == calc_FullRate) { //Print("next_ika\n"); SETCALC(Osc_next_ika); unit->m_phase = 0; } else { //Print("next_ikk\n"); SETCALC(Osc_next_ikk); unit->m_phase = (int32)(unit->m_phasein * unit->m_radtoinc); } } Osc_next_ikk(unit, 1); } force_inline bool Osc_get_table(Osc *unit, const float *& table0, const float *& table1, int inNumSamples) { const SndBuf * buf; const float * bufData; int tableSize; bool tableValid = UnitGetTable(unit, inNumSamples, buf, bufData, tableSize); if (!tableValid) return false; table0 = bufData; table1 = table0 + 1; if (tableSize != unit->mTableSize) { unit->mTableSize = tableSize; int tableSize2 = tableSize >> 1; unit->m_lomask = (tableSize2 - 1) << 3; // Osc, OscN, COsc, COsc, COsc2, OscX4, OscX2 unit->m_radtoinc = tableSize2 * (rtwopi * 65536.); // Osc, OscN, PMOsc // Osc, OscN, PMOsc, COsc, COsc2, OscX4, OscX2 unit->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.; } if (!verify_wavetable(unit, "Osc", tableSize, inNumSamples)) return false; return true; } void Osc_next_ikk(Osc *unit, int inNumSamples) { const float * table0; const float * table1; bool tableValid = Osc_get_table(unit, table0, table1, inNumSamples); if (!tableValid) return; Osc_ikk_perform(unit, table0, table1, inNumSamples); } void Osc_next_ika(Osc *unit, int inNumSamples) { const float * table0; const float * table1; bool tableValid = Osc_get_table(unit, table0, table1, inNumSamples); if (!tableValid) return; Osc_ika_perform(unit, table0, table1, inNumSamples); } void Osc_next_iaa(Osc *unit, int inNumSamples) { const float * table0; const float * table1; bool tableValid = Osc_get_table(unit, table0, table1, inNumSamples); if (!tableValid) return; Osc_iaa_perform(unit, table0, table1, inNumSamples); } void Osc_next_iak(Osc *unit, int inNumSamples) { const float * table0; const float * table1; bool tableValid = Osc_get_table(unit, table0, table1, inNumSamples); if (!tableValid) return; Osc_iak_perform(unit, table0, table1, inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////////// void OscN_Ctor(OscN *unit) { unit->mTableSize = -1; float fbufnum = ZIN0(0); uint32 bufnum = (uint32)fbufnum; World *world = unit->mWorld; SndBuf *buf; if (bufnum >= world->mNumSndBufs) { int localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = unit->m_buf = parent->mLocalSndBufs + localBufNum; } else { buf = unit->m_buf = world->mSndBufs; } } else { buf = unit->m_buf = world->mSndBufs + bufnum; } int tableSize = buf->samples; unit->m_radtoinc = tableSize * (rtwopi * 65536.); unit->m_phasein = ZIN0(2); //Print("OscN_Ctor\n"); if (INRATE(1) == calc_FullRate) { if (INRATE(2) == calc_FullRate) { //Print("next_naa\n"); SETCALC(OscN_next_naa); unit->m_phase = 0; } else { //Print("next_nak\n"); SETCALC(OscN_next_nak); unit->m_phase = 0; } } else { if (INRATE(2) == calc_FullRate) { //Print("next_nka\n"); SETCALC(OscN_next_nka); unit->m_phase = 0; } else { //Print("next_nkk\n"); SETCALC(OscN_next_nkk); unit->m_phase = (int32)(unit->m_phasein * unit->m_radtoinc); } } OscN_next_nkk(unit, 1); } void OscN_next_nkk(OscN *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; if (tableSize != unit->mTableSize) { unit->mTableSize = tableSize; unit->m_lomask = (tableSize - 1) << 2; unit->m_radtoinc = tableSize * (rtwopi * 65536.); unit->m_cpstoinc = tableSize * SAMPLEDUR * 65536.; } if (!verify_wavetable(unit, "OscN", tableSize, inNumSamples)) return; float *out = ZOUT(0); float freqin = ZIN0(1); float phasein = ZIN0(2); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; int32 freq = (int32)(unit->m_cpstoinc * freqin); int32 phaseinc = freq + (int32)(CALCSLOPE(phasein, unit->m_phasein) * unit->m_radtoinc); unit->m_phasein = phasein; LOOP1(inNumSamples, ZXP(out) = *(float*)((char*)table + ((phase >> xlobits) & lomask)); phase += phaseinc; ); unit->m_phase = phase; } void OscN_next_nka(OscN *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; if (tableSize != unit->mTableSize) { unit->mTableSize = tableSize; unit->m_lomask = (tableSize - 1) << 2; unit->m_radtoinc = tableSize * (rtwopi * 65536.); unit->m_cpstoinc = tableSize * SAMPLEDUR * 65536.; } if (!verify_wavetable(unit, "OscN", tableSize, inNumSamples)) return; float *out = ZOUT(0); float freqin = ZIN0(1); float *phasein = ZIN(2); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; int32 freq = (int32)(unit->m_cpstoinc * freqin); float radtoinc = unit->m_radtoinc; LOOP1(inNumSamples, int32 pphase = phase + (int32)(radtoinc * ZXP(phasein)); ZXP(out) = *(float*)((char*)table + ((pphase >> xlobits) & lomask)); phase += freq; ); unit->m_phase = phase; } void OscN_next_naa(OscN *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; if (tableSize != unit->mTableSize) { unit->mTableSize = tableSize; unit->m_lomask = (tableSize - 1) << 2; unit->m_radtoinc = tableSize * (rtwopi * 65536.); unit->m_cpstoinc = tableSize * SAMPLEDUR * 65536.; } if (!verify_wavetable(unit, "OscN", tableSize, inNumSamples)) return; float *out = ZOUT(0); float *freqin = ZIN(1); float *phasein = ZIN(2); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; float cpstoinc = unit->m_cpstoinc; float radtoinc = unit->m_radtoinc; LOOP1(inNumSamples, int32 pphase = phase + (int32)(radtoinc * ZXP(phasein)); float z = *(float*)((char*)table + ((pphase >> xlobits) & lomask)); phase += (int32)(cpstoinc * ZXP(freqin)); ZXP(out) = z; ); unit->m_phase = phase; } void OscN_next_nak(OscN *unit, int inNumSamples) { // get table GET_TABLE const float *table = bufData; if (tableSize != unit->mTableSize) { unit->mTableSize = tableSize; unit->m_lomask = (tableSize - 1) << 2; unit->m_radtoinc = tableSize * (rtwopi * 65536.); unit->m_cpstoinc = tableSize * SAMPLEDUR * 65536.; } if (!verify_wavetable(unit, "OscN", tableSize, inNumSamples)) return; float *out = ZOUT(0); float *freqin = ZIN(1); float phasein = ZIN0(2); int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; float cpstoinc = unit->m_cpstoinc; float radtoinc = unit->m_radtoinc; float phasemod = unit->m_phasein; float phaseslope = CALCSLOPE(phasein, phasemod); LOOP1(inNumSamples, int32 pphase = phase + (int32)(radtoinc * phasemod); phasemod += phaseslope; float z = *(float*)((char*)table + ((pphase >> xlobits) & lomask)); phase += (int32)(cpstoinc * ZXP(freqin)); ZXP(out) = z; ); unit->m_phase = phase; unit->m_phasein = phasein; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void COsc_Ctor(COsc *unit) { unit->m_fbufnum = std::numeric_limits::quiet_NaN(); SETCALC(COsc_next); unit->m_phase1 = 0; unit->m_phase2 = 0; unit->mTableSize = -1; COsc_next(unit, 1); } void COsc_next(COsc *unit, int inNumSamples) { // get table GET_TABLE const float *table0 = bufData; const float *table1 = table0 + 1; if (tableSize != unit->mTableSize) { unit->mTableSize = tableSize; int tableSize2 = tableSize >> 1; unit->m_lomask = (tableSize2 - 1) << 3; // Osc, OscN, COsc, COsc, COsc2, OscX4, OscX2 // Osc, OscN, PMOsc, COsc, COsc2, OscX4, OscX2 unit->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.; } if (!verify_wavetable(unit, "COsc", tableSize, inNumSamples)) return; float *out = ZOUT(0); float freqin = ZIN0(1); float beats = ZIN0(2) * 0.5f; int32 phase1 = unit->m_phase1; int32 phase2 = unit->m_phase2; int32 lomask = unit->m_lomask; int32 cfreq = (int32)(unit->m_cpstoinc * freqin); int32 beatf = (int32)(unit->m_cpstoinc * beats); int32 freq1 = cfreq + beatf; int32 freq2 = cfreq - beatf; LOOP1(inNumSamples, float a = lookupi1(table0, table1, phase1, lomask); float b = lookupi1(table0, table1, phase2, lomask); ZXP(out) = a + b; phase1 += freq1; phase2 += freq2; ); unit->m_phase1 = phase1; unit->m_phase2 = phase2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// static inline const SndBuf * VOscGetBuf(int & bufnum, World * world, Unit * unit) { if (bufnum < 0) bufnum = 0; const SndBuf * bufs; if (bufnum+1 >= world->mNumSndBufs) { int localBufNum = bufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { bufs = parent->mLocalSndBufs + localBufNum; } else { bufnum = 0; bufs = world->mSndBufs + bufnum; } } else { if (bufnum >= world->mNumSndBufs) bufnum = 0; bufs = world->mSndBufs + sc_max(0, bufnum); } return bufs; } void VOsc_Ctor(VOsc *unit) { float nextbufpos = ZIN0(0); unit->m_bufpos = nextbufpos; int bufnum = sc_floor(nextbufpos); World *world = unit->mWorld; const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); int tableSize = bufs[0].samples; unit->mTableSize = tableSize; int tableSize2 = tableSize >> 1; unit->m_lomask = (tableSize2 - 1) << 3; unit->m_radtoinc = tableSize2 * (rtwopi * 65536.); unit->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.; unit->m_phasein = ZIN0(2); unit->m_phaseoffset = (int32)(unit->m_phasein * unit->m_radtoinc); if (INRATE(2) == calc_FullRate) { SETCALC(VOsc_next_ika); unit->m_phase = 0; } else { SETCALC(VOsc_next_ikk); unit->m_phase = unit->m_phaseoffset; } VOsc_next_ikk(unit, 1); } void VOsc_next_ikk(VOsc *unit, int inNumSamples) { float *out = ZOUT(0); float nextbufpos = ZIN0(0); float freqin = ZIN0(1); float phasein = ZIN0(2); float prevbufpos = unit->m_bufpos; float bufdiff = nextbufpos - prevbufpos; int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; int32 freq = (int32)(unit->m_cpstoinc * freqin); int32 phaseinc = freq + (int32)(CALCSLOPE(phasein, unit->m_phasein) * unit->m_radtoinc); unit->m_phasein = phasein; int tableSize = unit->mTableSize; float cur = prevbufpos; World *world = unit->mWorld; if (bufdiff == 0.f) { float level = cur - sc_floor(cur); int32 bufnum = (int)sc_floor(cur); const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); if (!verify_wavetable(unit, "VOsc", tableSize, inNumSamples)) return; const float *table0 = bufs[0].data; const float *table2 = bufs[1].data; if (!table0 || !table2 || tableSize != bufs[0].samples|| tableSize != bufs[1].samples) { ClearUnitOutputs(unit, inNumSamples); return; } const float *table1 = table0 + 1; const float *table3 = table2 + 1; LOOP1(inNumSamples, float pfrac = PhaseFrac1(phase); uint32 index = ((phase >> xlobits1) & lomask); float val0 = *(float*)((char*)table0 + index); float val1 = *(float*)((char*)table1 + index); float val2 = *(float*)((char*)table2 + index); float val3 = *(float*)((char*)table3 + index); float a = val0 + val1 * pfrac; float b = val2 + val3 * pfrac; ZXP(out) = a + level * (b - a); phase += phaseinc; ); } else { int nsmps; int donesmps = 0; int remain = inNumSamples; while (remain) { float level = cur - sc_floor(cur); float cut; if (bufdiff > 0.) { cut = sc_min(nextbufpos, sc_floor(cur+1.f)); } else { cut = sc_max(nextbufpos, sc_ceil(cur-1.f)); } float sweepdiff = cut - cur; if (cut == nextbufpos) nsmps = remain; else { float sweep = (float)inNumSamples / bufdiff; nsmps = (int)sc_floor(sweep * sweepdiff + 0.5f) - donesmps; nsmps = sc_clip(nsmps, 1, remain); } float slope = sweepdiff / (float)nsmps; int32 bufnum = (int32)sc_floor(cur); const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); if (!verify_wavetable(unit, "VOsc", tableSize, inNumSamples)) return; const float *table0 = bufs[0].data; const float *table2 = bufs[1].data; if (!table0 || !table2 || tableSize != bufs[0].samples|| tableSize != bufs[1].samples) { ClearUnitOutputs(unit, inNumSamples); return; } const float *table1 = table0 + 1; const float *table3 = table2 + 1; LOOP(nsmps, float pfrac = PhaseFrac1(phase); uint32 index = ((phase >> xlobits1) & lomask); float val0 = *(float*)((char*)table0 + index); float val1 = *(float*)((char*)table1 + index); float val2 = *(float*)((char*)table2 + index); float val3 = *(float*)((char*)table3 + index); float a = val0 + val1 * pfrac; float b = val2 + val3 * pfrac; ZXP(out) = a + level * (b - a); phase += phaseinc; level += slope; ); donesmps += nsmps; remain -= nsmps; cur = cut; } } unit->m_bufpos = nextbufpos; unit->m_phase = phase; } void VOsc_next_ika(VOsc *unit, int inNumSamples) { float *out = ZOUT(0); float nextbufpos = ZIN0(0); float freqin = ZIN0(1); float *phasein = ZIN(2); float prevbufpos = unit->m_bufpos; float bufdiff = nextbufpos - prevbufpos; int32 phase = unit->m_phase; int32 lomask = unit->m_lomask; int32 freq = (int32)(unit->m_cpstoinc * freqin); int32 phaseinc = freq; int tableSize = unit->mTableSize; float cur = prevbufpos; World *world = unit->mWorld; if (bufdiff == 0.f) { float level = cur - sc_floor(cur); int32 bufnum = (int)sc_floor(cur); const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); if (!verify_wavetable(unit, "VOsc", tableSize, inNumSamples)) return; const float *table0 = bufs[0].data; const float *table2 = bufs[1].data; if (!table0 || !table2 || tableSize != bufs[0].samples|| tableSize != bufs[1].samples) { ClearUnitOutputs(unit, inNumSamples); return; } const float *table1 = table0 + 1; const float *table3 = table2 + 1; LOOP1(inNumSamples, int32 pphase = phase + (int32)(ZXP(phasein) * unit->m_radtoinc); float pfrac = PhaseFrac1(pphase); uint32 index = ((pphase >> xlobits1) & lomask); float val0 = *(float*)((char*)table0 + index); float val1 = *(float*)((char*)table1 + index); float val2 = *(float*)((char*)table2 + index); float val3 = *(float*)((char*)table3 + index); float a = val0 + val1 * pfrac; float b = val2 + val3 * pfrac; ZXP(out) = a + level * (b - a); phase += phaseinc; ); } else { int nsmps; int donesmps = 0; int remain = inNumSamples; while (remain) { float level = cur - sc_floor(cur); float cut; if (bufdiff > 0.) { cut = sc_min(nextbufpos, sc_floor(cur+1.f)); } else { cut = sc_max(nextbufpos, sc_ceil(cur-1.f)); } float sweepdiff = cut - cur; if (cut == nextbufpos) nsmps = remain; else { float sweep = (float)inNumSamples / bufdiff; nsmps = (int)sc_floor(sweep * sweepdiff + 0.5f) - donesmps; nsmps = sc_clip(nsmps, 1, remain); } float slope = sweepdiff / (float)nsmps; int32 bufnum = (int32)sc_floor(cur); const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); if (!verify_wavetable(unit, "VOsc", tableSize, inNumSamples)) return; const float *table0 = bufs[0].data; const float *table2 = bufs[1].data; if (!table0 || !table2 || tableSize != bufs[0].samples|| tableSize != bufs[1].samples) { ClearUnitOutputs(unit, inNumSamples); return; } const float *table1 = table0 + 1; const float *table3 = table2 + 1; LOOP(nsmps, int32 pphase = phase + (int32)(ZXP(phasein) * unit->m_radtoinc); float pfrac = PhaseFrac1(pphase); uint32 index = ((pphase >> xlobits1) & lomask); float val0 = *(float*)((char*)table0 + index); float val1 = *(float*)((char*)table1 + index); float val2 = *(float*)((char*)table2 + index); float val3 = *(float*)((char*)table3 + index); float a = val0 + val1 * pfrac; float b = val2 + val3 * pfrac; ZXP(out) = a + level * (b - a); phase += phaseinc; level += slope; ); donesmps += nsmps; remain -= nsmps; cur = cut; } } unit->m_bufpos = nextbufpos; unit->m_phase = phase; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void VOsc3_Ctor(VOsc3 *unit) { SETCALC(VOsc3_next_ik); float nextbufpos = ZIN0(0); unit->m_bufpos = nextbufpos; int32 bufnum = (int32)sc_floor(nextbufpos); World *world = unit->mWorld; const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); int tableSize = bufs[0].samples; unit->mTableSize = tableSize; int tableSize2 = tableSize >> 1; unit->m_lomask = (tableSize2 - 1) << 3; unit->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.; unit->m_phase1 = 0; unit->m_phase2 = 0; unit->m_phase3 = 0; VOsc3_next_ik(unit, 1); } void VOsc3_next_ik(VOsc3 *unit, int inNumSamples) { float *out = ZOUT(0); float nextbufpos = ZIN0(0); float freq1in = ZIN0(1); float freq2in = ZIN0(2); float freq3in = ZIN0(3); float prevbufpos = unit->m_bufpos; float bufdiff = nextbufpos - prevbufpos; int32 phase1 = unit->m_phase1; int32 phase2 = unit->m_phase2; int32 phase3 = unit->m_phase3; int32 freq1 = (int32)(unit->m_cpstoinc * freq1in); int32 freq2 = (int32)(unit->m_cpstoinc * freq2in); int32 freq3 = (int32)(unit->m_cpstoinc * freq3in); int32 lomask = unit->m_lomask; int tableSize = unit->mTableSize; float cur = prevbufpos; World *world = unit->mWorld; if (bufdiff == 0.f) { float level = cur - (int)cur; int bufnum = (int)cur; const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); if (!verify_wavetable(unit, "VOsc3", tableSize, inNumSamples)) return; const float *table0 = bufs[0].data; const float *table2 = bufs[1].data; if (!table0 || !table2 || tableSize != bufs[0].samples|| tableSize != bufs[1].samples) { ClearUnitOutputs(unit, inNumSamples); return; } const float *table1 = table0 + 1; const float *table3 = table2 + 1; LOOP1(inNumSamples, float pfrac1 = PhaseFrac1(phase1); float pfrac2 = PhaseFrac1(phase2); float pfrac3 = PhaseFrac1(phase3); int index1 = ((phase1 >> xlobits1) & lomask); int index2 = ((phase2 >> xlobits1) & lomask); int index3 = ((phase3 >> xlobits1) & lomask); phase1 += freq1; phase2 += freq2; phase3 += freq3; float val10 = *(float*)((char*)table0 + index1); float val11 = *(float*)((char*)table1 + index1); float val12 = *(float*)((char*)table2 + index1); float val13 = *(float*)((char*)table3 + index1); float a = val10 + val11 * pfrac1; float b = val12 + val13 * pfrac1; float val20 = *(float*)((char*)table0 + index2); float val21 = *(float*)((char*)table1 + index2); float val22 = *(float*)((char*)table2 + index2); float val23 = *(float*)((char*)table3 + index2); a += val20 + val21 * pfrac2; b += val22 + val23 * pfrac2; float val30 = *(float*)((char*)table0 + index3); float val31 = *(float*)((char*)table1 + index3); float val32 = *(float*)((char*)table2 + index3); float val33 = *(float*)((char*)table3 + index3); a += val30 + val31 * pfrac3; b += val32 + val33 * pfrac3; ZXP(out) = a + level * (b - a); ); } else { int nsmps; int donesmps = 0; int remain = inNumSamples; do { float level = cur - sc_trunc(cur); float cut; if (bufdiff >= 0.) cut = sc_min(nextbufpos, sc_trunc(cur+1.f)); else cut = sc_max(nextbufpos, sc_ceil(cur-1.f)); float sweepdiff = cut - cur; if (cut == nextbufpos) nsmps = remain; else { float sweep = (float)inNumSamples / bufdiff; nsmps = sc_floor(sweep * sweepdiff + 0.5f) - donesmps; nsmps = sc_clip(nsmps, 1, remain); } float slope = sweepdiff / (float)nsmps; int bufnum = (int)cur; const SndBuf *bufs = VOscGetBuf(bufnum, world, unit); if (!verify_wavetable(unit, "VOsc3", tableSize, inNumSamples)) return; const float *table0 = bufs[0].data; const float *table2 = bufs[1].data; if (!table0 || !table2 || tableSize != bufs[0].samples|| tableSize != bufs[1].samples) { ClearUnitOutputs(unit, inNumSamples); return; } const float *table1 = table0 + 1; const float *table3 = table2 + 1; LOOP(nsmps, float pfrac1 = PhaseFrac1(phase1); float pfrac2 = PhaseFrac1(phase2); float pfrac3 = PhaseFrac1(phase3); int index1 = ((phase1 >> xlobits1) & lomask); int index2 = ((phase2 >> xlobits1) & lomask); int index3 = ((phase3 >> xlobits1) & lomask); phase1 += freq1; phase2 += freq2; phase3 += freq3; float val10 = *(float*)((char*)table0 + index1); float val11 = *(float*)((char*)table1 + index1); float val12 = *(float*)((char*)table2 + index1); float val13 = *(float*)((char*)table3 + index1); float a = val10 + val11 * pfrac1; float b = val12 + val13 * pfrac1; float val20 = *(float*)((char*)table0 + index2); float val21 = *(float*)((char*)table1 + index2); float val22 = *(float*)((char*)table2 + index2); float val23 = *(float*)((char*)table3 + index2); a += val20 + val21 * pfrac2; b += val22 + val23 * pfrac2; float val30 = *(float*)((char*)table0 + index3); float val31 = *(float*)((char*)table1 + index3); float val32 = *(float*)((char*)table2 + index3); float val33 = *(float*)((char*)table3 + index3); a += val30 + val31 * pfrac3; b += val32 + val33 * pfrac3; ZXP(out) = a + level * (b - a); level += slope; ); donesmps += nsmps; remain -= nsmps; cur = cut; } while (remain); } unit->m_bufpos = nextbufpos; unit->m_phase1 = phase1; unit->m_phase2 = phase2; unit->m_phase3 = phase3; } ////////////////////////////////////////////////////////////////////////////////////////// void Formant_Ctor(Formant *unit) { SETCALC(Formant_next); unit->m_cpstoinc = ft->mSineSize * SAMPLEDUR * 65536.; unit->m_phase1 = 0; unit->m_phase2 = 0; unit->m_phase3 = 0; Formant_next(unit, 1); } #define tqcyc13 0x18000000 void Formant_next(Formant *unit, int inNumSamples) { float *out = ZOUT(0); float freq1in = ZIN0(0); float freq2in = ZIN0(1); float freq3in = ZIN0(2); int32 phase1 = unit->m_phase1; int32 phase2 = unit->m_phase2; int32 phase3 = unit->m_phase3; float cpstoinc = unit->m_cpstoinc; int32 freq1 = (int32)(cpstoinc * freq1in); int32 freq2 = (int32)(cpstoinc * freq2in); int32 freq3 = (int32)(cpstoinc * freq3in); float* sine = ft->mSine; int32 formfreq = sc_max(freq1, freq3); LOOP1(inNumSamples, if (phase3 < onecyc13) { ZXP(out) = (*(float*)((char*)sine + (((phase3 + tqcyc13) >> xlobits) & xlomask13)) + 1.f) * *(float*)((char*)sine + ((phase2 >> xlobits) & xlomask13)); phase3 += formfreq; } else { ZXP(out) = 0.f; } phase1 += freq1; phase2 += freq2; if (phase1 > onecyc13) { phase1 -= onecyc13; phase2 = phase1 * freq2 / freq1; phase3 = phase1 * freq3 / freq1; } ); unit->m_phase1 = phase1; unit->m_phase2 = phase2; unit->m_phase3 = phase3; } //////////////////////////////////////////////////////////////////////////////////////////////////////// inline float lookup13(float* table, int32 pphase) { float pfrac = PhaseFrac(pphase); float* tbl = (float*)((char*)table + ((pphase >> xlobits) & xlomask13)); return lininterp(pfrac, tbl[0], tbl[1]); } void Blip_Ctor(Blip *unit) { SETCALC(Blip_next); unit->m_freqin = ZIN0(0); unit->m_numharm = (int32)ZIN0(1); unit->m_cpstoinc = ft->mSineSize * SAMPLEDUR * 65536. * 0.5; int32 N = unit->m_numharm; int32 maxN = (int32)((SAMPLERATE * 0.5) / unit->m_freqin); if (N > maxN) N = maxN; if (N < 1) N = 1; unit->m_N = N; unit->m_scale = 0.5/N; unit->m_phase = 0; Blip_next(unit, 1); } void Blip_next(Blip *unit, int inNumSamples) { float *out = ZOUT(0); float freqin = ZIN0(0); int numharm = (int32)ZIN0(1); int32 phase = unit->m_phase; float* numtbl = ft->mSine; float* dentbl = ft->mCosecant; int32 freq, N, prevN; float scale, prevscale; bool crossfade; if (numharm != unit->m_numharm || freqin != unit->m_freqin) { N = numharm; int32 maxN = (int32)((SAMPLERATE * 0.5) / freqin); if (N > maxN) { float maxfreqin; N = maxN; maxfreqin = sc_max(unit->m_freqin, freqin); freq = (int32)(unit->m_cpstoinc * maxfreqin); } else { if (N < 1) { N = 1; } freq = (int32)(unit->m_cpstoinc * freqin); } crossfade = N != unit->m_N; prevN = unit->m_N; prevscale = unit->m_scale; unit->m_N = N; unit->m_scale = scale = 0.5/N; } else { N = unit->m_N; freq = (int32)(unit->m_cpstoinc * freqin); scale = unit->m_scale; crossfade = false; } int32 N2 = 2*N+1; if (crossfade) { int32 prevN2 = 2 * prevN + 1; float xfade_slope = unit->mRate->mSlopeFactor; float xfade = 0.f; LOOP1(inNumSamples, float* tbl = (float*)((char*)dentbl + ((phase >> xlobits) & xlomask13)); float t0 = tbl[0]; float t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { ZXP(out) = 1.f; } else { int32 rphase = phase * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer / denom - 1.f) * prevscale; rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer / denom - 1.f) * scale; ZXP(out) = lininterp(xfade, n1, n2); } } else { float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase * prevN2; pfrac = PhaseFrac(rphase); float* tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer * denom - 1.f) * prevscale; rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer * denom - 1.f) * scale; ZXP(out) = lininterp(xfade, n1, n2); } phase += freq; xfade += xfade_slope; ); } else { // hmm, if freq is above sr/4 then revert to sine table osc w/ no interpolation ? // why bother, it isn't a common choice for a fundamental. LOOP1(inNumSamples, float* tbl = (float*)((char*)dentbl + ((phase >> xlobits) & xlomask13)); float t0 = tbl[0]; float t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { ZXP(out) = 1.f; } else { int32 rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); ZXP(out) = (numer / denom - 1.f) * scale; } } else { float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); ZXP(out) = (numer * denom - 1.f) * scale; } phase += freq; ); } unit->m_phase = phase; unit->m_freqin = freqin; unit->m_numharm = numharm; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Saw_Ctor(Saw *unit) { SETCALC(Saw_next); unit->m_freqin = ZIN0(0); unit->m_cpstoinc = ft->mSineSize * SAMPLEDUR * 65536. * 0.5; unit->m_N = (int32)((SAMPLERATE * 0.5) / unit->m_freqin); unit->m_scale = 0.5/unit->m_N; unit->m_phase = 0; unit->m_y1 = -0.46f; ZOUT0(0) = 0.f; } void Saw_next(Saw *unit, int inNumSamples) { float *out = ZOUT(0); float freqin = ZIN0(0); int32 phase = unit->m_phase; float y1 = unit->m_y1; float* numtbl = ft->mSine; float* dentbl = ft->mCosecant; int32 freq, N, prevN; float scale, prevscale; bool crossfade; if (freqin != unit->m_freqin) { N = (int32)((SAMPLERATE * 0.5) / freqin); if (N != unit->m_N) { float maxfreqin; maxfreqin = sc_max(unit->m_freqin, freqin); freq = (int32)(unit->m_cpstoinc * maxfreqin); crossfade = true; } else { freq = (int32)(unit->m_cpstoinc * freqin); crossfade = false; } prevN = unit->m_N; prevscale = unit->m_scale; unit->m_N = N; unit->m_scale = scale = 0.5/N; } else { N = unit->m_N; freq = (int32)(unit->m_cpstoinc * freqin); scale = unit->m_scale; crossfade = false; } int32 N2 = 2*N+1; if (crossfade) { int32 prevN2 = 2 * prevN + 1; float xfade_slope = unit->mRate->mSlopeFactor; float xfade = 0.f; LOOP1(inNumSamples, float* tbl = (float*)((char*)dentbl + ((phase >> xlobits) & xlomask13)); float t0 = tbl[0]; float t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { ZXP(out) = y1 = 1.f + 0.999f * y1; } else { int32 rphase = phase * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer / denom - 1.f) * prevscale; rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer / denom - 1.f) * scale; ZXP(out) = y1 = n1 + xfade * (n2 - n1) + 0.999f * y1; } } else { float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer * denom - 1.f) * prevscale; rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer * denom - 1.f) * scale; ZXP(out) = y1 = n1 + xfade * (n2 - n1) + 0.999f * y1; } phase += freq; xfade += xfade_slope; ); } else { // hmm, if freq is above sr/4 then revert to sine table osc ? // why bother, it isn't a common choice for a fundamental. LOOP1(inNumSamples, float* tbl = (float*)((char*)dentbl + ((phase >> xlobits) & xlomask13)); float t0 = tbl[0]; float t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { ZXP(out) = y1 = 1.f + 0.999f * y1; } else { int32 rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); ZXP(out) = y1 = (numer / denom - 1.f) * scale + 0.999f * y1; } } else { float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase * N2; pfrac = PhaseFrac(rphase); float* tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); ZXP(out) = y1 = (numer * denom - 1.f) * scale + 0.999f * y1; } phase += freq; ); } unit->m_y1 = y1; unit->m_phase = phase; unit->m_freqin = freqin; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Pulse_Ctor(Pulse *unit) { SETCALC(Pulse_next); unit->m_freqin = ZIN0(0); unit->m_cpstoinc = ft->mSineSize * SAMPLEDUR * 65536. * 0.5; unit->m_N = (int32)((SAMPLERATE * 0.5) / unit->m_freqin); unit->m_scale = 0.5/unit->m_N; unit->m_phase = 0; unit->m_phaseoff = 0; unit->m_y1 = 0.f; ZOUT0(0) = 0.f; } void Pulse_next(Pulse *unit, int inNumSamples) { float *out = ZOUT(0); float freqin = ZIN0(0); float duty = ZIN0(1); int32 phase = unit->m_phase; float y1 = unit->m_y1; float* numtbl = ft->mSine; float* dentbl = ft->mCosecant; int32 freq, N, prevN; float scale, prevscale; bool crossfade; if (freqin != unit->m_freqin) { N = (int32)((SAMPLERATE * 0.5) / freqin); if (N != unit->m_N) { float maxfreqin; maxfreqin = sc_max(unit->m_freqin, freqin); freq = (int32)(unit->m_cpstoinc * maxfreqin); crossfade = true; } else { freq = (int32)(unit->m_cpstoinc * freqin); crossfade = false; } prevN = unit->m_N; prevscale = unit->m_scale; unit->m_N = N; unit->m_scale = scale = 0.5/N; } else { N = unit->m_N; freq = (int32)(unit->m_cpstoinc * freqin); scale = unit->m_scale; crossfade = false; } int32 N2 = 2*N+1; int32 phaseoff = unit->m_phaseoff; int32 next_phaseoff = (int32)(duty * (1L << 28)); int32 phaseoff_slope = (int32)((next_phaseoff - phaseoff) * unit->mRate->mSlopeFactor); unit->m_phaseoff = next_phaseoff; float rscale = 1.f / scale + 1.f; float pul1, pul2; if (crossfade) { int32 prevN2 = 2 * prevN + 1; float xfade_slope = unit->mRate->mSlopeFactor; float xfade = 0.f; LOOP1(inNumSamples, float* tbl = (float*)((char*)dentbl + ((phase >> xlobits) & xlomask13)); float t0 = tbl[0]; float t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { pul1 = 1.f; } else { int32 rphase = phase * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer / denom - 1.f) * prevscale; rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer / denom - 1.f) * scale; pul1 = lininterp(xfade, n1, n2); } } else { float pfrac = PhaseFrac(phase); float denom = lininterp(pfrac, t0, t1); int32 rphase = phase * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer * denom - 1.f) * prevscale; rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer * denom - 1.f) * scale; pul1 = lininterp(xfade, n1, n2); } int32 phase2 = phase + phaseoff; tbl = (float*)((char*)dentbl + ((phase2 >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase2 >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase2); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { pul2 = 1.f; } else { int32 rphase = phase2 * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer / denom - 1.f) * prevscale; rphase = phase2 * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer / denom - 1.f) * scale; pul2 = lininterp(xfade, n1, n2); } } else { float pfrac = PhaseFrac(phase2); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase2 * prevN2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); float n1 = (numer * denom - 1.f) * prevscale; rphase = phase2 * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); numer = lininterp(pfrac, tbl[0], tbl[1]); float n2 = (numer * denom - 1.f) * scale; pul2 = lininterp(xfade, n1, n2); } ZXP(out) = y1 = pul1 - pul2 + 0.999f * y1; phase += freq; phaseoff += phaseoff_slope; xfade += xfade_slope; ); } else { LOOP1(inNumSamples, float* tbl = (float*)((char*)dentbl + ((phase >> xlobits) & xlomask13)); float t0 = tbl[0]; float t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { pul1 = rscale; } else { int32 rphase = phase * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); pul1 = numer / denom; } } else { float pfrac = PhaseFrac(phase); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase * N2; pfrac = PhaseFrac(rphase); float* tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); pul1 = (numer * denom); } int32 phase2 = phase + phaseoff; tbl = (float*)((char*)dentbl + ((phase2 >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; if (t0 == kBadValue || t1 == kBadValue) { tbl = (float*)((char*)numtbl + ((phase2 >> xlobits) & xlomask13)); t0 = tbl[0]; t1 = tbl[1]; float pfrac = PhaseFrac(phase2); float denom = t0 + (t1 - t0) * pfrac; if (std::abs(denom) < 0.0005f) { pul2 = rscale; } else { int32 rphase = phase2 * N2; pfrac = PhaseFrac(rphase); tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); pul2 = numer / denom; } } else { float pfrac = PhaseFrac(phase2); float denom = t0 + (t1 - t0) * pfrac; int32 rphase = phase2 * N2; pfrac = PhaseFrac(rphase); float* tbl = (float*)((char*)numtbl + ((rphase >> xlobits) & xlomask13)); float numer = lininterp(pfrac, tbl[0], tbl[1]); pul2 = (numer * denom); } ZXP(out) = y1 = (pul1 - pul2) * scale + 0.999f * y1; phase += freq; phaseoff += phaseoff_slope; ); } unit->m_y1 = y1; unit->m_phase = phase; unit->m_freqin = freqin; } //////////////////////////////////////////////////////////////////////////////////////////////////////// static float Klang_SetCoefs(Klang *unit) { unit->m_numpartials = (unit->mNumInputs - 2)/3; int numcoefs = unit->m_numpartials * 3; unit->m_coefs = (float*)RTAlloc(unit->mWorld, numcoefs * sizeof(float)); if (!unit->m_coefs) { Print("Klang: RT memory allocation failed\n"); SETCALC(ClearUnitOutputs); return 0.f; } float freqscale = ZIN0(0) * unit->mRate->mRadiansPerSample; float freqoffset = ZIN0(1) * unit->mRate->mRadiansPerSample; float outf = 0.; float* coefs = unit->m_coefs - 1; for (int i=0,j=2; im_numpartials; ++i,j+=3) { float w = ZIN0(j) * freqscale + freqoffset; float level = ZIN0(j+1); float phase = ZIN0(j+2); if (phase != 0.f) { outf += *++coefs = level * sin(phase); // y1 *++coefs = level * sin(phase - w); // y2 } else { outf += *++coefs = 0.f; // y1 *++coefs = level * -sin(w); // y2 } *++coefs = 2. * cos(w); // b1 } return outf; } void Klang_Ctor(Klang *unit) { SETCALC(Klang_next); ZOUT0(0) = Klang_SetCoefs(unit); } void Klang_Dtor(Klang *unit) { RTFree(unit->mWorld, unit->m_coefs); } void Klang_next(Klang *unit, int inNumSamples) { float *out0 = ZOUT(0); float* out; float y0_0, y1_0, y2_0, b1_0; float y0_1, y1_1, y2_1, b1_1; float y0_2, y1_2, y2_2, b1_2; float y0_3, y1_3, y2_3, b1_3; float outf; float* coefs = unit->m_coefs - 1; int32 numpartials = unit->m_numpartials; switch (numpartials & 3) { case 3 : y1_0 = *++coefs; y2_0 = *++coefs; b1_0 = *++coefs; y1_1 = *++coefs; y2_1 = *++coefs; b1_1 = *++coefs; y1_2 = *++coefs; y2_2 = *++coefs; b1_2 = *++coefs; out = out0; LOOP(unit->mRate->mFilterLoops, outf = y0_0 = b1_0 * y1_0 - y2_0; outf += y0_1 = b1_1 * y1_1 - y2_1; outf += y0_2 = b1_2 * y1_2 - y2_2; ZXP(out) = outf; outf = y2_0 = b1_0 * y0_0 - y1_0; outf += y2_1 = b1_1 * y0_1 - y1_1; outf += y2_2 = b1_2 * y0_2 - y1_2; ZXP(out) = outf; outf = y1_0 = b1_0 * y2_0 - y0_0; outf += y1_1 = b1_1 * y2_1 - y0_1; outf += y1_2 = b1_2 * y2_2 - y0_2; ZXP(out) = outf; ); LOOP(unit->mRate->mFilterRemain, outf = y0_0 = b1_0 * y1_0 - y2_0; outf += y0_1 = b1_1 * y1_1 - y2_1; outf += y0_2 = b1_2 * y1_2 - y2_2; y2_0 = y1_0; y1_0 = y0_0; y2_1 = y1_1; y1_1 = y0_1; y2_2 = y1_2; y1_2 = y0_2; ZXP(out) = outf; ); coefs -= 9; *++coefs = y1_0; *++coefs = y2_0; ++coefs; *++coefs = y1_1; *++coefs = y2_1; ++coefs; *++coefs = y1_2; *++coefs = y2_2; ++coefs; break; case 2 : y1_0 = *++coefs; y2_0 = *++coefs; b1_0 = *++coefs; y1_1 = *++coefs; y2_1 = *++coefs; b1_1 = *++coefs; out = out0; LOOP(unit->mRate->mFilterLoops, outf = y0_0 = b1_0 * y1_0 - y2_0; outf += y0_1 = b1_1 * y1_1 - y2_1; ZXP(out) = outf; outf = y2_0 = b1_0 * y0_0 - y1_0; outf += y2_1 = b1_1 * y0_1 - y1_1; ZXP(out) = outf; outf = y1_0 = b1_0 * y2_0 - y0_0; outf += y1_1 = b1_1 * y2_1 - y0_1; ZXP(out) = outf; ); LOOP(unit->mRate->mFilterRemain, outf = y0_0 = b1_0 * y1_0 - y2_0; outf += y0_1 = b1_1 * y1_1 - y2_1; y2_0 = y1_0; y1_0 = y0_0; y2_1 = y1_1; y1_1 = y0_1; ZXP(out) = outf; ); coefs -= 6; *++coefs = y1_0; *++coefs = y2_0; ++coefs; *++coefs = y1_1; *++coefs = y2_1; ++coefs; break; case 1 : y1_0 = *++coefs; y2_0 = *++coefs; b1_0 = *++coefs; out = out0; LOOP(unit->mRate->mFilterLoops, ZXP(out) = y0_0 = b1_0 * y1_0 - y2_0; ZXP(out) = y2_0 = b1_0 * y0_0 - y1_0; ZXP(out) = y1_0 = b1_0 * y2_0 - y0_0; ); LOOP(unit->mRate->mFilterRemain, ZXP(out) = y0_0 = b1_0 * y1_0 - y2_0; y2_0 = y1_0; y1_0 = y0_0; ); coefs -= 3; *++coefs = y1_0; *++coefs = y2_0; ++coefs; break; case 0 : out = out0; ZClear(inNumSamples, out); break; } int32 imax = numpartials >> 2; for (int i=0; imRate->mFilterLoops, outf = y0_0 = b1_0 * y1_0 - y2_0; outf += y0_1 = b1_1 * y1_1 - y2_1; outf += y0_2 = b1_2 * y1_2 - y2_2; outf += y0_3 = b1_3 * y1_3 - y2_3; ZXP(out) += outf; outf = y2_0 = b1_0 * y0_0 - y1_0; outf += y2_1 = b1_1 * y0_1 - y1_1; outf += y2_2 = b1_2 * y0_2 - y1_2; outf += y2_3 = b1_3 * y0_3 - y1_3; ZXP(out) += outf; outf = y1_0 = b1_0 * y2_0 - y0_0; outf += y1_1 = b1_1 * y2_1 - y0_1; outf += y1_2 = b1_2 * y2_2 - y0_2; outf += y1_3 = b1_3 * y2_3 - y0_3; ZXP(out) += outf; ); LOOP(unit->mRate->mFilterRemain, outf = y0_0 = b1_0 * y1_0 - y2_0; outf += y0_1 = b1_1 * y1_1 - y2_1; outf += y0_2 = b1_2 * y1_2 - y2_2; outf += y0_3 = b1_3 * y1_3 - y2_3; y2_0 = y1_0; y1_0 = y0_0; y2_1 = y1_1; y1_1 = y0_1; y2_2 = y1_2; y1_2 = y0_2; y2_3 = y1_3; y1_3 = y0_3; ZXP(out) += outf; ); coefs -= 12; *++coefs = y1_0; *++coefs = y2_0; ++coefs; *++coefs = y1_1; *++coefs = y2_1; ++coefs; *++coefs = y1_2; *++coefs = y2_2; ++coefs; *++coefs = y1_3; *++coefs = y2_3; ++coefs; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// static void Klank_SetCoefs(Klank *unit) { int numpartials = (unit->mNumInputs - 4) / 3; unit->m_numpartials = numpartials; int numcoefs = ((unit->m_numpartials + 3) & ~3) * 5; unit->m_coefs = (float*)RTAlloc(unit->mWorld, (numcoefs + unit->mWorld->mBufLength) * sizeof(float)); if (!unit->m_coefs) { Print("Klang: RT memory allocation failed\n"); SETCALC(ClearUnitOutputs); return; } unit->m_buf = unit->m_coefs + numcoefs; float freqscale = ZIN0(1) * unit->mRate->mRadiansPerSample; float freqoffset = ZIN0(2) * unit->mRate->mRadiansPerSample; float decayscale = ZIN0(3); float* coefs = unit->m_coefs; float sampleRate = SAMPLERATE; for (int i=0,j=4; i>2) + (i & 3); coefs[k+0] = 0.f; // y1 coefs[k+4] = 0.f; // y2 coefs[k+8] = twoR * cost; // b1 coefs[k+12] = -R2; // b2 coefs[k+16] = level * 0.25; // a0 //Print("coefs %d %g %g %g\n", i, twoR * cost, -R2, ampf * 0.25); } } void Klank_Ctor(Klank *unit) { SETCALC(Klank_next); unit->m_x1 = unit->m_x2 = 0.f; Klank_SetCoefs(unit); ZOUT0(0) = 0.f; } void Klank_Dtor(Klank *unit) { RTFree(unit->mWorld, unit->m_coefs); } void Klank_next(Klank *unit, int inNumSamples) { float *out0 = ZOUT(0); float *in0 = ZIN(0); float *in, *out; float inf; float y0_0, y1_0, y2_0, a0_0, b1_0, b2_0; float y0_1, y1_1, y2_1, a0_1, b1_1, b2_1; float y0_2, y1_2, y2_2, a0_2, b1_2, b2_2; float y0_3, y1_3, y2_3, a0_3, b1_3, b2_3; int32 numpartials = unit->m_numpartials; int32 imax = numpartials >> 2; float* coefs = unit->m_coefs + imax * 20; switch (numpartials & 3) { case 3 : y1_0 = coefs[0]; y2_0 = coefs[4]; b1_0 = coefs[8]; b2_0 = coefs[12]; a0_0 = coefs[16]; y1_1 = coefs[1]; y2_1 = coefs[5]; b1_1 = coefs[9]; b2_1 = coefs[13]; a0_1 = coefs[17]; y1_2 = coefs[2]; y2_2 = coefs[6]; b1_2 = coefs[10]; b2_2 = coefs[14]; a0_2 = coefs[18]; in = in0; out = unit->m_buf - 1; LooP(unit->mRate->mFilterLoops) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; y0_1 = inf + b1_1 * y1_1 + b2_1 * y2_1; y0_2 = inf + b1_2 * y1_2 + b2_2 * y2_2; *++out = a0_0 * y0_0 + a0_1 * y0_1 + a0_2 * y0_2; inf = *++in; y2_0 = inf + b1_0 * y0_0 + b2_0 * y1_0; y2_1 = inf + b1_1 * y0_1 + b2_1 * y1_1; y2_2 = inf + b1_2 * y0_2 + b2_2 * y1_2; *++out = a0_0 * y2_0 + a0_1 * y2_1 + a0_2 * y2_2; inf = *++in; y1_0 = inf + b1_0 * y2_0 + b2_0 * y0_0; y1_1 = inf + b1_1 * y2_1 + b2_1 * y0_1; y1_2 = inf + b1_2 * y2_2 + b2_2 * y0_2; *++out = a0_0 * y1_0 + a0_1 * y1_1 + a0_2 * y1_2; } LooP(unit->mRate->mFilterRemain) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; y0_1 = inf + b1_1 * y1_1 + b2_1 * y2_1; y0_2 = inf + b1_2 * y1_2 + b2_2 * y2_2; *++out = a0_0 * y0_0 + a0_1 * y0_1 + a0_2 * y0_2; y2_0 = y1_0; y1_0 = y0_0; y2_1 = y1_1; y1_1 = y0_1; y2_2 = y1_2; y1_2 = y0_2; } coefs[0] = zapgremlins(y1_0); coefs[4] = zapgremlins(y2_0); coefs[1] = zapgremlins(y1_1); coefs[5] = zapgremlins(y2_1); coefs[2] = zapgremlins(y1_2); coefs[6] = zapgremlins(y2_2); break; case 2 : y1_0 = coefs[0]; y2_0 = coefs[4]; b1_0 = coefs[8]; b2_0 = coefs[12]; a0_0 = coefs[16]; y1_1 = coefs[1]; y2_1 = coefs[5]; b1_1 = coefs[9]; b2_1 = coefs[13]; a0_1 = coefs[17]; in = in0; out = unit->m_buf - 1; LooP(unit->mRate->mFilterLoops) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; y0_1 = inf + b1_1 * y1_1 + b2_1 * y2_1; *++out = a0_0 * y0_0 + a0_1 * y0_1; inf = *++in; y2_0 = inf + b1_0 * y0_0 + b2_0 * y1_0; y2_1 = inf + b1_1 * y0_1 + b2_1 * y1_1; *++out = a0_0 * y2_0 + a0_1 * y2_1; inf = *++in; y1_0 = inf + b1_0 * y2_0 + b2_0 * y0_0; y1_1 = inf + b1_1 * y2_1 + b2_1 * y0_1; *++out = a0_0 * y1_0 + a0_1 * y1_1; } LooP(unit->mRate->mFilterRemain) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; y0_1 = inf + b1_1 * y1_1 + b2_1 * y2_1; *++out = a0_0 * y0_0 + a0_1 * y0_1; y2_0 = y1_0; y1_0 = y0_0; y2_1 = y1_1; y1_1 = y0_1; } coefs[0] = zapgremlins(y1_0); coefs[4] = zapgremlins(y2_0); coefs[1] = zapgremlins(y1_1); coefs[5] = zapgremlins(y2_1); break; case 1 : y1_0 = coefs[0]; y2_0 = coefs[4]; b1_0 = coefs[8]; b2_0 = coefs[12]; a0_0 = coefs[16]; //Print("rcoefs %g %g %g %g %g\n", y1_0, y2_0, b1_0, b2_0, a0_0); in = in0; out = unit->m_buf - 1; LooP(unit->mRate->mFilterLoops) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; *++out = a0_0 * y0_0; inf = *++in; y2_0 = inf + b1_0 * y0_0 + b2_0 * y1_0; *++out = a0_0 * y2_0; inf = *++in; y1_0 = inf + b1_0 * y2_0 + b2_0 * y0_0; *++out = a0_0 * y1_0; //Print("out %g %g %g\n", y0_0, y2_0, y1_0); } LooP(unit->mRate->mFilterRemain) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; *++out = a0_0 * y0_0; y2_0 = y1_0; y1_0 = y0_0; //Print("out %g\n", y0_0); } /* coefs[0] = y1_0; coefs[4] = y2_0; */ coefs[0] = zapgremlins(y1_0); coefs[4] = zapgremlins(y2_0); break; case 0 : out = unit->m_buf - 1; LooP(inNumSamples) { *++out = 0.f; } break; } coefs = unit->m_coefs; for (int i=0; im_buf - 1; LooP(unit->mRate->mFilterLoops) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; y0_1 = inf + b1_1 * y1_1 + b2_1 * y2_1; y0_2 = inf + b1_2 * y1_2 + b2_2 * y2_2; y0_3 = inf + b1_3 * y1_3 + b2_3 * y2_3; *++out += a0_0 * y0_0 + a0_1 * y0_1 + a0_2 * y0_2 + a0_3 * y0_3; inf = *++in; y2_0 = inf + b1_0 * y0_0 + b2_0 * y1_0; y2_1 = inf + b1_1 * y0_1 + b2_1 * y1_1; y2_2 = inf + b1_2 * y0_2 + b2_2 * y1_2; y2_3 = inf + b1_3 * y0_3 + b2_3 * y1_3; *++out += a0_0 * y2_0 + a0_1 * y2_1 + a0_2 * y2_2 + a0_3 * y2_3; inf = *++in; y1_0 = inf + b1_0 * y2_0 + b2_0 * y0_0; y1_1 = inf + b1_1 * y2_1 + b2_1 * y0_1; y1_2 = inf + b1_2 * y2_2 + b2_2 * y0_2; y1_3 = inf + b1_3 * y2_3 + b2_3 * y0_3; *++out += a0_0 * y1_0 + a0_1 * y1_1 + a0_2 * y1_2 + a0_3 * y1_3; } LooP(unit->mRate->mFilterRemain) { inf = *++in; y0_0 = inf + b1_0 * y1_0 + b2_0 * y2_0; y0_1 = inf + b1_1 * y1_1 + b2_1 * y2_1; y0_2 = inf + b1_2 * y1_2 + b2_2 * y2_2; y0_3 = inf + b1_3 * y1_3 + b2_3 * y2_3; *++out += a0_0 * y0_0 + a0_1 * y0_1 + a0_2 * y0_2 + a0_3 * y0_3; y2_0 = y1_0; y1_0 = y0_0; y2_1 = y1_1; y1_1 = y0_1; y2_2 = y1_2; y1_2 = y0_2; y2_3 = y1_3; y1_3 = y0_3; } coefs[0] = zapgremlins(y1_0); coefs[4] = zapgremlins(y2_0); coefs[1] = zapgremlins(y1_1); coefs[5] = zapgremlins(y2_1); coefs[2] = zapgremlins(y1_2); coefs[6] = zapgremlins(y2_2); coefs[3] = zapgremlins(y1_3); coefs[7] = zapgremlins(y2_3); coefs += 20; } float x0; float x1 = unit->m_x1; float x2 = unit->m_x2; in = unit->m_buf - 1; out = out0; LooP(unit->mRate->mFilterLoops) { x0 = *++in; *++out = x0 - x2; x2 = *++in; *++out = x2 - x1; x1 = *++in; *++out = x1 - x0; } LooP(unit->mRate->mFilterRemain) { x0 = *++in; *++out = x0 - x2; x2 = x1; x1 = x0; } unit->m_x1 = x1; unit->m_x2 = x2; } //////////////////////////////////////////////////////////////////////////////////////////////////////// static void normalize_samples(int size, float* data, float peak) { float maxamp = 0.f; for (int i=0; i maxamp) maxamp = absamp; } if (maxamp != 0.f && maxamp != peak) { float ampfac = peak / maxamp; for (int i=0; i maxamp) maxamp = absamp; } if (maxamp != 0.f && maxamp != peak) { float ampfac = peak / maxamp; for (int i=0; i> 1; double w = (partial * 2.0 * 3.1415926535897932384626433832795) / (double)size2; double cur = amp * sin(phase); phase += w; for (int i=0; i> 1; double w = 2.0 / (double)size2; double phase = -1.0; double offset = -amp * cos (partial * pi2); double cur = amp * cos (partial * acos (phase)) + offset; phase += w; for (int i=0; i 0) && (flag == 1.f) ) { if (j % 3 == 1) { flag = 0.f; } j = j / 3; } if(flag) { data[i] += 1.f; } } } enum { flag_Normalize = 1, flag_Wavetable = 2, flag_Clear = 4 }; void ChebyFill(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { if (buf->channels != 1) return; int flags = msg->geti(); int size = buf->samples; int byteSize = size * sizeof(float); float *data = (float*)malloc(byteSize); if (flags & flag_Clear) Fill(size, data, 0.); else memcpy(data, buf->data, byteSize); for (int partial=1; msg->remain(); partial++) { double amp = msg->getf(); if (flags & flag_Wavetable) add_wchebyshev(size, data, partial, amp); else add_chebyshev(size, data, partial, amp); } if (flags & flag_Normalize) { if (flags & flag_Wavetable) normalize_wsamples(size, data, 1.); else normalize_samples(size, data, 1.); } memcpy(buf->data, data, byteSize); free(data); } void SineFill1(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { if (buf->channels != 1) return; int flags = msg->geti(); int size = buf->samples; int byteSize = size * sizeof(float); float *data = (float*)malloc(byteSize); if (flags & flag_Clear) Fill(size, data, 0.); else memcpy(data, buf->data, byteSize); for (int partial=1; msg->remain(); partial++) { double amp = msg->getf(); if (flags & flag_Wavetable) add_wpartial(size, data, partial, amp, 0.); else add_partial(size, data, partial, amp, 0.); } if (flags & flag_Normalize) { if (flags & flag_Wavetable) normalize_wsamples(size, data, 1.); else normalize_samples(size, data, 1.); } memcpy(buf->data, data, byteSize); free(data); } void SineFill2(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { if (buf->channels != 1) return; int flags = msg->geti(); int size = buf->samples; int byteSize = size * sizeof(float); float *data = (float*)malloc(byteSize); if (flags & flag_Clear) Fill(size, data, 0.); else memcpy(data, buf->data, byteSize); while (msg->remain()) { double partial = msg->getf(); double amp = msg->getf(); if (flags & flag_Wavetable) add_wpartial(size, data, partial, amp, 0.); else add_partial(size, data, partial, amp, 0.); } if (flags & flag_Normalize) { if (flags & flag_Wavetable) normalize_wsamples(size, data, 1.); else normalize_samples(size, data, 1.); } memcpy(buf->data, data, byteSize); free(data); } void SineFill3(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { if (buf->channels != 1) return; int flags = msg->geti(); int size = buf->samples; int byteSize = size * sizeof(float); float *data = (float*)malloc(byteSize); if (flags & flag_Clear) Fill(size, data, 0.); else memcpy(data, buf->data, byteSize); while (msg->remain()) { double partial = msg->getf(); double amp = msg->getf(); double phase = msg->getf(); if (flags & flag_Wavetable) add_wpartial(size, data, partial, amp, phase); else add_partial(size, data, partial, amp, phase); } if (flags & flag_Normalize) { if (flags & flag_Wavetable) normalize_wsamples(size, data, 1.); else normalize_samples(size, data, 1.); } memcpy(buf->data, data, byteSize); free(data); } void NormalizeBuf(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { float newmax; if(msg->remain() != 0){ newmax = msg->getf(); }else{ newmax = 1.f; } float *data = buf->data; int size = buf->samples; normalize_samples(size, data, newmax); } void NormalizeWaveBuf(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { float newmax; if(msg->remain() != 0){ newmax = msg->getf(); }else{ newmax = 1.f; } float *data = buf->data; int size = buf->samples; normalize_wsamples(size, data, newmax); } void CopyBuf(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { int frames1 = buf->frames; int channels1 = buf->channels; int toPos = msg->geti(); uint32 bufnum2 = msg->geti(); int fromPos = msg->geti(); int length = msg->geti(); if (bufnum2 >= world->mNumSndBufs) bufnum2 = 0; SndBuf* buf2 = world->mSndBufs + bufnum2; int frames2 = buf2->frames; int channels2 = buf2->channels; if (channels1 != channels2) return; fromPos = sc_clip(fromPos, 0, frames2-1); toPos = sc_clip(toPos, 0, frames1-1); int maxLength = sc_min(frames2 - fromPos, frames1 - toPos); if (length < 0) { length = maxLength; } else { length = sc_min(length, maxLength); } if (length <= 0) return; int numbytes = length * sizeof(float) * channels1; float *data1 = buf->data + toPos * channels1; float *data2 = buf2->data + fromPos * channels2; if ((((char*)data1 + numbytes) > (char*)data2) || (((char*)data2 + numbytes) > (char*)data1)) { memmove(data1, data2, numbytes); } else { memcpy(data1, data2, numbytes); } } void CantorFill(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { float *data = buf->data; int size = buf->samples; // double offset = msg->getf(); // double amp = msg->getf(); // long offs = (long) offset; cantorFill(size, data); } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(Osc) { ft = inTable; DefineSimpleUnit(DegreeToKey); DefineSimpleUnit(Select); DefineSimpleUnit(TWindex); DefineSimpleUnit(Index); DefineSimpleUnit(IndexL); DefineSimpleUnit(FoldIndex); DefineSimpleUnit(WrapIndex); DefineSimpleUnit(IndexInBetween); DefineSimpleUnit(DetectIndex); DefineSimpleUnit(Shaper); DefineSimpleUnit(FSinOsc); DefineSimpleUnit(PSinGrain); DefineSimpleUnit(SinOsc); DefineSimpleUnit(SinOscFB); DefineSimpleUnit(VOsc); DefineSimpleUnit(VOsc3); DefineSimpleUnit(Osc); DefineSimpleUnit(OscN); DefineSimpleUnit(COsc); DefineSimpleUnit(Formant); DefineSimpleUnit(Blip); DefineSimpleUnit(Saw); DefineSimpleUnit(Pulse); DefineDtorUnit(Klang); DefineDtorUnit(Klank); DefineBufGen("cheby", ChebyFill); DefineBufGen("sine1", SineFill1); DefineBufGen("sine2", SineFill2); DefineBufGen("sine3", SineFill3); DefineBufGen("normalize", NormalizeBuf); DefineBufGen("wnormalize", NormalizeWaveBuf); DefineBufGen("copy", CopyBuf); DefineBufGen("cantorFill", CantorFill); } ////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/plugins/PanUGens.cpp000644 000765 000024 00000136471 12756531745 023063 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include "function_attributes.h" #ifdef NOVA_SIMD #include "simd_memory.hpp" #include "simd_binary_arithmetic.hpp" #include "simd_pan.hpp" #include "simd_mix.hpp" using nova::slope_argument; #endif #include using namespace std; // for math functions static InterfaceTable *ft; struct LinPan2 : public Unit { float m_pos, m_level, m_leftamp, m_rightamp; }; struct Balance2 : public Unit { float m_pos, m_level, m_leftamp, m_rightamp; }; struct Rotate2 : public Unit { float m_pos, m_sint, m_cost; }; struct XFade2 : public Unit { float m_pos, m_level, m_leftamp, m_rightamp; }; struct LinXFade2 : public Unit { float m_pos, m_amp; }; struct Pan2 : public Unit { float m_pos, m_level, m_leftamp, m_rightamp; }; struct Pan4 : public Unit { float m_xpos, m_ypos, m_level, m_LF_amp, m_RF_amp, m_LB_amp, m_RB_amp; }; struct PanB : public Unit { float m_azimuth, m_elevation, m_level, m_W_amp, m_X_amp, m_Y_amp, m_Z_amp; }; struct PanB2 : public Unit { float m_azimuth, m_level, m_W_amp, m_X_amp, m_Y_amp; }; struct BiPanB2 : public Unit { float m_azimuth, m_level, m_W_amp, m_X_amp, m_Y_amp; }; struct PanAz : public Unit { float * m_chanamp; }; struct DecodeB2 : public Unit { float m_cosa, m_sina; float m_W_amp, m_X_amp, m_Y_amp; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void LinPan2_next_ak(LinPan2 *unit, int inNumSamples); void LinPan2_next_aa(LinPan2 *unit, int inNumSamples); void LinPan2_Ctor(LinPan2* unit); void Balance2_next_ak(Balance2 *unit, int inNumSamples); #ifdef NOVA_SIMD FLATTEN void Balance2_next_ak_nova(Balance2 *unit, int inNumSamples); FLATTEN void Balance2_next_ak_nova_64(Balance2 *unit, int inNumSamples); #endif void Balance2_next_aa(Balance2 *unit, int inNumSamples); void Balance2_Ctor(Balance2* unit); void XFade2_next_ak(XFade2 *unit, int inNumSamples); void XFade2_next_aa(XFade2 *unit, int inNumSamples); void XFade2_Ctor(XFade2* unit); void LinXFade2_next_k(LinXFade2 *unit, int inNumSamples); void LinXFade2_next_a(LinXFade2 *unit, int inNumSamples); void LinXFade2_Ctor(LinXFade2* unit); void Pan2_next_ak(Pan2 *unit, int inNumSamples); void vPan2_next_ak(Pan2 *unit, int inNumSamples); void Pan2_next_aa(Pan2 *unit, int inNumSamples); void Pan2_Ctor(Pan2* unit); void Pan4_next(Pan4 *unit, int inNumSamples); void Pan4_Ctor(Pan4* unit); void PanB_next(PanB *unit, int inNumSamples); void PanB_Ctor(PanB* unit); void PanB2_next(PanB2 *unit, int inNumSamples); void PanB2_Ctor(PanB2* unit); void BiPanB2_next(BiPanB2 *unit, int inNumSamples); void BiPanB2_Ctor(BiPanB2* unit); void DecodeB2_next(DecodeB2 *unit, int inNumSamples); void DecodeB2_next_nova(DecodeB2 *unit, int inNumSamples); void vDecodeB2_next(DecodeB2 *unit, int inNumSamples); void DecodeB2_Ctor(DecodeB2* unit); void PanAz_next_ak(PanAz *unit, int inNumSamples); void PanAz_next_aa(PanAz *unit, int inNumSamples); void PanAz_Ctor(PanAz* unit); void Rotate2_next_ak(Rotate2 *unit, int inNumSamples); void Rotate2_Ctor(Rotate2 *unit); } ////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef NOVA_SIMD FLATTEN void LinPan2_next_ak_nova(LinPan2 *unit, int inNumSamples); FLATTEN void LinPan2_next_ak_nova_64(LinPan2 *unit, int inNumSamples); #endif void LinPan2_Ctor(LinPan2 *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(LinPan2_next_aa); } else { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(LinPan2_next_ak_nova_64); if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(LinPan2_next_ak_nova); else #endif SETCALC(LinPan2_next_ak); } // Now we need to initialise some values, which on the first _next run will be "previous" float pan = ZIN0(1) * 0.5f + 0.5f; unit->m_level = ZIN0(2); unit->m_rightamp = unit->m_level * pan; unit->m_leftamp = unit->m_level - unit->m_rightamp; LinPan2_next_aa(unit, 1); } void LinPan2_next_ak(LinPan2 *unit, int inNumSamples) { float *leftout = ZOUT(0); float *rightout = ZOUT(1); float *in = ZIN(0); float pos = ZIN0(1); float level = ZIN0(2); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { float pan = pos * 0.5f + 0.5f; float nextrightamp = level * pan; float nextleftamp = level - nextrightamp; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; LOOP1(inNumSamples, float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; leftamp += leftampslope; rightamp += rightampslope; ); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else { LOOP1(inNumSamples, float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; ); } } #ifdef NOVA_SIMD void LinPan2_next_ak_nova(LinPan2 *unit, int inNumSamples) { float pos = ZIN0(1); float level = ZIN0(2); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { float pan = pos * 0.5f + 0.5f; float nextrightamp = level * pan; float nextleftamp = level - nextrightamp; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; nova::pan2_vec_simd(OUT(0), OUT(1), IN(0), leftamp, leftampslope, rightamp, rightampslope, inNumSamples); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else nova::pan2_vec_simd(OUT(0), OUT(1), IN(0), leftamp, rightamp, inNumSamples); } void LinPan2_next_ak_nova_64(LinPan2 *unit, int inNumSamples) { float pos = ZIN0(1); float level = ZIN0(2); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { float pan = pos * 0.5f + 0.5f; float nextrightamp = level * pan; float nextleftamp = level - nextrightamp; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; nova::pan2_vec_simd<64>(OUT(0), OUT(1), IN(0), leftamp, leftampslope, rightamp, rightampslope); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else nova::pan2_vec_simd<64>(OUT(0), OUT(1), IN(0), leftamp, rightamp); } #endif void LinPan2_next_aa(LinPan2 *unit, int inNumSamples) { float *leftout = ZOUT(0); float *rightout = ZOUT(1); float *in = ZIN(0); float *pos = ZIN(1); float nextlevel = ZIN0(2); float level = unit->m_level; float levelSlope = (nextlevel - level) * unit->mRate->mSlopeFactor; LOOP1(inNumSamples, float pan = ZXP(pos) * 0.5f + 0.5f; float rightamp = level * pan; float leftamp = level - rightamp; float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; level += levelSlope; ); unit->m_level = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Balance2_Ctor(Balance2 *unit) { if (INRATE(2) == calc_FullRate) { SETCALC(Balance2_next_aa); } else { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(Balance2_next_ak_nova_64); else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Balance2_next_ak_nova); else SETCALC(Balance2_next_ak); #else SETCALC(Balance2_next_ak); #endif } unit->m_pos = ZIN0(2); unit->m_level = ZIN0(3); int32 ipos = (int32)(1024.f * unit->m_pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); unit->m_leftamp = unit->m_level * ft->mSine[2048 - ipos]; unit->m_rightamp = unit->m_level * ft->mSine[ipos]; Balance2_next_aa(unit, 1); } void Balance2_next_ak(Balance2 *unit, int inNumSamples) { float *leftout = ZOUT(0); float *rightout = ZOUT(1); float *leftin = ZIN(0); float *rightin = ZIN(1); float pos = ZIN0(2); float level = ZIN0(3); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; LOOP1(inNumSamples, ZXP(leftout) = ZXP(leftin) * leftamp; ZXP(rightout) = ZXP(rightin) * rightamp; leftamp += leftampslope; rightamp += rightampslope; ); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else { LOOP1(inNumSamples, ZXP(leftout) = ZXP(leftin) * leftamp; ZXP(rightout) = ZXP(rightin) * rightamp; ); } } #ifdef NOVA_SIMD void Balance2_next_ak_nova(Balance2 *unit, int inNumSamples) { float pos = ZIN0(2); float level = ZIN0(3); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; //nova::times_vec2_ramp_simd(OUT(0), IN(0), leftamp, leftampslope, OUT(1), IN(1), rightamp, rightampslope, inNumSamples); nova::times_vec_simd(OUT(0), IN(0), slope_argument(leftamp, leftampslope), inNumSamples); nova::times_vec_simd(OUT(1), IN(1), slope_argument(rightamp, rightampslope), inNumSamples); } else { //nova::times_vec2_simd(OUT(0), IN(0), leftamp, OUT(1), IN(1), rightamp, inNumSamples); nova::times_vec_simd(OUT(0), IN(0), leftamp, inNumSamples); nova::times_vec_simd(OUT(1), IN(1), rightamp, inNumSamples); } } void Balance2_next_ak_nova_64(Balance2 *unit, int inNumSamples) { float pos = ZIN0(2); float level = ZIN0(3); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; //nova::times_vec2_ramp_simd(OUT(0), IN(0), leftamp, leftampslope, OUT(1), IN(1), rightamp, rightampslope, inNumSamples); nova::times_vec_simd(OUT(0), IN(0), slope_argument(leftamp, leftampslope), inNumSamples); nova::times_vec_simd(OUT(1), IN(1), slope_argument(rightamp, rightampslope), inNumSamples); } else { //nova::times_vec2_simd(OUT(0), IN(0), leftamp, OUT(1), IN(1), rightamp, inNumSamples); nova::times_vec_simd<64>(OUT(0), IN(0), leftamp); nova::times_vec_simd<64>(OUT(1), IN(1), rightamp); } } #endif void Balance2_next_aa(Balance2 *unit, int inNumSamples) { float *leftout = ZOUT(0); float *rightout = ZOUT(1); float *leftin = ZIN(0); float *rightin = ZIN(1); float *pos = ZIN(2); float nextlevel = ZIN0(3); float level = unit->m_level; float *sineTable = ft->mSine; if (level != nextlevel) { float levelSlope = (nextlevel - level) * unit->mRate->mSlopeFactor; LOOP1(inNumSamples, int32 ipos = (int32)(1024.f * ZXP(pos) + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float leftamp = level * sineTable[2048 - ipos]; float rightamp = level * sineTable[ipos]; ZXP(leftout) = ZXP(leftin) * leftamp; ZXP(rightout) = ZXP(rightin) * rightamp; level += levelSlope; ); unit->m_level = level; } else { LOOP1(inNumSamples, int32 ipos = (int32)(1024.f * ZXP(pos) + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float leftamp = level * sineTable[2048 - ipos]; float rightamp = level * sineTable[ipos]; ZXP(leftout) = ZXP(leftin) * leftamp; ZXP(rightout) = ZXP(rightin) * rightamp; ); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef NOVA_SIMD FLATTEN void XFade2_next_ak_nova(XFade2 *unit, int inNumSamples); FLATTEN void XFade2_next_ak_nova_64(XFade2 *unit, int inNumSamples); #endif void XFade2_Ctor(XFade2 *unit) { if (INRATE(2) == calc_FullRate) { SETCALC(XFade2_next_aa); } else { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(XFade2_next_ak_nova_64); if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(XFade2_next_ak_nova); else #endif SETCALC(XFade2_next_ak); } unit->m_pos = ZIN0(2); unit->m_level = ZIN0(3); int32 ipos = (int32)(1024.f * unit->m_pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); unit->m_leftamp = unit->m_level * ft->mSine[2048 - ipos]; unit->m_rightamp = unit->m_level * ft->mSine[ipos]; XFade2_next_aa(unit, 1); } void XFade2_next_ak(XFade2 *unit, int inNumSamples) { float *out = ZOUT(0); float *leftin = ZIN(0); float *rightin = ZIN(1); float pos = ZIN0(2); float level = ZIN0(3); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; LOOP1(inNumSamples, ZXP(out) = ZXP(leftin) * leftamp + ZXP(rightin) * rightamp; leftamp += leftampslope; rightamp += rightampslope; ); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else { LOOP1(inNumSamples, ZXP(out) = ZXP(leftin) * leftamp + ZXP(rightin) * rightamp; ); } } #ifdef NOVA_SIMD void XFade2_next_ak_nova(XFade2 *unit, int inNumSamples) { float pos = ZIN0(2); float level = ZIN0(3); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; nova::mix_vec_simd(OUT(0), IN(0), slope_argument(leftamp, leftampslope), IN(1), slope_argument(rightamp, rightampslope), inNumSamples); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else nova::mix_vec_simd(OUT(0), IN(0), leftamp, IN(1), rightamp, inNumSamples); } void XFade2_next_ak_nova_64(XFade2 *unit, int inNumSamples) { float pos = ZIN0(2); float level = ZIN0(3); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; nova::mix_vec_simd<64>(OUT(0), IN(0), slope_argument(leftamp, leftampslope), IN(1), slope_argument(rightamp, rightampslope)); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else nova::mix_vec_simd<64>(OUT(0), IN(0), leftamp, IN(1), rightamp); } #endif void XFade2_next_aa(XFade2 *unit, int inNumSamples) { float *out = ZOUT(0); float *leftin = ZIN(0); float *rightin = ZIN(1); float *pos = ZIN(2); float nextlevel = ZIN0(3); float level = unit->m_level; float *sineTable = ft->mSine; if (level != nextlevel) { float levelSlope = (nextlevel - level) * unit->mRate->mSlopeFactor; LOOP1(inNumSamples, int32 ipos = (int32)(1024.f * ZXP(pos) + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float leftamp = level * sineTable[2048 - ipos]; float rightamp = level * sineTable[ipos]; ZXP(out) = ZXP(leftin) * leftamp + ZXP(rightin) * rightamp; level += levelSlope; ); unit->m_level = level; } else { LOOP1(inNumSamples, int32 ipos = (int32)(1024.f * ZXP(pos) + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float leftamp = level * sineTable[2048 - ipos]; float rightamp = level * sineTable[ipos]; ZXP(out) = ZXP(leftin) * leftamp + ZXP(rightin) * rightamp; ); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void LinXFade2_next_i(LinXFade2 *unit, int inNumSamples) { float *out = ZOUT(0); float *leftin = ZIN(0); float *rightin = ZIN(1); float amp = unit->m_amp; LOOP1(inNumSamples, float l = ZXP(leftin); float r = ZXP(rightin); ZXP(out) = l + amp * (r - l); ); } void LinXFade2_next_k(LinXFade2 *unit, int inNumSamples) { float *out = ZOUT(0); float *leftin = ZIN(0); float *rightin = ZIN(1); float pos = ZIN0(2); float amp = unit->m_amp; if (pos != unit->m_pos) { pos = sc_clip(pos, -1.f, 1.f); float nextamp = pos * 0.5f + 0.5f; float amp_slope = (nextamp - amp) * unit->mRate->mSlopeFactor; LOOP1(inNumSamples, float l = ZXP(leftin); float r = ZXP(rightin); ZXP(out) = l + amp * (r - l); amp += amp_slope; ); unit->m_pos = pos; unit->m_amp = amp; } else { LOOP1(inNumSamples, float l = ZXP(leftin); float r = ZXP(rightin); ZXP(out) = l + amp * (r - l); ); } } void LinXFade2_next_a(LinXFade2 *unit, int inNumSamples) { float *out = ZOUT(0); float *leftin = ZIN(0); float *rightin = ZIN(1); float *posp = ZIN(2); LOOP1(inNumSamples, float pos = ZXP(posp); pos = sc_clip(pos, -1.f, 1.f); float amp = pos * 0.5f + 0.5f; float l = ZXP(leftin); float r = ZXP(rightin); ZXP(out) = l + amp * (r - l); ); } #ifdef NOVA_SIMD FLATTEN void LinXFade2_next_i_nova(LinXFade2 *unit, int inNumSamples) { float amp = unit->m_amp; nova::mix_vec_simd(OUT(0), IN(0), 1.f - amp, IN(1), amp, inNumSamples); } FLATTEN void LinXFade2_next_k_nova(LinXFade2 *unit, int inNumSamples) { float pos = ZIN0(2); float amp = unit->m_amp; if (pos != unit->m_pos) { float oldAmpRight = amp; float oldAmpLeft = 1.f - amp; pos = sc_clip(pos, -1.f, 1.f); float nextAmpRight = pos * 0.5f + 0.5f; float nextAmpLeft = 1.f - nextAmpRight; float leftSlope = CALCSLOPE(nextAmpLeft, oldAmpLeft); float rightSlope = CALCSLOPE(nextAmpRight, oldAmpRight); unit->m_amp = nextAmpRight; unit->m_pos = pos; nova::mix_vec_simd(OUT(0), IN(0), nova::slope_argument(oldAmpLeft, leftSlope), IN(1), nova::slope_argument(oldAmpRight, rightSlope), inNumSamples); } else nova::mix_vec_simd(OUT(0), IN(0), 1.f - amp, IN(1), amp, inNumSamples); } #endif void LinXFade2_Ctor(LinXFade2 *unit) { switch (INRATE(2)) { case calc_FullRate: SETCALC(LinXFade2_next_a); break; case calc_BufRate: #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(LinXFade2_next_k_nova); else SETCALC(LinXFade2_next_k); #else SETCALC(LinXFade2_next_k); #endif break; case calc_ScalarRate: #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(LinXFade2_next_i_nova); else SETCALC(LinXFade2_next_i); #else SETCALC(LinXFade2_next_i); #endif break; } unit->m_pos = ZIN0(2); unit->m_pos = sc_clip(unit->m_pos, -1.f, 1.f); unit->m_amp = unit->m_pos * 0.5f + 0.5f; LinXFade2_next_a(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Pan2_next_ak(Pan2 *unit, int inNumSamples) { float *leftout = ZOUT(0); float *rightout = ZOUT(1); float *in = ZIN(0); float pos = ZIN0(1); float level = ZIN0(2); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; LOOP1(inNumSamples, float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; leftamp += leftampslope; rightamp += rightampslope; ); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else { LOOP1(inNumSamples, float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; ); } } #ifdef NOVA_SIMD void Pan2_next_ak_nova(Pan2 *unit, int inNumSamples) { float pos = ZIN0(1); float level = ZIN0(2); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; nova::pan2_vec_simd(OUT(0), OUT(1), IN(0), leftamp, leftampslope, rightamp, rightampslope, inNumSamples); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else nova::pan2_vec_simd(OUT(0), OUT(1), IN(0), leftamp, rightamp, inNumSamples); } void Pan2_next_ak_nova_64(Pan2 *unit, int inNumSamples) { float pos = ZIN0(1); float level = ZIN0(2); float leftamp = unit->m_leftamp; float rightamp = unit->m_rightamp; if (pos != unit->m_pos || unit->m_level != level) { int32 ipos = (int32)(1024.f * pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float nextleftamp = level * ft->mSine[2048 - ipos]; float nextrightamp = level * ft->mSine[ipos]; float slopeFactor = unit->mRate->mSlopeFactor; float leftampslope = (nextleftamp - leftamp) * slopeFactor; float rightampslope = (nextrightamp - rightamp) * slopeFactor; nova::pan2_vec_simd<64>(OUT(0), OUT(1), IN(0), leftamp, leftampslope, rightamp, rightampslope); unit->m_pos = pos; unit->m_level = level; unit->m_leftamp = nextleftamp; unit->m_rightamp = nextrightamp; } else nova::pan2_vec_simd<64>(OUT(0), OUT(1), IN(0), leftamp, rightamp); } #endif void Pan2_next_aa(Pan2 *unit, int inNumSamples) { float *leftout = ZOUT(0); float *rightout = ZOUT(1); float *in = ZIN(0); float *pos = ZIN(1); float nextlevel = ZIN0(2); float level = unit->m_level; if (level != nextlevel) { float levelSlope = (nextlevel - level) * unit->mRate->mSlopeFactor; LOOP1(inNumSamples, int32 ipos = (int32)(1024.f * ZXP(pos) + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float leftamp = level * ft->mSine[2048 - ipos]; float rightamp = level * ft->mSine[ipos]; float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; level += levelSlope; ); unit->m_level = level; } else { LOOP1(inNumSamples, int32 ipos = (int32)(1024.f * ZXP(pos) + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); float leftamp = level * ft->mSine[2048 - ipos]; float rightamp = level * ft->mSine[ipos]; float zin = ZXP(in); ZXP(leftout) = zin * leftamp; ZXP(rightout) = zin * rightamp; ); } } void Pan2_Ctor(Pan2 *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(Pan2_next_aa); } else { #if defined(NOVA_SIMD) if (BUFLENGTH == 64) SETCALC(Pan2_next_ak_nova_64); if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Pan2_next_ak_nova); else SETCALC(Pan2_next_ak); #else SETCALC(Pan2_next_ak); #endif } unit->m_pos = ZIN0(1); unit->m_level = ZIN0(2); int32 ipos = (int32)(1024.f * unit->m_pos + 1024.f + 0.5f); ipos = sc_clip(ipos, 0, 2048); unit->m_leftamp = unit->m_level * ft->mSine[2048 - ipos]; unit->m_rightamp = unit->m_level * ft->mSine[ipos]; Pan2_next_aa(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Pan4_Ctor(Pan4 *unit) { SETCALC(Pan4_next); //float *in = ZIN(0); float xpos = ZIN0(1); float ypos = ZIN0(2); float level = ZIN0(3); unit->m_xpos = xpos; unit->m_ypos = ypos; unit->m_level = level; if (xpos < -1.f || xpos > 1.f || ypos < -1.f || ypos > 1.f) { float xabs = fabs(xpos); if (ypos > xabs) { xpos = (xpos + ypos) / ypos - 1.f; ypos = 1.f; } else if (ypos < -xabs) { xpos = (xpos - ypos) / -ypos - 1.f; ypos = -1.f; } else { float yabs = fabs(ypos); if (yabs < xpos) { ypos = (ypos + xpos) / xpos - 1.f; xpos = 1.f; } else { ypos = (ypos - xpos) / -xpos - 1.f; xpos = -1.f; } } } int32 ixpos = (int32)(1024.f * xpos + 1024.f + 0.5f); ixpos = sc_clip(ixpos, 0, 2048); float leftamp = ft->mSine[2048 - ixpos]; float rightamp = ft->mSine[ixpos]; int32 iypos = (int32)(1024.f * ypos + 1024.f + 0.5f); iypos = sc_clip(iypos, 0, 2048); float frontamp = ft->mSine[iypos]; float backamp = ft->mSine[2048 - iypos]; frontamp *= level; backamp *= level; unit->m_LF_amp = leftamp * frontamp; unit->m_RF_amp = rightamp * frontamp; unit->m_LB_amp = leftamp * backamp; unit->m_RB_amp = rightamp * backamp; float z = ZIN0(0); ZOUT0(0) = z * unit->m_LF_amp; ZOUT0(1) = z * unit->m_RF_amp; ZOUT0(2) = z * unit->m_LB_amp; ZOUT0(3) = z * unit->m_RB_amp; } void Pan4_next(Pan4 *unit, int inNumSamples) { float *LFout = ZOUT(0); float *RFout = ZOUT(1); float *LBout = ZOUT(2); float *RBout = ZOUT(3); float *in = ZIN(0); float xpos = ZIN0(1); float ypos = ZIN0(2); float level = ZIN0(3); float LF_amp = unit->m_LF_amp; float RF_amp = unit->m_RF_amp; float LB_amp = unit->m_LB_amp; float RB_amp = unit->m_RB_amp; if (xpos != unit->m_xpos || ypos != unit->m_ypos || level != unit->m_level) { unit->m_xpos = xpos; unit->m_ypos = ypos; unit->m_level = level; if (xpos < -1.f || xpos > 1.f || ypos < -1.f || ypos > 1.f) { float xabs = fabs(xpos); if (ypos > xabs) { xpos = (xpos + ypos) / ypos - 1.f; ypos = 1.f; } else if (ypos < -xabs) { xpos = (xpos - ypos) / -ypos - 1.f; ypos = -1.f; } else { float yabs = fabs(ypos); if (yabs < xpos) { ypos = (ypos + xpos) / xpos - 1.f; xpos = 1.f; } else { ypos = (ypos - xpos) / -xpos - 1.f; xpos = -1.f; } } } int32 ixpos = (int32)(1024.f * xpos + 1024.f + 0.5f); ixpos = sc_clip(ixpos, 0, 2048); float leftamp = ft->mSine[2048 - ixpos]; float rightamp = ft->mSine[ixpos]; int32 iypos = (int32)(1024.f * ypos + 1024.f + 0.5f); iypos = sc_clip(iypos, 0, 2048); float frontamp = ft->mSine[iypos]; float backamp = ft->mSine[2048 - iypos]; frontamp *= level; backamp *= level; float next_LF_amp = leftamp * frontamp; float next_RF_amp = rightamp * frontamp; float next_LB_amp = leftamp * backamp; float next_RB_amp = rightamp * backamp; float LF_slope = CALCSLOPE(next_LF_amp, LF_amp); float RF_slope = CALCSLOPE(next_RF_amp, RF_amp); float LB_slope = CALCSLOPE(next_LB_amp, LB_amp); float RB_slope = CALCSLOPE(next_RB_amp, RB_amp); LOOP1(inNumSamples, float z = ZXP(in); ZXP(LFout) = z * LF_amp; ZXP(RFout) = z * RF_amp; ZXP(LBout) = z * LB_amp; ZXP(RBout) = z * RB_amp; LF_amp += LF_slope; RF_amp += RF_slope; LB_amp += LB_slope; RB_amp += RB_slope; ); unit->m_LF_amp = LF_amp; unit->m_RF_amp = RF_amp; unit->m_LB_amp = LB_amp; unit->m_RB_amp = RB_amp; } else { LOOP1(inNumSamples, float z = ZXP(in); ZXP(LFout) = z * LF_amp; ZXP(RFout) = z * RF_amp; ZXP(LBout) = z * LB_amp; ZXP(RBout) = z * RB_amp; ); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void PanB_Ctor(PanB *unit) { SETCALC(PanB_next); float azimuth = unit->m_azimuth = ZIN0(1); float elevation = unit->m_elevation = ZIN0(2); float level = unit->m_level = ZIN0(3); int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; long iazimuth = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); long ielevation = kSineMask & (long)(elevation * (float)(kSineSize >> 2)); float sina = -ft->mSine[iazimuth]; float sinb = ft->mSine[ielevation]; iazimuth = kSineMask & (iazimuth + (kSineSize>>2)); ielevation = kSineMask & (ielevation + (kSineSize>>2)); float cosa = ft->mSine[iazimuth]; float cosb = ft->mSine[ielevation]; unit->m_W_amp = rsqrt2_f * level; unit->m_X_amp = cosa * cosb * level; unit->m_Y_amp = sina * cosb * level; unit->m_Z_amp = sinb * level; PanB_next(unit, 1); } void PanB_next(PanB *unit, int inNumSamples) { float *Wout = ZOUT(0); float *Xout = ZOUT(1); float *Yout = ZOUT(2); float *Zout = ZOUT(3); float *in = ZIN(0); float azimuth = ZIN0(1); float elevation = ZIN0(2); float level = ZIN0(3); float W_amp = unit->m_W_amp; float X_amp = unit->m_X_amp; float Y_amp = unit->m_Y_amp; float Z_amp = unit->m_Z_amp; int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; if (azimuth != unit->m_azimuth || elevation != unit->m_elevation || level != unit->m_level) { unit->m_azimuth = azimuth; unit->m_elevation = elevation; unit->m_level = level; long iazimuth = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); long ielevation = kSineMask & (long)(elevation * (float)(kSineSize >> 2)); float sina = -ft->mSine[iazimuth]; float sinb = ft->mSine[ielevation]; iazimuth = kSineMask & (iazimuth + (kSineSize>>2)); ielevation = kSineMask & (ielevation + (kSineSize>>2)); float cosa = ft->mSine[iazimuth]; float cosb = ft->mSine[ielevation]; float next_W_amp = rsqrt2_f * level; float next_X_amp = cosa * cosb * level; float next_Y_amp = sina * cosb * level; float next_Z_amp = sinb * level; float W_slope = CALCSLOPE(next_W_amp, W_amp); float X_slope = CALCSLOPE(next_X_amp, X_amp); float Y_slope = CALCSLOPE(next_Y_amp, Y_amp); float Z_slope = CALCSLOPE(next_Z_amp, Z_amp); LOOP1(inNumSamples, float z = ZXP(in); ZXP(Wout) = z * W_amp; ZXP(Xout) = z * X_amp; ZXP(Yout) = z * Y_amp; ZXP(Zout) = z * Z_amp; W_amp += W_slope; X_amp += X_slope; Y_amp += Y_slope; Z_amp += Z_slope; ); unit->m_W_amp = W_amp; unit->m_X_amp = X_amp; unit->m_Y_amp = Y_amp; unit->m_Z_amp = Z_amp; } else { LOOP1(inNumSamples, float z = ZXP(in); ZXP(Wout) = z * W_amp; ZXP(Xout) = z * X_amp; ZXP(Yout) = z * Y_amp; ZXP(Zout) = z * Z_amp; ); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// void PanB2_next(PanB2 *unit, int inNumSamples) { float *Wout = ZOUT(0); float *Xout = ZOUT(1); float *Yout = ZOUT(2); float *in = ZIN(0); float azimuth = ZIN0(1); float level = ZIN0(2); float W_amp = unit->m_W_amp; float X_amp = unit->m_X_amp; float Y_amp = unit->m_Y_amp; int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; if (azimuth != unit->m_azimuth || level != unit->m_level) { unit->m_azimuth = azimuth; unit->m_level = level; long isinpos = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); float sina = -ft->mSine[isinpos]; long icospos = kSineMask & (isinpos + (kSineSize>>2)); float cosa = ft->mSine[icospos]; float next_W_amp = rsqrt2_f * level; float next_X_amp = cosa * level; float next_Y_amp = sina * level; float W_slope = CALCSLOPE(next_W_amp, W_amp); float X_slope = CALCSLOPE(next_X_amp, X_amp); float Y_slope = CALCSLOPE(next_Y_amp, Y_amp); LOOP1(inNumSamples, float z = ZXP(in); ZXP(Wout) = z * W_amp; ZXP(Xout) = z * X_amp; ZXP(Yout) = z * Y_amp; W_amp += W_slope; X_amp += X_slope; Y_amp += Y_slope; ); unit->m_W_amp = W_amp; unit->m_X_amp = X_amp; unit->m_Y_amp = Y_amp; } else { LOOP1(inNumSamples, float z = ZXP(in); ZXP(Wout) = z * W_amp; ZXP(Xout) = z * X_amp; ZXP(Yout) = z * Y_amp; ); } } #ifdef NOVA_SIMD FLATTEN void PanB2_next_nova(PanB2 *unit, int inNumSamples) { float *Wout = OUT(0); float *Xout = OUT(1); float *Yout = OUT(2); float *in = IN(0); float azimuth = ZIN0(1); float level = ZIN0(2); float W_amp = unit->m_W_amp; float X_amp = unit->m_X_amp; float Y_amp = unit->m_Y_amp; int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; if (azimuth != unit->m_azimuth || level != unit->m_level) { unit->m_azimuth = azimuth; unit->m_level = level; long isinpos = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); float sina = -ft->mSine[isinpos]; long icospos = kSineMask & (isinpos + (kSineSize>>2)); float cosa = ft->mSine[icospos]; float next_W_amp = rsqrt2_f * level; float next_X_amp = cosa * level; float next_Y_amp = sina * level; float W_slope = CALCSLOPE(next_W_amp, W_amp); float X_slope = CALCSLOPE(next_X_amp, X_amp); float Y_slope = CALCSLOPE(next_Y_amp, Y_amp); nova::times_vec_simd(Wout, in, slope_argument(W_amp, W_slope), inNumSamples); nova::times_vec_simd(Xout, in, slope_argument(X_amp, X_slope), inNumSamples); nova::times_vec_simd(Yout, in, slope_argument(Y_amp, Y_slope), inNumSamples); unit->m_W_amp = next_W_amp; unit->m_X_amp = next_X_amp; unit->m_Y_amp = next_Y_amp; } else { // TODO: can be further optimized by joining the loops nova::times_vec_simd(Wout, in, W_amp, inNumSamples); nova::times_vec_simd(Xout, in, X_amp, inNumSamples); nova::times_vec_simd(Yout, in, Y_amp, inNumSamples); } } #endif void PanB2_Ctor(PanB2 *unit) { #if defined(NOVA_SIMD) if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(PanB2_next_nova); else #endif SETCALC(PanB2_next); float azimuth = unit->m_azimuth = ZIN0(1); float level = unit->m_level = ZIN0(2); int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; long isinpos = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); float sina = -ft->mSine[isinpos]; long icospos = kSineMask & (isinpos + (kSineSize>>2)); float cosa = ft->mSine[icospos]; unit->m_W_amp = rsqrt2_f * level; unit->m_X_amp = cosa * level; unit->m_Y_amp = sina * level; PanB2_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void BiPanB2_next(BiPanB2 *unit, int inNumSamples) { float *Wout = ZOUT(0); float *Xout = ZOUT(1); float *Yout = ZOUT(2); float *inA = ZIN(0); float *inB = ZIN(1); float azimuth = ZIN0(2); float level = ZIN0(3); float W_amp = unit->m_W_amp; float X_amp = unit->m_X_amp; float Y_amp = unit->m_Y_amp; int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; if (azimuth != unit->m_azimuth || level != unit->m_level) { unit->m_azimuth = azimuth; unit->m_level = level; long isinpos = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); float sina = -ft->mSine[isinpos]; long icospos = kSineMask & (isinpos + (kSineSize>>2)); float cosa = ft->mSine[icospos]; float next_W_amp = rsqrt2_f * level; float next_X_amp = cosa * level; float next_Y_amp = sina * level; float W_slope = CALCSLOPE(next_W_amp, W_amp); float X_slope = CALCSLOPE(next_X_amp, X_amp); float Y_slope = CALCSLOPE(next_Y_amp, Y_amp); if (W_slope == 0.f) { LOOP1(inNumSamples, float a = ZXP(inA); float b = ZXP(inB); float abdiff = a - b; ZXP(Wout) = (a + b) * W_amp; ZXP(Xout) = abdiff * X_amp; ZXP(Yout) = abdiff * Y_amp; X_amp += X_slope; Y_amp += Y_slope; ); } else { LOOP1(inNumSamples, float a = ZXP(inA); float b = ZXP(inB); float abdiff = a - b; ZXP(Wout) = (a + b) * W_amp; ZXP(Xout) = abdiff * X_amp; ZXP(Yout) = abdiff * Y_amp; W_amp += W_slope; X_amp += X_slope; Y_amp += Y_slope; ); unit->m_W_amp = W_amp; } unit->m_X_amp = X_amp; unit->m_Y_amp = Y_amp; } else { LOOP1(inNumSamples, float a = ZXP(inA); float b = ZXP(inB); float abdiff = a - b; ZXP(Wout) = (a + b) * W_amp; ZXP(Xout) = abdiff * X_amp; ZXP(Yout) = abdiff * Y_amp; ); } } void BiPanB2_Ctor(BiPanB2 *unit) { SETCALC(BiPanB2_next); float azimuth = unit->m_azimuth = ZIN0(2); float level = unit->m_level = ZIN0(3); int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; long iazimuth = kSineMask & (long)(azimuth * (float)(kSineSize >> 1)); float sina = -ft->mSine[iazimuth]; iazimuth = kSineMask & (iazimuth + (kSineSize>>2)); float cosa = ft->mSine[iazimuth]; unit->m_W_amp = rsqrt2_f * level; unit->m_X_amp = cosa * level; unit->m_Y_amp = sina * level; BiPanB2_next(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// /* void calcPos(float pos, int numOutputs, float width, float orientation) { float rwidth = 1.f / width; float range = numOutputs * rwidth; float rrange = 1.f / range; float zpos = pos * 0.5 * numOutputs + width * 0.5 + orientation; Print("pos %6.2g rwidth %6.3g range %6.3g rrange %6.3g zpos %6.3g\n", pos, rwidth, range, rrange, zpos); for (int i=0; i 1.f) { amp = 0.f; } else { amp = ft->mSine[(long)(4096.f * zchanpos)]; } Print(" %d chanpos %6.3g zchanpos %6.3g amp %g\n", i, chanpos, zchanpos, amp); } } */ #ifdef NOVA_SIMD void PanAz_next_ak_nova(PanAz *unit, int inNumSamples); #endif void PanAz_Ctor(PanAz *unit) { if (INRATE(1) == calc_FullRate) { unit->m_chanamp = NULL; SETCALC(PanAz_next_aa); } else { int numOutputs = unit->mNumOutputs; for (int i=0; im_chanamp = (float*)RTAlloc(unit->mWorld, numOutputs*sizeof(float)); if (!unit->m_chanamp) { Print("PanAz: RT memory allocation failed\n"); SETCALC(ClearUnitOutputs); return; } std::fill_n(unit->m_chanamp, numOutputs, 0); #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(PanAz_next_ak_nova); else SETCALC(PanAz_next_ak); #else SETCALC(PanAz_next_ak); #endif } } void PanAz_Dtor(PanAz *unit) { if (unit->m_chanamp) RTFree(unit->mWorld, unit->m_chanamp); } void PanAz_next_ak(PanAz *unit, int inNumSamples) { float pos = ZIN0(1); float level = ZIN0(2); float width = ZIN0(3); float orientation = ZIN0(4); int numOutputs = unit->mNumOutputs; float rwidth = sc_reciprocal( width ); float range = numOutputs * rwidth; float rrange = sc_reciprocal( range ); pos = pos * 0.5f * numOutputs + width * 0.5f + orientation; float *zin0 = ZIN(0); for (int i=0; i 1.f) { nextchanamp = 0.f; } else { nextchanamp = level * ft->mSine[(long)(4096.f * chanpos)]; } float chanamp = unit->m_chanamp[i]; if (nextchanamp == chanamp) { if (nextchanamp == 0.f) { ZClear(inNumSamples, out); } else { float *in = zin0; LOOP1(inNumSamples, ZXP(out) = ZXP(in) * chanamp; ) } } else { float chanampslope = CALCSLOPE(nextchanamp, chanamp); float *in = zin0; LOOP1(inNumSamples, ZXP(out) = ZXP(in) * chanamp; chanamp += chanampslope; ) unit->m_chanamp[i] = nextchanamp; } } } #ifdef NOVA_SIMD FLATTEN void PanAz_next_ak_nova(PanAz *unit, int inNumSamples) { float pos = ZIN0(1); float level = ZIN0(2); float width = ZIN0(3); float orientation = ZIN0(4); int numOutputs = unit->mNumOutputs; float rwidth = sc_reciprocal( width ); float range = numOutputs * rwidth; float rrange = sc_reciprocal( range ); pos = pos * 0.5f * numOutputs + width * 0.5f + orientation; float * __restrict__ in = IN(0); float * __restrict__ chanamps = unit->m_chanamp; for (int i=0; i 1.f) { nextchanamp = 0.f; } else { nextchanamp = level * ft->mSine[(long)(4096.f * chanpos)]; } float *out = OUT(i); if (nextchanamp == chanamp) { if (nextchanamp == 0.f) nova::zerovec_simd(out, inNumSamples); else nova::times_vec_simd(out, in, chanamp, inNumSamples); } else { float chanampslope = CALCSLOPE(nextchanamp, chanamp); nova::times_vec_simd(out, in, slope_argument(chanamp, chanampslope), inNumSamples); chanamps[i] = nextchanamp; } } } #endif void PanAz_next_aa(PanAz *unit, int inNumSamples) { float level = ZIN0(2); float width = ZIN0(3); float orientation = ZIN0(4); int numOutputs = unit->mNumOutputs; float rwidth = sc_reciprocal( width ); float range = numOutputs * rwidth; float rrange = sc_reciprocal( range ); // compute constant parts with which the pos has to be multiplied/added to respect numOutputs, width and orientation // see PanAz_next_ak for details float alignedPosFac = 0.5f * numOutputs; float alignedPosConst = width * 0.5f + orientation; float *zin0 = ZIN(0); float *pos = ZIN(1); for (int i=0; i 1.f) { chanamp = 0.f; } else { chanamp = level * ft->mSine[(long)(4096.f * chanpos)]; } ZXP(out) = ZXP(in) * chanamp; ) } } //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// void Rotate2_next_ak(Rotate2 *unit, int inNumSamples) { float *xout = ZOUT(0); float *yout = ZOUT(1); float *xin = ZIN(0); float *yin = ZIN(1); float pos = ZIN0(2); float sint = unit->m_sint; float cost = unit->m_cost; if (pos != unit->m_pos) { int kSineSize = ft->mSineSize; int kSineMask = kSineSize - 1; int32 isinpos = kSineMask & (int32)(pos * (float)(kSineSize >> 1)); int32 icospos = kSineMask & ((kSineSize>>2) + isinpos); float nextsint = unit->m_sint = ft->mSine[isinpos]; float nextcost = unit->m_cost = ft->mSine[icospos]; float slopeFactor = unit->mRate->mSlopeFactor; float sinslope = (nextsint - sint) * slopeFactor; float cosslope = (nextcost - cost) * slopeFactor; LOOP1(inNumSamples, float x = ZXP(xin); float y = ZXP(yin); ZXP(xout) = cost * x + sint * y; ZXP(yout) = cost * y - sint * x; sint += sinslope; cost += cosslope; ); unit->m_pos = pos; } else { LOOP1(inNumSamples, float x = ZXP(xin); float y = ZXP(yin); ZXP(xout) = cost * x + sint * y; ZXP(yout) = cost * y - sint * x; ); } } void Rotate2_Ctor(Rotate2 *unit) { SETCALC(Rotate2_next_ak); unit->m_pos = ZIN0(2); int32 isinpos = 8191 & (int32)(4096.f * unit->m_pos); int32 icospos = 8191 & (2048 + isinpos); unit->m_sint = ft->mSine[isinpos]; unit->m_cost = ft->mSine[icospos]; Rotate2_next_ak(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// void DecodeB2_Ctor(DecodeB2 *unit) { #if defined(NOVA_SIMD) if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(DecodeB2_next_nova); else #endif SETCALC(DecodeB2_next); DecodeB2_next(unit, 1); float orientation = ZIN0(3); int numOutputs = unit->mNumOutputs; float angle = twopi_f / numOutputs; unit->m_cosa = cos(angle); unit->m_sina = sin(angle); unit->m_W_amp = 0.7071067811865476f; unit->m_X_amp = 0.5f * (float)cos(orientation * angle); unit->m_Y_amp = 0.5f * (float)sin(orientation * angle); } void DecodeB2_next(DecodeB2 *unit, int inNumSamples) { float *Win0 = ZIN(0); float *Xin0 = ZIN(1); float *Yin0 = ZIN(2); float W_amp = unit->m_W_amp; float X_amp = unit->m_X_amp; float Y_amp = unit->m_Y_amp; float X_tmp; float cosa = unit->m_cosa; float sina = unit->m_sina; int numOutputs = unit->mNumOutputs; for (int i=0; i W_amp = unit->m_W_amp; vec X_amp = unit->m_X_amp; vec Y_amp = unit->m_Y_amp; vec X_tmp; vec cosa = unit->m_cosa; vec sina = unit->m_sina; int numOutputs = unit->mNumOutputs; int vs = vec::size; int loops = inNumSamples / vs; for (int i=0; i result, w, x, y; w.load_aligned(Win); x.load_aligned(Xin); y.load_aligned(Yin); result = w * W_amp + x * X_amp + y * Y_amp; result.store_aligned(out); out += vs; Win += vs; Xin += vs; Yin += vs; }; X_tmp = X_amp * cosa + Y_amp * sina; Y_amp = Y_amp * cosa - X_amp * sina; X_amp = X_tmp; } } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(Pan) { ft = inTable; DefineSimpleUnit(Pan2); DefineSimpleUnit(Pan4); DefineSimpleUnit(LinPan2); DefineSimpleCantAliasUnit(Balance2); DefineSimpleUnit(Rotate2); DefineSimpleUnit(XFade2); DefineSimpleUnit(LinXFade2); DefineSimpleUnit(PanB); DefineSimpleCantAliasUnit(PanB2); DefineSimpleUnit(BiPanB2); DefineDtorCantAliasUnit(PanAz); DefineSimpleCantAliasUnit(DecodeB2); } ////////////////////////////////////////////////////////////////////////////////////////////////// SuperCollider-Source/server/plugins/PartitionedConvolution.cpp000644 000765 000024 00000032361 12756531745 026116 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //Partitioned Convolution, Nick Collins mid October 2008 //PartConv(in, fftsize, irbufnum, accumbufnum) #include "FFT_UGens.h" #include struct PartConv : public Unit { int m_counter; uint32 m_specbufnumcheck; float* m_fd_accumulate; //will be exactly fftsize*frames in size float * m_irspectra; int m_fd_accum_pos; int m_partitions; //number of frames impulse response is partitioned into int m_fullsize; //sliding window code int m_fftsize; //must be power of two //int m_windowsize; //also half fftsize, was partition size, just use nover2 for this int m_nover2; //int m_hopsize; //hopsize will be half fftsize //int m_shuntsize; int m_pos; float * m_inputbuf; float * m_spectrum; scfft* m_scfft; float * m_inputbuf2; float * m_spectrum2; scfft* m_scifft; //inverse int m_outputpos; float * m_output; //amortisation state int m_blocksize, m_sr; int m_spareblocks; int m_numamort; //will relate number of partitions to number of spare blocks int m_lastamort; int m_amortcount; int m_partitionsdone; }; extern "C" { void PartConv_next(PartConv *unit, int inNumSamples); void PartConv_Ctor(PartConv* unit); void PartConv_Dtor(PartConv* unit); } void PartConv_Ctor( PartConv* unit ) { unit->m_fftsize= (int) ZIN0(1); unit->m_nover2= unit->m_fftsize>>1; unit->m_inputbuf= (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float)); unit->m_spectrum= (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float)); SCWorld_Allocator alloc(ft, unit->mWorld); unit->m_scfft = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_inputbuf, unit->m_spectrum, kForward, alloc); //inverse unit->m_inputbuf2= (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float)); unit->m_spectrum2= (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float)); //in place this time unit->m_scifft = scfft_create(unit->m_fftsize, unit->m_fftsize, kRectWindow, unit->m_inputbuf2, unit->m_spectrum2, kBackward, alloc); //debug test: changing scale factors in case amplitude summation is a problem //unit->m_scfft->scalefac=1.0/45.254833995939; //unit->m_scifft->scalefac=1.0/45.254833995939; unit->m_output= (float*)RTAlloc(unit->mWorld, unit->m_fftsize * sizeof(float)); unit->m_outputpos=0; memset(unit->m_output, 0, unit->m_fftsize * sizeof(float)); memset(unit->m_inputbuf, 0, unit->m_fftsize * sizeof(float)); unit->m_pos=0; //get passed in buffer unit->m_fd_accumulate=NULL; uint32 bufnum = (uint32)ZIN0(2); SndBuf *buf; if (bufnum >= unit->mWorld->mNumSndBufs) { int localBufNum = bufnum - unit->mWorld->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localMaxBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { printf("PartConv Error: Invalid Spectral data bufnum %d \n", bufnum); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } } buf = unit->mWorld->mSndBufs + bufnum; unit->m_specbufnumcheck = bufnum; if (!buf->data) { //unit->mDone = true; printf("PartConv Error: Spectral data buffer not allocated \n"); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } unit->m_irspectra = buf->data; unit->m_fullsize = buf->samples; unit->m_partitions=buf->samples/(unit->m_fftsize); //should be exact //printf("another check partitions %d irspecsize %d fftsize %d \n", unit->m_partitions,unit->m_fullsize, unit->m_fftsize); if((buf->samples % unit->m_fftsize !=0) || (buf->samples==0)) { printf("PartConv Error: fftsize doesn't divide spectral data buffer size or spectral data buffer size is zero\n"); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } //CHECK SAMPLING RATE AND BUFFER SIZE unit->m_blocksize = unit->mWorld->mFullRate.mBufLength; //if(unit->m_blocksize!=64) printf("TPV complains: block size not 64, you have %d\n", unit->m_blocksize); unit->m_sr = unit->mWorld->mSampleRate; //if(unit->m_sr!=44100) printf("TPV complains: sample rate not 44100, you have %d\n", unit->m_sr); if(unit->m_nover2 % unit->m_blocksize !=0) { printf("PartConv Error: block size doesn't divide partition size\n"); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } else { //must be exact divisor int blocksperpartition = unit->m_nover2/unit->m_blocksize; unit->m_spareblocks = blocksperpartition-1; if(unit->m_spareblocks<1) { printf("PartConv Error: no spareblocks, amortisation not possible! \n"); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } //won't be exact unit->m_numamort = (unit->m_partitions-1)/unit->m_spareblocks; //will relate number of partitions to number of spare blocks unit->m_lastamort= (unit->m_partitions-1)- ((unit->m_spareblocks-1)*(unit->m_numamort)); //allow for error on last one unit->m_amortcount= -1; //starts as flag to avoid any amortisation before have first fft done unit->m_partitionsdone=1; //printf("Amortisation stats partitions %d nover2 %d blocksize %d spareblocks %d numamort %d lastamort %d \n", unit->m_partitions,unit->m_nover2, unit->m_blocksize, unit->m_spareblocks, unit->m_numamort, unit->m_lastamort); unit->m_fd_accumulate= (float*)RTAlloc(unit->mWorld, unit->m_fullsize * sizeof(float)); memset(unit->m_fd_accumulate, 0, unit->m_fullsize * sizeof(float)); unit->m_fd_accum_pos=0; SETCALC(PartConv_next); } } void PartConv_Dtor(PartConv *unit) { RTFree(unit->mWorld, unit->m_inputbuf); RTFree(unit->mWorld, unit->m_inputbuf2); RTFree(unit->mWorld, unit->m_spectrum); RTFree(unit->mWorld, unit->m_spectrum2); RTFree(unit->mWorld, unit->m_output); if (unit->m_fd_accumulate) RTFree(unit->mWorld, unit->m_fd_accumulate); SCWorld_Allocator alloc(ft, unit->mWorld); if(unit->m_scfft) scfft_destroy(unit->m_scfft, alloc); if(unit->m_scifft) scfft_destroy(unit->m_scifft, alloc); } void PartConv_next( PartConv *unit, int inNumSamples ) { float *in = IN(0); float *out = OUT(0); int pos = unit->m_pos; //safety check if (!(unit->mWorld->mSndBufs + unit->m_specbufnumcheck)->data) { printf("PartConv Error: Spectral data buffer not allocated \n"); ClearUnitOutputs(unit, inNumSamples); SETCALC(*ClearUnitOutputs); unit->mDone = true; return; } float * input= unit->m_inputbuf; float * output= unit->m_output; int outputpos= unit->m_outputpos; //into input buffer memcpy(input+pos, in, inNumSamples * sizeof(float)); pos += inNumSamples; //if ready for new FFT int nover2 = unit->m_nover2; //assumes that blocksize perfectly divides windowsize if (pos == nover2) { //FFT this input, second half of input always zero //memset(input+unit->m_nover2, 0, sizeof(float)*unit->m_nover2); scfft_dofft(unit->m_scfft); //reset pos into input buffer pos=0; //reset outputpos outputpos= 0; float * spectrum = unit->m_spectrum; float * spectrum2 = unit->m_spectrum2; //multiply spectra and accumulate for all ir spectra across storage buffer int fftsize = unit->m_fftsize; int accumpos = unit->m_fd_accum_pos; float * accumbuffer = unit->m_fd_accumulate; float * irspectrum = unit->m_irspectra; int fullsize = unit->m_fullsize; //JUST DO FIRST ONE FOR NOW, AMORTISED FOR OTHERS //frames for (int i=0; i<1; ++i) { int irpos= (i*fftsize); int posnow= (accumpos+irpos)%fullsize; float * target= accumbuffer+posnow; float * ir= irspectrum+irpos; //real multiply for dc and nyquist target[0] += ir[0]*spectrum[0]; target[1] += ir[1]*spectrum[1]; //complex multiply for frequency bins for (int j=1; jm_inputbuf2; memcpy(input2, accumbuffer+accumpos, fftsize * sizeof(float)); scfft_doifft(unit->m_scifft); //shunt output data down and zero top bit memcpy(output, output+nover2, nover2 * sizeof(float)); memset(output+nover2, 0, nover2 * sizeof(float)); //sum into output for (int j=0; jm_fd_accum_pos= accumpos; //set up for amortisation (calculate output for other partitions of impulse response) unit->m_amortcount=0; unit->m_partitionsdone=1; } else { //amortisation steps: //complex multiply of this new fft spectrum against existing irspectrums and sum to accumbuffer if (unit->m_amortcount>=0) { float * spectrum= unit->m_spectrum; //multiply spectra and accumulate for all ir spectra across storage buffer int fftsize= unit->m_fftsize; int nover2= unit->m_nover2; //int frames= unit->m_partitions; int accumpos= unit->m_fd_accum_pos; float * accumbuffer= unit->m_fd_accumulate; float * irspectrum= unit->m_irspectra; int fullsize= unit->m_fullsize; int starti, stopi; int number; if(unit->m_amortcount==(unit->m_spareblocks-1)) { number= unit->m_lastamort; }else{ number= unit->m_numamort; } starti= unit->m_partitionsdone;//-1; stopi= starti+number-1; //printf("amort check count %d starti %d stopi %d number %d framesdone %d \n",unit->m_amortcount, starti, stopi, number, unit->m_partitionsdone); unit->m_partitionsdone += number; ++unit->m_amortcount; for (int i=starti; i<=stopi; ++i) { int posnow= (accumpos+((i-1)*fftsize))%fullsize; float * target= accumbuffer+posnow; int irpos= (i*fftsize); float * ir= irspectrum+irpos; //real multiply for dc and nyquist target[0]+= ir[0]*spectrum[0]; target[1]+= ir[1]*spectrum[1]; //complex multiply for frequency bins for (int j=1; jmParent->mRGen; // int testindex= rgen.irand(inNumSamples-1); // printf("inNumSamples %d testindex %d out %f output %f \n",inNumSamples, testindex, out[testindex], *(output+outputpos+testindex)); outputpos+=inNumSamples; unit->m_outputpos= outputpos; unit->m_pos= pos; } //buffer preparation void PreparePartConv(World *world, struct SndBuf *buf, struct sc_msg_iter *msg) { // 'channels' not used- should just be mono, num frames= num samples float *data1 = buf->data; uint32 frombufnum = msg->geti(); int fftsize = msg->geti(); //output size must be frombuf->frames*2 if (frombufnum >= world->mNumSndBufs) frombufnum = 0; SndBuf* frombuf = world->mSndBufs + frombufnum; int frames2 = frombuf->frames; float *data2 = frombuf->data; //scfft int nover2= fftsize>>1; int numpartitions; if(frames2 % nover2 == 0){ numpartitions= frames2/nover2; }else{ numpartitions= (frames2/nover2)+1; } //printf("reality check numpartitions %d fftsize %d product %d numinputframes %d \n", numpartitions, fftsize, numpartitions*fftsize, frames2); float * inputbuf= (float*)RTAlloc(world, fftsize * sizeof(float)); float * spectrum= (float*)RTAlloc(world, fftsize * sizeof(float)); SCWorld_Allocator alloc(ft, world); scfft* m_scfft = scfft_create(fftsize, fftsize, kRectWindow, inputbuf, spectrum, kForward, alloc); memset(inputbuf, 0, sizeof(float)*fftsize); // for zero padding //run through input data buffer, taking nover2 chunks, zero padding each for (int i=0; im_vel = 0.f; unit->m_pos = 0.f; Spring_next(unit, 1); } // in, spring, damping void Spring_next(Spring *unit, int inNumSamples) { float pos = unit->m_pos; float vel = unit->m_vel; float *out = ZOUT(0); // out force float *in = ZIN(0); // in force float spring = ZIN0(1); // spring constant float damping = 1.f - ZIN0(2);// damping float c = SAMPLEDUR; float rc = SAMPLERATE; spring = spring * c; LOOP1(inNumSamples, float force = ZXP(in) * c - pos * spring; vel = (force + vel) * damping; pos += vel; ZXP(out) = force * rc; ); unit->m_pos = pos; unit->m_vel = vel; } ////////////////////////////////////////////////////////////////////////////////////////// void Ball_Ctor(Ball *unit) { SETCALC(Ball_next); unit->m_vel = 0.f; unit->m_pos = ZIN0(0); unit->m_prev = ZIN0(0); Ball_next(unit, 1); } void Ball_next(Ball *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); // floor position float g_in = ZIN0(1); // gravity float damping = 1 - ZIN0(2); // damping float k = ZIN0(3); // friction float pos = unit->m_pos; float vel = unit->m_vel; float prev_floor = unit->m_prev; float c = SAMPLEDUR; float maxvel = c * 1000.f; float minvel = 0.f - maxvel; float inter = c * 1000.f; RGen& rgen = *unit->mParent->mRGen; float g = c * g_in; k = (double) k * (double) g_in; // stickyness proportional to gravity LOOP1(inNumSamples, float floor = ZXP(in); float floorvel; float dither; vel -= g; pos += vel; float dist = pos - floor; floorvel = floor - prev_floor; floorvel = sc_clip(floorvel, minvel, maxvel); float vel_diff = floorvel - vel; if(sc_abs(dist) < k) { // sticky friction: maybe vel dependant? if(sc_abs(dist) < (k*0.005)) { vel = 0.f; pos = floor + g; } else { vel = vel_diff * inter + vel; pos = (floor - pos) * inter + pos; } } else if(dist <= 0.f) { pos = floor - dist; vel = vel_diff; vel *= damping; dither = rgen.frand() * 0.00005f * g_in; // dither to reduce jitter //if(sc_abs(dist) < 0.000001) { vel += dither; } vel += dither; } prev_floor = floor; ZXP(out) = pos; ); unit->m_pos = pos; unit->m_vel = vel; unit->m_prev = prev_floor; } ////////////////////////////////////////////////////////////////////////////////////////// void TBall_Ctor(TBall *unit) { SETCALC(TBall_next); unit->m_vel = 0.f; unit->m_pos = ZIN0(0); unit->m_prev = ZIN0(0); TBall_next(unit, 1); } void TBall_next(TBall *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); // floor position float g_in = ZIN0(1); // gravity float damping = 1 - ZIN0(2);// damping float k = ZIN0(3); // friction double pos = unit->m_pos; float vel = unit->m_vel; double prev_floor = unit->m_prev; float c = SAMPLEDUR; float maxvel = c * 1000.f; float minvel = 0.f - maxvel; float inter = c * 10000.f; RGen& rgen = *unit->mParent->mRGen; float g = c * g_in; k = (double) k * (double) g_in; // stickyness proportional to gravity LOOP1(inNumSamples, double floor = ZXP(in); float floorvel; float outval = 0.f; float dither; vel -= g; pos += vel; double dist = pos - floor; floorvel = floor - prev_floor; floorvel = sc_clip(floorvel, minvel, maxvel); float vel_diff = floorvel - vel; if(sc_abs(dist) < k) { // sticky friction: vel dependant? if(sc_abs(dist) < (k*0.005)) { vel = 0.f; pos = floor + g; } else { vel = vel_diff * inter + vel; pos = (floor - pos) * inter + pos; } } else if(dist <= 0.f) { pos = floor - dist; vel = floorvel - vel; vel *= damping; outval = vel; dither = rgen.frand() * 0.001f * g_in; // dither to reduce sampling jitter //if(sc_abs(dist) < 0.003) { vel += dither; } vel += dither; } prev_floor = floor; ZXP(out) = outval; ); unit->m_pos = pos; unit->m_vel = vel; unit->m_prev = prev_floor; } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(PhysicalModeling) { ft = inTable; DefineSimpleUnit(Spring); DefineSimpleUnit(Ball); DefineSimpleUnit(TBall); } SuperCollider-Source/server/plugins/PV_ThirdParty.cpp000644 000765 000024 00000004241 12321461511 024044 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ //third party Phase Vocoder UGens #include "FFT_UGens.h" extern "C" { void PV_ConformalMap_Ctor(PV_Unit *unit); void PV_ConformalMap_next(PV_Unit *unit, int inNumSamples); } void PV_ConformalMap_Ctor(PV_Unit *unit) { SETCALC(PV_ConformalMap_next); ZOUT0(0) = ZIN0(0); } void PV_ConformalMap_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCComplexBuf *p = ToComplexApx(buf); float real2 = ZIN0(1); float imag2 = ZIN0(2); for (int i=0; ibin[i].real; float imag1 = p->bin[i].imag; //apply conformal map z-> z-a/(1-za*) where z is the existing complex number in the bin and a is defined by inputs 1 and 2 float numr= real1-real2; float numi= imag1-imag2; float denomr= 1.f - (real1*real2+imag1*imag2); float denomi= (real1*imag2- real2*imag1); numr= numr*denomr+numi*denomi; numi= numi*denomr-numr*denomi; //squared modulus denomr= denomr*denomr+denomi*denomi; //avoid possible divide by zero if(denomr<0.001f) denomr=0.001f; denomr=1.f/denomr; p->bin[i].real = numr*denomr; p->bin[i].imag = numi*denomr; } } #define DefinePVUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(PV_Unit), (UnitCtorFunc)&name##_Ctor, 0, 0); //void initPV_ThirdParty(InterfaceTable *it); void initPV_ThirdParty(InterfaceTable *it) { DefinePVUnit(PV_ConformalMap); } SuperCollider-Source/server/plugins/PV_UGens.cpp000644 000765 000024 00000072560 12321461511 023004 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "FFT_UGens.h" #define TWOPI 6.28318530717952646f struct PV_OutOfPlace : Unit { int m_numbins; float *m_tempbuf; }; struct PV_MagSmear : PV_OutOfPlace { }; struct PV_MagShift : PV_OutOfPlace { }; struct PV_BinShift : PV_OutOfPlace { }; struct PV_PhaseShift : Unit { float m_phase_integral; }; struct PV_Diffuser : Unit { int m_numbins; float m_prevtrig, *m_shift; bool m_triggered; }; struct PV_MagFreeze : Unit { int m_numbins; float *m_mags, m_dc, m_nyq; }; struct PV_RandWipe : Unit { int *m_ordering, m_numbins; float m_prevtrig; bool m_triggered; }; struct PV_RandComb : Unit { int *m_ordering, m_numbins; float m_prevtrig; bool m_triggered; }; struct PV_BinScramble : Unit { int *m_from, *m_to, m_numbins; float m_prevtrig; float *m_tempbuf; bool m_triggered; }; struct PV_Conj : PV_Unit {}; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void PV_PhaseShift_Ctor(PV_PhaseShift *unit); void PV_PhaseShift_next(PV_PhaseShift *unit, int inNumSamples); void PV_PhaseShift90_Ctor(PV_Unit *unit); void PV_PhaseShift90_next(PV_Unit *unit, int inNumSamples); void PV_PhaseShift270_Ctor(PV_Unit *unit); void PV_PhaseShift270_next(PV_Unit *unit, int inNumSamples); void PV_MagClip_Ctor(PV_Unit *unit); void PV_MagClip_next(PV_Unit *unit, int inNumSamples); void PV_MagAbove_Ctor(PV_Unit *unit); void PV_MagAbove_next(PV_Unit *unit, int inNumSamples); void PV_MagBelow_Ctor(PV_Unit *unit); void PV_MagBelow_next(PV_Unit *unit, int inNumSamples); void PV_Min_Ctor(PV_Unit *unit); void PV_Min_next(PV_Unit *unit, int inNumSamples); void PV_Max_Ctor(PV_Unit *unit); void PV_Max_next(PV_Unit *unit, int inNumSamples); void PV_Mul_Ctor(PV_Unit *unit); void PV_Mul_next(PV_Unit *unit, int inNumSamples); void PV_Div_Ctor(PV_Unit *unit); void PV_Div_next(PV_Unit *unit, int inNumSamples); void PV_Add_Ctor(PV_Unit *unit); void PV_Add_next(PV_Unit *unit, int inNumSamples); void PV_RectComb_Ctor(PV_Unit *unit); void PV_RectComb_next(PV_Unit *unit, int inNumSamples); void PV_RectComb2_Ctor(PV_Unit *unit); void PV_RectComb2_next(PV_Unit *unit, int inNumSamples); void PV_MagSquared_Ctor(PV_Unit *unit); void PV_MagSquared_next(PV_Unit *unit, int inNumSamples); void PV_MagMul_Ctor(PV_Unit *unit); void PV_MagMul_next(PV_Unit *unit, int inNumSamples); void PV_MagDiv_Ctor(PV_Unit *unit); void PV_MagDiv_next(PV_Unit *unit, int inNumSamples); void PV_Copy_Ctor(PV_Unit *unit); void PV_Copy_next(PV_Unit *unit, int inNumSamples); void PV_CopyPhase_Ctor(PV_Unit *unit); void PV_CopyPhase_next(PV_Unit *unit, int inNumSamples); void PV_MagSmear_Ctor(PV_MagSmear *unit); void PV_MagSmear_Dtor(PV_MagSmear *unit); void PV_MagSmear_next(PV_MagSmear *unit, int inNumSamples); void PV_BinShift_Ctor(PV_BinShift *unit); void PV_BinShift_Dtor(PV_BinShift *unit); void PV_BinShift_next(PV_BinShift *unit, int inNumSamples); void PV_MagShift_Ctor(PV_MagShift *unit); void PV_MagShift_Dtor(PV_MagShift *unit); void PV_MagShift_next(PV_MagShift *unit, int inNumSamples); void PV_MagNoise_Ctor(PV_Unit *unit); void PV_MagNoise_next(PV_Unit *unit, int inNumSamples); void PV_BrickWall_Ctor(PV_Unit *unit); void PV_BrickWall_next(PV_Unit *unit, int inNumSamples); void PV_BinWipe_Ctor(PV_Unit *unit); void PV_BinWipe_next(PV_Unit *unit, int inNumSamples); void PV_LocalMax_Ctor(PV_Unit *unit); void PV_LocalMax_next(PV_Unit *unit, int inNumSamples); void PV_RandComb_Ctor(PV_RandComb *unit); void PV_RandComb_Dtor(PV_RandComb *unit); void PV_RandComb_next(PV_RandComb *unit, int inNumSamples); void PV_RandWipe_Ctor(PV_RandWipe *unit); void PV_RandWipe_Dtor(PV_RandWipe *unit); void PV_RandWipe_next(PV_RandWipe *unit, int inNumSamples); void PV_Diffuser_Ctor(PV_Diffuser *unit); void PV_Diffuser_Dtor(PV_Diffuser *unit); void PV_Diffuser_next(PV_Diffuser *unit, int inNumSamples); void PV_MagFreeze_Ctor(PV_MagFreeze *unit); void PV_MagFreeze_Dtor(PV_MagFreeze *unit); void PV_MagFreeze_next(PV_MagFreeze *unit, int inNumSamples); void PV_BinScramble_Ctor(PV_BinScramble *unit); void PV_BinScramble_Dtor(PV_BinScramble *unit); void PV_BinScramble_next(PV_BinScramble *unit, int inNumSamples); void PV_Conj_Ctor(PV_Unit *unit); void PV_Conj_next(PV_Unit *unit, int inNumSamples); /* spectral feature extractors? : bin freq bin magnitude bin phase bin laden ;-} average magnitude over a range of bins max magnitude over a range of bins max magnitude bin freq */ } ////////////////////////////////////////////////////////////////////////////////////////////////// //SCPolarBuf* ToPolarApx(SndBuf *buf); /* SCPolarBuf* ToPolarApx(SndBuf *buf) { if (buf->coord == coord_Complex) { SCComplexBuf* p = (SCComplexBuf*)buf->data; int numbins = buf->samples - 2 >> 1; for (int i=0; ibin[i].ToPolarApxInPlace(); } buf->coord = coord_Polar; } return (SCPolarBuf*)buf->data; } */ //SCComplexBuf* ToComplexApx(SndBuf *buf); /* SCComplexBuf* ToComplexApx(SndBuf *buf) { if (buf->coord == coord_Polar) { SCPolarBuf* p = (SCPolarBuf*)buf->data; int numbins = buf->samples - 2 >> 1; for (int i=0; ibin[i].ToComplexApxInPlace(); } buf->coord = coord_Complex; } return (SCComplexBuf*)buf->data; } */ ///////////////////////////////////////////////////////////////////////////////////////////// void PV_MagAbove_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float thresh = ZIN0(1); if(std::abs(p->dc ) < thresh) p->dc = 0.f; if(std::abs(p->nyq) < thresh) p->nyq = 0.f; for (int i=0; ibin[i].mag; if (mag < thresh) p->bin[i].mag = 0.f; } } void PV_MagAbove_Ctor(PV_Unit *unit) { SETCALC(PV_MagAbove_next); ZOUT0(0) = ZIN0(0); } void PV_MagBelow_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float thresh = ZIN0(1); if(std::abs(p->dc ) > thresh) p->dc = 0.f; if(std::abs(p->nyq) > thresh) p->nyq = 0.f; for (int i=0; ibin[i].mag; if (mag > thresh) p->bin[i].mag = 0.f; } } void PV_MagBelow_Ctor(PV_Unit *unit) { SETCALC(PV_MagBelow_next); ZOUT0(0) = ZIN0(0); } void PV_MagClip_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float thresh = ZIN0(1); if(std::abs(p->dc ) > thresh) p->dc = p->dc < 0.f ? -thresh : thresh; if(std::abs(p->nyq) > thresh) p->nyq = p->nyq < 0.f ? -thresh : thresh; for (int i=0; ibin[i].mag; if (mag > thresh) p->bin[i].mag = thresh; } } void PV_MagClip_Ctor(PV_Unit *unit) { SETCALC(PV_MagClip_next); ZOUT0(0) = ZIN0(0); } void PV_LocalMax_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float thresh = ZIN0(1); float dc, nyq, mag; // DC is only compared with the one above it dc = std::abs(p->dc); mag = p->bin[0].mag; if(dc < thresh || dc < mag) p->dc = 0.f; // 0th bin compared against DC and 1th if(mag < thresh || mag < dc || mag < p->bin[1].mag) p->bin[0].mag = 0.f; // All the middling bins for (int i=1; ibin[i].mag; if (mag < thresh || mag < p->bin[i-1].mag || mag < p->bin[i+1].mag) { p->bin[i].mag = 0.f; } } // Penultimate is compared against the one below and the nyq nyq = std::abs(p->nyq); mag = p->bin[numbins-1].mag; if(mag < thresh || mag < nyq || mag < p->bin[numbins-2].mag) p->bin[numbins-1].mag = 0.f; // Nyquist compared against penultimate if(nyq < thresh || nyq < mag) p->nyq = 0.f; } void PV_LocalMax_Ctor(PV_Unit *unit) { SETCALC(PV_LocalMax_next); ZOUT0(0) = ZIN0(0); } void PV_MagSmear_next(PV_MagSmear *unit, int inNumSamples) { PV_GET_BUF MAKE_TEMP_BUF SCPolarBuf *p = ToPolarApx(buf); SCPolarBuf *q = (SCPolarBuf*)unit->m_tempbuf; int width = (int)ZIN0(1); width = sc_clip(width, 0, numbins-1); float scale = 1.f / (2*width+1); q->dc = p->dc; q->nyq = p->nyq; for (int j=0; j= 0 && pos < numbins) { sum += p->bin[pos].mag; } } q->bin[j].Set( sum * scale, p->bin[j].phase ); } for (int i=0; ibin[i] = q->bin[i]; } } void PV_MagSmear_Ctor(PV_MagSmear *unit) { SETCALC(PV_MagSmear_next); ZOUT0(0) = ZIN0(0); unit->m_tempbuf = 0; } void PV_MagSmear_Dtor(PV_MagSmear *unit) { RTFree(unit->mWorld, unit->m_tempbuf); } void PV_BinShift_next(PV_BinShift *unit, int inNumSamples) { PV_GET_BUF MAKE_TEMP_BUF // get shift and stretch params float stretch = ZIN0(1); float shift = ZIN0(2); float interp = ZIN0(3); SCComplexBuf *p = ToComplexApx(buf); SCComplexBuf *q = (SCComplexBuf*)unit->m_tempbuf; // initialize output buf to zeroes for (int i=0; ibin[i] = 0.f; } float fpos; int i; q->dc = p->dc; q->nyq = p->nyq; if(interp > 0){ for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) { int32 fpos0 = (int32)std::floor(fpos); int32 fpos1 = fpos0+1; float beta = fpos - std::floor(fpos); float alpha = 1.0f - beta; if (fpos0 >= 0 && fpos0 < numbins) { q->bin[fpos0] += alpha * p->bin[i]; } if (fpos1 >= 0 && fpos1 < numbins) { q->bin[fpos1] += beta * p->bin[i]; } } } else { for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) { int32 pos = (int32)(fpos + 0.5); if (pos >= 0 && pos < numbins) { q->bin[pos] += p->bin[i]; } } } memcpy(p->bin, q->bin, numbins * sizeof(SCComplex)); } void PV_BinShift_Ctor(PV_BinShift *unit) { SETCALC(PV_BinShift_next); ZOUT0(0) = ZIN0(0); unit->m_tempbuf = 0; } void PV_BinShift_Dtor(PV_BinShift *unit) { RTFree(unit->mWorld, unit->m_tempbuf); } void PV_MagShift_next(PV_MagShift *unit, int inNumSamples) { PV_GET_BUF MAKE_TEMP_BUF // get shift and stretch params float stretch = ZIN0(1); float shift = ZIN0(2); SCPolarBuf *p = ToPolarApx(buf); SCPolarBuf *q = (SCPolarBuf*)unit->m_tempbuf; // initialize output buf to zeroes for (int i=0; ibin[i].mag = 0.f; q->bin[i].phase = p->bin[i].phase; } float fpos; int i; q->dc = p->dc; q->nyq = p->nyq; for (i=0, fpos = shift; i < numbins; ++i, fpos += stretch) { int32 pos = (int32)(fpos + 0.5); if (pos >= 0 && pos < numbins) { q->bin[pos].mag += p->bin[i].mag; } } memcpy(p->bin, q->bin, numbins * sizeof(SCComplex)); } void PV_MagShift_Ctor(PV_MagShift *unit) { SETCALC(PV_MagShift_next); ZOUT0(0) = ZIN0(0); unit->m_tempbuf = 0; } void PV_MagShift_Dtor(PV_MagShift *unit) { RTFree(unit->mWorld, unit->m_tempbuf); } void PV_MagNoise_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF RGET if (buf->coord == coord_Complex) { SCComplexBuf *p = (SCComplexBuf*)buf->data; for (int i=0; ibin[i].real *= r; p->bin[i].imag *= r; } p->dc *= frand2(s1, s2, s3); p->nyq *= frand2(s1, s2, s3); } else { SCPolarBuf *p = (SCPolarBuf*)buf->data; for (int i=0; ibin[i].mag *= r; } p->dc *= frand2(s1, s2, s3); p->nyq *= frand2(s1, s2, s3); } RPUT } void PV_MagNoise_Ctor(PV_Unit *unit) { SETCALC(PV_MagNoise_next); ZOUT0(0) = ZIN0(0); } void PV_PhaseShift_next(PV_PhaseShift *unit, int inNumSamples) { PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); float shift = ZIN0(1); int integrate = ZIN0(2); float ashift = shift; if (integrate > 0) { ashift += unit->m_phase_integral; unit->m_phase_integral = fmod(ashift, TWOPI); } for (int i=0; ibin[i].phase += ashift; } } void PV_PhaseShift_Ctor(PV_PhaseShift *unit) { SETCALC(PV_PhaseShift_next); ZOUT0(0) = ZIN0(0); unit->m_phase_integral = 0; } void PV_PhaseShift90_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCComplexBuf *p = ToComplexApx(buf); for (int i=0; ibin[i].real; p->bin[i].real = -p->bin[i].imag; p->bin[i].imag = temp; } } void PV_PhaseShift90_Ctor(PV_Unit *unit) { SETCALC(PV_PhaseShift90_next); ZOUT0(0) = ZIN0(0); } void PV_PhaseShift270_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCComplexBuf *p = ToComplexApx(buf); for (int i=0; ibin[i].real; p->bin[i].real = p->bin[i].imag; p->bin[i].imag = -temp; } } void PV_PhaseShift270_Ctor(PV_Unit *unit) { SETCALC(PV_PhaseShift270_next); ZOUT0(0) = ZIN0(0); } void PV_MagSquared_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCPolarBuf *p = ToPolarApx(buf); p->dc = p->dc * p->dc; p->nyq = p->nyq * p->nyq; for (int i=0; ibin[i].mag; p->bin[i].mag = mag * mag; } } void PV_MagSquared_Ctor(PV_Unit *unit) { SETCALC(PV_MagSquared_next); ZOUT0(0) = ZIN0(0); } void PV_BrickWall_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCComplexBuf *p = (SCComplexBuf*)buf->data; int wipe = (int)(ZIN0(1) * numbins); if (wipe > 0) { wipe = sc_min(wipe, numbins); p->dc = 0.f; for (int i=0; i < wipe; ++i) { p->bin[i] = 0.f; } if(wipe==numbins) p->nyq = 0.f; } else if (wipe < 0) { wipe = sc_max(wipe, -numbins); if(wipe==-numbins) p->dc = 0.f; for (int i=numbins+wipe; i < numbins; ++i) { p->bin[i] = 0.f; } p->nyq = 0.f; } } void PV_BrickWall_Ctor(PV_Unit *unit) { SETCALC(PV_BrickWall_next); ZOUT0(0) = ZIN0(0); } void PV_BinWipe_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCComplexBuf *p = (SCComplexBuf*)buf1->data; SCComplexBuf *q = (SCComplexBuf*)buf2->data; int wipe = (int)(ZIN0(2) * numbins); if (wipe > 0) { wipe = sc_min(wipe, numbins); p->dc = q->dc; for (int i=0; i < wipe; ++i) { p->bin[i] = q->bin[i]; } if(wipe==numbins) p->nyq = q->nyq; } else if (wipe < 0) { wipe = sc_max(wipe, -numbins); if(wipe==-numbins) p->dc = q->dc; for (int i=numbins+wipe; i < numbins; ++i) { p->bin[i] = q->bin[i]; } p->nyq = q->nyq; } } void PV_BinWipe_Ctor(PV_Unit *unit) { SETCALC(PV_BinWipe_next); ZOUT0(0) = ZIN0(0); } void PV_MagMul_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCPolarBuf *p = ToPolarApx(buf1); SCPolarBuf *q = ToPolarApx(buf2); p->dc *= q->dc; p->nyq *= q->nyq; for (int i=0; ibin[i].mag *= q->bin[i].mag; } } void PV_MagMul_Ctor(PV_Unit *unit) { SETCALC(PV_MagMul_next); ZOUT0(0) = ZIN0(0); } void PV_MagDiv_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCPolarBuf *p = ToPolarApx(buf1); SCPolarBuf *q = ToPolarApx(buf2); float zeroed = ZIN0(2); p->dc /= sc_max(q->dc, zeroed); p->nyq /= sc_max(q->nyq, zeroed); for (int i=0; ibin[i].mag /= sc_max(q->bin[i].mag, zeroed); } } void PV_MagDiv_Ctor(PV_Unit *unit) { SETCALC(PV_MagDiv_next); ZOUT0(0) = ZIN0(0); } void PV_Copy_next(PV_Unit *unit, int inNumSamples) { float fbufnum1 = ZIN0(0); float fbufnum2 = ZIN0(1); if (fbufnum1 < 0.f || fbufnum2 < 0.f) { ZOUT0(0) = -1.f; return; } ZOUT0(0) = fbufnum2; uint32 ibufnum1 = (int)fbufnum1; uint32 ibufnum2 = (int)fbufnum2; World *world = unit->mWorld; SndBuf *buf1; SndBuf *buf2; if (ibufnum1 >= world->mNumSndBufs) { int localBufNum = ibufnum1 - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf1 = parent->mLocalSndBufs + localBufNum; } else { buf1 = world->mSndBufs; } } else { buf1 = world->mSndBufs + ibufnum1; } if (ibufnum2 >= world->mNumSndBufs) { int localBufNum = ibufnum2 - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf2 = parent->mLocalSndBufs + localBufNum; } else { buf2 = world->mSndBufs; } } else { buf2 = world->mSndBufs + ibufnum2; } if (buf1->samples != buf2->samples) return; // copy to buf2 LOCK_SNDBUF2_SHARED_EXCLUSIVE(buf1, buf2); buf2->coord = buf1->coord; memcpy(buf2->data, buf1->data, buf1->samples * sizeof(float)); } void PV_Copy_Ctor(PV_Unit *unit) { SETCALC(PV_Copy_next); ZOUT0(0) = ZIN0(1); } void PV_CopyPhase_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCPolarBuf *p = ToPolarApx(buf1); SCPolarBuf *q = ToPolarApx(buf2); if((p->dc > 0.f) == (q->dc < 0.f)) p->dc = -p->dc ; if((p->nyq > 0.f) == (q->nyq < 0.f)) p->nyq = -p->nyq; for (int i=0; ibin[i].phase = q->bin[i].phase; } } void PV_CopyPhase_Ctor(PV_Unit *unit) { SETCALC(PV_CopyPhase_next); ZOUT0(0) = ZIN0(0); } void PV_Mul_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCComplexBuf *p = ToComplexApx(buf1); SCComplexBuf *q = ToComplexApx(buf2); float preal, realmul, imagmul; p->dc *= q->dc; p->nyq *= q->nyq; for (int i=0; ibin[i].real; // Complex multiply using only 3 multiplications rather than 4. http://mathworld.wolfram.com/ComplexMultiplication.html realmul = (preal * q->bin[i].real); imagmul = (p->bin[i].imag * q->bin[i].imag); p->bin[i].real = realmul - imagmul; p->bin[i].imag = (preal + p->bin[i].imag) * (q->bin[i].real + q->bin[i].imag) - realmul - imagmul; } } void PV_Mul_Ctor(PV_Unit *unit) { SETCALC(PV_Mul_next); ZOUT0(0) = ZIN0(0); } void PV_Div_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCComplexBuf *p = ToComplexApx(buf1); SCComplexBuf *q = ToComplexApx(buf2); p->dc /= q->dc; p->nyq /= q->nyq; for (int i=0; ibin[i].real * q->bin[i].real + q->bin[i].imag * q->bin[i].imag; float preal = p->bin[i].real; p->bin[i].real = (preal * q->bin[i].real + p->bin[i].imag * q->bin[i].imag) / hypot; p->bin[i].imag = (p->bin[i].imag * q->bin[i].real - preal * q->bin[i].imag) / hypot; } } void PV_Div_Ctor(PV_Unit *unit) { SETCALC(PV_Div_next); ZOUT0(0) = ZIN0(0); } void PV_Add_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCComplexBuf *p = ToComplexApx(buf1); SCComplexBuf *q = ToComplexApx(buf2); p->dc += q->dc; p->nyq += q->nyq; for (int i=0; ibin[i].real += q->bin[i].real; p->bin[i].imag += q->bin[i].imag; } } void PV_Add_Ctor(PV_Unit *unit) { SETCALC(PV_Add_next); ZOUT0(0) = ZIN0(0); } void PV_Max_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCPolarBuf *p = ToPolarApx(buf1); SCPolarBuf *q = ToPolarApx(buf2); if(std::abs(q->dc ) > std::abs(p->dc )) p->dc = q->dc ; if(std::abs(q->nyq) > std::abs(p->nyq)) p->nyq = q->nyq; for (int i=0; ibin[i].mag > p->bin[i].mag) { p->bin[i] = q->bin[i]; } } } void PV_Max_Ctor(PV_Unit *unit) { SETCALC(PV_Max_next); ZOUT0(0) = ZIN0(0); } void PV_Min_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 SCPolarBuf *p = ToPolarApx(buf1); SCPolarBuf *q = ToPolarApx(buf2); if(std::abs(q->dc ) < std::abs(p->dc )) p->dc = q->dc ; if(std::abs(q->nyq) < std::abs(p->nyq)) p->nyq = q->nyq; for (int i=0; ibin[i].mag < p->bin[i].mag) { p->bin[i] = q->bin[i]; } } } void PV_Min_Ctor(PV_Unit *unit) { SETCALC(PV_Min_next); ZOUT0(0) = ZIN0(0); } void PV_RectComb_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF float numTeeth = ZIN0(1); float phase = ZIN0(2); float width = ZIN0(3); float freq = numTeeth / (numbins + 1); SCComplexBuf *p = (SCComplexBuf*)buf->data; if (phase > width) p->dc = 0.f; phase += freq; if (phase >= 1.f) phase -= 1.f; else if (phase < 0.f) phase += 1.f; for (int i=0; i < numbins; ++i) { if (phase > width) p->bin[i] = 0.f; phase += freq; if (phase >= 1.f) phase -= 1.f; else if (phase < 0.f) phase += 1.f; } if (phase > width) p->nyq = 0.f; } void PV_RectComb_Ctor(PV_Unit *unit) { SETCALC(PV_RectComb_next); ZOUT0(0) = ZIN0(0); } void PV_RectComb2_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF2 float numTeeth = ZIN0(2); float phase = ZIN0(3); float width = ZIN0(4); float freq = numTeeth / (numbins + 1); SCComplexBuf *p = (SCComplexBuf*)buf1->data; SCComplexBuf *q = (SCComplexBuf*)buf2->data; if (phase > width) p->dc = q->dc; phase += freq; if (phase >= 1.f) phase -= 1.f; else if (phase < 0.f) phase += 1.f; for (int i=0; i < numbins; ++i) { if (phase > width) p->bin[i] = q->bin[i]; phase += freq; if (phase >= 1.f) phase -= 1.f; else if (phase < 0.f) phase += 1.f; } if (phase > width) p->nyq = q->nyq; } void PV_RectComb2_Ctor(PV_Unit *unit) { SETCALC(PV_RectComb2_next); ZOUT0(0) = ZIN0(0); } static void PV_RandComb_choose(PV_RandComb* unit) { int numbins = unit->m_numbins; for (int i=0; im_ordering[i] = i; } RGET for (int i=0; im_ordering[i]; unit->m_ordering[i] = unit->m_ordering[j]; unit->m_ordering[j] = temp; } RPUT } void PV_RandComb_next(PV_RandComb *unit, int inNumSamples) { float trig = ZIN0(2); if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true; unit->m_prevtrig = trig; PV_GET_BUF if (!unit->m_ordering) { unit->m_ordering = (int*)RTAlloc(unit->mWorld, numbins * sizeof(int)); unit->m_numbins = numbins; PV_RandComb_choose(unit); } else { if (numbins != unit->m_numbins) return; if (unit->m_triggered) { unit->m_triggered = false; PV_RandComb_choose(unit); } } int n = (int)(ZIN0(1) * numbins); n = sc_clip(n, 0, numbins); SCComplexBuf *p = (SCComplexBuf*)buf->data; int *ordering = unit->m_ordering; for (int i=0; ibin[ordering[i]] = 0.f; } if(n==numbins){ // including dc and nyq in the above shuffle would add too much complexity. but at full "wipe" we should get silence. p->dc = 0.f; p->nyq = 0.f; } } void PV_RandComb_Ctor(PV_RandComb* unit) { SETCALC(PV_RandComb_next); ZOUT0(0) = ZIN0(0); unit->m_ordering = 0; unit->m_prevtrig = 0.f; unit->m_triggered = false; } void PV_RandComb_Dtor(PV_RandComb* unit) { RTFree(unit->mWorld, unit->m_ordering); } ////////////////////// static void PV_RandWipe_choose(PV_RandWipe* unit) { int numbins = unit->m_numbins; for (int i=0; im_ordering[i] = i; } RGET for (int i=0; im_ordering[i]; unit->m_ordering[i] = unit->m_ordering[j]; unit->m_ordering[j] = temp; } RPUT } void PV_RandWipe_next(PV_RandWipe *unit, int inNumSamples) { float trig = ZIN0(3); if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true; unit->m_prevtrig = trig; PV_GET_BUF2 if (!unit->m_ordering) { unit->m_ordering = (int*)RTAlloc(unit->mWorld, numbins * sizeof(int)); unit->m_numbins = numbins; PV_RandWipe_choose(unit); } else { if (numbins != unit->m_numbins) return; if (unit->m_triggered) { unit->m_triggered = false; PV_RandWipe_choose(unit); } } int n = (int)(ZIN0(2) * numbins); n = sc_clip(n, 0, numbins); SCComplexBuf *p = (SCComplexBuf*)buf1->data; SCComplexBuf *q = (SCComplexBuf*)buf2->data; int *ordering = unit->m_ordering; for (int i=0; ibin[ordering[i]] = q->bin[ordering[i]]; } } void PV_RandWipe_Ctor(PV_RandWipe* unit) { SETCALC(PV_RandWipe_next); ZOUT0(0) = ZIN0(0); unit->m_ordering = 0; unit->m_prevtrig = 0.f; unit->m_triggered = false; } void PV_RandWipe_Dtor(PV_RandWipe* unit) { RTFree(unit->mWorld, unit->m_ordering); } ////////////////////// static void PV_Diffuser_choose(PV_Diffuser* unit) { RGET for (int i=0; im_numbins; ++i) { unit->m_shift[i] = frand(s1,s2,s3) * twopi; } RPUT } void PV_Diffuser_next(PV_Diffuser *unit, int inNumSamples) { float trig = ZIN0(1); if (trig > 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true; unit->m_prevtrig = trig; PV_GET_BUF if (!unit->m_shift) { unit->m_shift = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float)); unit->m_numbins = numbins; PV_Diffuser_choose(unit); } else { if (numbins != unit->m_numbins) return; if (unit->m_triggered) { unit->m_triggered = false; PV_Diffuser_choose(unit); } } int n = (int)(ZIN0(1) * numbins); n = sc_clip(n, 0, numbins); SCPolarBuf *p = ToPolarApx(buf); float *shift = unit->m_shift; for (int i=0; ibin[i].phase += shift[i]; } } void PV_Diffuser_Ctor(PV_Diffuser* unit) { SETCALC(PV_Diffuser_next); ZOUT0(0) = ZIN0(0); unit->m_shift = 0; unit->m_prevtrig = 0.f; unit->m_triggered = false; } void PV_Diffuser_Dtor(PV_Diffuser* unit) { RTFree(unit->mWorld, unit->m_shift); } ////////////////////// void PV_MagFreeze_next(PV_MagFreeze *unit, int inNumSamples) { PV_GET_BUF float freeze = ZIN0(1); if (!unit->m_mags) { unit->m_mags = (float*)RTAlloc(unit->mWorld, numbins * sizeof(float)); unit->m_numbins = numbins; // The first fft frame must use the else branch below // so that unit->m_mags gets populated with actual mag data // before reading; otherwise it might be used uninitialized. freeze = 0.f; } else if (numbins != unit->m_numbins) return; SCPolarBuf *p = ToPolarApx(buf); float *mags = unit->m_mags; if (freeze > 0.f) { for (int i=0; ibin[i].mag = mags[i]; } p->dc = unit->m_dc; p->nyq = unit->m_nyq; } else { for (int i=0; ibin[i].mag; } unit->m_dc = p->dc; unit->m_nyq = p->nyq; } } void PV_MagFreeze_Ctor(PV_MagFreeze* unit) { SETCALC(PV_MagFreeze_next); ZOUT0(0) = ZIN0(0); unit->m_mags = 0; } void PV_MagFreeze_Dtor(PV_MagFreeze* unit) { RTFree(unit->mWorld, unit->m_mags); } ////////////////////// static void PV_BinScramble_choose(PV_BinScramble* unit) { int numbins = unit->m_numbins; int *to = unit->m_to; int *from = unit->m_from; for (int i=0; i 0.f && unit->m_prevtrig <= 0.f) unit->m_triggered = true; unit->m_prevtrig = trig; PV_GET_BUF if (!unit->m_to) { unit->m_to = (int*)RTAlloc(unit->mWorld, numbins * 2 * sizeof(int)); unit->m_from = unit->m_to + numbins; unit->m_numbins = numbins; unit->m_tempbuf = (float*)RTAlloc(unit->mWorld, buf->samples * sizeof(float)); PV_BinScramble_choose(unit); } else { if (numbins != unit->m_numbins) return; if (unit->m_triggered) { unit->m_triggered = false; PV_BinScramble_choose(unit); } } SCComplexBuf *p = (SCComplexBuf*)buf->data; SCComplexBuf *q = (SCComplexBuf*)unit->m_tempbuf; float wipe = ZIN0(1); int32 scrambleBins = (int32)(numbins * sc_clip(wipe, 0.f, 1.f)); int *to = unit->m_to; int *from = unit->m_from; for (int j=0; jbin[to[j]] = p->bin[from[j]]; } for (int j=scrambleBins; jbin[a] = p->bin[a]; } q->dc = p->dc; q->nyq = p->nyq; memcpy(p->bin, q->bin, numbins * sizeof(SCComplex)); } void PV_BinScramble_Ctor(PV_BinScramble* unit) { SETCALC(PV_BinScramble_next); ZOUT0(0) = ZIN0(0); unit->m_to = 0; unit->m_prevtrig = 0.f; unit->m_triggered = false; unit->m_tempbuf = 0; } void PV_BinScramble_Dtor(PV_BinScramble* unit) { RTFree(unit->mWorld, unit->m_to); RTFree(unit->mWorld, unit->m_tempbuf); } void PV_Conj_Ctor(PV_Unit *unit) { SETCALC(PV_Conj_next); ZOUT0(0) = ZIN0(0); } void PV_Conj_next(PV_Unit *unit, int inNumSamples) { PV_GET_BUF SCComplexBuf *p = ToComplexApx(buf); for (int i=0; ibin[i].imag = 0.f - p->bin[i].imag; } } //////////////////////////////////////////////////////////////////////////////////////////////////////// #define DefinePVUnit(name) \ (*ft->fDefineUnit)(#name, sizeof(PV_Unit), (UnitCtorFunc)&name##_Ctor, 0, 0); void initPV(InterfaceTable *inTable) { DefinePVUnit(PV_MagAbove); DefinePVUnit(PV_MagBelow); DefinePVUnit(PV_MagClip); DefinePVUnit(PV_MagMul); DefinePVUnit(PV_MagDiv); DefinePVUnit(PV_MagSquared); DefinePVUnit(PV_MagNoise); DefinePVUnit(PV_Copy); DefinePVUnit(PV_CopyPhase); DefinePVUnit(PV_PhaseShift); DefinePVUnit(PV_PhaseShift90); DefinePVUnit(PV_PhaseShift270); DefinePVUnit(PV_Min); DefinePVUnit(PV_Max); DefinePVUnit(PV_Mul); DefinePVUnit(PV_Div); DefinePVUnit(PV_Add); DefinePVUnit(PV_RectComb); DefinePVUnit(PV_RectComb2); DefinePVUnit(PV_BrickWall); DefinePVUnit(PV_BinWipe); DefinePVUnit(PV_LocalMax); DefinePVUnit(PV_Conj); DefineDtorUnit(PV_BinScramble); DefineDtorUnit(PV_MagSmear); DefineDtorUnit(PV_MagShift); DefineDtorUnit(PV_BinShift); DefineDtorUnit(PV_RandWipe); DefineDtorUnit(PV_Diffuser); DefineDtorUnit(PV_RandComb); DefineDtorUnit(PV_MagFreeze); } SuperCollider-Source/server/plugins/ReverbUGens.cpp000644 000765 000024 00000113377 12321461511 023547 0ustar00crucialstaff000000 000000 // FreeVerb UGens // faust code generation experiments. blackrain 07/2005 /* Copyright (c) 2005 blackrain . All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" // gcc3.3 mathlib doesnt know these yet #if gccversion < 4 #define powf pow #define sqrtf sqrt #endif static InterfaceTable *ft; struct FreeVerb : public Unit { int iota0; int iota1; int iota2; int iota3; int iota4; int iota5; int iota6; int iota7; int iota8; int iota9; int iota10; int iota11; float R0_1; float R1_1; float R2_1; float R3_1; float R0_0; float R1_0; float R2_0; float R3_0; float R4_0; float R5_0; float R6_0; float R7_0; float R8_0; float R9_0; float R10_0; float R11_0; float R12_0; float R13_0; float R14_0; float R15_0; float R16_0; float R17_0; float R18_0; float R19_0; float dline0[225]; float dline1[341]; float dline2[441]; float dline3[556]; float dline4[1617]; float dline5[1557]; float dline6[1491]; float dline7[1422]; float dline8[1277]; float dline9[1116]; float dline10[1188]; float dline11[1356]; }; /* GVerb work */ #define FDNORDER 4 typedef struct { int size; int idx; float* buf; } g_fixeddelay; typedef struct { int size; float coef; int idx; float* buf; } g_diffuser; typedef struct { float damping; float delay; } g_damper; struct GVerb : public Unit { float roomsize, revtime, damping, spread, inputbandwidth, drylevel, earlylevel, taillevel; float maxroomsize; float maxdelay, largestdelay; g_damper *inputdamper; g_fixeddelay *fdndels[FDNORDER]; float fdngains[FDNORDER]; int fdnlens[FDNORDER]; g_damper *fdndamps[FDNORDER]; double alpha; float u[FDNORDER], f[FDNORDER], d[FDNORDER]; g_diffuser *ldifs[FDNORDER]; g_diffuser *rdifs[FDNORDER]; g_fixeddelay *tapdelay; int taps[FDNORDER]; float tapgains[FDNORDER]; float earlylevelslope, taillevelslope, drylevelslope; float fdngainslopes[FDNORDER], tapgainslopes[FDNORDER]; // make the CALCSLOPE values part of the struct // calculate changes first, store them // grab values and use in the sample loop }; extern "C" { void FreeVerb_Ctor(FreeVerb *unit); void FreeVerb_next(FreeVerb *unit, int inNumSamples); void GVerb_Ctor(GVerb *unit); void GVerb_Dtor(GVerb *unit); void GVerb_next(GVerb* unit, int inNumSamples); }; void FreeVerb_Ctor(FreeVerb *unit) { SETCALC(FreeVerb_next); unit->iota0 = 0; unit->iota1 = 0; unit->iota2 = 0; unit->iota3 = 0; unit->iota4 = 0; unit->iota5 = 0; unit->iota6 = 0; unit->iota7 = 0; unit->iota8 = 0; unit->iota9 = 0; unit->iota10 = 0; unit->iota11 = 0; unit->R0_0 = 0.0; unit->R1_0 = 0.0; unit->R2_0 = 0.0; unit->R3_0 = 0.0; unit->R4_0 = 0.0; unit->R5_0 = 0.0; unit->R6_0 = 0.0; unit->R7_0 = 0.0; unit->R8_0 = 0.0; unit->R9_0 = 0.0; unit->R10_0 = 0.0; unit->R11_0 = 0.0; unit->R12_0 = 0.0; unit->R13_0 = 0.0; unit->R14_0 = 0.0; unit->R15_0 = 0.0; unit->R16_0 = 0.0; unit->R17_0 = 0.0; unit->R18_0 = 0.0; unit->R19_0 = 0.0; unit->R0_1 = 0.0; unit->R1_1 = 0.0; unit->R2_1 = 0.0; unit->R3_1 = 0.0; for(int i=0; i<225; i++) unit->dline0[i] = 0.0; for(int i=0; i<341; i++) unit->dline1[i] = 0.0; for(int i=0; i<441; i++) unit->dline2[i] = 0.0; for(int i=0; i<556; i++) unit->dline3[i] = 0.0; for(int i=0; i<1617; i++) unit->dline4[i] = 0.0; for(int i=0; i<1557; i++) unit->dline5[i] = 0.0; for(int i=0; i<1491; i++) unit->dline6[i] = 0.0; for(int i=0; i<1422; i++) unit->dline7[i] = 0.0; for(int i=0; i<1277; i++) unit->dline8[i] = 0.0; for(int i=0; i<1116; i++) unit->dline9[i] = 0.0; for(int i=0; i<1188; i++) unit->dline10[i] = 0.0; for(int i=0; i<1356; i++) unit->dline11[i] = 0.0; FreeVerb_next(unit, 1); } void FreeVerb_next(FreeVerb *unit, int inNumSamples) { float* input0 = IN(0); float* output0 = OUT(0); float ftemp0 = IN0(1); // mix if (ftemp0 > 1.) ftemp0 = 1.; if (ftemp0 < 0.) ftemp0 = 0.; float ftemp1 = (1 - ftemp0); float room = IN0(2); // room if (room > 1.) room = 1.; if (room < 0.) room = 0.; float ftemp5 = (0.700000f + (0.280000f * room)); float damp = IN0(3); // damp if (damp > 1.) damp = 1.; if (damp < 0.) damp = 0.; float ftemp6 = (0.400000f * damp); float ftemp7 = (1 - ftemp6); int iota0 = unit->iota0; int iota1 = unit->iota1; int iota2 = unit->iota2; int iota3 = unit->iota3; int iota4 = unit->iota4; int iota5 = unit->iota5; int iota6 = unit->iota6; int iota7 = unit->iota7; int iota8 = unit->iota8; int iota9 = unit->iota9; int iota10 = unit->iota10; int iota11 = unit->iota11; float R0_1 = unit->R0_1; float R1_1 = unit->R1_1; float R2_1 = unit->R2_1; float R3_1 = unit->R3_1; float R0_0 = unit->R0_0; float R1_0 = unit->R1_0; float R2_0 = unit->R2_0; float R3_0 = unit->R3_0; float R4_0 = unit->R4_0; float R5_0 = unit->R5_0; float R6_0 = unit->R6_0; float R7_0 = unit->R7_0; float R8_0 = unit->R8_0; float R9_0 = unit->R9_0; float R10_0 = unit->R10_0; float R11_0 = unit->R11_0; float R12_0 = unit->R12_0; float R13_0 = unit->R13_0; float R14_0 = unit->R14_0; float R15_0 = unit->R15_0; float R16_0 = unit->R16_0; float R17_0 = unit->R17_0; float R18_0 = unit->R18_0; float R19_0 = unit->R19_0; float *dline0 = unit->dline0; float *dline1 = unit->dline1; float *dline2 = unit->dline2; float *dline3 = unit->dline3; float *dline4 = unit->dline4; float *dline5 = unit->dline5; float *dline6 = unit->dline6; float *dline7 = unit->dline7; float *dline8 = unit->dline8; float *dline9 = unit->dline9; float *dline10 = unit->dline10; float *dline11 = unit->dline11; for (int i=0; iiota0 = iota0; unit->iota1 = iota1; unit->iota2 = iota2; unit->iota3 = iota3; unit->iota4 = iota4; unit->iota5 = iota5; unit->iota6 = iota6; unit->iota7 = iota7; unit->iota8 = iota8; unit->iota9 = iota9; unit->iota10 = iota10; unit->iota11 = iota11; unit->R0_1 = R0_1; unit->R1_1 = R1_1; unit->R2_1 = R2_1; unit->R3_1 = R3_1; unit->R0_0 = R0_0; unit->R1_0 = R1_0; unit->R2_0 = R2_0; unit->R3_0 = R3_0; unit->R4_0 = R4_0; unit->R5_0 = R5_0; unit->R6_0 = R6_0; unit->R7_0 = R7_0; unit->R8_0 = R8_0; unit->R9_0 = R9_0; unit->R10_0 = R10_0; unit->R11_0 = R11_0; unit->R12_0 = R12_0; unit->R13_0 = R13_0; unit->R14_0 = R14_0; unit->R15_0 = R15_0; unit->R16_0 = R16_0; unit->R17_0 = R17_0; unit->R18_0 = R18_0; unit->R19_0 = R19_0; } // FreeVerb2 struct FreeVerb2 : public Unit { int iota0; int iota1; int iota2; int iota3; int iota4; int iota5; int iota6; int iota7; int iota8; int iota9; int iota10; int iota11; int iota12; int iota13; int iota14; int iota15; int iota16; int iota17; int iota18; int iota19; int iota20; int iota21; int iota22; int iota23; float R0_1; float R1_1; float R2_1; float R3_1; float R0_0; float R1_0; float R2_0; float R3_0; float R4_0; float R5_0; float R6_0; float R7_0; float R8_0; float R9_0; float R10_0; float R11_0; float R12_0; float R13_0; float R14_0; float R15_0; float R16_0; float R17_0; float R18_0; float R19_0; float R20_0; float R21_0; float R22_0; float R23_0; float R24_0; float R25_0; float R26_0; float R27_0; float R28_0; float R29_0; float R30_0; float R31_0; float R32_0; float R33_0; float R34_0; float R35_0; float R36_0; float R37_0; float R38_0; float R39_0; float R20_1; float R21_1; float R22_1; float R23_1; float dline0[225]; float dline1[341]; float dline2[441]; float dline3[556]; float dline4[1617]; float dline5[1557]; float dline6[1491]; float dline7[1422]; float dline8[1277]; float dline9[1116]; float dline10[1188]; float dline11[1356]; float dline12[248]; float dline13[364]; float dline14[464]; float dline15[579]; float dline16[1640]; float dline17[1580]; float dline18[1514]; float dline19[1445]; float dline20[1300]; float dline21[1139]; float dline22[1211]; float dline23[1379]; }; extern "C" { void FreeVerb2_Ctor(FreeVerb2 *unit); void FreeVerb2_next(FreeVerb2 *unit, int inNumSamples); }; void FreeVerb2_Ctor(FreeVerb2 *unit) { SETCALC(FreeVerb2_next); unit->iota0 = 0; unit->iota1 = 0; unit->iota2 = 0; unit->iota3 = 0; unit->iota4 = 0; unit->iota5 = 0; unit->iota6 = 0; unit->iota7 = 0; unit->iota8 = 0; unit->iota9 = 0; unit->iota10 = 0; unit->iota11 = 0; unit->iota12 = 0; unit->iota13 = 0; unit->iota14 = 0; unit->iota15 = 0; unit->iota16 = 0; unit->iota17 = 0; unit->iota18 = 0; unit->iota19 = 0; unit->iota20 = 0; unit->iota21 = 0; unit->iota22 = 0; unit->iota23 = 0; unit->R0_0 = 0.0; unit->R1_0 = 0.0; unit->R2_0 = 0.0; unit->R3_0 = 0.0; unit->R4_0 = 0.0; unit->R5_0 = 0.0; unit->R6_0 = 0.0; unit->R7_0 = 0.0; unit->R8_0 = 0.0; unit->R9_0 = 0.0; unit->R10_0 = 0.0; unit->R11_0 = 0.0; unit->R12_0 = 0.0; unit->R13_0 = 0.0; unit->R14_0 = 0.0; unit->R15_0 = 0.0; unit->R16_0 = 0.0; unit->R17_0 = 0.0; unit->R18_0 = 0.0; unit->R19_0 = 0.0; unit->R20_0 = 0.0; unit->R21_0 = 0.0; unit->R22_0 = 0.0; unit->R23_0 = 0.0; unit->R24_0 = 0.0; unit->R25_0 = 0.0; unit->R26_0 = 0.0; unit->R27_0 = 0.0; unit->R28_0 = 0.0; unit->R29_0 = 0.0; unit->R30_0 = 0.0; unit->R31_0 = 0.0; unit->R32_0 = 0.0; unit->R33_0 = 0.0; unit->R34_0 = 0.0; unit->R35_0 = 0.0; unit->R36_0 = 0.0; unit->R37_0 = 0.0; unit->R38_0 = 0.0; unit->R39_0 = 0.0; unit->R0_1 = 0.0; unit->R1_1 = 0.0; unit->R2_1 = 0.0; unit->R3_1 = 0.0; unit->R23_1 = 0.0; unit->R22_1 = 0.0; unit->R21_1 = 0.0; unit->R20_1 = 0.0; for(int i=0; i<225; i++) unit->dline0[i] = 0.0; for(int i=0; i<341; i++) unit->dline1[i] = 0.0; for(int i=0; i<441; i++) unit->dline2[i] = 0.0; for(int i=0; i<556; i++) unit->dline3[i] = 0.0; for(int i=0; i<1617; i++) unit->dline4[i] = 0.0; for(int i=0; i<1557; i++) unit->dline5[i] = 0.0; for(int i=0; i<1491; i++) unit->dline6[i] = 0.0; for(int i=0; i<1422; i++) unit->dline7[i] = 0.0; for(int i=0; i<1277; i++) unit->dline8[i] = 0.0; for(int i=0; i<1116; i++) unit->dline9[i] = 0.0; for(int i=0; i<1188; i++) unit->dline10[i] = 0.0; for(int i=0; i<1356; i++) unit->dline11[i] = 0.0; for(int i=0; i<248; i++) unit->dline12[i] = 0.0; for(int i=0; i<364; i++) unit->dline13[i] = 0.0; for(int i=0; i<464; i++) unit->dline14[i] = 0.0; for(int i=0; i<579; i++) unit->dline15[i] = 0.0; for(int i=0; i<1640; i++) unit->dline16[i] = 0.0; for(int i=0; i<1580; i++) unit->dline17[i] = 0.0; for(int i=0; i<1514; i++) unit->dline18[i] = 0.0; for(int i=0; i<1445; i++) unit->dline19[i] = 0.0; for(int i=0; i<1300; i++) unit->dline20[i] = 0.0; for(int i=0; i<1139; i++) unit->dline21[i] = 0.0; for(int i=0; i<1211; i++) unit->dline22[i] = 0.0; for(int i=0; i<1379; i++) unit->dline23[i] = 0.0; FreeVerb2_next(unit, 1); } void FreeVerb2_next(FreeVerb2 *unit, int inNumSamples) { float* input0 = IN(0); float* input1 = IN(1); float* output0 = OUT(0); float* output1 = OUT(1); float ftemp0 = IN0(2); // mix if (ftemp0 > 1.) ftemp0 = 1.; if (ftemp0 < 0.) ftemp0 = 0.; float ftemp1 = (1 - ftemp0); float room = IN0(3); // room if (room > 1.) room = 1.; if (room < 0.) room = 0.; float ftemp5 = (0.700000f + (0.280000f * room)); float damp = IN0(4); // damp if (damp > 1.) damp = 1.; if (damp < 0.) damp = 0.; float ftemp6 = (0.400000f * damp); float ftemp7 = (1 - ftemp6); float R0_0 = unit->R0_0; float R1_0 = unit->R1_0; float R2_0 = unit->R2_0; float R3_0 = unit->R3_0; float R4_0 = unit->R4_0; float R5_0 = unit->R5_0; float R6_0 = unit->R6_0; float R7_0 = unit->R7_0; float R8_0 = unit->R8_0; float R9_0 = unit->R9_0; float R10_0 = unit->R10_0; float R11_0 = unit->R11_0; float R12_0 = unit->R12_0; float R13_0 = unit->R13_0; float R14_0 = unit->R14_0; float R15_0 = unit->R15_0; float R16_0 = unit->R16_0; float R17_0 = unit->R17_0; float R18_0 = unit->R18_0; float R19_0 = unit->R19_0; float R20_0 = unit->R20_0; float R21_0 = unit->R21_0; float R22_0 = unit->R22_0; float R23_0 = unit->R23_0; float R24_0 = unit->R24_0; float R25_0 = unit->R25_0; float R26_0 = unit->R26_0; float R27_0 = unit->R27_0; float R28_0 = unit->R28_0; float R29_0 = unit->R29_0; float R30_0 = unit->R30_0; float R31_0 = unit->R31_0; float R32_0 = unit->R32_0; float R33_0 = unit->R33_0; float R34_0 = unit->R34_0; float R35_0 = unit->R35_0; float R36_0 = unit->R36_0; float R37_0 = unit->R37_0; float R38_0 = unit->R38_0; float R39_0 = unit->R39_0; float R0_1 = unit->R0_1; float R1_1 = unit->R1_1; float R2_1 = unit->R2_1; float R3_1 = unit->R3_1; float R23_1 = unit->R23_1; float R22_1 = unit->R22_1; float R21_1 = unit->R21_1; float R20_1 = unit->R20_1; int iota0 = unit->iota0; int iota1 = unit->iota1; int iota2 = unit->iota2; int iota3 = unit->iota3; int iota4 = unit->iota4; int iota5 = unit->iota5; int iota6 = unit->iota6; int iota7 = unit->iota7; int iota8 = unit->iota8; int iota9 = unit->iota9; int iota10 = unit->iota10; int iota11 = unit->iota11; int iota12 = unit->iota12; int iota13 = unit->iota13; int iota14 = unit->iota14; int iota15 = unit->iota15; int iota16 = unit->iota16; int iota17 = unit->iota17; int iota18 = unit->iota18; int iota19 = unit->iota19; int iota20 = unit->iota20; int iota21 = unit->iota21; int iota22 = unit->iota22; int iota23 = unit->iota23; float *dline0 = unit->dline0; float *dline1 = unit->dline1; float *dline2 = unit->dline2; float *dline3 = unit->dline3; float *dline4 = unit->dline4; float *dline5 = unit->dline5; float *dline6 = unit->dline6; float *dline7 = unit->dline7; float *dline8 = unit->dline8; float *dline9 = unit->dline9; float *dline10 = unit->dline10; float *dline11 = unit->dline11; float *dline12 = unit->dline12; float *dline13 = unit->dline13; float *dline14 = unit->dline14; float *dline15 = unit->dline15; float *dline16 = unit->dline16; float *dline17 = unit->dline17; float *dline18 = unit->dline18; float *dline19 = unit->dline19; float *dline20 = unit->dline20; float *dline21 = unit->dline21; float *dline22 = unit->dline22; float *dline23 = unit->dline23; for (int i=0; iiota0 = iota0; unit->iota1 = iota1; unit->iota2 = iota2; unit->iota3 = iota3; unit->iota4 = iota4; unit->iota5 = iota5; unit->iota6 = iota6; unit->iota7 = iota7; unit->iota8 = iota8; unit->iota9 = iota9; unit->iota10 = iota10; unit->iota11 = iota11; unit->iota12 = iota12; unit->iota13 = iota13; unit->iota14 = iota14; unit->iota15 = iota15; unit->iota16 = iota16; unit->iota17 = iota17; unit->iota18 = iota18; unit->iota19 = iota19; unit->iota20 = iota20; unit->iota21 = iota21; unit->iota22 = iota22; unit->iota23 = iota23; unit->R0_1 = R0_1; unit->R1_1 = R1_1; unit->R2_1 = R2_1; unit->R3_1 = R3_1; unit->R20_1 = R20_1; unit->R21_1 = R21_1; unit->R22_1 = R22_1; unit->R23_1 = R23_1; unit->R0_0 = R0_0; unit->R1_0 = R1_0; unit->R2_0 = R2_0; unit->R3_0 = R3_0; unit->R4_0 = R4_0; unit->R5_0 = R5_0; unit->R6_0 = R6_0; unit->R7_0 = R7_0; unit->R8_0 = R8_0; unit->R9_0 = R9_0; unit->R10_0 = R10_0; unit->R11_0 = R11_0; unit->R12_0 = R12_0; unit->R13_0 = R13_0; unit->R14_0 = R14_0; unit->R15_0 = R15_0; unit->R16_0 = R16_0; unit->R17_0 = R17_0; unit->R18_0 = R18_0; unit->R19_0 = R19_0; unit->R20_0 = R20_0; unit->R21_0 = R21_0; unit->R22_0 = R22_0; unit->R23_0 = R23_0; unit->R24_0 = R24_0; unit->R25_0 = R25_0; unit->R26_0 = R26_0; unit->R27_0 = R27_0; unit->R28_0 = R28_0; unit->R29_0 = R29_0; unit->R30_0 = R30_0; unit->R31_0 = R31_0; unit->R32_0 = R32_0; unit->R33_0 = R33_0; unit->R34_0 = R34_0; unit->R35_0 = R35_0; unit->R36_0 = R36_0; unit->R37_0 = R37_0; unit->R38_0 = R38_0; unit->R39_0 = R39_0; } #define TRUE 1 #define FALSE 0 typedef union { float f; #ifdef _WIN32 long int i; #else int32_t i; #endif } ls_pcast32; static inline float flush_to_zero(float f) { ls_pcast32 v; v.f = f; // original: return (v.i & 0x7f800000) == 0 ? 0.0f : f; // version from Tim Blechmann return (v.i & 0x7f800000) < 0x08000000 ? 0.0f : f; } int isprime(int n) { unsigned int i; const unsigned int lim = (int)sqrtf((float)n); if (n == 2) return(TRUE); if ((n & 1) == 0) return(FALSE); for(i = 3; i <= lim; i += 2) if ((n % i) == 0) return(FALSE); return(TRUE); } int nearestprime(int n, float rerror) { int bound,k; if (isprime(n)) return(n); /* assume n is large enough and n*rerror enough smaller than n */ bound = (int)(n * rerror); for(k = 1; k <= bound; k++) { if (isprime(n+k)) return(n+k); if (isprime(n-k)) return(n-k); } return(-1); } static inline int f_round(float f){ ls_pcast32 p; p.f = f; p.f += (3<<22); return p.i - 0x4b400000; } g_damper *make_damper(GVerb *unit, float damping){ g_damper* p; p = (g_damper*)RTAlloc(unit->mWorld, sizeof(g_damper)); p->damping = damping; p->delay = 0.f; return(p); } void free_damper(GVerb *unit, g_damper *p){ RTFree(unit->mWorld, p); }; g_diffuser *make_diffuser(GVerb *unit, int size, float coef){ g_diffuser* p; p = (g_diffuser*)RTAlloc(unit->mWorld, sizeof(g_diffuser)); p->size = size; p->coef = coef; p->idx = 0; p->buf = (float*)RTAlloc(unit->mWorld, size * sizeof(float)); Clear(size, p->buf); return(p); } void free_diffuser(GVerb *unit, g_diffuser *p){ RTFree(unit->mWorld, p->buf); RTFree(unit->mWorld, p); } g_fixeddelay *make_fixeddelay(GVerb *unit, int size, int maxsize){ g_fixeddelay *p; p = (g_fixeddelay*)RTAlloc(unit->mWorld, sizeof(g_fixeddelay)); p->size = size; p->idx = 0; p->buf = (float*)RTAlloc(unit->mWorld, maxsize * sizeof(float)); Clear(maxsize, p->buf); return(p); } void free_fixeddelay(GVerb *unit, g_fixeddelay *p){ RTFree(unit->mWorld, p->buf); RTFree(unit->mWorld, p); } static inline float diffuser_do(GVerb *unit, g_diffuser *p, float x){ float y,w; w = x - p->buf[p->idx] * p->coef; w = flush_to_zero(w); y = p->buf[p->idx] + w * p->coef; p->buf[p->idx] = zapgremlins(w); p->idx = (p->idx + 1) % p->size; return(y); } static inline float fixeddelay_read(GVerb *unit, g_fixeddelay *p, int n){ int i; i = (p->idx - n + p->size) % p->size; return(p->buf[i]); } static inline void fixeddelay_write(GVerb *unit, g_fixeddelay *p, float x){ p->buf[p->idx] = zapgremlins(x); p->idx = (p->idx + 1) % p->size; } static inline void damper_set(GVerb *unit, g_damper *p, float damping){ p->damping = damping; } static inline float damper_do(GVerb *unit, g_damper *p, float x){ float y; y = x*(1.0-p->damping) + p->delay*p->damping; p->delay = zapgremlins(y); return(y); } static inline void gverb_fdnmatrix(float *a, float *b){ const float dl0 = a[0], dl1 = a[1], dl2 = a[2], dl3 = a[3]; b[0] = 0.5f*(+dl0 + dl1 - dl2 - dl3); b[1] = 0.5f*(+dl0 - dl1 - dl2 + dl3); b[2] = 0.5f*(-dl0 + dl1 - dl2 + dl3); b[3] = 0.5f*(+dl0 + dl1 + dl2 + dl3); } static inline void gverb_set_roomsize(GVerb *unit, const float a) { unsigned int i; if (a <= 1.0 || sc_isnan(a)) { unit->roomsize = 1.0; } else { if(a >= unit->maxroomsize) unit->roomsize = unit->maxroomsize - 1.; else unit->roomsize = a; }; unit->largestdelay = SAMPLERATE * unit->roomsize / 340.0; // * 0.00294f; // the line below causes everything to blow up.... why????? // unit->fdnlens[0] = nearestprime((int)(unit->largestdelay), 0.5); unit->fdnlens[1] = (int)(0.816490*unit->largestdelay); unit->fdnlens[2] = (int)(0.707100*unit->largestdelay); unit->fdnlens[3] = (int)(0.632450*unit->largestdelay); for(i = 0; i < FDNORDER; i++) { float oldfdngain = unit->fdngains[i]; unit->fdngains[i] = -powf((float)unit->alpha, unit->fdnlens[i]); unit->fdngainslopes[i] = CALCSLOPE(unit->fdngains[i], oldfdngain); } unit->taps[0] = 5 + (int)(0.410 * unit->largestdelay); unit->taps[1] = 5 + (int)(0.300 * unit->largestdelay); unit->taps[2] = 5 + (int)(0.155 * unit->largestdelay); unit->taps[3] = 5; //+ f_round(0.000 * largestdelay); for(i = 0; i < FDNORDER; i++) { float oldtapgain = unit->tapgains[i]; unit->tapgains[i] = pow(unit->alpha, unit->taps[i]); unit->tapgainslopes[i] = CALCSLOPE(unit->tapgains[i], oldtapgain); } } static inline void gverb_set_revtime(GVerb *unit, float a) { float ga; double n; unsigned int i; unit->revtime = a; ga = 0.001; n = SAMPLERATE * a; unit->alpha = (double)powf(ga,(float)(1.f/n)); for(i = 0; i < FDNORDER; i++) { float oldfdngain = unit->fdngains[i]; unit->fdngains[i] = -powf((float)unit->alpha, unit->fdnlens[i]); unit->fdngainslopes[i] = CALCSLOPE(unit->fdngains[i], oldfdngain); } } static inline void gverb_set_damping(GVerb *unit,float a) { unsigned int i; unit->damping = a; for(i = 0; i < FDNORDER; i++) { damper_set(unit, unit->fdndamps[i], unit->damping); } } static inline void gverb_set_inputbandwidth(GVerb *unit,float a) { unit->inputbandwidth = a; damper_set(unit, unit->inputdamper, 1.0 - unit->inputbandwidth); } static inline float gverb_set_earlylevel(GVerb *unit, float a) { float oldearly = unit->earlylevel; unit->earlylevel = a; unit->earlylevelslope = CALCSLOPE(a, oldearly); return(oldearly); } static inline float gverb_set_taillevel(GVerb *unit, float a) { float oldtail = unit->taillevel; unit->taillevel = a; unit->taillevelslope = CALCSLOPE(a, oldtail); return(oldtail); } static inline float gverb_set_drylevel(GVerb *unit, float a) { float olddry = unit->drylevel; unit->drylevel = a; unit->drylevelslope = CALCSLOPE(a, olddry); return(olddry); } void GVerb_Ctor(GVerb *unit) { SETCALC(GVerb_next); float roomsize = unit->roomsize = IN0(1); float revtime = unit->revtime = IN0(2); float damping = unit->damping = IN0(3); float inputbandwidth = unit->inputbandwidth = 0.; //IN0(4); float spread = unit->spread = IN0(5); unit->drylevel = 0.; //IN0(6); unit->earlylevel = 0.; // IN0(7); unit->taillevel = 0.; //IN0(8); float maxroomsize = unit->maxroomsize = IN0(9); float maxdelay = unit->maxdelay = SAMPLERATE*maxroomsize/340.f; float largestdelay = unit->largestdelay = SAMPLERATE*roomsize/340.f; // make the inputdamper unit->inputdamper = make_damper(unit, 1. - inputbandwidth); //float ga = powf(10.f, -60.f/20.f); float ga = 0.001f; float n = SAMPLERATE * revtime; double alpha = unit->alpha = pow((double)ga, 1./(double)n); float gbmul[4] = {1.000, 0.816490, 0.707100, 0.632450}; for(int i = 0; i < FDNORDER; ++i){ float gb = gbmul[i] * largestdelay; if(i == 0){ unit->fdnlens[i] = nearestprime((int)gb, 0.5); } else { unit->fdnlens[i] = f_round(gb); } unit->fdngains[i] = -powf((float)alpha, unit->fdnlens[i]); } // make the fixeddelay lines and dampers for(int i = 0; i < FDNORDER; i++){ unit->fdndels[i] = make_fixeddelay(unit, (int)unit->fdnlens[i], (int)maxdelay+1000); unit->fdndamps[i] = make_damper(unit, damping); // damping is the same as fdndamping in source } // diffuser section float diffscale = (float)unit->fdnlens[3]/(210. + 159. + 562. + 410.); float spread1 = spread; float spread2 = 3.0 * spread; int b = 210; float r = 0.125541; int a = (int)(spread1 * r); int c = 210+159 + a; int cc = c - b; r = 0.854046; a = (int)(spread2 * r); int d = 210 + 159 + 562 + a; int dd = d - c; int e = 1341 - d; unit->ldifs[0] = make_diffuser(unit, f_round(diffscale * b), 0.75); unit->ldifs[1] = make_diffuser(unit, f_round(diffscale * cc), 0.75); unit->ldifs[2] = make_diffuser(unit, f_round(diffscale * dd), 0.625); unit->ldifs[3] = make_diffuser(unit, f_round(diffscale * e), 0.625); b = 210; r = -0.568366; a = (int)(spread1 * r); c = 210 + 159 + a; cc = c - b; r = -0.126815; a = (int)(spread2 * r); d = 210 + 159 + 562 + a; dd = d - c; e = 1341 - d; unit->rdifs[0] = make_diffuser(unit, f_round(diffscale * b), 0.75); unit->rdifs[1] = make_diffuser(unit, f_round(diffscale * cc), 0.75); unit->rdifs[2] = make_diffuser(unit, f_round(diffscale * dd), 0.625); unit->rdifs[3] = make_diffuser(unit, f_round(diffscale * e), 0.625); unit->taps[0] = 5 + (int)(0.410 * largestdelay); unit->taps[1] = 5 + (int)(0.300 * largestdelay); unit->taps[2] = 5 + (int)(0.155 * largestdelay); unit->taps[3] = 5; //+ f_round(0.000 * largestdelay); for(int i = 0; i < FDNORDER; i++) { unit->tapgains[i] = pow(alpha,(double)unit->taps[i]); } unit->tapdelay = make_fixeddelay(unit, 44000, 44000); // init the slope values unit->earlylevelslope = unit->drylevelslope = unit->taillevelslope = 0.f; ClearUnitOutputs(unit, 1); } void GVerb_Dtor(GVerb *unit) { free_damper(unit, unit->inputdamper); free_fixeddelay(unit, unit->tapdelay); for(int i = 0; i < FDNORDER; i++){ free_fixeddelay(unit, unit->fdndels[i]); free_damper(unit, unit->fdndamps[i]); free_diffuser(unit, unit->ldifs[i]); free_diffuser(unit, unit->rdifs[i]); } } void GVerb_next(GVerb* unit, int inNumSamples) { float* in = IN(0); float* outl = OUT(0); float* outr = OUT(1); float roomsize = IN0(1); float revtime = IN0(2); float damping = IN0(3); float inputbandwidth = IN0(4); //float spread = IN0(5); // spread can only be set at inittime float drylevel = IN0(6); float earlylevel = IN0(7); float taillevel = IN0(8); float earlylevelslope, taillevelslope, drylevelslope; float* fdngainslopes; float* tapgainslopes; g_diffuser** ldifs = unit->ldifs; g_diffuser** rdifs = unit->rdifs; float* u = unit->u; float* f = unit->f; float* d = unit->d; g_damper* inputdamper = unit->inputdamper; float* tapgains = unit->tapgains; g_fixeddelay* tapdelay = unit->tapdelay; int* taps = unit->taps; g_damper** fdndamps = unit->fdndamps; g_fixeddelay** fdndels = unit->fdndels; float* fdngains = unit->fdngains; int* fdnlens = unit->fdnlens; if((roomsize != unit->roomsize) || (revtime != unit->revtime) || (damping != unit->damping) || (inputbandwidth != unit->inputbandwidth) || (drylevel != unit->drylevel) || (earlylevel != unit->earlylevel) || (taillevel != unit->taillevel)) { // these should calc slopes for k-rate interpolation gverb_set_roomsize(unit, roomsize); gverb_set_revtime(unit, revtime); gverb_set_damping(unit, damping); gverb_set_inputbandwidth(unit, inputbandwidth); drylevel = gverb_set_drylevel(unit, drylevel); earlylevel = gverb_set_earlylevel(unit, earlylevel); taillevel = gverb_set_taillevel(unit, taillevel); } earlylevelslope = unit->earlylevelslope; taillevelslope = unit->taillevelslope; drylevelslope = unit->drylevelslope; fdngainslopes = unit->fdngainslopes; tapgainslopes = unit->tapgainslopes; for(int i = 0; i < inNumSamples; i++){ float sign, sum, lsum, rsum, x; if(sc_isnan(in[i])) x = 0.f; else x = in[i]; sum = 0.f; sign = 1.f; float z = damper_do(unit, inputdamper, x); z = diffuser_do(unit, ldifs[0], z); for(int j = 0; j < FDNORDER; j++) { u[j] = tapgains[j] * fixeddelay_read(unit, tapdelay, taps[j]); } fixeddelay_write(unit, tapdelay, z); for(int j = 0; j < FDNORDER; j++) { d[j] = damper_do(unit, fdndamps[j], fdngains[j] * fixeddelay_read(unit, fdndels[j], fdnlens[j])); } for(int j = 0; j < FDNORDER; j++) { sum += sign * (taillevel * d[j] + earlylevel * u[j]); sign = -sign; } sum += x * earlylevel; lsum = sum; rsum = sum; gverb_fdnmatrix(d, f); for(int j = 0; j < FDNORDER; j++) { fixeddelay_write(unit, fdndels[j], u[j] + f[j]); } lsum = diffuser_do(unit, ldifs[1],lsum); lsum = diffuser_do(unit, ldifs[2],lsum); lsum = diffuser_do(unit, ldifs[3],lsum); rsum = diffuser_do(unit, rdifs[1],rsum); rsum = diffuser_do(unit, rdifs[2],rsum); rsum = diffuser_do(unit, rdifs[3],rsum); x = x * drylevel; outl[i] = lsum + x; outr[i] = rsum + x; drylevel += drylevelslope; taillevel += taillevelslope; earlylevel += earlylevelslope; for(int j = 0; j < FDNORDER; j++){ fdngains[j] += fdngainslopes[j]; tapgains[j] += tapgainslopes[j]; } } // store vals back to the struct for(int i = 0; i < FDNORDER; i++){ unit->ldifs[i] = ldifs[i]; unit->rdifs[i] = rdifs[i]; unit->u[i] = u[i]; unit->f[i] = f[i]; unit->d[i] = d[i]; unit->tapgains[i] = tapgains[i]; unit->taps[i] = taps[i]; unit->fdndamps[i] = fdndamps[i]; unit->fdndels[i] = fdndels[i]; unit->fdngains[i] = fdngains[i]; unit->fdnlens[i] = fdnlens[i]; unit->fdngainslopes[i] = 0.f; unit->tapgainslopes[i] = 0.f; } unit->inputdamper = inputdamper; unit->tapdelay = tapdelay; // clear the slopes unit->earlylevelslope = unit->taillevelslope = unit->drylevelslope = 0.f; } PluginLoad(Reverb) { ft = inTable; DefineSimpleUnit(FreeVerb); DefineSimpleUnit(FreeVerb2); DefineDtorUnit(GVerb); } SuperCollider-Source/server/plugins/SIMD_Unit.hpp000644 000765 000024 00000012603 12321461511 023106 0ustar00crucialstaff000000 000000 /* * SuperCollider real time audio synthesis system * Copyright (c) 2002 James McCartney. All rights reserved. * Copyright (c) 2011 Tim Blechmann. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SIMD_UNIT_HPP #define SIMD_UNIT_HPP #include "SC_PlugIn.hpp" #include "simd_memory.hpp" #include "simd_binary_arithmetic.hpp" #include "simd_ternary_arithmetic.hpp" #include "simd_mix.hpp" using nova::slope_argument; #if defined(__GNUC__) && !defined(__clang__) #define inline_functions __attribute__ ((flatten)) #else #define inline_functions #endif struct SIMD_Unit: SCUnit { enum { scalar, unrolled, unrolled_64}; bool canUseSIMD (void) const { return (mBufLength & (nova::vec< float >::objects_per_cacheline - 1)) == 0; } template struct ControlRateInput { float value; void init(const SIMD_Unit * parent) { value = parent->in0(index); } bool changed(const SIMD_Unit * parent) const { return value != parent->in0(index); } #if __cplusplus <= 199711L nova::detail::scalar_ramp_argument slope(const SIMD_Unit * parent) #else decltype(nova::slope_argument(0.f, 0.f)) slope(const SIMD_Unit * parent) #endif { float next = parent->in0(index); float current = value; float slope = parent->calcSlope(next, current); value = next; return slope_argument(current, slope); } operator float(void) { return value; } }; template void set_unrolled_calc_function(void) { if (bufferSize() == 64) SCUnit::set_vector_calc_function(); else set_vector_calc_function(); } template void set_vector_calc_function(void) { if (canUseSIMD()) SCUnit::set_vector_calc_function(); else SCUnit::set_calc_function(); } template static void muladd(float * out, Arg1 const & arg1, Arg2 const & arg2, Arg3 const & arg3, int inNumSamples) { if (type == scalar) nova::muladd_vec(out, arg1, arg2, arg3, inNumSamples); if (type == unrolled) nova::muladd_vec_simd(out, arg1, arg2, arg3, inNumSamples); if (type == unrolled_64) nova::muladd_vec_simd<64>(out, arg1, arg2, arg3); } template static void plus_vec(float * out, Arg1 const & arg1, Arg2 const & arg2, int inNumSamples) { if (type == scalar) nova::plus_vec(out, arg1, arg2, inNumSamples); if (type == unrolled) nova::plus_vec_simd(out, arg1, arg2, inNumSamples); if (type == unrolled_64) nova::plus_vec_simd<64>(out, arg1, arg2); } template static void times_vec(float * out, Arg1 const & arg1, Arg2 const & arg2, int inNumSamples) { if (type == scalar) nova::times_vec(out, arg1, arg2, inNumSamples); if (type == unrolled) nova::times_vec_simd(out, arg1, arg2, inNumSamples); if (type == unrolled_64) nova::times_vec_simd<64>(out, arg1, arg2); } template static void slope_vec(float * out, Arg1 const & base, Arg2 const & slope, int inNumSamples) { if (type == scalar) nova::set_slope_vec(out, base, slope, inNumSamples); else nova::set_slope_vec_simd(out, base, slope, inNumSamples); } template static void slope_vec(float * out, Arg1 const & slope, int inNumSamples) { if (type == scalar) nova::set_slope_vec(out, slope.data, slope.slope_, inNumSamples); else nova::set_slope_vec_simd(out, slope.data, slope.slope_, inNumSamples); } template static void copy_vec(float * out, const float * in, int inNumSamples) { if (in == out) return; if (type == scalar) nova::copyvec(out, in, inNumSamples); if (type == unrolled) nova::copyvec_simd(out, in, inNumSamples); if (type == unrolled_64) nova::copyvec_simd<64>(out, in); } template static void set_vec(float * out, float value, int inNumSamples) { if (type == scalar) nova::setvec(out, value, inNumSamples); if (type == unrolled) nova::setvec_simd(out, value, inNumSamples); if (type == unrolled_64) nova::setvec_simd<64>(out, value); } template static void zero_vec(float * out, int inNumSamples) { if (type == scalar) nova::zerovec(out, inNumSamples); if (type == unrolled) nova::zerovec_simd(out, inNumSamples); if (type == unrolled_64) nova::zerovec_simd<64>(out); } }; #endif /* SIMD_UNIT_HPP */ SuperCollider-Source/server/plugins/TestUGens.cpp000644 000765 000024 00000011432 12756531745 023251 0ustar00crucialstaff000000 000000 /* * TestUGens.cpp * Plugins * Copyright (c) 2007 Scott Wilson . All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Created by Scott Wilson on 22/06/2007. * Modified by James Harkins on 28/07/2007. * * */ #include "SC_PlugIn.h" #include ////////////////////////////////////////////////////////////////////////////////////////////////// inline int sc_fpclassify(float x) { return std::fpclassify(x); } ////////////////////////////////////////////////////////////////////////////////////////////////// static InterfaceTable *ft; struct CheckBadValues : public Unit { long sameCount; int prevclass; }; // declare unit generator functions extern "C" { void CheckBadValues_Ctor(CheckBadValues* unit); void CheckBadValues_next(CheckBadValues* unit, int inNumSamples); }; static const char *CheckBadValues_fpclassString(int fpclass); inline int CheckBadValues_fold_fpclasses(int fpclass); ////////////////////////////////////////////////////////////////////////////////////////////////// void CheckBadValues_Ctor(CheckBadValues* unit) { unit->prevclass = FP_NORMAL; unit->sameCount = 0; SETCALC(CheckBadValues_next); CheckBadValues_next(unit, 1); } void CheckBadValues_next(CheckBadValues* unit, int inNumSamples) { float *in = ZIN(0); float *out = ZOUT(0); float id = ZIN0(1); int post = (int) ZIN0(2); float samp; int classification; switch(post) { case 1: // post a line on every bad value LOOP1(inNumSamples, samp = ZXP(in); classification = sc_fpclassify(samp); switch (classification) { case FP_INFINITE: Print("Infinite number found in Synth %d, ID: %d\n", unit->mParent->mNode.mID, (int)id); ZXP(out) = 2; break; case FP_NAN: Print("NaN found in Synth %d, ID: %d\n", unit->mParent->mNode.mID, (int)id); ZXP(out) = 1; break; case FP_SUBNORMAL: Print("Denormal found in Synth %d, ID: %d\n", unit->mParent->mNode.mID, (int)id); ZXP(out) = 3; break; default: ZXP(out) = 0; }; ); break; case 2: LOOP1(inNumSamples, samp = ZXP(in); classification = CheckBadValues_fold_fpclasses(sc_fpclassify(samp)); if(classification != unit->prevclass) { if(unit->sameCount == 0) { Print("CheckBadValues: %s found in Synth %d, ID %d\n", CheckBadValues_fpclassString(classification), unit->mParent->mNode.mID, (int)id); } else { Print("CheckBadValues: %s found in Synth %d, ID %d (previous %d values were %s)\n", CheckBadValues_fpclassString(classification), unit->mParent->mNode.mID, (int)id, (int)unit->sameCount, CheckBadValues_fpclassString(unit->prevclass) ); }; unit->sameCount = 0; }; switch (classification) { case FP_INFINITE: ZXP(out) = 2; break; case FP_NAN: ZXP(out) = 1; break; case FP_SUBNORMAL: ZXP(out) = 3; break; default: ZXP(out) = 0; }; unit->sameCount++; unit->prevclass = classification; ); break; default: // no post LOOP1(inNumSamples, samp = ZXP(in); classification = sc_fpclassify(samp); switch (classification) { case FP_INFINITE: ZXP(out) = 2; break; case FP_NAN: ZXP(out) = 1; break; case FP_SUBNORMAL: ZXP(out) = 3; break; default: ZXP(out) = 0; }; ); break; } } const char *CheckBadValues_fpclassString(int fpclass) { switch(fpclass) { case FP_NORMAL: return "normal"; case FP_NAN: return "NaN"; case FP_INFINITE: return "infinity"; #ifndef _MSC_VER case FP_ZERO: return "zero"; #endif case FP_SUBNORMAL: return "denormal"; default: return "unknown"; } } #ifndef _MSC_VER inline int CheckBadValues_fold_fpclasses(int fpclass) { switch(fpclass) { case FP_ZERO: return FP_NORMAL; // a bit hacky. we mean "zero is fine too". default: return fpclass; } } #else inline int CheckBadValues_fold_fpclasses(int fpclass) { return fpclass; } #endif //////////////////////////////////////////////////////////////////// // the load function is called by the host when the plug-in is loaded PluginLoad(Test) { ft = inTable; DefineSimpleUnit(CheckBadValues); } SuperCollider-Source/server/plugins/TriggerUGens.cpp000644 000765 000024 00000205401 12756531745 023736 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include /* for std::min and std::max */ #include #include "simd_peakmeter.hpp" #ifdef NOVA_SIMD #include "simd_memory.hpp" #include "function_attributes.h" #endif static InterfaceTable *ft; ////////////////////////////////////////////////////////////////////////////////////////////////// struct Trig1 : public Unit { float m_prevtrig; long mCounter; }; struct Trig : public Unit { float mLevel; float m_prevtrig; long mCounter; }; struct SendTrig : public Unit { float m_prevtrig; }; struct SendReply : public Unit { float m_prevtrig; int m_valueSize; int m_valueOffset; float *m_values; int m_cmdNameSize; char *m_cmdName; }; struct Poll : public Unit { int m_samplesRemain, m_intervalSamples; float m_trig; float m_lastPoll; char *m_id_string; bool m_mayprint; }; struct ToggleFF : public Unit { float mLevel; float m_prevtrig; }; struct SetResetFF : public Unit { float mLevel; float m_prevtrig, m_prevreset; }; struct Latch : public Unit { float mLevel; float m_prevtrig; }; struct Gate : public Unit { float mLevel; }; struct Schmidt : public Unit { float mLevel; }; struct PulseDivider : public Unit { float mLevel; float m_prevtrig; long mCounter; }; struct PulseCount : public Unit { float mLevel; float m_prevtrig, m_prevreset; }; struct Stepper : public Unit { float mLevel; float m_prevtrig, m_prevreset; }; struct TDelay : public Unit { long mCounter; float m_prevtrig; }; struct ZeroCrossing : public Unit { float mLevel, m_prevfrac, m_previn; int32 mCounter; }; struct Timer : public Unit { float mLevel, m_prevfrac, m_previn; int32 mCounter; }; struct Sweep : public Unit { double mLevel; float m_previn; }; struct Phasor : public Unit { double mLevel; float m_previn; }; struct Peak : public Unit { float mLevel; float m_prevtrig; }; struct RunningMin : public Unit { float mLevel; float m_prevtrig; }; struct RunningMax : public Unit { float mLevel; float m_prevtrig; }; struct PeakFollower : public Unit { float mLevel; float mDecay; }; struct MostChange : public Unit { float mPrevA, mPrevB; int mRecent; }; struct LeastChange : public Unit { float mPrevA, mPrevB; int mRecent; }; struct LastValue : public Unit { float mPrev; float mCurr; }; struct Done : public Unit { Unit *m_src; }; struct FreeSelf : public Unit { float m_prevtrig; }; struct PauseSelf : public Unit { float m_prevtrig; }; struct Pause : public Unit { int m_state; }; struct Free : public Unit { float m_prevtrig; }; struct FreeSelfWhenDone : public Unit { Unit *m_src; }; struct PauseSelfWhenDone : public Unit { Unit *m_src; }; extern "C" { void Trig1_Ctor(Trig1 *unit); void Trig1_next(Trig1 *unit, int inNumSamples); void Trig1_next_k(Trig1 *unit, int inNumSamples); void Trig_Ctor(Trig *unit); void Trig_next(Trig *unit, int inNumSamples); void Trig_next_k(Trig *unit, int inNumSamples); void SendTrig_Ctor(SendTrig *unit); void SendTrig_next(SendTrig *unit, int inNumSamples); void SendTrig_next_aka(SendTrig *unit, int inNumSamples); void SendReply_Ctor(SendReply *unit); void SendReply_next(SendReply *unit, int inNumSamples); void SendReply_next_aka(SendReply *unit, int inNumSamples); void Poll_Ctor(Poll* unit); void Poll_next_aa(Poll *unit, int inNumSamples); void Poll_next_ak(Poll *unit, int inNumSamples); void Poll_next_kk(Poll *unit, int inNumSamples); void SetResetFF_Ctor(SetResetFF *unit); void SetResetFF_next_a(SetResetFF *unit, int inNumSamples); void SetResetFF_next_k(SetResetFF *unit, int inNumSamples); void ToggleFF_Ctor(ToggleFF *unit); void ToggleFF_next(ToggleFF *unit, int inNumSamples); void Latch_Ctor(Latch *unit); void Latch_next_ak(Latch *unit, int inNumSamples); void Latch_next_aa(Latch *unit, int inNumSamples); void Gate_Ctor(Gate *unit); void Gate_next_ak(Gate *unit, int inNumSamples); void Gate_next_aa(Gate *unit, int inNumSamples); void Schmidt_Ctor(Schmidt *unit); void Schmidt_next(Schmidt *unit, int inNumSamples); void PulseDivider_Ctor(PulseDivider *unit); void PulseDivider_next(PulseDivider *unit, int inNumSamples); void PulseCount_Ctor(PulseCount *unit); void PulseCount_next_a(PulseCount *unit, int inNumSamples); void PulseCount_next_k(PulseCount *unit, int inNumSamples); void PulseCount_next_0(PulseCount *unit, int inNumSamples); void Stepper_Ctor(Stepper *unit); void Stepper_next_aa(Stepper *unit, int inNumSamples); void Stepper_next_ak(Stepper *unit, int inNumSamples); void Stepper_next_a0(Stepper *unit, int inNumSamples); void TDelay_Ctor(TDelay *unit); void TDelay_next(TDelay *unit, int inNumSamples); void ZeroCrossing_Ctor(ZeroCrossing *unit); void ZeroCrossing_next_a(ZeroCrossing *unit, int inNumSamples); void Timer_Ctor(Timer *unit); void Timer_next_a(Timer *unit, int inNumSamples); void Sweep_Ctor(Sweep *unit); void Sweep_next_0k(Sweep *unit, int inNumSamples); void Sweep_next_0a(Sweep *unit, int inNumSamples); void Sweep_next_kk(Sweep *unit, int inNumSamples); void Sweep_next_ka(Sweep *unit, int inNumSamples); void Sweep_next_ak(Sweep *unit, int inNumSamples); void Sweep_next_aa(Sweep *unit, int inNumSamples); void Phasor_Ctor(Phasor *unit); void Phasor_next_kk(Phasor *unit, int inNumSamples); void Phasor_next_ak(Phasor *unit, int inNumSamples); void Phasor_next_aa(Phasor *unit, int inNumSamples); void Peak_Ctor(Peak *unit); void Peak_next_ak(Peak *unit, int inNumSamples); void Peak_next_ai(Peak *unit, int inNumSamples); void Peak_next_aa(Peak *unit, int inNumSamples); void Peak_next_ak_k(Peak *unit, int inNumSamples); void Peak_next_ai_k(Peak *unit, int inNumSamples); void Peak_next_aa_k(Peak *unit, int inNumSamples); void RunningMin_Ctor(RunningMin *unit); void RunningMin_next_ak(RunningMin *unit, int inNumSamples); void RunningMin_next_ai(RunningMin *unit, int inNumSamples); void RunningMin_next_aa(RunningMin *unit, int inNumSamples); void RunningMax_Ctor(RunningMax *unit); void RunningMax_next_ak(RunningMax *unit, int inNumSamples); void RunningMax_next_ai(RunningMax *unit, int inNumSamples); void RunningMax_next_aa(RunningMax *unit, int inNumSamples); void PeakFollower_Ctor(PeakFollower *unit); void PeakFollower_next(PeakFollower *unit, int inNumSamples); void PeakFollower_next_ai(PeakFollower *unit, int inNumSamples); void MostChange_Ctor(MostChange *unit); void MostChange_next_ak(MostChange *unit, int inNumSamples); void MostChange_next_ka(MostChange *unit, int inNumSamples); void MostChange_next_aa(MostChange *unit, int inNumSamples); void LeastChange_Ctor(LeastChange *unit); void LeastChange_next_ak(LeastChange *unit, int inNumSamples); void LeastChange_next_ka(LeastChange *unit, int inNumSamples); void LeastChange_next_aa(LeastChange *unit, int inNumSamples); void LastValue_Ctor(LastValue *unit); void LastValue_next_ak(LastValue *unit, int inNumSamples); void LastValue_next_kk(LastValue *unit, int inNumSamples); void Done_Ctor(Done *unit); void Done_next(Done *unit, int inNumSamples); void FreeSelf_Ctor(FreeSelf *unit); void FreeSelf_next(FreeSelf *unit, int inNumSamples); void FreeSelfWhenDone_Ctor(FreeSelfWhenDone *unit); void FreeSelfWhenDone_next(FreeSelfWhenDone *unit, int inNumSamples); void PauseSelf_Ctor(PauseSelf *unit); void PauseSelf_next(PauseSelf *unit, int inNumSamples); void Pause_Ctor(Pause *unit); void Pause_next(Pause *unit, int inNumSamples); void Free_Ctor(Free *unit); void Free_next(Free *unit, int inNumSamples); void PauseSelfWhenDone_Ctor(PauseSelfWhenDone *unit); void PauseSelfWhenDone_next(PauseSelfWhenDone *unit, int inNumSamples); } //////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef NOVA_SIMD FLATTEN void Trig1_next_nova(Trig1 *unit, int inNumSamples); FLATTEN void Trig1_next_k_nova(Trig1 *unit, int inNumSamples); #endif void Trig1_Ctor(Trig1 *unit) { if (unit->mCalcRate == calc_FullRate && INRATE(0) != calc_FullRate) { #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Trig1_next_k_nova); else #endif SETCALC(Trig1_next_k); } else { #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Trig1_next_nova); else #endif SETCALC(Trig1_next); } unit->mCounter = 0; unit->m_prevtrig = 0.f; Trig1_next(unit, 1); } void Trig1_next(Trig1 *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; unsigned long counter = unit->mCounter; LOOP1(inNumSamples, float curtrig = ZXP(trig); float zout; if (counter > 0) { zout = --counter ? 1.f : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; zout = 1.f; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); unit->m_prevtrig = prevtrig; unit->mCounter = counter; } void Trig1_next_k(Trig1 *unit, int inNumSamples) { float *out = ZOUT(0); float curtrig = ZIN0(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; unsigned long counter = unit->mCounter; LOOP1(inNumSamples, float zout; if (counter > 0) { zout = --counter ? 1.f : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; zout = 1.f; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); unit->m_prevtrig = prevtrig; unit->mCounter = counter; } #ifdef NOVA_SIMD void Trig1_next_nova(Trig1 *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; unsigned long counter = unit->mCounter; if (counter > inNumSamples) { nova::setvec_simd(OUT(0), 1.f, inNumSamples); counter -= inNumSamples; assert(counter > 0); prevtrig = IN(0)[inNumSamples-1]; } else { LOOP1(inNumSamples, float curtrig = ZXP(trig); float zout; if (counter > 0) { zout = --counter ? 1.f : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; zout = 1.f; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); } unit->m_prevtrig = prevtrig; unit->mCounter = counter; } void Trig1_next_k_nova(Trig1 *unit, int inNumSamples) { float *out = ZOUT(0); float curtrig = ZIN0(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; unsigned long counter = unit->mCounter; if (counter > inNumSamples) { nova::setvec_simd(OUT(0), 1.f, inNumSamples); counter -= inNumSamples; assert(counter > 0); prevtrig = curtrig; } else if (counter == 0 && (curtrig <= 0.f || prevtrig > 0.f)) { nova::zerovec_simd(OUT(0), inNumSamples); prevtrig = curtrig; } else { LOOP1(inNumSamples, float zout; if (counter > 0) { zout = --counter ? 1.f : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; zout = 1.f; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); } unit->m_prevtrig = prevtrig; unit->mCounter = counter; } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef NOVA_SIMD void Trig_next_nova(Trig *unit, int inNumSamples); void Trig_next_k_nova(Trig *unit, int inNumSamples); #endif void Trig_Ctor(Trig *unit) { if (unit->mCalcRate == calc_FullRate && INRATE(0) != calc_FullRate) { #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Trig_next_k_nova); else #endif SETCALC(Trig_next_k); } else { #ifdef NOVA_SIMD if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Trig_next_nova); else #endif SETCALC(Trig_next); } unit->mCounter = 0; unit->m_prevtrig = 0.f; unit->mLevel = 0.f; Trig_next(unit, 1); } void Trig_next(Trig *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; float level = unit->mLevel; unsigned long counter = unit->mCounter; LOOP1(inNumSamples, float curtrig = ZXP(trig); float zout; if (counter > 0) { zout = --counter ? level : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; level = curtrig; zout = level; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); unit->m_prevtrig = prevtrig; unit->mCounter = counter; unit->mLevel = level; } void Trig_next_k(Trig *unit, int inNumSamples) { float *out = ZOUT(0); float curtrig = ZIN0(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; float level = unit->mLevel; unsigned long counter = unit->mCounter; LOOP1(inNumSamples, float zout; if (counter > 0) { zout = --counter ? level : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; level = curtrig; zout = level; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); unit->m_prevtrig = prevtrig; unit->mCounter = counter; unit->mLevel = level; } #ifdef NOVA_SIMD void Trig_next_nova(Trig *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; float level = unit->mLevel; unsigned long counter = unit->mCounter; if (counter > inNumSamples) { nova::setvec_simd(OUT(0), level, inNumSamples); counter -= inNumSamples; assert(counter > 0); prevtrig = IN(0)[inNumSamples-1]; } else { LOOP1(inNumSamples, float curtrig = ZXP(trig); float zout; if (counter > 0) { zout = --counter ? level : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; level = curtrig; zout = level; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); } unit->m_prevtrig = prevtrig; unit->mCounter = counter; unit->mLevel = level; } void Trig_next_k_nova(Trig *unit, int inNumSamples) { float *out = ZOUT(0); float curtrig = ZIN0(0); float dur = ZIN0(1); float sr = unit->mRate->mSampleRate; float prevtrig = unit->m_prevtrig; float level = unit->mLevel; unsigned long counter = unit->mCounter; if (counter > inNumSamples) { nova::setvec_simd(OUT(0), level, inNumSamples); counter -= inNumSamples; assert(counter > 0); prevtrig = curtrig; } else if (counter == 0 && (curtrig <= 0.f || prevtrig > 0.f)) { nova::zerovec_simd(OUT(0), inNumSamples); prevtrig = curtrig; } else { LOOP1(inNumSamples, float zout; if (counter > 0) { zout = --counter ? level : 0.f; } else { if (curtrig > 0.f && prevtrig <= 0.f) { counter = (long)(dur * sr + .5f); if (counter < 1) counter = 1; level = curtrig; zout = level; } else { zout = 0.f; } } prevtrig = curtrig; ZXP(out) = zout; ); } unit->m_prevtrig = prevtrig; unit->mCounter = counter; unit->mLevel = level; } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// void SendTrig_Ctor(SendTrig *unit) { if (INRATE(2) == calc_FullRate) { SETCALC(SendTrig_next_aka); } else { SETCALC(SendTrig_next); } unit->m_prevtrig = 0.f; } void SendTrig_next(SendTrig *unit, int inNumSamples) { float *trig = ZIN(0); float prevtrig = unit->m_prevtrig; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (curtrig > 0.f && prevtrig <= 0.f) { SendTrigger(&unit->mParent->mNode, (int)ZIN0(1), ZIN0(2)); } prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; } void SendTrig_next_aka(SendTrig *unit, int inNumSamples) { float *trig = ZIN(0); int id = (int)ZIN0(1); float *value = ZIN(2); float prevtrig = unit->m_prevtrig; LOOP1(inNumSamples, float curtrig = ZXP(trig); float curval = ZXP(value); if (curtrig > 0.f && prevtrig <= 0.f) { SendTrigger(&unit->mParent->mNode, id, curval); } prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; } //////////////////////////////////////////////////////////////////////////////////////////////////////// static void Unit_next_nop(SendReply * unit, int inNumSamples) {} void SendReply_Ctor(SendReply *unit) { const int kVarOffset = 3; unit->m_prevtrig = 0.f; unit->m_cmdNameSize = IN0(2); unit->m_valueSize = unit->mNumInputs - unit->m_cmdNameSize - kVarOffset; unit->m_valueOffset = kVarOffset + unit->m_cmdNameSize; // allocations const int cmdNameAllocSize = (unit->m_cmdNameSize + 1) * sizeof(char); const int valuesAllocSize = unit->m_valueSize * sizeof(float); char * chunk = (char*)RTAlloc(unit->mWorld,cmdNameAllocSize + valuesAllocSize); if (!chunk) { Print("SendReply: RT memory allocation failed\n"); SETCALC(Unit_next_nop); return; } unit->m_cmdName = chunk; unit->m_values = (float*)(chunk + cmdNameAllocSize); for(int i = 0; i < (int)unit->m_cmdNameSize; i++) unit->m_cmdName[i] = (char)IN0(kVarOffset+i); // terminate string unit->m_cmdName[unit->m_cmdNameSize] = 0; if (INRATE(0) == calc_FullRate) SETCALC(SendReply_next_aka); else SETCALC(SendReply_next); } void SendReply_Dtor(SendReply* unit) { RTFree(unit->mWorld, unit->m_cmdName); } void SendReply_next(SendReply *unit, int inNumSamples) { float *trig = IN(0); float prevtrig = unit->m_prevtrig; float *values = unit->m_values; int valueSize = unit->m_valueSize; int valueOffset = unit->m_valueOffset; for(int j = 0; j < inNumSamples; j++) { float curtrig = trig[j]; if (curtrig > 0.f && prevtrig <= 0.f) { for (int i=0; imParent->mNode, (int)ZIN0(1), unit->m_cmdName, unit->m_valueSize, values); } prevtrig = curtrig; } unit->m_prevtrig = prevtrig; } void SendReply_next_aka(SendReply *unit, int inNumSamples) { float *trig = IN(0); float prevtrig = unit->m_prevtrig; float *values = unit->m_values; int valueSize = unit->m_valueSize; int valueOffset = unit->m_valueOffset; for(int j = 0; j < inNumSamples; j++) { float curtrig = trig[j]; if (curtrig > 0.f && prevtrig <= 0.f) { for (int i=0; imParent->mNode, (int)ZIN0(1), unit->m_cmdName, unit->m_valueSize, values); } prevtrig = curtrig; } unit->m_prevtrig = prevtrig; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Poll_Ctor(Poll* unit) { if (INRATE(0) == calc_FullRate){ if (INRATE(1) == calc_FullRate){ SETCALC(Poll_next_aa); } else { SETCALC(Poll_next_ak); } } else { SETCALC(Poll_next_kk); } unit->m_trig = IN0(0); const int idSize = (int)IN0(3); // number of chars in the id string unit->m_id_string = (char*)RTAlloc(unit->mWorld, (idSize + 1) * sizeof(char)); if (!unit->m_id_string) { Print("Poll: RT memory allocation failed\n"); SETCALC(Unit_next_nop); return; } for(int i = 0; i < idSize; i++) unit->m_id_string[i] = (char)IN0(4+i); unit->m_id_string[idSize] = '\0'; unit->m_mayprint = unit->mWorld->mVerbosity >= -1; Poll_next_kk(unit, 1); } void Poll_Dtor(Poll* unit) { RTFree(unit->mWorld, unit->m_id_string); } void Poll_next_aa(Poll *unit, int inNumSamples) { float* in = IN(1); float* trig = IN(0); float lasttrig = unit->m_trig; for (int i = 0; i < inNumSamples; i++){ if((lasttrig <= 0.0) && (trig[i] > 0.0)){ if (unit->m_mayprint) Print("%s: %g\n", unit->m_id_string, in[i]); if (IN0(2) >= 0.0) SendTrigger(&unit->mParent->mNode, (int)IN0(2), in[i]); } lasttrig = trig[i]; } unit->m_trig = lasttrig; } void Poll_next_kk(Poll *unit, int inNumSamples){ float in = IN0(1); float trig = IN0(0); if((unit->m_trig <= 0.0) && (trig > 0.0)){ if(unit->m_mayprint) Print("%s: %g\n", unit->m_id_string, in); if(IN0(2) >= 0.0) SendTrigger(&unit->mParent->mNode, (int)IN0(2), in); } unit->m_trig = trig; } void Poll_next_ak(Poll *unit, int inNumSamples){ float in = IN0(1); float* trig = IN(0); float lasttrig = unit->m_trig; for(int i = 0; i < inNumSamples; i++){ if((lasttrig <= 0.0) && (trig[i] > 0.0)){ if(unit->m_mayprint){ Print("%s: %g\n", unit->m_id_string, in); } if(IN0(2) >= 0.0) SendTrigger(&unit->mParent->mNode, (int)IN0(2), in); } lasttrig = trig[i]; } unit->m_trig = lasttrig; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void SetResetFF_Ctor(SetResetFF *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(SetResetFF_next_a); } else { SETCALC(SetResetFF_next_k); } unit->m_prevtrig = 0.f; unit->m_prevreset = 0.f; unit->mLevel = 0.f; SetResetFF_next_k(unit, 1); } void SetResetFF_next_a(SetResetFF *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float *reset = ZIN(1); float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); float curreset = ZXP(reset); if (prevreset <= 0.f && curreset > 0.f) level = 0.f; else if (prevtrig <= 0.f && curtrig > 0.f) level = 1.f; ZXP(out) = level; prevtrig = curtrig; prevreset = curreset; ); unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; unit->mLevel = level; } void SetResetFF_next_k(SetResetFF *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float curreset = ZIN0(1); float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; float level = unit->mLevel; float curtrig = ZXP(trig); if (prevreset <= 0.f && curreset > 0.f) level = 0.f; else if (prevtrig <= 0.f && curtrig > 0.f) level = 1.f; ZXP(out) = level; prevtrig = curtrig; LOOP(inNumSamples - 1, curtrig = ZXP(trig); if (prevtrig <= 0.f && curtrig > 0.f) level = 1.f; ZXP(out) = level; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->m_prevreset = curreset; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void ToggleFF_Ctor(ToggleFF *unit) { SETCALC(ToggleFF_next); unit->m_prevtrig = 0.f; unit->mLevel = 0.f; ZOUT0(0) = 0.f; } void ToggleFF_next(ToggleFF *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (prevtrig <= 0.f && curtrig > 0.f) level = 1.f - level; ZXP(out) = level; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef NOVA_SIMD void Latch_next_ak_nova(Latch *unit, int inNumSamples) { float level = unit->mLevel; float curtrig = ZIN0(1); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = ZIN0(0); nova::setvec_simd(OUT(0), level, inNumSamples); unit->m_prevtrig = curtrig; unit->mLevel = level; } void Latch_next_ak_nova_64(Latch *unit, int inNumSamples) { float level = unit->mLevel; float curtrig = ZIN0(1); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = ZIN0(0); nova::setvec_simd<64>(OUT(0), level); unit->m_prevtrig = curtrig; unit->mLevel = level; } #endif void Latch_Ctor(Latch *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(Latch_next_aa); } else { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(Latch_next_ak_nova_64); if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Latch_next_ak_nova); else #endif SETCALC(Latch_next_ak); } unit->m_prevtrig = 0.f; unit->mLevel = 0.f; ZOUT0(0) = ZIN0(1) > 0.f ? ZIN0(0) : 0.f; } void Latch_next_ak(Latch *unit, int inNumSamples) { float *out = ZOUT(0); float level = unit->mLevel; float curtrig = ZIN0(1); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = ZIN0(0); LOOP1(inNumSamples, ZXP(out) = level; ); unit->m_prevtrig = curtrig; unit->mLevel = level; } void Latch_next_aa(Latch *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (prevtrig <= 0.f && curtrig > 0.f) level = ZXP(in); else { PZ(in); } ZXP(out) = level; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef NOVA_SIMD FLATTEN void Gate_next_ak_nova(Gate *unit, int inNumSamples) { float *trig = ZIN(1); float level = unit->mLevel; float curtrig = ZXP(trig); if (curtrig > 0.f) { nova::copyvec_simd(OUT(0), IN(0), inNumSamples); unit->mLevel = IN(0)[inNumSamples-1]; } else nova::setvec_simd(OUT(0), level, inNumSamples); } FLATTEN void Gate_next_ak_nova_64(Gate *unit, int inNumSamples) { float *trig = ZIN(1); float level = unit->mLevel; float curtrig = ZXP(trig); if (curtrig > 0.f) { nova::copyvec_simd<64>(OUT(0), IN(0)); unit->mLevel = IN(0)[inNumSamples-1]; } else nova::setvec_simd<64>(OUT(0), level); } #endif void Gate_Ctor(Gate *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(Gate_next_aa); } else { #ifdef NOVA_SIMD if (BUFLENGTH == 64) SETCALC(Gate_next_ak_nova_64); if (boost::alignment::is_aligned( BUFLENGTH, 16 )) SETCALC(Gate_next_ak_nova); else #endif SETCALC(Gate_next_ak); } unit->mLevel = 0.f; Gate_next_ak(unit, 1); } void Gate_next_ak(Gate *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float level = unit->mLevel; float curtrig = ZXP(trig); if (curtrig > 0.f) { LOOP1(inNumSamples, level = ZXP(in); ZXP(out) = level; ); unit->mLevel = level; } else { LOOP1(inNumSamples, ZXP(out) = level; ); } } void Gate_next_aa(Gate *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (curtrig > 0.f) level = ZXP(in); else { PZ(in); } ZXP(out) = level; ); unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Schmidt_Ctor(Schmidt *unit) { SETCALC(Schmidt_next); unit->mLevel = 0.f; Schmidt_next(unit, 1); } void Schmidt_next(Schmidt *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float lo = ZIN0(1); float hi = ZIN0(2); float level = unit->mLevel; LOOP1(inNumSamples, float zin = ZXP(in); if (level == 1.) { if (zin < lo) level = 0.f; } else { if (zin > hi) level = 1.f; } ZXP(out) = level; ); unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void PulseDivider_Ctor(PulseDivider *unit) { SETCALC(PulseDivider_next); unit->m_prevtrig = 0.f; unit->mLevel = 0.f; unit->mCounter = (long)floor(ZIN0(2) + 0.5); PulseDivider_next(unit, 1); } void PulseDivider_next(PulseDivider *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); long div = (long)ZIN0(1); float prevtrig = unit->m_prevtrig; long counter = unit->mCounter; LOOP1(inNumSamples, float z; float curtrig = ZXP(trig); if (prevtrig <= 0.f && curtrig > 0.f) { counter++; if (counter >= div) { counter = 0; z = 1.f; } else { z = 0.f; } } else { z = 0.f; } ZXP(out) = z; prevtrig = curtrig; ); unit->mCounter = counter; unit->m_prevtrig = prevtrig; } ////////////////////////////////////////////////////////////////////////////////////////// void PulseCount_Ctor(PulseCount *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(PulseCount_next_a); } else if (INRATE(1) == calc_BufRate) { SETCALC(PulseCount_next_k); } else { SETCALC(PulseCount_next_0); } unit->m_prevtrig = 0.f; unit->m_prevreset = 0.f; unit->mLevel = 0.f; PulseCount_next_k(unit, 1); } void PulseCount_next_a(PulseCount *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float *reset = ZIN(1); float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); float curreset = ZXP(reset); if (prevreset <= 0.f && curreset > 0.f) level = 0.f; else if (prevtrig <= 0.f && curtrig > 0.f) { level += 1.f; } ZXP(out) = level; prevtrig = curtrig; prevreset = curreset; ); unit->mLevel = level; unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void PulseCount_next_k(PulseCount *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float curreset = ZIN0(1); float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (prevreset <= 0.f && curreset > 0.f) level = 0.f; else if (prevtrig <= 0.f && curtrig > 0.f) { level += 1.f; } ZXP(out) = level; prevtrig = curtrig; prevreset = curreset; ); unit->mLevel = level; unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void PulseCount_next_0(PulseCount *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (prevtrig <= 0.f && curtrig > 0.f) { level += 1.f; } ZXP(out) = level; prevtrig = curtrig; ); unit->mLevel = level; unit->m_prevtrig = prevtrig; } ////////////////////////////////////////////////////////////////////////////////////////// void Stepper_Ctor(Stepper *unit) { if (unit->mCalcRate == calc_FullRate && INRATE(0) == calc_FullRate && INRATE(1) == calc_ScalarRate) { SETCALC(Stepper_next_a0); } else if (unit->mCalcRate == calc_FullRate && INRATE(0) == calc_FullRate && INRATE(1) != calc_FullRate) { SETCALC(Stepper_next_ak); } else { SETCALC(Stepper_next_aa); } int32 resetval = (int32)ZIN0(5); unit->m_prevtrig = 0.f; unit->m_prevreset = 0.f; unit->mLevel = (float)resetval; Stepper_next_ak(unit, 1); } void Stepper_next_aa(Stepper *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float *reset = ZIN(1); int32 zmin = (int32)ZIN0(2); int32 zmax = (int32)ZIN0(3); int32 step = (int32)ZIN0(4); int32 resetval = (int32)ZIN0(5); float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); float curreset = ZXP(reset); if (prevreset <= 0.f && curreset > 0.f) { level = (float)sc_wrap(resetval, zmin, zmax); } else if (prevtrig <= 0.f && curtrig > 0.f) { level = (float)sc_wrap((int32)level + step, zmin, zmax); } ZXP(out) = level; prevtrig = curtrig; prevreset = curreset; ); unit->mLevel = level; unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void Stepper_next_ak(Stepper *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float curreset = ZIN0(1); int32 zmin = (int32)ZIN0(2); int32 zmax = (int32)ZIN0(3); int32 step = (int32)ZIN0(4); int32 resetval = (int32)ZIN0(5); float prevtrig = unit->m_prevtrig; float prevreset = unit->m_prevreset; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (prevreset <= 0.f && curreset > 0.f) { level = (float)sc_wrap(resetval, zmin, zmax); } else if (prevtrig <= 0.f && curtrig > 0.f) { level = (float)sc_wrap((int32)level + step, zmin, zmax); } ZXP(out) = level; prevtrig = curtrig; prevreset = curreset; ); unit->mLevel = level; unit->m_prevtrig = prevtrig; unit->m_prevreset = prevreset; } void Stepper_next_a0(Stepper *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); int32 zmin = (int32)ZIN0(2); int32 zmax = (int32)ZIN0(3); int32 step = (int32)ZIN0(4); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); if (prevtrig <= 0.f && curtrig > 0.f) { level = (float)sc_wrap((int32)level + step, zmin, zmax); } ZXP(out) = level; prevtrig = curtrig; ); unit->mLevel = level; unit->m_prevtrig = prevtrig; } ////////////////////////////////////////////////////////////////////////////////////////// void TDelay_Ctor(TDelay *unit) { SETCALC(TDelay_next); unit->m_prevtrig = 0.f; unit->mCounter = 0; TDelay_next(unit, 1); } void TDelay_next(TDelay *unit, int inNumSamples) { float *out = ZOUT(0); float *trig = ZIN(0); float dur = ZIN0(1); float prevtrig = unit->m_prevtrig; long counter = unit->mCounter; LOOP1(inNumSamples, float curtrig = ZXP(trig); float zout; if (counter > 1) { counter--; zout = 0.f; } else if (counter<=0) { if (prevtrig <= 0.f && curtrig > 0.f) { counter = (long)(dur * unit->mRate->mSampleRate + .5f); if (counter < 1) counter = 1; } zout = 0.f; } else { counter = 0; zout = 1.f; } ZXP(out) = zout; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->mCounter = counter; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void ZeroCrossing_Ctor(ZeroCrossing *unit) { SETCALC(ZeroCrossing_next_a); unit->m_prevfrac = 0.f; unit->m_previn = ZIN0(0); ZOUT0(0) = unit->mLevel = 0.f; unit->mCounter = 0; } void ZeroCrossing_next_a(ZeroCrossing *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float previn = unit->m_previn; float prevfrac = unit->m_prevfrac; float level = unit->mLevel; long counter = unit->mCounter; LOOP1(inNumSamples, counter++; float curin = ZXP(in); if (counter > 4 && previn <= 0.f && curin > 0.f) { float frac = -previn/(curin-previn); level = unit->mRate->mSampleRate / (frac + counter - prevfrac); prevfrac = frac; counter = 0; } ZXP(out) = level; previn = curin; ); unit->m_previn = previn; unit->m_prevfrac = prevfrac; unit->mLevel = level; unit->mCounter = counter; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Timer_Ctor(Timer *unit) { SETCALC(Timer_next_a); unit->m_prevfrac = 0.f; unit->m_previn = ZIN0(0); ZOUT0(0) = unit->mLevel = 0.f; unit->mCounter = 0; } void Timer_next_a(Timer *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float previn = unit->m_previn; float prevfrac = unit->m_prevfrac; float level = unit->mLevel; long counter = unit->mCounter; LOOP1(inNumSamples, counter++; float curin = ZXP(in); if (previn <= 0.f && curin > 0.f) { float frac = -previn/(curin-previn); level = unit->mRate->mSampleDur * (frac + counter - prevfrac); prevfrac = frac; counter = 0; } ZXP(out) = level; previn = curin; ); unit->m_previn = previn; unit->m_prevfrac = prevfrac; unit->mLevel = level; unit->mCounter = counter; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Sweep_Ctor(Sweep *unit) { if (INRATE(0) == calc_ScalarRate) { if (INRATE(1) == calc_FullRate) { SETCALC(Sweep_next_0a); } else { SETCALC(Sweep_next_0k); } } else if (INRATE(0) == calc_BufRate) { if (INRATE(1) == calc_FullRate) { SETCALC(Sweep_next_ka); } else { SETCALC(Sweep_next_kk); } } else { if (INRATE(1) == calc_FullRate) { SETCALC(Sweep_next_aa); } else { SETCALC(Sweep_next_ak); } } unit->m_previn = ZIN0(0); ZOUT0(0) = unit->mLevel = 0.f; } void Sweep_next_0k(Sweep *unit, int inNumSamples) { float *out = ZOUT(0); double rate = ZIN0(1) * SAMPLEDUR; double level = unit->mLevel; LOOP1(inNumSamples, level += rate; ZXP(out) = level; ); unit->mLevel = level; } void Sweep_next_0a(Sweep *unit, int inNumSamples) { float *out = ZOUT(0); float *rate = ZIN(1); double level = unit->mLevel; float sampledur = SAMPLEDUR; LOOP1(inNumSamples, float zrate = ZXP(rate) * sampledur; level += zrate; ZXP(out) = level; ); unit->mLevel = level; } void Sweep_next_kk(Sweep *unit, int inNumSamples) { float *out = ZOUT(0); float curin = ZIN0(0); double rate = ZIN0(1) * SAMPLEDUR; float previn = unit->m_previn; double level = unit->mLevel; if (previn <= 0.f && curin > 0.f) { float frac = -previn/(curin-previn); level = frac * rate; } LOOP1(inNumSamples, level += rate; ZXP(out) = level; ); unit->m_previn = curin; unit->mLevel = level; } void Sweep_next_ka(Sweep *unit, int inNumSamples) { float *out = ZOUT(0); float curin = ZIN0(0); float *rate = ZIN(1); float previn = unit->m_previn; double level = unit->mLevel; float sampledur = SAMPLEDUR; if (previn <= 0.f && curin > 0.f) { float frac = -previn/(curin-previn); level = frac * rate[ZOFF] * sampledur; } LOOP1(inNumSamples, float zrate = ZXP(rate) * sampledur; level += zrate; ZXP(out) = level; ); unit->m_previn = curin; unit->mLevel = level; } void Sweep_next_ak(Sweep *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double rate = ZIN0(1) * SAMPLEDUR; float previn = unit->m_previn; double level = unit->mLevel; LOOP1(inNumSamples, float curin = ZXP(in); if (previn <= 0.f && curin > 0.f) { float frac = -previn/(curin-previn); level = frac * rate; } else { level += rate; } ZXP(out) = level; previn = curin; ); unit->m_previn = previn; unit->mLevel = level; } void Sweep_next_aa(Sweep *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *rate = ZIN(1); float previn = unit->m_previn; double level = unit->mLevel; float sampledur = SAMPLEDUR; LOOP1(inNumSamples, float curin = ZXP(in); float zrate = ZXP(rate) * sampledur; if (previn <= 0.f && curin > 0.f) { float frac = -previn/(curin-previn); level = frac * zrate; } else { level += zrate; } ZXP(out) = level; previn = curin; ); unit->m_previn = previn; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Phasor_Ctor(Phasor *unit) { if (unit->mCalcRate == calc_FullRate) { if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) { SETCALC(Phasor_next_aa); } else { SETCALC(Phasor_next_ak); } } else { SETCALC(Phasor_next_kk); } } else { SETCALC(Phasor_next_ak); } unit->m_previn = ZIN0(0); ZOUT0(0) = unit->mLevel = ZIN0(2); } void Phasor_next_kk(Phasor *unit, int inNumSamples) { float *out = ZOUT(0); float in = ZIN0(0); double rate = ZIN0(1); double start = ZIN0(2); double end = ZIN0(3); float resetPos = ZIN0(4); float previn = unit->m_previn; double level = unit->mLevel; if (previn <= 0.f && in > 0.f) { level = resetPos; } LOOP1(inNumSamples, level = sc_wrap(level, start, end); ZXP(out) = level; level += rate; ); unit->m_previn = in; unit->mLevel = level; } void Phasor_next_ak(Phasor *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); double rate = ZIN0(1); double start = ZIN0(2); double end = ZIN0(3); float resetPos = ZIN0(4); float previn = unit->m_previn; double level = unit->mLevel; LOOP1(inNumSamples, float curin = ZXP(in); if (previn <= 0.f && curin > 0.f) { float frac = 1.f - previn/(curin-previn); level = resetPos + frac * rate; } ZXP(out) = level; level += rate; level = sc_wrap(level, start, end); previn = curin; ); unit->m_previn = previn; unit->mLevel = level; } void Phasor_next_aa(Phasor *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *rate = ZIN(1); double start = ZIN0(2); double end = ZIN0(3); float resetPos = ZIN0(4); float previn = unit->m_previn; double level = unit->mLevel; LOOP1(inNumSamples, float curin = ZXP(in); double zrate = ZXP(rate); if (previn <= 0.f && curin > 0.f) { float frac = 1.f - previn/(curin-previn); level = resetPos + frac * zrate; } ZXP(out) = level; level += zrate; level = sc_wrap(level, start, end); previn = curin; ); unit->m_previn = previn; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void Peak_next_ak_unroll(Peak *unit, int inNumSamples); void Peak_next_ai_unroll(Peak *unit, int inNumSamples); #ifdef NOVA_SIMD FLATTEN void Peak_next_ak_k_nova(Peak *unit, int inNumSamples); FLATTEN void Peak_next_ai_k_nova(Peak *unit, int inNumSamples); #endif void Peak_Ctor(Peak *unit) { if (BUFLENGTH == 1 && INRATE(0) == calc_FullRate) { /* audio-rate input with control-rate output */ if (INRATE(1) == calc_FullRate) { SETCALC(Peak_next_aa_k); } else if (INRATE(1) == calc_ScalarRate) { #ifdef NOVA_SIMD if (INBUFLENGTH(0) & 7) SETCALC(Peak_next_ai_k); else SETCALC(Peak_next_ai_k_nova); #else SETCALC(Peak_next_ai_k); #endif } else { #ifdef NOVA_SIMD if (INBUFLENGTH(0) & 7) SETCALC(Peak_next_ak_k); else SETCALC(Peak_next_ak_k_nova); #else SETCALC(Peak_next_ak_k); #endif } } else { if (INRATE(1) == calc_FullRate) { SETCALC(Peak_next_aa); } else if (INRATE(1) == calc_ScalarRate) { if (BUFLENGTH & 15) SETCALC(Peak_next_ai); else SETCALC(Peak_next_ai_unroll); } else { if (BUFLENGTH & 15) SETCALC(Peak_next_ak); else SETCALC(Peak_next_ak_unroll); } } unit->m_prevtrig = 0.f; ZOUT0(0) = unit->mLevel = ZIN0(0); } void Peak_next_ak(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float curtrig = ZIN0(1); float level = unit->mLevel; float inlevel; LOOP1(inNumSamples, inlevel = std::abs(ZXP(in)); level = std::max(inlevel, level); ZXP(out) = level; ); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = inlevel; unit->m_prevtrig = curtrig; unit->mLevel = level; } void Peak_next_ai(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float level = unit->mLevel; float inlevel; LOOP1(inNumSamples, inlevel = std::abs(ZXP(in)); level = std::max(inlevel, level); ZXP(out) = level; ); unit->mLevel = level; } void Peak_next_aa(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); float inlevel = std::abs(ZXP(in)); level = std::max(inlevel, level); ZXP(out) = level; if (prevtrig <= 0.f && curtrig > 0.f) level = inlevel; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->mLevel = level; } static inline float Peak_unroll_body(Peak *unit, int inNumSamples, float & level) { float *out = OUT(0); float *in = IN(0); float inlevel; using namespace std; for (int i = 0; i != inNumSamples; i += 8, out += 8, in += 8) { float level0 = max(abs(in[0]), level); float level1 = max(abs(in[1]), level0); float level2 = max(abs(in[2]), level1); float level3 = max(abs(in[3]), level2); float level4 = max(abs(in[4]), level3); float level5 = max(abs(in[5]), level4); float level6 = max(abs(in[6]), level5); inlevel = abs(in[7]); float level7 = max(inlevel, level6); out[0] = level0; out[1] = level1; out[2] = level2; out[3] = level3; out[4] = level4; out[5] = level5; out[6] = level6; out[7] = level7; level = level7; } return inlevel; /* input level of the last sample */ } void Peak_next_ak_unroll(Peak *unit, int inNumSamples) { float curtrig = ZIN0(1); float level = unit->mLevel; float inlevel = Peak_unroll_body(unit, inNumSamples, level); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = inlevel; unit->m_prevtrig = curtrig; unit->mLevel = level; } void Peak_next_ai_unroll(Peak *unit, int inNumSamples) { float level = unit->mLevel; Peak_unroll_body(unit, inNumSamples, level); unit->mLevel = level; } void Peak_next_ak_k(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float curtrig = ZIN0(1); float level; inNumSamples = INBUFLENGTH(0); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) { level = std::abs(ZXP(in)); inNumSamples -= 1; } else level = unit->mLevel; LOOP1(inNumSamples, level = std::max(std::abs(ZXP(in)), level); ); ZXP(out) = level; unit->m_prevtrig = curtrig; unit->mLevel = level; } void Peak_next_ai_k(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float level = unit->mLevel; inNumSamples = INBUFLENGTH(0); LOOP1(inNumSamples, level = std::max(std::abs(ZXP(in)), level); ); ZXP(out) = level; unit->mLevel = level; } void Peak_next_aa_k(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; float out_level; bool triggered = false; inNumSamples = INBUFLENGTH(0); LOOP1(inNumSamples, float curtrig = ZXP(trig); float inlevel = std::abs(ZXP(in)); level = std::max(inlevel, level); if (prevtrig <= 0.f && curtrig > 0.f) { triggered = true; out_level = level; level = inlevel; } prevtrig = curtrig; ); if (triggered) ZXP(out) = out_level; else ZXP(out) = level; unit->m_prevtrig = prevtrig; unit->mLevel = level; } #ifdef NOVA_SIMD void Peak_next_ak_k_nova(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = IN(0); float curtrig = ZIN0(1); float level = unit->mLevel; float inlevel; inNumSamples = INBUFLENGTH(0); inlevel = nova::peak_vec_simd(in, &level, inNumSamples); ZXP(out) = level; if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = inlevel; unit->m_prevtrig = curtrig; unit->mLevel = level; } void Peak_next_ai_k_nova(Peak *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float level = unit->mLevel; float inlevel; inNumSamples = INBUFLENGTH(0); inlevel = nova::peak_vec_simd(in, &level, inNumSamples); ZXP(out) = level; unit->mLevel = level; } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// void RunningMin_Ctor(RunningMin *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(RunningMin_next_aa); } else if (INRATE(1) == calc_ScalarRate) { SETCALC(RunningMin_next_ai); } else { SETCALC(RunningMin_next_ak); } unit->m_prevtrig = 0.f; ZOUT0(0) = unit->mLevel = ZIN0(0); } void RunningMin_next_ak(RunningMin *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float curtrig = ZIN0(1); float level = unit->mLevel; float inlevel; LOOP1(inNumSamples, inlevel = ZXP(in); if (inlevel < level) level = inlevel; ZXP(out) = level; ); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = inlevel; unit->m_prevtrig = curtrig; unit->mLevel = level; } void RunningMin_next_ai(RunningMin *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float level = unit->mLevel; float inlevel; LOOP1(inNumSamples, inlevel = ZXP(in); if (inlevel < level) level = inlevel; ZXP(out) = level; ); unit->mLevel = level; } void RunningMin_next_aa(RunningMin *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); float inlevel = ZXP(in); if (inlevel < level) level = inlevel; ZXP(out) = level; if (prevtrig <= 0.f && curtrig > 0.f) level = inlevel; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void RunningMax_Ctor(RunningMax *unit) { if (INRATE(1) == calc_FullRate) { SETCALC(RunningMax_next_aa); } else if (INRATE(1) == calc_ScalarRate) { SETCALC(RunningMax_next_ai); } else { SETCALC(RunningMax_next_ak); } unit->m_prevtrig = 0.f; ZOUT0(0) = unit->mLevel = ZIN0(0); } void RunningMax_next_ak(RunningMax *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float curtrig = ZIN0(1); float level = unit->mLevel; float inlevel; LOOP1(inNumSamples, inlevel = ZXP(in); if (inlevel > level) level = inlevel; ZXP(out) = level; ); if (unit->m_prevtrig <= 0.f && curtrig > 0.f) level = inlevel; unit->m_prevtrig = curtrig; unit->mLevel = level; } void RunningMax_next_ai(RunningMax *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float level = unit->mLevel; float inlevel; LOOP1(inNumSamples, inlevel = ZXP(in); if (inlevel > level) level = inlevel; ZXP(out) = level; ); unit->mLevel = level; } void RunningMax_next_aa(RunningMax *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float *trig = ZIN(1); float prevtrig = unit->m_prevtrig; float level = unit->mLevel; LOOP1(inNumSamples, float curtrig = ZXP(trig); float inlevel = ZXP(in); if (inlevel > level) level = inlevel; ZXP(out) = level; if (prevtrig <= 0.f && curtrig > 0.f) level = inlevel; prevtrig = curtrig; ); unit->m_prevtrig = prevtrig; unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void PeakFollower_Ctor(PeakFollower *unit) { if (INRATE(1) == calc_ScalarRate) { SETCALC(PeakFollower_next_ai); } else { SETCALC(PeakFollower_next); } unit->mDecay = ZIN0(1); ZOUT0(0) = unit->mLevel = ZIN0(0); } void PeakFollower_next(PeakFollower *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float decay = ZIN0(1); float level = unit->mLevel; if(decay == unit->mDecay) { LOOP1(inNumSamples, float inlevel = std::abs(ZXP(in)); if (inlevel >= level) { level = inlevel; } else { level = inlevel + decay * (level - inlevel); } ZXP(out) = level; ); } else { float decay_slope = CALCSLOPE(decay, unit->mDecay); if (decay >= 0.f && unit->mDecay >= 0.f) { LOOP1(inNumSamples, float inlevel = std::abs(ZXP(in)); if (inlevel >= level) { level = inlevel; } else { level = inlevel + decay * (level - inlevel); decay += decay_slope; }; ZXP(out) = level; ); } else if (decay <= 0.f && unit->mDecay <= 0.f) { LOOP1(inNumSamples, float inlevel = std::abs(ZXP(in)); if (inlevel >= level) { level = inlevel; } else { level = inlevel + decay * (level + inlevel); decay += decay_slope; }; ZXP(out) = level; ); } else { LOOP1(inNumSamples, float inlevel = std::abs(ZXP(in)); if (inlevel >= level) { level = inlevel; } else { level = (1.f - std::abs(decay)) * inlevel + decay * level; decay += decay_slope; }; ZXP(out) = level; ); }; } unit->mLevel = level; unit->mDecay = decay; } void PeakFollower_next_ai(PeakFollower *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float decay = ZIN0(1); float level = unit->mLevel; LOOP1(inNumSamples, float inlevel = std::abs(ZXP(in)); if (inlevel >= level) { level = inlevel; } else { level = inlevel + decay * (level - inlevel); } ZXP(out) = level; ); unit->mLevel = level; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void MostChange_Ctor(MostChange *unit) { if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) { SETCALC(MostChange_next_aa); } else { SETCALC(MostChange_next_ak); } } else { if (INRATE(1) == calc_FullRate) { SETCALC(MostChange_next_ka); } else { SETCALC(MostChange_next_aa); } } unit->mPrevA = 0.f; unit->mPrevB = 0.f; unit->mRecent = 1; MostChange_next_aa(unit, 1); } void MostChange_next_ak(MostChange *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); float prevA = unit->mPrevA; float prevB = unit->mPrevB; int recent = unit->mRecent; LOOP1(inNumSamples, float xa = ZXP(a); float diff = std::abs(xa - prevA) - std::abs(xb - prevB); if (diff > 0.f) { recent = 0; ZXP(out) = xa; } else if (diff < 0.f) { recent = 1; ZXP(out) = xb; } else { ZXP(out) = recent ? xb : xa; } prevA = xa; prevB = xb; ); unit->mPrevA = prevA; unit->mPrevB = prevB; unit->mRecent = recent; } void MostChange_next_aa(MostChange *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); float prevA = unit->mPrevA; float prevB = unit->mPrevB; int recent = unit->mRecent; LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); float diff = std::abs(xa - prevA) - std::abs(xb - prevB); if (diff > 0.f) { recent = 0; ZXP(out) = xa; } else if (diff < 0.f) { recent = 1; ZXP(out) = xb; } else { ZXP(out) = recent ? xb : xa; } prevA = xa; prevB = xb; ); unit->mPrevA = prevA; unit->mPrevB = prevB; unit->mRecent = recent; } void MostChange_next_ka(MostChange *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); float prevA = unit->mPrevA; float prevB = unit->mPrevB; int recent = unit->mRecent; LOOP1(inNumSamples, float xb = ZXP(b); float diff = std::abs(xa - prevA) - std::abs(xb - prevB); if (diff > 0.f) { recent = 0; ZXP(out) = xa; } else if (diff < 0.f) { recent = 1; ZXP(out) = xb; } else { ZXP(out) = recent ? xb : xa; } prevA = xa; prevB = xb; ); unit->mPrevA = prevA; unit->mPrevB = prevB; unit->mRecent = recent; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void LeastChange_Ctor(LeastChange *unit) { if (INRATE(0) == calc_FullRate) { if (INRATE(1) == calc_FullRate) { SETCALC(LeastChange_next_aa); } else { SETCALC(LeastChange_next_ak); } } else { if (INRATE(1) == calc_FullRate) { SETCALC(LeastChange_next_ka); } else { SETCALC(LeastChange_next_aa); } } unit->mPrevA = 0.f; unit->mPrevB = 0.f; unit->mRecent = 0; LeastChange_next_aa(unit, 1); } void LeastChange_next_ak(LeastChange *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float xb = ZIN0(1); float prevA = unit->mPrevA; float prevB = unit->mPrevB; int recent = unit->mRecent; LOOP1(inNumSamples, float xa = ZXP(a); float diff = std::abs(xa - prevA) - std::abs(xb - prevB); if (diff < 0.f) { recent = 0; ZXP(out) = xa; } else if (diff > 0.f) { recent = 1; ZXP(out) = xb; } else { ZXP(out) = recent ? xb : xa; } prevA = xa; prevB = xb; ); unit->mPrevA = prevA; unit->mPrevB = prevB; unit->mRecent = recent; } void LeastChange_next_aa(LeastChange *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); float *b = ZIN(1); float prevA = unit->mPrevA; float prevB = unit->mPrevB; int recent = unit->mRecent; LOOP1(inNumSamples, float xa = ZXP(a); float xb = ZXP(b); float diff = std::abs(xa - prevA) - std::abs(xb - prevB); if (diff < 0.f) { recent = 0; ZXP(out) = xa; } else if (diff > 0.f) { recent = 1; ZXP(out) = xb; } else { ZXP(out) = recent ? xb : xa; } prevA = xa; prevB = xb; ); unit->mPrevA = prevA; unit->mPrevB = prevB; unit->mRecent = recent; } void LeastChange_next_ka(LeastChange *unit, int inNumSamples) { float *out = ZOUT(0); float xa = ZIN0(0); float *b = ZIN(1); float prevA = unit->mPrevA; float prevB = unit->mPrevB; int recent = unit->mRecent; LOOP1(inNumSamples, float xb = ZXP(b); float diff = std::abs(xa - prevA) - std::abs(xb - prevB); if (diff < 0.f) { recent = 0; ZXP(out) = xa; } else if (diff > 0.f) { recent = 1; ZXP(out) = xb; } else { ZXP(out) = recent ? xb : xa; } prevA = xa; prevB = xb; ); unit->mPrevA = prevA; unit->mPrevB = prevB; unit->mRecent = recent; } //////////////////// void LastValue_Ctor(LastValue *unit) { if (INRATE(0) == calc_FullRate) { SETCALC(LastValue_next_ak); } else { SETCALC(LastValue_next_kk); } unit->mPrev = ZIN0(0); unit->mCurr = ZIN0(0); LastValue_next_kk(unit, 1); } void LastValue_next_kk(LastValue *unit, int inNumSamples) { float *out = ZOUT(0); float inval = ZIN0(0); float delta = ZIN0(1); float diff = std::abs(inval - unit->mCurr); if(diff >= delta) { unit->mPrev = unit->mCurr; unit->mCurr = inval; } float level = unit->mPrev; LOOP1(inNumSamples, ZXP(out) = level; ); } void LastValue_next_ak(LastValue *unit, int inNumSamples) { float *out = ZOUT(0); float *in = ZIN(0); float delta = ZIN0(1); float prev = unit->mPrev; float curr = unit->mCurr; LOOP1(inNumSamples, float inval = ZXP(in); float diff = std::abs(inval - curr); if(diff >= delta) { prev = curr; curr = inval; } ZXP(out) = prev ); unit->mPrev = prev; unit->mCurr = curr; } ////////////////////////////////////////////////////////////////////////////////////////// void Done_Ctor(Done *unit) { SETCALC(Done_next); unit->m_src = unit->mInput[0]->mFromUnit; Done_next(unit, 1); } void Done_next(Done *unit, int inNumSamples) { float *out = OUT(0); Unit *src = unit->m_src; if (src) *out = src->mDone ? 1.f : 0.f; else *out = 0.f; } ////////////////////////////////////////////////////////////////////////////////////////// void FreeSelf_Ctor(FreeSelf *unit) { SETCALC(FreeSelf_next); unit->m_prevtrig = 0.f; FreeSelf_next(unit, 1); } void FreeSelf_next(FreeSelf *unit, int inNumSamples) { float in = ZIN0(0); if (in > 0.f && unit->m_prevtrig <= 0.f) { NodeEnd(&unit->mParent->mNode); } unit->m_prevtrig = in; } ////////////////////////////////////////////////////////////////////////////////////////// void PauseSelf_Ctor(PauseSelf *unit) { SETCALC(PauseSelf_next); unit->m_prevtrig = 0.f; PauseSelf_next(unit, 1); } void PauseSelf_next(PauseSelf *unit, int inNumSamples) { float in = ZIN0(0); if (in > 0.f && unit->m_prevtrig <= 0.f) { NodeRun(&unit->mParent->mNode, 0); } unit->m_prevtrig = in; } ////////////////////////////////////////////////////////////////////////////////////////// void Pause_Ctor(Pause *unit) { SETCALC(Pause_next); unit->m_state = 1; ZOUT0(0) = ZIN0(0); } void Pause_next(Pause *unit, int inNumSamples) { float in = ZIN0(0); int state = in == 0.f ? 0 : 1; if (state != unit->m_state) { unit->m_state = state; int id = (int)ZIN0(1); Node *node = SC_GetNode(unit->mWorld, id); if (node) { NodeRun(node, state); } } ZOUT0(0) = in; } ////////////////////////////////////////////////////////////////////////////////////////// void Free_Ctor(Free *unit) { SETCALC(Free_next); unit->m_prevtrig = 0.f; ZOUT0(0) = ZIN0(0); } void Free_next(Free *unit, int inNumSamples) { float trig = ZIN0(0); if (trig > 0.f && unit->m_prevtrig <= 0) { int id = (int)ZIN0(1); Node *node = SC_GetNode(unit->mWorld, id); if (node) { NodeEnd(node); } } unit->m_prevtrig = trig; ZOUT0(0) = trig; } ////////////////////////////////////////////////////////////////////////////////////////// void FreeSelfWhenDone_Ctor(FreeSelfWhenDone *unit) { unit->m_src = unit->mInput[0]->mFromUnit; if (unit->m_src) { SETCALC(FreeSelfWhenDone_next); FreeSelfWhenDone_next(unit, 1); } else { SETCALC(ClearUnitOutputs); ClearUnitOutputs(unit, 1); } } void FreeSelfWhenDone_next(FreeSelfWhenDone *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); Unit *src = unit->m_src; if (src->mDone) { NodeEnd(&unit->mParent->mNode); SETCALC(ClearUnitOutputs); } *out = *in; } ////////////////////////////////////////////////////////////////////////////////////////// void PauseSelfWhenDone_Ctor(PauseSelfWhenDone *unit) { unit->m_src = unit->mInput[0]->mFromUnit; if (unit->m_src) { SETCALC(PauseSelfWhenDone_next); PauseSelfWhenDone_next(unit, 1); } else { SETCALC(ClearUnitOutputs); ClearUnitOutputs(unit, 1); } } void PauseSelfWhenDone_next(PauseSelfWhenDone *unit, int inNumSamples) { float *out = OUT(0); float *in = IN(0); Unit *src = unit->m_src; if (src->mDone) { NodeRun(&unit->mParent->mNode, 0); SETCALC(ClearUnitOutputs); } *out = *in; } //////////////////////////////////////////////////////////////////////////////////////////////////////// struct SendPeakRMS: public Unit { // rate, level lag, replyid, channel count, [channels, ], cmd name size, [cmdname, ] static const int rateIndex = 0; static const int levelLagIndex = 1; static const int replyIdIndex = 2; static const int channelCountIndex = 3; static const int signalStartIndex = 4; SendPeakRMS(void) { SendPeakRMS * unit = this; mChannelCount = (unsigned int)IN0(channelCountIndex); size_t channelDataAllocSize = mChannelCount * 3 * sizeof(float); int cmdSizeIndex = signalStartIndex + mChannelCount; size_t cmdNameSize = IN0(cmdSizeIndex); size_t cmdNameAllocSize = (cmdNameSize + 1) * sizeof(char); void * allocData = RTAlloc(unit->mWorld, channelDataAllocSize + cmdNameAllocSize); if (!allocData) { Print("SendPeakRMS: RT memory allocation failed\n"); SETCALC(Unit_next_nop); return; } memset(allocData, 0, channelDataAllocSize); mChannelData = (float*)allocData; char * cmdName = (char*)(allocData) + channelDataAllocSize; size_t cmdNameIndex = cmdSizeIndex + 1; for(int i = 0; i < cmdNameSize; i++) cmdName[i] = (char)IN0(cmdNameIndex + i); cmdName[cmdNameSize] = 0; if ((FULLBUFLENGTH & 15) == 0) { if (mCalcRate == calc_FullRate) SETCALC(SendPeakRMS::perform_a); else SETCALC(SendPeakRMS::perform_k); } else { if (mCalcRate == calc_FullRate) SETCALC(SendPeakRMS::perform_a); else SETCALC(SendPeakRMS::perform_k); } float replyRate = IN0(rateIndex); mAudioSamplesPerTick = FULLRATE / replyRate; mControlSamplesPerTick = BUFRATE / replyRate; mPhaseRemain = (mCalcRate == calc_FullRate) ? mAudioSamplesPerTick : mControlSamplesPerTick; float32 lag = ZIN0(levelLagIndex); mB1 = (lag != 0.f) ? exp(log001 / (lag * replyRate)) : 0.f; } ~SendPeakRMS (void) { SendPeakRMS * unit = this; RTFree(unit->mWorld, mChannelData); } unsigned int mChannelCount; float * mChannelData; float mB1; int mAudioSamplesPerTick; int mControlSamplesPerTick; int mPhaseRemain; void performLevelLag(float & out, float y0, float & y1) { if (y0 >= y1) out = y1 = y0; else out = y1 = y0 + mB1 * (y1 - y0); } char * getCmdName (void) { void * buffer = mChannelData; return (char*)(buffer) + mChannelCount * 3 * sizeof(float); } void sendReply(void) { SendPeakRMS * unit = this; float * reply = (float*)alloca(mChannelCount * 2 * sizeof(float)); for (int i = 0; i != mChannelCount; ++i) { float & maxLevel = reply[2*i]; float & rms = reply[2*i + 1]; performLevelLag(maxLevel, mChannelData[2*i], mChannelData[2*mChannelCount + i]); if (INRATE(signalStartIndex + i) == calc_FullRate) rms = std::sqrt(mChannelData[2*i + 1] / (float)mAudioSamplesPerTick); else rms = std::sqrt(mChannelData[2*i + 1] / (float)mControlSamplesPerTick); } SendNodeReply(&unit->mParent->mNode, (int)ZIN0(replyIdIndex), getCmdName(), mChannelCount*2, reply); memset(mChannelData, 0, mChannelCount * 2 * sizeof(float)); } template void analyzeFullBlock(void) { SendPeakRMS * unit = this; for (int i = 0; i != mChannelCount; ++i) { float * in = IN(signalStartIndex + i); int numSamples = INBUFLENGTH(signalStartIndex + i); float & level = mChannelData[2*i]; float & sqrsum = mChannelData[2*i + 1]; if (numSamples == 1) nova::peak_rms_vec(in, &level, &sqrsum, 1); else { if (simd) nova::peak_rms_vec_simd(in, &level, &sqrsum, numSamples); else nova::peak_rms_vec(in, &level, &sqrsum, numSamples); } } } void analyzePartialBlock(int firstSample, int samplesToAnalyze) { SendPeakRMS * unit = this; for (int i = 0; i != mChannelCount; ++i) { float * in = IN(signalStartIndex + i) + firstSample; int numSamples = INBUFLENGTH(signalStartIndex + i); float & level = mChannelData[2*i]; float & sqrsum = mChannelData[2*i + 1]; if (numSamples == 1) { if (firstSample == 0) nova::peak_rms_vec(in, &level, &sqrsum, 1); } else { if (!(samplesToAnalyze & 15) && !(firstSample & 3)) // check for unrolling and alignment nova::peak_rms_vec_simd(in, &level, &sqrsum, samplesToAnalyze); else nova::peak_rms_vec(in, &level, &sqrsum, samplesToAnalyze); } } } template inline void next_k(int inNumSamples) { mPhaseRemain -= 1; if (mPhaseRemain <= 0) { mPhaseRemain += mControlSamplesPerTick; sendReply(); } analyzeFullBlock(); } template inline void next_a(int inNumSamples) { if (mPhaseRemain >= inNumSamples) { mPhaseRemain -= inNumSamples; analyzeFullBlock(); } else { if (mPhaseRemain == 0) { sendReply(); mPhaseRemain = mAudioSamplesPerTick; } int startSample = 0; int samplesToAnalyze = std::min(mPhaseRemain, inNumSamples); int remain = inNumSamples; do { analyzePartialBlock(startSample, samplesToAnalyze); startSample += samplesToAnalyze; mPhaseRemain -= samplesToAnalyze; if (mPhaseRemain == 0) { sendReply(); mPhaseRemain = mAudioSamplesPerTick; } remain -= samplesToAnalyze; samplesToAnalyze = std::min(remain, mPhaseRemain); } while(remain); } } template static void perform_k(Unit * unit, int inNumSamples) { static_cast(unit)->next_k(inNumSamples); } template static void perform_a(Unit * unit, int inNumSamples) { static_cast(unit)->next_a(inNumSamples); } }; static void SendPeakRMS_Ctor(SendPeakRMS * unit) { new(unit) SendPeakRMS (); } static void SendPeakRMS_Dtor(SendPeakRMS * unit) { unit->~SendPeakRMS (); } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(Trigger) { ft = inTable; DefineSimpleUnit(Trig1); DefineSimpleUnit(Trig); DefineSimpleUnit(SendTrig); DefineDtorUnit(SendReply); DefineDtorUnit(Poll); DefineSimpleUnit(ToggleFF); DefineSimpleUnit(SetResetFF); DefineSimpleUnit(Latch); DefineSimpleUnit(Gate); DefineSimpleUnit(Schmidt); DefineSimpleUnit(PulseDivider); DefineSimpleUnit(PulseCount); DefineSimpleUnit(Stepper); DefineSimpleUnit(TDelay); DefineSimpleUnit(ZeroCrossing); DefineSimpleUnit(Timer); DefineSimpleUnit(Sweep); DefineSimpleUnit(Phasor); DefineSimpleUnit(Peak); DefineSimpleUnit(RunningMin); DefineSimpleUnit(RunningMax); DefineSimpleUnit(PeakFollower); DefineSimpleUnit(MostChange); DefineSimpleUnit(LeastChange); DefineSimpleUnit(LastValue); DefineSimpleUnit(Done); DefineSimpleUnit(Pause); DefineSimpleUnit(FreeSelf); DefineSimpleUnit(PauseSelf); DefineSimpleUnit(Free); DefineSimpleUnit(FreeSelfWhenDone); DefineSimpleUnit(PauseSelfWhenDone); DefineDtorUnit(SendPeakRMS); } SuperCollider-Source/server/plugins/UIUGens.cpp000644 000765 000024 00000026510 12756531745 022652 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // ********** this version for windows and linux. for mac see UIUGens.mm #include #include # ifndef _WIN32 # include # else #include "SC_Win32Utils.h" #include # endif #include "SC_PlugIn.h" static InterfaceTable *ft; struct KeyboardUGenGlobalState { uint8 keys[32]; } gKeyStateGlobals; struct KeyState : public Unit { float m_y1, m_b1, m_lag; }; struct MouseUGenGlobalState { float mouseX, mouseY; bool mouseButton; } gMouseUGenGlobals; struct MouseInputUGen : public Unit { float m_y1, m_b1, m_lag; }; ////////////////////////////////////////////////////////////////////////////////////////////////// std::atomic_bool inputThreadRunning = { false }; #ifdef _WIN32 void gstate_update_func() { POINT p; int mButton; if(GetSystemMetrics(SM_SWAPBUTTON)) mButton = VK_RBUTTON; // if swapped else mButton = VK_LBUTTON; // not swapped (normal) int screenWidth = GetSystemMetrics( SM_CXSCREEN ); int screenHeight = GetSystemMetrics( SM_CYSCREEN ); // default: SM_CX/CYSCREEN gets the size of a primary screen. // lines uncommented below are just for a specially need on multi-display. //int screenWidth = GetSystemMetrics( SM_CXVIRTUALSCREEN ); //int screenHeight = GetSystemMetrics( SM_CYVIRTUALSCREEN ); float r_screenWidth = 1.f / (float)(screenWidth -1); float r_screenHeight = 1.f / (float)(screenHeight -1); while ( inputThreadRunning.load( std::memory_order_relaxed ) ) { // "KeyState" is disabled for now, on Windows... //GetKey((long*)gstate->keys); GetCursorPos(&p); gMouseUGenGlobals.mouseX = (float)p.x * r_screenWidth; gMouseUGenGlobals.mouseY = 1.f - (float)p.y * r_screenHeight; gMouseUGenGlobals.mouseButton = (GetKeyState(mButton) < 0); std::this_thread::sleep_for( std::chrono::milliseconds( 17 ) ); } } # else static Display * d = 0; void gstate_update_func() { Window r; struct timespec requested_time , remaining_time; // NOTE: should not be required as this is the only thread accessing the x11 API // but omitting seems to cause troubles. XInitThreads(); d = XOpenDisplay ( NULL ); if (!d) return; Window rep_root, rep_child; XWindowAttributes attributes; int rep_rootx, rep_rooty ; unsigned int rep_mask; int dx, dy; float r_width; float r_height; r = DefaultRootWindow ( d ); XGetWindowAttributes ( d, r, &attributes ); r_width = 1.0 / (float)attributes.width; r_height = 1.0 / (float)attributes.height; while ( inputThreadRunning.load( std::memory_order_relaxed ) ) { XQueryKeymap ( d , (char *) (gKeyStateGlobals.keys) ); XQueryPointer ( d, r, &rep_root, &rep_child, &rep_rootx, &rep_rooty, &dx, &dy, &rep_mask); gMouseUGenGlobals.mouseX = (float)dx * r_width; gMouseUGenGlobals.mouseY = 1.f - ( (float)dy * r_height ); gMouseUGenGlobals.mouseButton = (bool) ( rep_mask & Button1Mask ); std::this_thread::sleep_for( std::chrono::milliseconds( 17 ) ); } } #endif ////////////////////////////////////////////////////////////////////////////////////////////////// void KeyState_next(KeyState *unit, int inNumSamples) { // minval, maxval, warp, lag uint8 *keys = (uint8*)gKeyStateGlobals.keys; int keynum = (int)ZIN0(0); int byte = (keynum >> 3) & 31; int bit = keynum & 7; int val = keys[byte] & (1 << bit); float minval = ZIN0(1); float maxval = ZIN0(2); float lag = ZIN0(3); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = val ? maxval : minval; ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void KeyState_Ctor(KeyState *unit) { SETCALC(KeyState_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; KeyState_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void MouseX_next(MouseInputUGen *unit, int inNumSamples) { // minval, maxval, warp, lag float minval = ZIN0(0); float maxval = ZIN0(1); float warp = ZIN0(2); float lag = ZIN0(3); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = gMouseUGenGlobals.mouseX; if (warp == 0.0) { y0 = (maxval - minval) * y0 + minval; } else { y0 = pow(maxval/minval, y0) * minval; } ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void MouseX_Ctor(MouseInputUGen *unit) { SETCALC(MouseX_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; MouseX_next(unit, 1); } void MouseY_next(MouseInputUGen *unit, int inNumSamples) { // minval, maxval, warp, lag float minval = ZIN0(0); float maxval = ZIN0(1); float warp = ZIN0(2); float lag = ZIN0(3); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = gMouseUGenGlobals.mouseY; if (warp == 0.0) { y0 = (maxval - minval) * y0 + minval; } else { y0 = pow(maxval/minval, y0) * minval; } ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void MouseY_Ctor(MouseInputUGen *unit) { SETCALC(MouseY_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; MouseY_next(unit, 1); } void MouseButton_next(MouseInputUGen *unit, int inNumSamples) { // minval, maxval, warp, lag float minval = ZIN0(0); float maxval = ZIN0(1); float lag = ZIN0(2); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = gMouseUGenGlobals.mouseButton ? maxval : minval; ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void MouseButton_Ctor(MouseInputUGen *unit) { SETCALC(MouseButton_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; MouseButton_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// // example of implementing a plug in command with async execution. struct MyPluginData // data for the global instance of the plugin { float a, b; }; struct MyCmdData // data for each command { MyPluginData* myPlugin; float x, y; char *name; }; MyPluginData gMyPlugin; // global bool cmdStage2(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; // just print out the values Print("cmdStage2 a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); return true; } bool cmdStage3(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; // just print out the values Print("cmdStage3 a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); // scsynth will perform completion message after this returns return true; } bool cmdStage4(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; // just print out the values Print("cmdStage4 a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); // scsynth will send /done after this returns return true; } void cmdCleanup(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; Print("cmdCleanup a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); RTFree(world, myCmdData->name); // free the string RTFree(world, myCmdData); // free command data // scsynth will delete the completion message for you. } void cmdDemoFunc(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr) { Print("->cmdDemoFunc %p\n", inUserData); // user data is the plug-in's user data. MyPluginData* thePlugInData = (MyPluginData*)inUserData; // allocate command data, free it in cmdCleanup. MyCmdData* myCmdData = (MyCmdData*)RTAlloc(inWorld, sizeof(MyCmdData)); myCmdData->myPlugin = thePlugInData; // ..get data from args.. myCmdData->x = 0.; myCmdData->y = 0.; myCmdData->name = 0; // float arguments myCmdData->x = args->getf(); myCmdData->y = args->getf(); // how to pass a string argument: const char *name = args->gets(); // get the string argument if (name) { myCmdData->name = (char*)RTAlloc(inWorld, strlen(name)+1); // allocate space, free it in cmdCleanup. strcpy(myCmdData->name, name); // copy the string } // how to pass a completion message int msgSize = args->getbsize(); char* msgData = 0; if (msgSize) { // allocate space for completion message // scsynth will delete the completion message for you. msgData = (char*)RTAlloc(inWorld, msgSize); args->getb(msgData, msgSize); // copy completion message. } DoAsynchronousCommand(inWorld, replyAddr, "cmdDemoFunc", (void*)myCmdData, (AsyncStageFn)cmdStage2, (AsyncStageFn)cmdStage3, (AsyncStageFn)cmdStage4, cmdCleanup, msgSize, msgData); Print("<-cmdDemoFunc\n"); } /* * to test the above, send the server these commands: * * * SynthDef(\sine, { Out.ar(0, SinOsc.ar(800,0,0.2)) }).load(s); * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno, [\s_new, \sine, 900, 0, 0]); * s.sendMsg(\n_free, 900); * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno); * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9); * s.sendMsg(\cmd, \pluginCmdDemo, 7); * s.sendMsg(\cmd, \pluginCmdDemo); * */ thread uiListenThread; PluginLoad(UIUGens) { ft = inTable; inputThreadRunning = true; uiListenThread = std::thread ( gstate_update_func ); DefineSimpleUnit(KeyState); DefineUnit("MouseX", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseX_Ctor, 0, 0); DefineUnit("MouseY", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseY_Ctor, 0, 0); DefineUnit("MouseButton", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseButton_Ctor, 0, 0); // define a plugin command - example code gMyPlugin.a = 1.2f; gMyPlugin.b = 3.4f; DefinePlugInCmd("pluginCmdDemo", cmdDemoFunc, (void*)&gMyPlugin); } C_LINKAGE SC_API_EXPORT void unload(InterfaceTable *inTable) { inputThreadRunning = false; uiListenThread.join(); #ifndef _WIN32 if (d) XCloseDisplay(d); #endif } SuperCollider-Source/server/plugins/UIUGens.mm000644 000765 000024 00000022747 12756531745 022511 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ // ********** this version for mac. for windows and linux see UIUGens.cpp #include #import #include #include "SC_PlugIn.h" static InterfaceTable *ft; struct KeyState : public Unit { float m_y1, m_b1, m_lag; }; struct MouseUGenGlobalState { float mouseX, mouseY; bool mouseButton; } gMouseUGenGlobals; struct MouseInputUGen : public Unit { float m_y1, m_b1, m_lag; }; ////////////////////////////////////////////////////////////////////////////////////////////////// std::atomic_bool inputThreadRunning = { false }; void gstate_update_func() { CGDirectDisplayID display = kCGDirectMainDisplay; // to grab the main display ID CGRect bounds = CGDisplayBounds(display); float rscreenWidth = 1. / bounds.size.width; float rscreenHeight = 1. / bounds.size.height; while ( inputThreadRunning.load( std::memory_order_relaxed ) ) { NSPoint p; p = [NSEvent mouseLocation]; gMouseUGenGlobals.mouseX = (float)p.x * rscreenWidth; gMouseUGenGlobals.mouseY = (float)p.y * rscreenHeight; gMouseUGenGlobals.mouseButton = (bool)[NSEvent pressedMouseButtons]; std::this_thread::sleep_for( std::chrono::milliseconds( 17 ) ); } return; } ////////////////////////////////////////////////////////////////////////////////////////////////// void KeyState_next(KeyState *unit, int inNumSamples) { CGKeyCode keynum = (CGKeyCode)ZIN0(0); int val = CGEventSourceKeyState(kCGEventSourceStateCombinedSessionState, keynum); float minval = ZIN0(1); float maxval = ZIN0(2); float lag = ZIN0(3); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = val ? maxval : minval; ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void KeyState_Ctor(KeyState *unit) { SETCALC(KeyState_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; KeyState_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// void MouseX_next(MouseInputUGen *unit, int inNumSamples) { // minval, maxval, warp, lag float minval = ZIN0(0); float maxval = ZIN0(1); float warp = ZIN0(2); float lag = ZIN0(3); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = gMouseUGenGlobals.mouseX; if (warp == 0.0) { y0 = (maxval - minval) * y0 + minval; } else { y0 = pow(maxval/minval, y0) * minval; } ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void MouseX_Ctor(MouseInputUGen *unit) { SETCALC(MouseX_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; MouseX_next(unit, 1); } void MouseY_next(MouseInputUGen *unit, int inNumSamples) { // minval, maxval, warp, lag float minval = ZIN0(0); float maxval = ZIN0(1); float warp = ZIN0(2); float lag = ZIN0(3); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = gMouseUGenGlobals.mouseY; if (warp == 0.0) { y0 = (maxval - minval) * y0 + minval; } else { y0 = pow(maxval/minval, y0) * minval; } ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void MouseY_Ctor(MouseInputUGen *unit) { SETCALC(MouseY_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; MouseY_next(unit, 1); } void MouseButton_next(MouseInputUGen *unit, int inNumSamples) { // minval, maxval, warp, lag float minval = ZIN0(0); float maxval = ZIN0(1); float lag = ZIN0(2); float y1 = unit->m_y1; float b1 = unit->m_b1; if (lag != unit->m_lag) { unit->m_b1 = lag == 0.f ? 0.f : (float)exp(log001 / (lag * unit->mRate->mSampleRate)); unit->m_lag = lag; } float y0 = gMouseUGenGlobals.mouseButton ? maxval : minval; ZOUT0(0) = y1 = y0 + b1 * (y1 - y0); unit->m_y1 = zapgremlins(y1); } void MouseButton_Ctor(MouseInputUGen *unit) { SETCALC(MouseButton_next); unit->m_b1 = 0.f; unit->m_lag = 0.f; MouseButton_next(unit, 1); } ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////// // example of implementing a plug in command with async execution. struct MyPluginData // data for the global instance of the plugin { float a, b; }; struct MyCmdData // data for each command { MyPluginData* myPlugin; float x, y; char *name; }; MyPluginData gMyPlugin; // global bool cmdStage2(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; // just print out the values Print("cmdStage2 a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); return true; } bool cmdStage3(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; // just print out the values Print("cmdStage3 a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); // scsynth will perform completion message after this returns return true; } bool cmdStage4(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; // just print out the values Print("cmdStage4 a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); // scsynth will send /done after this returns return true; } void cmdCleanup(World* world, void* inUserData) { // user data is the command. MyCmdData* myCmdData = (MyCmdData*)inUserData; Print("cmdCleanup a %g b %g x %g y %g name %s\n", myCmdData->myPlugin->a, myCmdData->myPlugin->b, myCmdData->x, myCmdData->y, myCmdData->name); RTFree(world, myCmdData->name); // free the string RTFree(world, myCmdData); // free command data // scsynth will delete the completion message for you. } void cmdDemoFunc(World *inWorld, void* inUserData, struct sc_msg_iter *args, void *replyAddr) { Print("->cmdDemoFunc %p\n", inUserData); // user data is the plug-in's user data. MyPluginData* thePlugInData = (MyPluginData*)inUserData; // allocate command data, free it in cmdCleanup. MyCmdData* myCmdData = (MyCmdData*)RTAlloc(inWorld, sizeof(MyCmdData)); myCmdData->myPlugin = thePlugInData; // ..get data from args.. myCmdData->x = 0.; myCmdData->y = 0.; myCmdData->name = 0; // float arguments myCmdData->x = args->getf(); myCmdData->y = args->getf(); // how to pass a string argument: const char *name = args->gets(); // get the string argument if (name) { myCmdData->name = (char*)RTAlloc(inWorld, strlen(name)+1); // allocate space, free it in cmdCleanup. strcpy(myCmdData->name, name); // copy the string } // how to pass a completion message int msgSize = args->getbsize(); char* msgData = 0; if (msgSize) { // allocate space for completion message // scsynth will delete the completion message for you. msgData = (char*)RTAlloc(inWorld, msgSize); args->getb(msgData, msgSize); // copy completion message. } DoAsynchronousCommand(inWorld, replyAddr, "cmdDemoFunc", (void*)myCmdData, (AsyncStageFn)cmdStage2, (AsyncStageFn)cmdStage3, (AsyncStageFn)cmdStage4, cmdCleanup, msgSize, msgData); Print("<-cmdDemoFunc\n"); } /* * to test the above, send the server these commands: * * * SynthDef(\sine, { Out.ar(0, SinOsc.ar(800,0,0.2)) }).load(s); * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno, [\s_new, \sine, 900, 0, 0]); * s.sendMsg(\n_free, 900); * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9, \mno); * s.sendMsg(\cmd, \pluginCmdDemo, 7, 9); * s.sendMsg(\cmd, \pluginCmdDemo, 7); * s.sendMsg(\cmd, \pluginCmdDemo); * */ thread uiListenThread; PluginLoad(UIUGens) { ft = inTable; inputThreadRunning = true; uiListenThread = std::thread ( gstate_update_func ); DefineSimpleUnit(KeyState); DefineUnit("MouseX", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseX_Ctor, 0, 0); DefineUnit("MouseY", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseY_Ctor, 0, 0); DefineUnit("MouseButton", sizeof(MouseInputUGen), (UnitCtorFunc)&MouseButton_Ctor, 0, 0); // define a plugin command - example code gMyPlugin.a = 1.2f; gMyPlugin.b = 3.4f; DefinePlugInCmd("pluginCmdDemo", cmdDemoFunc, (void*)&gMyPlugin); } C_LINKAGE SC_API_EXPORT void unload(InterfaceTable *inTable) { inputThreadRunning = false; uiListenThread.join(); } SuperCollider-Source/server/plugins/UnaryOpUGens.cpp000644 000765 000024 00000061165 12756531745 023737 0ustar00crucialstaff000000 000000 /* SuperCollider real time audio synthesis system Copyright (c) 2002 James McCartney. All rights reserved. http://www.audiosynth.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include #include #ifdef NOVA_SIMD #include "simd_unary_arithmetic.hpp" #include "simd_binary_arithmetic.hpp" #include "simd_ternary_arithmetic.hpp" #include "simd_math.hpp" #include "simd_memory.hpp" #include "softclip.hpp" #include "simd_unit_conversion.hpp" #include "function_attributes.h" using nova::wrap_argument; #define NOVA_WRAPPER(NAME, NOVANAME) \ FLATTEN void NAME##_nova(UnaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), inNumSamples); \ } #define NOVA_WRAPPER_CT_UNROLL(NAME, NOVANAME) \ FLATTEN void NAME##_nova(UnaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd(OUT(0), IN(0), inNumSamples); \ } \ \ FLATTEN void NAME##_nova_64(UnaryOpUGen *unit, int inNumSamples) \ { \ nova::NOVANAME##_vec_simd<64>(OUT(0), IN(0)); \ } struct sc_distort_functor { template inline FloatType operator()(FloatType arg) const { return sc_distort(arg); } template inline nova::vec operator()(nova::vec arg) const { nova::vec one (1.f); return arg * reciprocal(one + abs(arg)); } }; struct sc_scurve_functor { template inline FloatType operator()(FloatType arg) const { return sc_scurve(arg); } template inline nova::vec operator()(nova::vec arg) const { return perform(arg); } template inline typename boost::disable_if_c::type perform(VecType arg) const { typedef VecType vec; vec result; for (int i = 0; i != result.size; ++i) result.set(i, sc_scurve(arg.get(i))); return result; } template inline typename boost::enable_if_c::type perform(VecType arg) const { typedef VecType vec; vec one (1.f); vec zero (0.f); vec two (2.f); vec three (3.f); vec result = (arg * arg) * ( three - (two * arg)); vec boundLow = mask_lt(arg, zero); vec boundHigh = mask_gt(arg, one); result = select(result, zero, boundLow); result = select(result, one, boundHigh); return result; } }; namespace nova { NOVA_SIMD_DEFINE_UNARY_WRAPPER (distort, sc_distort_functor) NOVA_SIMD_DEFINE_UNARY_WRAPPER (scurve, sc_scurve_functor) } #endif using namespace std; // for math functions static InterfaceTable *ft; ////////////////////////////////////////////////////////////////////////////////////////////////// /* special unary math operators */ enum { opNeg, opNot, opIsNil, opNotNil, opBitNot, opAbs, opAsFloat, opAsInt, opCeil, opFloor, opFrac, opSign, opSquared, opCubed, opSqrt, opExp, opRecip, opMIDICPS, opCPSMIDI, opMIDIRatio, opRatioMIDI, opDbAmp, opAmpDb, opOctCPS, opCPSOct, opLog, opLog2, opLog10, opSin, opCos, opTan, opArcSin, opArcCos, opArcTan, opSinH, opCosH, opTanH, opRand, opRand2, opLinRand, opBiLinRand, opSum3Rand, opDistort, opSoftClip, opCoin, opDigitValue, opSilence, opThru, opRectWindow, opHanWindow, opWelchWindow, opTriWindow, opRamp, opSCurve, opNumUnarySelectors }; struct UnaryOpUGen : public Unit { }; typedef void (*UnaryOpFunc)(UnaryOpUGen *unit, int inNumSamples); extern "C" { void UnaryOpUGen_Ctor(UnaryOpUGen *unit); } bool ChooseOperatorFunc(UnaryOpUGen *unit); void UnaryOpUGen_Ctor(UnaryOpUGen *unit) { bool initialized = ChooseOperatorFunc(unit); if (!initialized) (unit->mCalcFunc)(unit, 1); } //////////////////////////////////////////////////////////////////////////////////////////////////////// #define DEFINE_UNARY_OP_FUNCS(name, function) \ extern "C" void name##_a(UnaryOpUGen *unit, int inNumSamples) \ { \ float *out = ZOUT(0); \ float *a = ZIN(0); \ \ LOOP1(inNumSamples, \ ZXP(out) = function(ZXP(a)); \ ); \ } \ \ extern "C" void name##_1(UnaryOpUGen *unit, int inNumSamples) \ { \ ZOUT0(0) = function(ZIN0(0)); \ } \ \ extern "C" void name##_d(UnaryOpUGen *unit, int inNumSamples) \ { \ if (inNumSamples) { \ float x = DEMANDINPUT_A(0, inNumSamples); \ OUT0(0) = sc_isnan(x) ? NAN : function(x); \ } else { \ RESETINPUT(0); \ } \ } template inline F sc_invert(F x) { return -x; } DEFINE_UNARY_OP_FUNCS(invert, sc_invert) #ifdef NOVA_SIMD FLATTEN void invert_nova(UnaryOpUGen *unit, int inNumSamples) { nova::minus_vec_simd(OUT(0), 0.f, IN(0), inNumSamples); } FLATTEN void invert_nova_64(UnaryOpUGen *unit, int inNumSamples) { nova::minus_vec_simd<64>(OUT(0), 0.f, IN(0)); } #endif template inline F sc_not(F x) { return x > 0.f ? 0.f : 1.f; } DEFINE_UNARY_OP_FUNCS(not, sc_not) void zero_a(UnaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); ZClear(inNumSamples, out); } void thru_a(UnaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); ZCopy(inNumSamples, out, a); } DEFINE_UNARY_OP_FUNCS(abs, std::abs) #ifdef NOVA_SIMD FLATTEN void zero_nova(UnaryOpUGen *unit, int inNumSamples) { nova::zerovec_simd(OUT(0), inNumSamples); } FLATTEN void zero_nova_64(UnaryOpUGen *unit, int inNumSamples) { nova::zerovec_simd<64>(OUT(0)); } FLATTEN void thru_nova(UnaryOpUGen *unit, int inNumSamples) { nova::copyvec_simd(OUT(0), IN(0), inNumSamples); } FLATTEN void thru_nova_64(UnaryOpUGen *unit, int inNumSamples) { nova::copyvec_simd<64>(OUT(0), IN(0)); } FLATTEN void abs_nova(UnaryOpUGen *unit, int inNumSamples) { nova::abs_vec_simd(OUT(0), IN(0), inNumSamples); } FLATTEN void abs_nova_64(UnaryOpUGen *unit, int inNumSamples) { nova::abs_vec_simd<64>(OUT(0), IN(0)); } #endif DEFINE_UNARY_OP_FUNCS(recip, sc_reciprocal) #ifdef NOVA_SIMD FLATTEN void recip_nova(UnaryOpUGen *unit, int inNumSamples) { nova::reciprocal_vec_simd(OUT(0), IN(0), inNumSamples); } FLATTEN void recip_nova_64(UnaryOpUGen *unit, int inNumSamples) { nova::reciprocal_vec_simd<64>(OUT(0), IN(0)); } #endif DEFINE_UNARY_OP_FUNCS(floor, floor) DEFINE_UNARY_OP_FUNCS(ceil, ceil) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(floor, floor) NOVA_WRAPPER_CT_UNROLL(ceil, ceil) #endif DEFINE_UNARY_OP_FUNCS(sin, sin) DEFINE_UNARY_OP_FUNCS(cos, cos) DEFINE_UNARY_OP_FUNCS(tan, tan) DEFINE_UNARY_OP_FUNCS(asin, asin) DEFINE_UNARY_OP_FUNCS(acos, acos) DEFINE_UNARY_OP_FUNCS(atan, atan) DEFINE_UNARY_OP_FUNCS(sinh, sinh) DEFINE_UNARY_OP_FUNCS(cosh, cosh) DEFINE_UNARY_OP_FUNCS(tanh, tanh) #ifdef NOVA_SIMD NOVA_WRAPPER(sin, sin) NOVA_WRAPPER(cos, cos) NOVA_WRAPPER(tan, tan) NOVA_WRAPPER(asin, asin) NOVA_WRAPPER(acos, acos) NOVA_WRAPPER(atan, atan) NOVA_WRAPPER(tanh, tanh) #endif DEFINE_UNARY_OP_FUNCS(log, std::log) DEFINE_UNARY_OP_FUNCS(log2, sc_log2) DEFINE_UNARY_OP_FUNCS(log10, sc_log10) DEFINE_UNARY_OP_FUNCS(exp, exp) #ifdef NOVA_SIMD NOVA_WRAPPER(log, log) NOVA_WRAPPER(log2, log2) NOVA_WRAPPER(log10, log10) NOVA_WRAPPER(exp, exp) #endif DEFINE_UNARY_OP_FUNCS(sqrt, sc_sqrt) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(sqrt, signed_sqrt) #endif DEFINE_UNARY_OP_FUNCS(ampdb, sc_ampdb) DEFINE_UNARY_OP_FUNCS(dbamp, sc_dbamp) DEFINE_UNARY_OP_FUNCS(midicps, sc_midicps) DEFINE_UNARY_OP_FUNCS(cpsmidi, sc_cpsmidi) DEFINE_UNARY_OP_FUNCS(midiratio, sc_midiratio) DEFINE_UNARY_OP_FUNCS(ratiomidi, sc_ratiomidi) DEFINE_UNARY_OP_FUNCS(cpsoct, sc_cpsoct) DEFINE_UNARY_OP_FUNCS(octcps, sc_octcps) #ifdef NOVA_SIMD NOVA_WRAPPER(ampdb, amp2db) NOVA_WRAPPER(dbamp, db2amp) NOVA_WRAPPER(midicps, midi2freq) NOVA_WRAPPER(cpsmidi, freq2midi) NOVA_WRAPPER(midiratio, midi2ratio) NOVA_WRAPPER(ratiomidi, ratio2midi) NOVA_WRAPPER(cpsoct, freq2oct) NOVA_WRAPPER(octcps, oct2freq) #endif DEFINE_UNARY_OP_FUNCS(frac, sc_frac) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(frac, frac) #endif DEFINE_UNARY_OP_FUNCS(squared, sc_squared) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(squared, square) #endif DEFINE_UNARY_OP_FUNCS(cubed, sc_cubed) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(cubed, cube) #endif DEFINE_UNARY_OP_FUNCS(sign, sc_sign) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(sign, sgn) #endif DEFINE_UNARY_OP_FUNCS(distort, sc_distort) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(distort, distort) #endif DEFINE_UNARY_OP_FUNCS(distortneg, sc_distortneg) DEFINE_UNARY_OP_FUNCS(softclip, sc_softclip) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(softclip, softclip) #endif DEFINE_UNARY_OP_FUNCS(rectwindow, sc_rectwindow) DEFINE_UNARY_OP_FUNCS(hanwindow, sc_hanwindow) DEFINE_UNARY_OP_FUNCS(welwindow, sc_welwindow) DEFINE_UNARY_OP_FUNCS(triwindow, sc_triwindow) DEFINE_UNARY_OP_FUNCS(scurve, sc_scurve) #ifdef NOVA_SIMD NOVA_WRAPPER_CT_UNROLL(scurve, scurve) #endif DEFINE_UNARY_OP_FUNCS(ramp, sc_ramp) #ifdef NOVA_SIMD FLATTEN void ramp_nova(UnaryOpUGen *unit, int inNumSamples) { nova::clip_vec_simd(OUT(0), wrap_argument(IN(0)), wrap_argument(0.f), wrap_argument(1.f), inNumSamples); } FLATTEN void ramp_nova_64(UnaryOpUGen *unit, int inNumSamples) { nova::clip_vec_simd<64>(OUT(0), wrap_argument(IN(0)), wrap_argument(0.f), wrap_argument(1.f)); } #endif //////////////////////////////////////////////////////////////////////////////////////////////////////// void zero_d(UnaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float x = DEMANDINPUT_A(0, inNumSamples); OUT0(0) = sc_isnan(x) ? NAN : 0.f; } else { RESETINPUT(0); } } void thru_d(UnaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float x = DEMANDINPUT_A(0, inNumSamples); OUT0(0) = sc_isnan(x) ? NAN : (x); } else { RESETINPUT(0); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// #define DEFINE_UNARY_OP_RANDOM_FUNCS(name, function) \ extern "C" void name##_a(UnaryOpUGen *unit, int inNumSamples) \ { \ float *out = ZOUT(0); \ float *a = ZIN(0); \ RGen& rgen = *unit->mParent->mRGen; \ LOOP1(inNumSamples, \ ZXP(out) = rgen.function() * ZXP(a); \ ); \ } \ \ extern "C" void name##_1(UnaryOpUGen *unit, int inNumSamples) \ { \ RGen& rgen = *unit->mParent->mRGen; \ ZOUT0(0) = rgen.function() * ZIN0(0); \ } \ \ extern "C" void name##_d(UnaryOpUGen *unit, int inNumSamples) \ { \ if (inNumSamples) { \ float x = DEMANDINPUT_A(0, inNumSamples); \ RGen& rgen = *unit->mParent->mRGen; \ OUT0(0) = sc_isnan(x) ? NAN : (rgen.function() * x); \ } else { \ RESETINPUT(0); \ } \ } DEFINE_UNARY_OP_RANDOM_FUNCS(rand, frand); DEFINE_UNARY_OP_RANDOM_FUNCS(rand2, frand2); DEFINE_UNARY_OP_RANDOM_FUNCS(linrand, flinrand); DEFINE_UNARY_OP_RANDOM_FUNCS(bilinrand, fbilinrand); DEFINE_UNARY_OP_RANDOM_FUNCS(sum3rand, fsum3rand); void coin_a(UnaryOpUGen *unit, int inNumSamples) { float *out = ZOUT(0); float *a = ZIN(0); RGen& rgen = *unit->mParent->mRGen; LOOP1(inNumSamples, ZXP(out) = (rgen.frand() < ZXP(a)) ? 1.f : 0.f; ); } void coin_1(UnaryOpUGen *unit, int inNumSamples) { RGen& rgen = *unit->mParent->mRGen; float x = ZIN0(0); ZOUT0(0) = (rgen.frand() < x) ? 1.f : 0.f; } void coin_d(UnaryOpUGen *unit, int inNumSamples) { if (inNumSamples) { float x = DEMANDINPUT_A(0, inNumSamples); RGen& rgen = *unit->mParent->mRGen; float val = (rgen.frand() < x) ? 1.f : 0.f; OUT0(0) = sc_isnan(x) ? NAN : val; } else { RESETINPUT(0); } } //////////////////////////////////////////////////////////////////////////////////////////////////////// static UnaryOpFunc ChooseNormalFunc(UnaryOpUGen *unit) { void (*func)(UnaryOpUGen *unit, int inNumSamples); switch (unit->mSpecialIndex) { case opSilence : func = &zero_a; break; case opThru : func = &thru_a; break; case opNeg : func = &invert_a; break; case opNot : func = ¬_a; break; case opAbs : func = &abs_a; break; case opCeil : func = &ceil_a; break; case opFloor : func = &floor_a; break; case opFrac : func = &frac_a; break; case opSign : func = &sign_a; break; case opSquared : func = &squared_a; break; case opCubed : func = &cubed_a; break; case opSqrt : func = &sqrt_a; break; case opExp : func = &exp_a; break; case opRecip : func = &recip_a; break; case opMIDICPS : func = &midicps_a; break; case opCPSMIDI : func = &cpsmidi_a; break; case opMIDIRatio : func = &midiratio_a; break; case opRatioMIDI : func = &ratiomidi_a; break; case opDbAmp : func = &dbamp_a; break; case opAmpDb : func = &db_a; break; case opOctCPS : func = &octcps_a; break; case opCPSOct : func = &cpsoct_a; break; case opLog : func = &log_a; break; case opLog2 : func = &log2_a; break; case opLog10 : func = &log10_a; break; case opSin : func = &sin_a; break; case opCos : func = &cos_a; break; case opTan : func = &tan_a; break; case opArcSin : func = &asin_a; break; case opArcCos : func = &acos_a; break; case opArcTan : func = &atan_a; break; case opSinH : func = &sinh_a; break; case opCosH : func = &cosh_a; break; case opTanH : func = &tanh_a; break; case opRand : func = &rand_a; break; case opRand2 : func = &rand2_a; break; case opLinRand : func = &linrand_a; break; case opBiLinRand : func = &bilinrand_a; break; case opSum3Rand : func = &sum3rand_a; break; case opCoin : func = &coin_a; break; case opDistort : func = &distort_a; break; case opSoftClip : func = &softclip_a; break; case opRectWindow : func = &rectwindow_a; break; case opHanWindow : func = &hanwindow_a; break; case opWelchWindow : func = &welwindow_a; break; case opTriWindow : func = &triwindow_a; break; case opSCurve : func = &scurve_a; break; case opRamp : func = &ramp_a; break; default : func = &thru_a; break; } return func; } static UnaryOpFunc ChooseOneFunc(UnaryOpUGen *unit) { void (*func)(UnaryOpUGen *unit, int inNumSamples); switch (unit->mSpecialIndex) { case opSilence : func = &zero_a; break; case opThru : func = &thru_a; break; case opNeg : func = &invert_1; break; case opNot : func = ¬_1; break; case opAbs : func = &abs_1; break; case opCeil : func = &ceil_1; break; case opFloor : func = &floor_1; break; case opFrac : func = &frac_1; break; case opSign : func = &sign_1; break; case opSquared : func = &squared_1; break; case opCubed : func = &cubed_1; break; case opSqrt : func = &sqrt_1; break; case opExp : func = &exp_1; break; case opRecip : func = &recip_1; break; case opMIDICPS : func = &midicps_1; break; case opCPSMIDI : func = &cpsmidi_1; break; case opMIDIRatio : func = &midiratio_1; break; case opRatioMIDI : func = &ratiomidi_1; break; case opDbAmp : func = &dbamp_1; break; case opAmpDb : func = &db_1; break; case opOctCPS : func = &octcps_1; break; case opCPSOct : func = &cpsoct_1; break; case opLog : func = &log_1; break; case opLog2 : func = &log2_1; break; case opLog10 : func = &log10_1; break; case opSin : func = &sin_1; break; case opCos : func = &cos_1; break; case opTan : func = &tan_1; break; case opArcSin : func = &asin_1; break; case opArcCos : func = &acos_1; break; case opArcTan : func = &atan_1; break; case opSinH : func = &sinh_1; break; case opCosH : func = &cosh_1; break; case opTanH : func = &tanh_1; break; case opRand : func = &rand_1; break; case opRand2 : func = &rand2_1; break; case opLinRand : func = &linrand_1; break; case opBiLinRand : func = &bilinrand_1; break; case opSum3Rand : func = &sum3rand_1; break; case opCoin : func = &coin_1; break; case opDistort : func = &distort_1; break; case opSoftClip : func = &softclip_1; break; case opRectWindow : func = &rectwindow_1; break; case opHanWindow : func = &hanwindow_1; break; case opWelchWindow : func = &welwindow_1; break; case opTriWindow : func = &triwindow_1; break; case opSCurve : func = &scurve_1; break; case opRamp : func = &ramp_1; break; default : func = &thru_a; break; } return func; } static UnaryOpFunc ChooseDemandFunc(UnaryOpUGen *unit) { void (*func)(UnaryOpUGen *unit, int inNumSamples); switch (unit->mSpecialIndex) { case opSilence : func = &zero_d; break; case opThru : func = &thru_d; break; case opNeg : func = &invert_d; break; case opNot : func = ¬_d; break; case opAbs : func = &abs_d; break; case opCeil : func = &ceil_d; break; case opFloor : func = &floor_d; break; case opFrac : func = &frac_d; break; case opSign : func = &sign_d; break; case opSquared : func = &squared_d; break; case opCubed : func = &cubed_d; break; case opSqrt : func = &sqrt_d; break; case opExp : func = &exp_d; break; case opRecip : func = &recip_d; break; case opMIDICPS : func = &midicps_d; break; case opCPSMIDI : func = &cpsmidi_d; break; case opMIDIRatio : func = &midiratio_d; break; case opRatioMIDI : func = &ratiomidi_d; break; case opDbAmp : func = &dbamp_d; break; case opAmpDb : func = &db_d; break; case opOctCPS : func = &octcps_d; break; case opCPSOct : func = &cpsoct_d; break; case opLog : func = &log_d; break; case opLog2 : func = &log2_d; break; case opLog10 : func = &log10_d; break; case opSin : func = &sin_d; break; case opCos : func = &cos_d; break; case opTan : func = &tan_d; break; case opArcSin : func = &asin_d; break; case opArcCos : func = &acos_d; break; case opArcTan : func = &atan_d; break; case opSinH : func = &sinh_d; break; case opCosH : func = &cosh_d; break; case opTanH : func = &tanh_d; break; case opRand : func = &rand_d; break; case opRand2 : func = &rand2_d; break; case opLinRand : func = &linrand_d; break; case opBiLinRand : func = &bilinrand_d; break; case opSum3Rand : func = &sum3rand_d; break; case opCoin : func = &coin_d; break; case opDistort : func = &distort_d; break; case opSoftClip : func = &softclip_d; break; case opRectWindow : func = &rectwindow_d; break; case opHanWindow : func = &hanwindow_d; break; case opWelchWindow : func = &welwindow_d; break; case opTriWindow : func = &triwindow_d; break; case opSCurve : func = &scurve_d; break; case opRamp : func = &ramp_d; break; default : func = &thru_d; break; } return func; } #ifdef NOVA_SIMD static UnaryOpFunc ChooseNovaSimdFunc(UnaryOpUGen *unit) { void (*func)(UnaryOpUGen *unit, int inNumSamples); if (BUFLENGTH == 64) { switch (unit->mSpecialIndex) { case opSilence : return &zero_nova_64; case opThru : func = &thru_nova; break; case opNeg : return &invert_nova_64; case opNot : func = ¬_a; break; case opAbs : return &abs_nova_64; case opCeil : func = &ceil_nova_64; break; case opFloor : func = &floor_nova_64; break; case opFrac : func = &frac_nova_64; break; case opSign : return &sign_nova_64; case opSquared : return &squared_nova_64; case opCubed : return &cubed_nova_64; case opSqrt : func = &sqrt_nova_64; break; case opExp : func = &exp_nova; break; case opRecip : return &recip_nova_64; case opMIDICPS : func = &midicps_nova; break; case opCPSMIDI : func = &cpsmidi_nova; break; case opMIDIRatio : func = &midiratio_nova; break; case opRatioMIDI : func = &ratiomidi_nova; break; case opDbAmp : func = &dbamp_nova; break; case opAmpDb : func = &db_nova; break; case opOctCPS : func = &octcps_nova; break; case opCPSOct : func = &cpsoct_nova; break; case opLog : func = &log_nova; break; case opLog2 : func = &log2_nova; break; case opLog10 : func = &log10_nova; break; case opSin : func = &sin_nova; break; case opCos : func = &cos_nova; break; case opTan : func = &tan_nova; break; case opArcSin : func = &asin_nova; break; case opArcCos : func = &acos_nova; break; case opArcTan : func = &atan_nova; break; case opSinH : func = &sinh_a; break; case opCosH : func = &cosh_a; break; case opTanH : func = &tanh_nova; break; case opRand : func = &rand_a; break; case opRand2 : func = &rand2_a; break; case opLinRand : func = &linrand_a; break; case opBiLinRand : func = &bilinrand_a; break; case opSum3Rand : func = &sum3rand_a; break; case opCoin : func = &coin_a; break; case opDistort : func = &distort_nova_64; break; case opSoftClip : func = &softclip_nova_64; break; case opRectWindow : func = &rectwindow_a; break; case opHanWindow : func = &hanwindow_a; break; case opWelchWindow : func = &welwindow_a; break; case opTriWindow : func = &triwindow_a; break; case opSCurve : func = &scurve_nova_64; break; case opRamp : return &ramp_nova_64; default : return &thru_nova_64; } return func; } switch (unit->mSpecialIndex) { case opSilence : func = &zero_nova; break; case opThru : func = &thru_nova; break; case opNeg : func = &invert_nova; break; case opNot : func = ¬_a; break; case opAbs : func = &abs_nova; break; case opCeil : func = &ceil_nova; break; case opFloor : func = &floor_nova; break; case opFrac : func = &frac_nova; break; case opSign : func = &sign_nova; break; case opSquared : func = &squared_nova; break; case opCubed : func = &cubed_nova; break; case opSqrt : func = &sqrt_nova; break; case opExp : func = &exp_nova; break; case opRecip : func = &recip_nova; break; case opMIDICPS : func = &midicps_nova; break; case opCPSMIDI : func = &cpsmidi_nova; break; case opMIDIRatio : func = &midiratio_nova; break; case opRatioMIDI : func = &ratiomidi_nova; break; case opDbAmp : func = &dbamp_nova; break; case opAmpDb : func = &db_nova; break; case opOctCPS : func = &octcps_nova; break; case opCPSOct : func = &cpsoct_nova; break; case opLog : func = &log_nova; break; case opLog2 : func = &log2_nova; break; case opLog10 : func = &log10_nova; break; case opSin : func = &sin_nova; break; case opCos : func = &cos_nova; break; case opTan : func = &tan_nova; break; case opArcSin : func = &asin_nova; break; case opArcCos : func = &acos_nova; break; case opArcTan : func = &atan_nova; break; case opSinH : func = &sinh_a; break; case opCosH : func = &cosh_a; break; case opTanH : func = &tanh_nova; break; case opRand : func = &rand_a; break; case opRand2 : func = &rand2_a; break; case opLinRand : func = &linrand_a; break; case opBiLinRand : func = &bilinrand_a; break; case opSum3Rand : func = &sum3rand_a; break; case opCoin : func = &coin_a; break; case opDistort : func = &distort_nova; break; case opSoftClip : func = &softclip_nova; break; case opRectWindow : func = &rectwindow_a; break; case opHanWindow : func = &hanwindow_a; break; case opWelchWindow : func = &welwindow_a; break; case opTriWindow : func = &triwindow_a; break; case opSCurve : func = &scurve_nova; break; case opRamp : func = &ramp_nova; break; default : func = &thru_nova; break; } return func; } #endif bool ChooseOperatorFunc(UnaryOpUGen *unit) { //Print("->ChooseOperatorFunc %d\n", unit->mSpecialIndex); UnaryOpFunc func; bool ret = false; if (unit->mCalcRate == calc_DemandRate) { func = ChooseDemandFunc(unit); } else if (BUFLENGTH == 1) { func = ChooseOneFunc(unit); #if defined(NOVA_SIMD) } else if (boost::alignment::is_aligned( BUFLENGTH, 16 )) { /* select normal function for initialization */ func = ChooseNormalFunc(unit); func(unit, 1); /* select simd function */ func = ChooseNovaSimdFunc(unit); ret = true; #endif } else { func = ChooseNormalFunc(unit); } unit->mCalcFunc = (UnitCalcFunc)func; //Print("<-ChooseOperatorFunc %p\n", func); //Print("calc %d\n", unit->mCalcRate); return ret; } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(UnaryOp) { ft = inTable; DefineSimpleUnit(UnaryOpUGen); } SuperCollider-Source/server/plugins/UnpackFFTUGens.cpp000644 000765 000024 00000021643 12321461511 024075 0ustar00crucialstaff000000 000000 /* "Unpack FFT" UGens for SuperCollider 3. Copyright (c) 2007 Dan Stowell. All rights reserved. (Written during the SC Symposium 2007! Thanks to all whose conversation fed into this.) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "SC_PlugIn.h" #include "SCComplex.h" #include "FFT_UGens.h" struct Unpack1FFT : Unit { int bufsize; int latestMomentProcessed; // To avoid processing a given FFT frame more than once int binindex; bool wantmag; // yes for mag, no for phase float outval; //int numOldSkipped; // for debug }; struct PackFFT : Unit { int bufsize, numinvals, frombin, tobin; bool zeroothers; }; ////////////////////////////////////////////////////////////////////////////////////////////////// extern "C" { void Unpack1FFT_Ctor(Unpack1FFT *unit); void Unpack1FFT_next_dc(Unpack1FFT *unit, int inNumSamples); void Unpack1FFT_next_nyq(Unpack1FFT *unit, int inNumSamples); void Unpack1FFT_next_mag(Unpack1FFT *unit, int inNumSamples); void Unpack1FFT_next_phase(Unpack1FFT *unit, int inNumSamples); void PackFFT_Ctor(PackFFT *unit); void PackFFT_Dtor(PackFFT *unit); void PackFFT_next(PackFFT *unit, int inNumSamples); } InterfaceTable *ft; //////////////////////////////////////////////////////////////////////////////////////////////////////// void Unpack1FFT_Ctor(Unpack1FFT* unit) { unit->bufsize = (int)ZIN0(1); unit->latestMomentProcessed = -1; //unit->numOldSkipped = 0; unit->outval = 0.f; unit->binindex = (int)ZIN0(2); if(ZIN0(3) == 0.f){ // Mags if(unit->binindex == 0){ SETCALC(Unpack1FFT_next_dc); }else if(unit->binindex == unit->bufsize >> 1){ SETCALC(Unpack1FFT_next_nyq); } else { SETCALC(Unpack1FFT_next_mag); } }else{ // Phases if(unit->binindex == 0){ SETCALC(*ClearUnitOutputs); }else if(unit->binindex == unit->bufsize >> 1){ SETCALC(*ClearUnitOutputs); } else { SETCALC(Unpack1FFT_next_phase); } } } #define UNPACK1FFT_NEXT_COMMON float fbufnum = ZIN0(0); \ if (fbufnum < 0.f) { \ if(unit->mWorld->mVerbosity > -1){ \ Print("Unpack1FFT_next: warning, fbufnum < 0\n"); \ } \ ZOUT0(0) = unit->outval; \ return; \ } \ uint32 ibufnum = (uint32)fbufnum; \ World *world = unit->mWorld; \ SndBuf *buf; \ if (ibufnum >= world->mNumSndBufs) { \ int localBufNum = ibufnum - world->mNumSndBufs; \ Graph *parent = unit->mParent; \ if(localBufNum <= parent->localBufNum) { \ buf = parent->mLocalSndBufs + localBufNum; \ } else { \ buf = world->mSndBufs; \ if(unit->mWorld->mVerbosity > -1){ \ Print("Unpack1FFT_next: warning, bufnum too large: i%\n", ibufnum); \ } \ } \ } else { \ buf = world->mSndBufs + ibufnum; \ } \ int binindex __attribute__((__unused__)) = unit->binindex; \ LOCK_SNDBUF(buf); \ SCComplexBuf *p = ToComplexApx(buf); \ void Unpack1FFT_next_mag(Unpack1FFT *unit, int inNumSamples) { if(unit->latestMomentProcessed != unit->mWorld->mBufCounter){ UNPACK1FFT_NEXT_COMMON unit->outval = hypotf(p->bin[binindex-1].real, p->bin[binindex-1].imag); unit->latestMomentProcessed = unit->mWorld->mBufCounter; // So we won't copy it again, not this frame anyway //unit->numOldSkipped = 0; //}else{ //Print("skipold{%i,%i}", unit->mWorld->mBufCounter, ++unit->numOldSkipped); //Print("Calculation previously done - skipping. unit->mWorld->mBufCounter = %i\n", unit->mWorld->mBufCounter); } ZOUT0(0) = unit->outval; } void Unpack1FFT_next_phase(Unpack1FFT *unit, int inNumSamples) { if(unit->latestMomentProcessed != unit->mWorld->mBufCounter){ UNPACK1FFT_NEXT_COMMON unit->outval = atan2(p->bin[binindex-1].imag, p->bin[binindex-1].real); unit->latestMomentProcessed = unit->mWorld->mBufCounter; // So we won't copy it again, not this frame anyway //unit->numOldSkipped = 0; //}else{ //Print("skipold{%i,%i}", unit->mWorld->mBufCounter, ++unit->numOldSkipped); //Print("Calculation previously done - skipping. unit->mWorld->mBufCounter = %i\n", unit->mWorld->mBufCounter); } ZOUT0(0) = unit->outval; } void Unpack1FFT_next_dc(Unpack1FFT *unit, int inNumSamples) { if(unit->latestMomentProcessed != unit->mWorld->mBufCounter){ UNPACK1FFT_NEXT_COMMON unit->outval = p->dc; unit->latestMomentProcessed = unit->mWorld->mBufCounter; // So we won't copy it again, not this frame anyway //unit->numOldSkipped = 0; //}else{ //Print("skipold{%i,%i}", unit->mWorld->mBufCounter, ++unit->numOldSkipped); //Print("Calculation previously done - skipping. unit->mWorld->mBufCounter = %i\n", unit->mWorld->mBufCounter); } ZOUT0(0) = unit->outval; } void Unpack1FFT_next_nyq(Unpack1FFT *unit, int inNumSamples) { if(unit->latestMomentProcessed != unit->mWorld->mBufCounter){ UNPACK1FFT_NEXT_COMMON unit->outval = p->nyq; unit->latestMomentProcessed = unit->mWorld->mBufCounter; // So we won't copy it again, not this frame anyway //unit->numOldSkipped = 0; //}else{ //Print("skipold{%i,%i}", unit->mWorld->mBufCounter, ++unit->numOldSkipped); //Print("Calculation previously done - skipping. unit->mWorld->mBufCounter = %i\n", unit->mWorld->mBufCounter); } ZOUT0(0) = unit->outval; } //////////////////////////////////////////////////////////////////////////////////////////////////////// void PackFFT_Ctor(PackFFT* unit) { SETCALC(PackFFT_next); unit->bufsize = (int)ZIN0(1); unit->frombin = (int)ZIN0(2); unit->tobin = (int)ZIN0(3); unit->zeroothers = ZIN0(4) > 0; unit->numinvals = (int)ZIN0(5); // Print("PackFFT_Ctor: Passing chain through, val %g\n", ZIN0(0)); ZOUT0(0) = ZIN0(0); // Required: allows the buffer index to fall through nicely to the IFFT } #define PACKFFT_INPUTSOFFSET 6 void PackFFT_next(PackFFT *unit, int inNumSamples) { /////////////////// cf PV_GET_BUF float fbufnum = ZIN0(0); if (fbufnum < 0.f) { ZOUT0(0) = -1.f; return; } uint32 ibufnum = (uint32)fbufnum; World *world = unit->mWorld; SndBuf *buf; if (ibufnum >= world->mNumSndBufs) { int localBufNum = ibufnum - world->mNumSndBufs; Graph *parent = unit->mParent; if(localBufNum <= parent->localBufNum) { buf = parent->mLocalSndBufs + localBufNum; } else { buf = world->mSndBufs; } } else { buf = world->mSndBufs + ibufnum; } LOCK_SNDBUF(buf); int numbins = (buf->samples - 2) >> 1; /////////////////// cf PV_GET_BUF //RM Print("PackFFT_next: fbufnum = %g\n", fbufnum); int numinvals = unit->numinvals; SCComplexBuf *p = ToComplexApx(buf); int frombin = unit->frombin; int tobin = unit->tobin; int zeroothers = unit->zeroothers; // Load data from inputs into "p" if(frombin==0){ p->dc = DEMANDINPUT(PACKFFT_INPUTSOFFSET); }else if(zeroothers){ p->dc = 0.f; } //Print("New DC is %g\n", p->dc); if(tobin == numbins + 1){ //Print("PackFFT: Fetching nyquist from input #%i\n", (PACKFFT_INPUTSOFFSET + numinvals - 2 - frombin - frombin)); p->nyq = DEMANDINPUT(PACKFFT_INPUTSOFFSET + numinvals - 2 - frombin - frombin); }else if(zeroothers){ p->nyq = 0.f; } //Print("New nyq (input #%i) is %g\n", numinvals, p->nyq); // real, imag = (mag * cos(phase), mag * sin(phase)) float mag, phase; int startat = frombin==0 ? 0 : frombin-1; int endbefore = sc_min(numbins, tobin); for(int i = startat; i < endbefore; i++){ //Print("PackFFT: Fetching mag from input #%i\n", (i + i + PACKFFT_INPUTSOFFSET + 2 - frombin - frombin)); mag = DEMANDINPUT(i + i + PACKFFT_INPUTSOFFSET + 2 - frombin - frombin); phase = DEMANDINPUT(i + i + PACKFFT_INPUTSOFFSET + 3 - frombin - frombin); p->bin[i].real = mag * cos(phase); p->bin[i].imag = mag * sin(phase); } //Print("New bin 7 is %g,%g\n", p->bin[7].real, p->bin[7].imag); if(zeroothers){ // Iterate through the ones we didn't fill in, wiping the magnitude for(int i=0; ibin[i].real = p->bin[i].imag = 0.f; for(int i=endbefore; ibin[i].real = p->bin[i].imag = 0.f; } ZOUT0(0) = fbufnum; //Print("PackFFT: fbufnum=%g, ibufnum=%i, numinvals=%i, frombin=%i, tobin=%i, zeroothers=%i\n", // fbufnum, ibufnum, numinvals, frombin, tobin, zeroothers); //Print("PackFFT: p->bin[4].real=%g, p->bin[4].imag=%g, p->bin[5].real=%g, p->bin[5].imag=%g\n", // p->bin[4].real, p->bin[4].imag, p->bin[5].real, p->bin[5].imag); } //////////////////////////////////////////////////////////////////////////////////////////////////////// PluginLoad(UnpackFFTUGens) { ft= inTable; DefineSimpleUnit(Unpack1FFT); DefineSimpleUnit(PackFFT); } SuperCollider-Source/SCDoc/build_parser.sh000755 000765 000024 00000000272 12321461510 021616 0ustar00crucialstaff000000 000000 #!/bin/sh flex -P scdoc -o lex.scdoc.cpp SCDoc.l && bison -p scdoc --defines -o SCDoc.tab.cpp SCDoc.y #g++ -g -O3 -o scdoc_parse_dump lex.scdoc.cpp SCDoc.tab.cpp SCDoc.cpp main.cpp -ll SuperCollider-Source/SCDoc/CMakeLists.txt000644 000765 000024 00000000704 12524671172 021360 0ustar00crucialstaff000000 000000 set(SCDOC_DIR ${CMAKE_SOURCE_DIR}/SCDoc) set(SCDOC_SRCS ${SCDOC_DIR}/SCDoc.cpp ${SCDOC_DIR}/SCDoc.h ${SCDOC_DIR}/SCDoc.tab.cpp ${SCDOC_DIR}/lex.scdoc.cpp ${SCDOC_DIR}/SCDocPrim.cpp ${SCDOC_DIR}/SCDocPrim.h ) if(CMAKE_COMPILER_IS_CLANG) set_source_files_properties( ${SCDOC_DIR}/lex.scdoc.cpp PROPERTIES COMPILE_FLAGS "-Wno-deprecated-register -Wno-null-conversion") endif() include_directories( ${SCDOC_DIR} ) SuperCollider-Source/SCDoc/lex.scdoc.cpp000644 000765 000024 00000404441 12756531745 021224 0ustar00crucialstaff000000 000000 #line 2 "lex.scdoc.cpp" #line 4 "lex.scdoc.cpp" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex */ #define yy_create_buffer scdoc_create_buffer #define yy_delete_buffer scdoc_delete_buffer #define yy_flex_debug scdoc_flex_debug #define yy_init_buffer scdoc_init_buffer #define yy_flush_buffer scdoc_flush_buffer #define yy_load_buffer_state scdoc_load_buffer_state #define yy_switch_to_buffer scdoc_switch_to_buffer #define yyin scdocin #define yyleng scdocleng #define yylex scdoclex #define yylineno scdoclineno #define yyout scdocout #define yyrestart scdocrestart #define yytext scdoctext #define yywrap scdocwrap #define yyalloc scdocalloc #define yyrealloc scdocrealloc #define yyfree scdocfree #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 35 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! C99 */ #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ /* C99 requires __STDC__ to be defined as 1. */ #if defined (__STDC__) #define YY_USE_CONST #endif /* defined (__STDC__) */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE scdocrestart(scdocin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k. * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. * Ditto for the __ia64__ case accordingly. */ #define YY_BUF_SIZE 32768 #else #define YY_BUF_SIZE 16384 #endif /* __ia64__ */ #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int scdocleng; extern FILE *scdocin, *scdocout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Note: We specifically omit the test for yy_rule_can_match_eol because it requires * access to the local variable yy_act. Since yyless() is a macro, it would break * existing scanners that call yyless() from OUTSIDE scdoclex. * One obvious solution it to make yy_act a global. I tried that, and saw * a 5% performance hit in a non-scdoclineno scanner, because yy_act is * normally declared as a register variable-- so it is not worth it. */ #define YY_LESS_LINENO(n) \ do { \ int yyl;\ for ( yyl = n; yyl < scdocleng; ++yyl )\ if ( scdoctext[yyl] == '\n' )\ --scdoclineno;\ }while(0) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up scdoctext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up scdoctext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef size_t yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via scdocrestart()), so that the user can continue scanning by * just pointing scdocin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when scdoctext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int scdocleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow scdocwrap()'s to do buffer switches * instead of setting up a fresh scdocin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void scdocrestart (FILE *input_file ); void scdoc_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE scdoc_create_buffer (FILE *file,int size ); void scdoc_delete_buffer (YY_BUFFER_STATE b ); void scdoc_flush_buffer (YY_BUFFER_STATE b ); void scdocpush_buffer_state (YY_BUFFER_STATE new_buffer ); void scdocpop_buffer_state (void ); static void scdocensure_buffer_stack (void ); static void scdoc_load_buffer_state (void ); static void scdoc_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER scdoc_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE scdoc_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE scdoc_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE scdoc_scan_bytes (yyconst char *bytes,int len ); void *scdocalloc (yy_size_t ); void *scdocrealloc (void *,yy_size_t ); void scdocfree (void * ); #define yy_new_buffer scdoc_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ scdocensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ scdoc_create_buffer(scdocin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ scdocensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ scdoc_create_buffer(scdocin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) /* Begin user sect3 */ #define scdocwrap(n) 1 #define YY_SKIP_YYWRAP typedef unsigned char YY_CHAR; FILE *scdocin = (FILE *) 0, *scdocout = (FILE *) 0; typedef int yy_state_type; extern int scdoclineno; int scdoclineno = 1; extern char *scdoctext; #define yytext_ptr scdoctext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up scdoctext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ scdocleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 103 #define YY_END_OF_BUFFER 104 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[1235] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 64, 53, 46, 54, 62, 64, 48, 65, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 65, 64, 63, 52, 45, 65, 62, 65, 52, 44, 54, 65, 87, 87, 83, 54, 84, 86, 88, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 88, 102, 102, 54, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 54, 102, 102, 60, 58, 59, 54, 56, 60, 48, 56, 53, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 62, 43, 48, 39, 0, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 0, 0, 0, 42, 63, 45, 62, 0, 0, 0, 0, 87, 87, 84, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 84, 86, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 58, 58, 56, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 50, 51, 49, 42, 40, 0, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 41, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 61, 61, 61, 61, 0, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 0, 0, 61, 0, 61, 61, 61, 61, 61, 61, 0, 61, 61, 61, 61, 61, 61, 0, 61, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 61, 61, 0, 61, 61, 35, 61, 61, 61, 61, 61, 61, 61, 0, 61, 61, 29, 21, 61, 28, 61, 61, 61, 61, 61, 61, 32, 61, 61, 61, 0, 61, 0, 22, 61, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 0, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 61, 1, 61, 61, 35, 37, 61, 61, 61, 61, 61, 61, 61, 31, 61, 61, 29, 21, 0, 28, 61, 61, 61, 61, 61, 61, 32, 0, 61, 61, 25, 61, 2, 22, 61, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 66, 85, 85, 85, 85, 85, 85, 85, 0, 85, 85, 85, 85, 85, 85, 67, 0, 0, 0, 0, 0, 0, 96, 98, 0, 0, 0, 0, 92, 0, 0, 90, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 61, 61, 1, 61, 61, 61, 61, 61, 61, 61, 61, 61, 31, 61, 0, 13, 61, 0, 61, 0, 0, 0, 33, 61, 0, 25, 61, 2, 0, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 66, 85, 85, 85, 85, 85, 85, 0, 78, 0, 85, 0, 0, 85, 0, 67, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 92, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 0, 61, 61, 61, 61, 61, 61, 61, 0, 0, 0, 61, 8, 13, 61, 9, 0, 4, 19, 10, 33, 61, 3, 0, 27, 87, 87, 87, 87, 87, 87, 87, 87, 87, 85, 85, 85, 85, 85, 0, 85, 73, 78, 74, 0, 69, 75, 85, 68, 0, 91, 0, 0, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 61, 61, 0, 61, 61, 61, 61, 34, 18, 26, 61, 8, 61, 9, 6, 4, 19, 10, 61, 3, 36, 27, 87, 87, 87, 87, 87, 87, 87, 85, 85, 0, 85, 85, 82, 85, 73, 74, 71, 69, 75, 85, 68, 0, 0, 0, 0, 0, 95, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 61, 7, 0, 61, 61, 0, 34, 18, 26, 61, 61, 6, 0, 36, 38, 87, 87, 87, 87, 87, 87, 0, 85, 72, 0, 85, 82, 85, 71, 0, 0, 0, 0, 95, 0, 97, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 61, 7, 12, 61, 0, 20, 61, 61, 11, 87, 87, 87, 70, 85, 72, 77, 0, 85, 76, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 12, 61, 15, 20, 61, 0, 11, 87, 87, 70, 0, 77, 79, 85, 76, 0, 0, 0, 0, 0, 16, 61, 15, 61, 23, 87, 80, 79, 85, 0, 0, 0, 16, 0, 61, 23, 87, 80, 85, 0, 0, 0, 24, 0, 87, 0, 0, 24, 17, 81, 17, 81, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 6, 7, 8, 1, 9, 9, 7, 10, 11, 9, 9, 12, 9, 7, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 1, 9, 9, 9, 6, 9, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 25, 32, 33, 34, 35, 36, 37, 38, 39, 25, 7, 40, 7, 1, 41, 1, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 51, 58, 59, 60, 61, 62, 63, 64, 65, 51, 7, 66, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[67] = { 0, 1, 2, 3, 3, 2, 1, 1, 1, 1, 4, 4, 5, 1, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 1 } ; static yyconst flex_int16_t yy_base[1243] = { 0, 0, 0, 65, 104, 143, 182, 222, 0, 288, 0, 353, 0, 79, 83, 413, 0, 3900, 3901, 478, 87, 118, 89, 3891, 72, 3883, 97, 3882, 109, 117, 102, 86, 144, 58, 119, 155, 146, 145, 159, 519, 346, 175, 476, 3830, 0, 206, 514, 543, 353, 3880, 3901, 557, 3901, 3901, 0, 596, 3901, 3901, 126, 3880, 3901, 656, 722, 536, 557, 596, 652, 657, 658, 723, 773, 659, 3878, 3901, 833, 3901, 109, 665, 148, 337, 354, 158, 156, 354, 344, 467, 721, 531, 602, 629, 3877, 742, 3901, 581, 3901, 210, 630, 0, 211, 0, 0, 756, 3883, 388, 3875, 456, 756, 544, 457, 470, 472, 523, 526, 550, 738, 542, 589, 656, 781, 595, 3823, 839, 843, 800, 866, 487, 3901, 3875, 3872, 722, 656, 770, 603, 805, 769, 759, 739, 840, 765, 857, 848, 810, 865, 861, 869, 665, 873, 881, 886, 890, 874, 897, 901, 895, 894, 916, 887, 3878, 3870, 3818, 953, 0, 961, 932, 965, 969, 3868, 3867, 0, 0, 586, 959, 771, 822, 898, 913, 915, 920, 957, 961, 958, 835, 3867, 967, 972, 994, 1000, 1010, 1018, 1028, 1038, 1048, 1069, 1070, 1091, 1132, 1086, 3865, 0, 1111, 965, 949, 962, 972, 973, 1001, 1021, 1094, 1086, 1028, 1028, 1063, 1112, 1065, 1099, 1121, 1129, 1117, 1112, 1123, 1120, 1134, 1146, 1143, 1145, 1136, 1153, 1145, 1145, 1198, 3864, 3901, 1206, 3863, 1210, 945, 1184, 3866, 0, 1182, 1172, 1200, 1198, 1198, 1185, 1204, 1193, 1192, 1187, 1194, 1194, 1199, 1206, 1211, 1229, 1218, 1230, 1221, 1212, 1206, 1221, 1236, 1267, 3863, 1260, 1261, 1265, 1262, 1266, 1263, 1264, 1272, 1282, 1276, 1277, 1283, 1286, 1289, 1278, 1292, 1295, 1304, 1315, 1321, 1288, 1318, 1324, 1317, 1322, 1331, 1330, 1336, 1339, 1332, 1342, 1343, 1356, 1348, 3901, 3901, 3901, 1370, 3901, 3860, 1345, 1364, 1350, 1350, 1368, 1354, 1350, 1356, 1368, 1381, 1376, 1384, 1363, 1401, 1403, 1419, 1421, 1425, 1453, 1455, 1473, 1474, 1475, 1505, 1507, 1523, 1524, 1532, 3901, 1467, 1371, 1376, 1394, 1409, 1424, 1411, 1470, 1470, 1466, 1485, 1504, 1505, 1517, 1521, 1509, 1522, 1539, 1523, 1539, 1545, 1551, 1558, 1567, 1562, 3901, 3901, 1555, 1571, 1559, 1573, 1555, 1571, 1578, 1579, 1570, 1566, 1568, 1566, 1570, 1582, 1586, 1590, 1572, 1585, 1595, 1579, 1591, 1594, 1608, 1611, 1619, 1614, 1622, 1614, 0, 1629, 1630, 1632, 1633, 3859, 1635, 1631, 1640, 1641, 1655, 1642, 1646, 1659, 1662, 1666, 3858, 3857, 1673, 3854, 1667, 1675, 1668, 1678, 1679, 1691, 3852, 1680, 1699, 1692, 1701, 1705, 1703, 3850, 1709, 3901, 1690, 1692, 1688, 1710, 1702, 1697, 1695, 1717, 1706, 1719, 1728, 1712, 1715, 1722, 1725, 1755, 1757, 1764, 1777, 1796, 1798, 1815, 1816, 1820, 1847, 1848, 1864, 1865, 1882, 1899, 1735, 1740, 1732, 1741, 1742, 3849, 1751, 1763, 1780, 1767, 1795, 1813, 1804, 3846, 1809, 1828, 1829, 1833, 1860, 3839, 1867, 1877, 1883, 1868, 1893, 1888, 1905, 1897, 3834, 1903, 1903, 1901, 1899, 1905, 1908, 1924, 1913, 3832, 1914, 3830, 1926, 1931, 1916, 1915, 1918, 1927, 1934, 1945, 1944, 1931, 1947, 3826, 1944, 0, 1956, 1963, 1966, 1964, 205, 1969, 1971, 1982, 1967, 1970, 1984, 1986, 3824, 1990, 1993, 985, 1036, 1998, 1451, 1995, 1989, 1987, 2015, 2005, 2016, 1787, 2025, 2021, 2023, 3822, 2013, 3818, 2035, 2029, 2019, 2021, 2028, 2025, 2028, 2046, 2033, 2034, 2050, 2036, 2035, 2046, 2051, 2058, 2055, 2075, 2117, 2083, 2096, 2100, 2134, 2142, 2138, 2151, 2172, 2185, 2190, 2192, 2210, 2234, 3814, 2059, 2066, 2078, 2239, 3813, 2089, 2087, 2081, 2088, 3787, 2093, 2128, 3786, 2178, 2169, 2189, 2193, 2191, 3784, 2208, 2215, 2212, 2212, 3783, 2233, 2225, 2250, 3777, 2237, 2236, 2238, 2236, 2244, 2242, 2245, 2243, 3776, 2261, 3773, 2250, 2251, 2269, 2271, 2263, 2264, 2278, 2270, 3757, 2264, 3751, 3750, 2276, 3718, 2292, 2294, 2064, 2299, 2298, 2322, 2301, 2308, 2317, 2318, 2319, 2321, 2323, 2091, 2322, 2331, 1033, 2360, 3717, 2368, 2329, 2338, 2363, 2340, 2364, 2365, 2384, 3713, 2367, 2375, 2378, 2377, 2383, 2400, 2384, 2365, 2385, 2389, 2386, 2384, 2383, 2383, 2397, 2383, 2398, 2402, 2394, 2407, 2394, 3706, 2430, 3705, 2438, 2437, 2443, 2471, 2462, 2489, 2490, 2495, 2514, 2496, 2520, 2539, 2545, 2547, 3648, 3577, 2390, 3531, 2398, 2429, 2439, 2580, 2440, 2523, 2534, 2544, 3478, 2553, 2559, 1071, 3421, 2568, 2573, 2574, 2567, 2604, 3415, 2565, 2563, 2579, 2582, 2581, 3404, 2595, 2584, 2618, 2584, 2590, 2595, 2594, 2609, 2596, 2613, 2613, 3359, 2613, 2614, 2617, 2619, 2607, 2614, 2611, 2607, 3351, 2616, 3350, 2626, 2418, 2634, 2639, 1090, 2636, 2647, 2673, 3330, 2662, 2664, 2650, 2666, 2665, 2667, 2671, 1427, 2672, 3312, 1647, 2699, 2448, 2703, 2680, 3291, 2694, 3290, 3187, 3156, 2717, 2544, 2708, 3065, 2731, 2722, 1759, 2736, 3060, 2695, 2709, 2698, 2697, 2712, 2724, 2727, 2727, 3059, 2727, 2730, 2730, 2721, 2717, 2713, 2763, 1854, 2764, 2765, 2773, 2798, 2811, 2815, 2832, 3052, 2850, 2856, 2866, 2884, 2891, 2908, 1881, 2710, 2729, 3047, 2738, 2748, 2763, 2761, 3048, 2761, 2763, 2771, 2801, 2116, 2817, 3029, 2177, 3022, 2809, 3018, 2972, 2925, 2968, 2825, 2962, 2830, 2818, 2855, 2850, 2867, 2892, 2868, 2896, 2891, 2907, 2899, 2914, 2916, 2887, 2874, 2920, 2858, 2908, 2841, 2840, 2831, 2919, 2824, 2925, 2797, 2797, 2786, 2933, 2831, 2940, 2934, 2937, 2944, 2951, 2955, 2682, 2668, 2538, 2899, 2958, 2746, 2976, 2957, 2752, 2514, 2975, 2979, 2982, 3000, 2961, 2983, 3004, 2506, 3011, 3005, 2932, 2965, 2994, 2992, 2985, 2988, 3002, 2466, 2461, 2989, 2451, 2432, 3000, 2413, 3012, 3024, 3030, 3036, 3043, 3060, 3078, 3079, 2345, 3025, 2339, 3085, 2324, 2297, 3061, 2243, 3029, 3033, 3023, 3059, 3035, 3048, 3078, 3074, 3087, 2209, 2201, 3117, 3090, 2181, 3143, 3093, 2160, 2151, 3105, 3103, 3108, 3099, 3106, 3115, 3110, 2147, 2140, 3114, 2128, 3116, 2092, 2072, 2071, 2061, 1997, 3120, 1851, 1833, 1822, 3151, 3144, 3145, 3143, 1768, 3148, 3146, 3149, 3155, 3159, 3167, 3168, 3170, 3184, 3186, 3172, 3190, 3185, 3192, 3204, 3209, 3215, 3197, 3219, 3200, 3225, 3157, 3200, 3205, 3201, 3208, 1752, 3205, 1458, 3204, 3220, 3238, 3240, 3245, 3247, 1445, 3265, 3233, 3235, 3237, 1407, 3239, 3241, 3283, 3243, 1396, 3264, 3238, 3248, 1389, 3264, 3258, 1333, 3282, 3327, 3279, 1305, 1298, 3282, 3286, 1291, 3298, 3290, 3290, 3293, 1222, 1209, 3303, 3300, 1180, 3297, 1174, 3335, 1168, 3332, 3271, 1167, 3329, 3338, 1119, 3355, 3359, 3366, 3320, 3370, 3340, 3374, 3376, 3381, 3385, 3389, 1102, 3390, 3395, 3399, 3351, 3355, 1068, 3377, 3375, 3386, 3378, 3393, 3397, 1024, 3399, 3418, 3454, 3435, 3416, 3423, 3435, 3459, 3461, 3452, 3470, 1014, 989, 3393, 980, 3388, 3481, 3410, 975, 3487, 964, 3435, 945, 902, 3449, 3449, 898, 3447, 3454, 859, 3494, 3496, 3496, 3485, 3501, 3497, 3499, 818, 3502, 3517, 3522, 3526, 3517, 3501, 3531, 3524, 3540, 829, 807, 3515, 772, 3509, 3507, 747, 733, 3532, 3545, 727, 3541, 3549, 3554, 3553, 719, 3570, 3530, 711, 3596, 3546, 3577, 722, 705, 3543, 691, 3554, 645, 644, 3563, 3553, 632, 3603, 3588, 588, 3609, 3613, 3594, 3604, 3618, 3601, 587, 3623, 3591, 556, 3603, 3627, 3618, 3633, 3634, 552, 3614, 3635, 3644, 542, 3612, 525, 3610, 493, 3621, 488, 3653, 3646, 3660, 3639, 3676, 3680, 3657, 3651, 3684, 470, 3645, 3685, 379, 3686, 3690, 3681, 3701, 3677, 374, 3664, 3685, 204, 3710, 185, 3714, 3692, 3736, 3686, 3740, 3744, 3734, 3676, 180, 3677, 3750, 3714, 167, 3754, 3727, 3766, 3747, 156, 120, 112, 3776, 3760, 98, 82, 78, 3780, 3792, 3802, 3806, 3810, 3901, 3815, 3818, 3826, 3834, 3842, 3850, 3854, 3862 } ; static yyconst flex_int16_t yy_def[1243] = { 0, 1234, 1, 1235, 1235, 1235, 1235, 1234, 7, 1234, 9, 9, 11, 11, 11, 1234, 15, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1234, 1237, 1234, 1234, 1234, 1237, 1234, 1234, 1234, 1234, 1234, 1238, 1238, 1234, 1234, 1234, 1238, 1234, 1239, 1239, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1240, 1234, 1241, 19, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1234, 1234, 1234, 1237, 1234, 1237, 1234, 1234, 1234, 1234, 1238, 55, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1234, 1238, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1234, 74, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1240, 1241, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1234, 1234, 1234, 1234, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1242, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1242, 1236, 1236, 1236, 1236, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1234, 1236, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1236, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1236, 1234, 1236, 1236, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1236, 1236, 1234, 1234, 1236, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1236, 1236, 1236, 1234, 1236, 1234, 1234, 1236, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 1234, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1234, 1236, 1236, 1234, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1236, 1236, 1234, 1234, 1234, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1234, 1236, 1236, 1234, 1236, 1234, 1234, 1236, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 1234, 62, 62, 62, 62, 62, 62, 62, 1234, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1236, 1234, 1234, 1236, 1234, 1236, 1234, 1234, 1234, 1234, 1236, 1234, 1234, 1236, 1234, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 1234, 62, 62, 62, 62, 62, 62, 1234, 1234, 1234, 62, 1234, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1234, 1234, 1234, 1236, 1234, 1234, 1236, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1234, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 62, 62, 62, 62, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1236, 1234, 1236, 1236, 1236, 1236, 1234, 1234, 1234, 1236, 1234, 1236, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1234, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 62, 62, 1234, 62, 62, 1234, 62, 1234, 1234, 1234, 1234, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1234, 1236, 1236, 1234, 1234, 1234, 1234, 1236, 1236, 1234, 1234, 1234, 1234, 1238, 1238, 1238, 1238, 1238, 1238, 1234, 62, 1234, 1234, 62, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1234, 1236, 1234, 1234, 1236, 1236, 1234, 1238, 1238, 1238, 1234, 62, 1234, 1234, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1234, 1236, 1234, 1234, 1238, 1238, 1234, 1234, 1234, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1236, 1234, 1238, 1234, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1236, 1234, 1238, 1234, 62, 1234, 1234, 1234, 1234, 1234, 1238, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 0, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234 } ; static yyconst flex_int16_t yy_nxt[3968] = { 0, 18, 19, 20, 21, 19, 22, 22, 23, 18, 22, 22, 24, 18, 22, 25, 26, 27, 28, 29, 30, 31, 27, 27, 32, 27, 33, 34, 35, 36, 27, 37, 38, 39, 40, 27, 27, 41, 27, 27, 42, 18, 26, 27, 28, 29, 30, 31, 27, 27, 32, 27, 33, 34, 35, 36, 27, 37, 38, 39, 40, 27, 27, 41, 27, 27, 43, 45, 46, 21, 47, 48, 48, 127, 125, 48, 48, 125, 141, 48, 25, 73, 91, 75, 73, 73, 91, 75, 73, 121, 122, 121, 121, 1230, 73, 123, 123, 1231, 73, 123, 123, 127, 104, 123, 141, 49, 45, 46, 21, 47, 48, 48, 127, 1227, 48, 48, 138, 127, 48, 25, 101, 101, 101, 101, 127, 131, 129, 1228, 181, 130, 136, 181, 127, 104, 127, 1224, 132, 134, 209, 133, 137, 135, 138, 142, 49, 50, 51, 52, 53, 48, 48, 131, 129, 48, 48, 130, 136, 48, 53, 127, 127, 127, 132, 134, 209, 133, 137, 135, 213, 142, 127, 1227, 139, 140, 127, 143, 144, 146, 218, 147, 219, 145, 1225, 53, 50, 51, 52, 53, 48, 48, 127, 156, 48, 48, 213, 1222, 48, 53, 139, 140, 1215, 143, 144, 146, 218, 147, 219, 145, 101, 101, 101, 101, 235, 125, 235, 235, 125, 156, 263, 1206, 631, 104, 53, 54, 55, 56, 57, 55, 54, 54, 54, 54, 54, 54, 58, 54, 59, 60, 61, 61, 62, 63, 64, 61, 61, 61, 65, 61, 66, 61, 67, 61, 61, 68, 69, 70, 71, 61, 61, 61, 61, 61, 72, 54, 61, 61, 62, 63, 64, 61, 61, 61, 65, 61, 66, 61, 67, 61, 61, 68, 69, 70, 71, 61, 61, 61, 61, 61, 54, 73, 74, 73, 75, 74, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 76, 73, 77, 78, 79, 73, 73, 73, 80, 73, 81, 82, 83, 73, 73, 84, 85, 86, 87, 73, 73, 73, 73, 73, 73, 73, 76, 73, 77, 78, 79, 73, 73, 73, 80, 73, 81, 82, 83, 73, 73, 84, 85, 86, 87, 73, 73, 73, 73, 73, 73, 88, 88, 89, 88, 163, 163, 127, 152, 163, 163, 214, 153, 163, 90, 73, 154, 73, 73, 73, 220, 215, 221, 73, 155, 73, 73, 73, 216, 217, 73, 73, 73, 73, 152, 1202, 125, 214, 153, 125, 1208, 73, 154, 73, 73, 73, 220, 215, 221, 73, 155, 73, 73, 73, 216, 217, 73, 73, 73, 73, 92, 93, 94, 95, 93, 96, 92, 92, 96, 97, 92, 98, 96, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 96, 100, 101, 101, 100, 157, 1192, 102, 222, 239, 125, 103, 158, 125, 104, 105, 245, 106, 107, 108, 109, 246, 247, 110, 1201, 111, 112, 113, 114, 1184, 115, 116, 117, 118, 222, 239, 119, 101, 162, 101, 101, 105, 245, 106, 107, 108, 109, 246, 247, 110, 104, 111, 112, 113, 114, 127, 115, 116, 117, 118, 148, 1198, 119, 159, 248, 120, 101, 101, 101, 101, 149, 249, 227, 183, 150, 151, 228, 187, 1192, 104, 164, 165, 165, 164, 183, 243, 148, 183, 1194, 244, 248, 250, 1169, 166, 183, 253, 149, 249, 227, 183, 150, 151, 228, 187, 234, 183, 235, 234, 183, 181, 183, 243, 181, 183, 103, 244, 188, 250, 167, 169, 183, 253, 169, 1187, 1181, 229, 229, 229, 229, 170, 254, 183, 261, 183, 183, 171, 172, 173, 230, 127, 267, 174, 188, 175, 183, 176, 189, 183, 177, 178, 179, 180, 229, 229, 229, 229, 254, 236, 261, 183, 236, 171, 172, 173, 236, 230, 267, 174, 1161, 175, 183, 176, 189, 183, 177, 178, 179, 180, 168, 168, 1158, 1177, 168, 168, 168, 168, 168, 168, 168, 183, 168, 168, 127, 190, 183, 183, 183, 255, 191, 265, 183, 127, 210, 183, 196, 183, 183, 183, 183, 183, 183, 192, 256, 211, 283, 183, 212, 236, 168, 190, 183, 183, 183, 255, 191, 265, 183, 1155, 210, 183, 196, 183, 183, 183, 183, 183, 183, 192, 256, 211, 283, 1152, 212, 168, 168, 168, 1141, 1169, 168, 168, 168, 168, 168, 168, 168, 1171, 168, 168, 127, 184, 183, 264, 223, 1168, 193, 232, 232, 232, 232, 1165, 185, 183, 224, 186, 183, 127, 225, 226, 233, 101, 101, 101, 101, 1134, 168, 184, 183, 264, 223, 251, 193, 273, 104, 240, 252, 127, 185, 183, 224, 186, 183, 127, 225, 226, 241, 127, 127, 242, 1129, 168, 183, 270, 307, 272, 194, 251, 275, 273, 257, 240, 252, 183, 258, 271, 183, 266, 259, 123, 123, 195, 241, 123, 123, 242, 260, 123, 183, 270, 307, 272, 194, 127, 275, 1126, 257, 268, 127, 183, 258, 271, 183, 266, 259, 1119, 1157, 195, 198, 269, 181, 198, 260, 181, 121, 122, 121, 121, 121, 122, 121, 121, 278, 268, 199, 200, 201, 104, 127, 274, 202, 104, 203, 308, 204, 269, 127, 205, 206, 207, 208, 262, 262, 262, 262, 127, 276, 1150, 278, 127, 199, 200, 201, 127, 277, 274, 202, 127, 203, 308, 204, 127, 127, 205, 206, 207, 208, 279, 281, 127, 284, 280, 276, 285, 127, 127, 282, 288, 127, 290, 277, 286, 127, 127, 289, 127, 1147, 291, 287, 127, 1144, 293, 297, 279, 281, 294, 284, 280, 292, 285, 309, 295, 282, 288, 127, 290, 310, 286, 311, 296, 289, 163, 163, 291, 287, 163, 163, 293, 297, 163, 235, 294, 235, 235, 292, 312, 309, 295, 301, 301, 301, 301, 310, 1106, 311, 296, 101, 162, 101, 101, 164, 165, 165, 164, 165, 165, 165, 165, 304, 104, 313, 312, 1142, 166, 314, 316, 183, 166, 213, 305, 215, 183, 306, 1134, 217, 218, 220, 183, 1129, 315, 183, 263, 183, 642, 304, 183, 313, 1126, 167, 317, 314, 316, 183, 318, 213, 305, 215, 183, 306, 183, 217, 218, 220, 183, 183, 315, 183, 183, 183, 183, 183, 183, 1135, 183, 319, 317, 221, 321, 763, 318, 183, 763, 1128, 183, 222, 183, 320, 183, 183, 335, 183, 183, 263, 183, 643, 183, 183, 183, 183, 183, 319, 183, 221, 321, 322, 336, 183, 183, 183, 183, 222, 183, 320, 183, 183, 335, 829, 183, 183, 829, 323, 183, 337, 183, 183, 324, 1071, 183, 183, 183, 322, 336, 326, 183, 183, 866, 325, 183, 866, 183, 327, 340, 183, 183, 183, 183, 323, 183, 337, 334, 183, 324, 328, 228, 183, 183, 183, 223, 326, 183, 1117, 183, 325, 331, 183, 183, 327, 340, 183, 183, 210, 183, 226, 341, 338, 334, 183, 1110, 328, 228, 342, 211, 183, 223, 333, 183, 339, 183, 343, 331, 183, 183, 329, 344, 345, 346, 210, 347, 226, 341, 338, 348, 183, 330, 351, 183, 342, 211, 349, 352, 333, 353, 339, 354, 343, 356, 350, 183, 329, 344, 345, 346, 357, 347, 355, 1107, 1104, 348, 183, 330, 351, 183, 1102, 236, 349, 352, 236, 353, 1054, 354, 236, 356, 350, 229, 229, 229, 229, 360, 357, 361, 355, 232, 232, 232, 232, 234, 230, 235, 234, 362, 363, 367, 365, 368, 233, 103, 369, 1049, 370, 371, 372, 373, 364, 360, 366, 361, 374, 375, 376, 380, 1048, 383, 384, 385, 386, 362, 363, 367, 365, 368, 381, 377, 369, 236, 370, 371, 372, 373, 364, 378, 366, 382, 374, 375, 376, 380, 379, 383, 384, 385, 386, 387, 262, 262, 262, 262, 381, 377, 127, 127, 127, 127, 127, 127, 127, 378, 389, 382, 391, 393, 127, 395, 379, 396, 127, 127, 127, 387, 392, 390, 127, 127, 398, 397, 127, 394, 127, 127, 399, 1094, 127, 401, 389, 127, 391, 393, 1039, 395, 403, 396, 400, 404, 127, 1091, 392, 390, 402, 409, 398, 397, 406, 394, 405, 127, 399, 127, 127, 401, 407, 127, 127, 408, 127, 411, 403, 410, 400, 404, 127, 127, 127, 1088, 402, 409, 127, 412, 406, 127, 405, 413, 127, 127, 418, 415, 407, 419, 127, 408, 414, 411, 417, 410, 416, 420, 127, 301, 301, 301, 301, 421, 422, 412, 424, 425, 426, 413, 427, 428, 418, 415, 429, 419, 430, 431, 414, 432, 417, 435, 416, 420, 438, 455, 456, 433, 436, 421, 422, 1071, 424, 425, 426, 434, 427, 428, 1083, 437, 429, 457, 430, 431, 183, 432, 183, 435, 439, 1078, 438, 455, 456, 433, 436, 183, 876, 183, 183, 876, 183, 434, 183, 440, 183, 437, 442, 457, 183, 458, 183, 459, 183, 183, 439, 183, 183, 460, 183, 183, 443, 183, 183, 183, 183, 441, 183, 1074, 183, 440, 183, 263, 442, 645, 183, 458, 183, 459, 183, 183, 1007, 183, 183, 460, 183, 183, 443, 183, 183, 183, 183, 441, 183, 454, 444, 461, 183, 183, 183, 445, 462, 463, 183, 446, 183, 339, 448, 183, 183, 183, 183, 183, 183, 183, 464, 183, 183, 447, 183, 454, 444, 461, 183, 183, 183, 445, 462, 463, 449, 446, 183, 339, 448, 183, 183, 183, 183, 183, 183, 183, 464, 183, 183, 447, 183, 465, 183, 183, 450, 466, 467, 468, 469, 470, 449, 183, 183, 183, 183, 452, 183, 183, 471, 451, 472, 183, 453, 183, 183, 183, 183, 465, 183, 183, 450, 466, 467, 468, 469, 470, 473, 183, 474, 183, 183, 452, 183, 183, 471, 451, 472, 475, 453, 476, 477, 183, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 473, 488, 474, 489, 490, 491, 492, 493, 494, 495, 496, 475, 497, 476, 477, 498, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 499, 488, 500, 489, 490, 491, 492, 493, 494, 495, 496, 501, 497, 502, 503, 498, 504, 505, 506, 127, 127, 127, 127, 127, 763, 127, 499, 763, 500, 510, 127, 127, 127, 509, 508, 514, 127, 501, 513, 502, 503, 511, 504, 505, 506, 127, 517, 515, 518, 127, 519, 516, 127, 521, 520, 510, 127, 127, 127, 509, 508, 514, 527, 127, 513, 127, 528, 511, 127, 127, 127, 522, 517, 515, 518, 529, 519, 516, 525, 521, 520, 127, 127, 536, 534, 542, 531, 530, 527, 127, 532, 127, 528, 127, 535, 127, 537, 522, 539, 127, 543, 529, 544, 545, 525, 546, 547, 548, 541, 536, 534, 542, 531, 530, 538, 549, 532, 550, 551, 552, 535, 553, 537, 554, 539, 555, 543, 556, 544, 545, 572, 546, 547, 548, 541, 573, 891, 574, 575, 891, 538, 549, 1002, 550, 551, 552, 183, 553, 183, 554, 576, 555, 557, 556, 578, 183, 572, 183, 1042, 183, 183, 573, 183, 574, 575, 558, 183, 559, 183, 183, 579, 580, 183, 581, 183, 263, 576, 652, 557, 183, 578, 183, 183, 183, 560, 183, 183, 183, 183, 562, 582, 558, 183, 559, 183, 183, 579, 580, 183, 581, 183, 183, 561, 183, 583, 183, 183, 183, 183, 584, 560, 565, 987, 183, 586, 562, 582, 183, 183, 587, 563, 564, 183, 1038, 183, 183, 183, 183, 561, 183, 583, 908, 183, 183, 908, 584, 588, 565, 183, 183, 586, 985, 589, 183, 183, 587, 563, 564, 183, 183, 183, 183, 183, 183, 566, 183, 183, 567, 923, 590, 569, 923, 588, 568, 183, 183, 183, 183, 589, 183, 183, 592, 593, 570, 594, 183, 183, 595, 183, 183, 566, 183, 183, 567, 183, 590, 569, 183, 596, 568, 183, 597, 183, 183, 571, 183, 183, 592, 593, 570, 594, 183, 598, 595, 183, 599, 601, 602, 603, 604, 183, 605, 606, 183, 596, 607, 183, 597, 608, 610, 571, 612, 613, 614, 615, 616, 617, 183, 598, 618, 183, 599, 601, 602, 603, 604, 619, 605, 606, 620, 621, 607, 622, 624, 608, 610, 127, 612, 613, 614, 615, 616, 617, 127, 628, 618, 127, 127, 626, 127, 127, 127, 619, 625, 632, 620, 621, 629, 622, 624, 633, 627, 127, 630, 127, 635, 127, 127, 636, 127, 127, 634, 648, 127, 626, 127, 637, 982, 127, 625, 632, 638, 644, 629, 640, 127, 633, 627, 647, 630, 641, 635, 646, 127, 636, 127, 127, 634, 648, 650, 649, 127, 637, 127, 654, 127, 661, 638, 644, 127, 640, 651, 653, 263, 647, 659, 641, 657, 646, 662, 655, 663, 664, 660, 665, 650, 649, 666, 667, 668, 654, 669, 661, 670, 671, 672, 673, 651, 653, 674, 675, 981, 263, 657, 748, 662, 655, 663, 664, 660, 665, 980, 1036, 666, 667, 668, 183, 669, 694, 670, 671, 672, 673, 695, 183, 674, 675, 183, 680, 263, 676, 760, 978, 696, 700, 183, 701, 183, 183, 702, 703, 183, 183, 934, 694, 681, 934, 705, 183, 695, 183, 183, 682, 183, 680, 183, 676, 677, 183, 696, 700, 183, 701, 183, 183, 702, 703, 183, 975, 183, 678, 681, 183, 705, 183, 183, 679, 183, 682, 183, 1033, 183, 685, 183, 183, 706, 183, 1032, 683, 183, 183, 1024, 183, 183, 183, 183, 678, 183, 183, 684, 1023, 183, 679, 183, 829, 183, 183, 829, 685, 183, 686, 706, 183, 183, 683, 183, 183, 687, 183, 183, 183, 1007, 708, 183, 183, 684, 183, 183, 709, 183, 688, 183, 183, 183, 710, 690, 686, 183, 711, 183, 183, 1002, 183, 687, 183, 689, 712, 183, 708, 1019, 183, 183, 183, 183, 709, 714, 688, 183, 715, 183, 710, 690, 183, 183, 711, 183, 183, 691, 183, 716, 183, 689, 712, 183, 692, 183, 717, 183, 718, 677, 719, 714, 724, 1011, 715, 725, 183, 726, 183, 183, 720, 183, 697, 691, 727, 716, 728, 729, 698, 730, 731, 183, 717, 721, 718, 732, 719, 733, 724, 722, 734, 725, 183, 726, 735, 183, 736, 737, 697, 738, 727, 739, 728, 729, 698, 730, 731, 740, 742, 721, 744, 732, 127, 733, 127, 722, 734, 1009, 127, 127, 735, 127, 736, 737, 749, 738, 746, 739, 127, 751, 752, 747, 751, 740, 742, 750, 744, 127, 127, 127, 753, 127, 127, 127, 1008, 761, 758, 754, 757, 127, 749, 127, 746, 755, 767, 762, 756, 747, 127, 1006, 127, 750, 759, 768, 770, 1004, 753, 764, 764, 764, 764, 761, 758, 754, 757, 766, 766, 766, 766, 755, 767, 762, 756, 127, 127, 127, 769, 127, 759, 768, 770, 773, 773, 773, 773, 127, 263, 127, 777, 772, 782, 263, 771, 779, 127, 677, 775, 780, 780, 780, 780, 781, 769, 778, 785, 786, 787, 788, 783, 776, 789, 790, 791, 792, 784, 772, 782, 793, 771, 794, 795, 796, 775, 922, 815, 817, 263, 781, 863, 778, 785, 786, 787, 788, 783, 776, 789, 790, 791, 792, 784, 183, 920, 793, 818, 794, 795, 796, 183, 183, 815, 817, 183, 799, 183, 183, 263, 797, 879, 183, 183, 919, 183, 183, 800, 183, 819, 183, 183, 822, 818, 917, 801, 183, 183, 183, 915, 803, 183, 799, 183, 183, 183, 797, 183, 183, 183, 183, 183, 183, 800, 183, 819, 183, 183, 822, 183, 802, 801, 183, 183, 183, 804, 803, 805, 806, 183, 183, 183, 808, 183, 183, 183, 183, 183, 183, 986, 183, 183, 183, 183, 183, 183, 802, 979, 183, 183, 183, 804, 807, 805, 183, 183, 183, 809, 808, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 973, 823, 183, 183, 263, 824, 886, 807, 183, 183, 183, 825, 809, 183, 183, 810, 183, 183, 827, 183, 183, 183, 183, 183, 183, 828, 811, 823, 183, 820, 821, 824, 820, 812, 183, 830, 183, 825, 831, 183, 832, 810, 183, 833, 827, 183, 836, 183, 183, 837, 183, 828, 811, 834, 834, 834, 834, 838, 839, 812, 840, 830, 841, 842, 831, 844, 832, 843, 752, 833, 843, 845, 836, 846, 847, 837, 848, 849, 850, 851, 853, 854, 855, 838, 839, 856, 840, 857, 841, 842, 858, 844, 859, 860, 861, 862, 127, 845, 127, 846, 847, 127, 848, 849, 850, 851, 853, 854, 855, 127, 865, 856, 127, 857, 868, 864, 858, 867, 859, 860, 861, 862, 751, 752, 127, 751, 127, 127, 127, 127, 972, 871, 869, 127, 127, 870, 865, 872, 875, 877, 868, 864, 127, 867, 971, 873, 880, 874, 764, 764, 764, 764, 766, 766, 766, 766, 127, 871, 869, 924, 821, 870, 924, 872, 875, 877, 773, 773, 773, 773, 127, 873, 880, 874, 893, 882, 894, 895, 896, 887, 889, 889, 889, 889, 127, 780, 780, 780, 780, 890, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 893, 882, 894, 895, 896, 887, 263, 925, 975, 927, 820, 821, 263, 820, 978, 890, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 183, 183, 183, 928, 929, 930, 910, 925, 907, 927, 183, 183, 183, 183, 183, 183, 183, 911, 931, 909, 962, 183, 963, 962, 183, 932, 183, 183, 183, 928, 929, 930, 910, 961, 907, 183, 183, 183, 183, 183, 183, 183, 183, 911, 931, 909, 183, 183, 183, 183, 183, 932, 183, 912, 866, 933, 914, 866, 935, 183, 959, 183, 183, 183, 936, 913, 183, 957, 915, 183, 938, 939, 183, 940, 183, 183, 956, 955, 183, 912, 183, 933, 914, 183, 935, 183, 917, 183, 183, 183, 936, 913, 183, 183, 953, 183, 938, 939, 183, 940, 941, 183, 919, 183, 183, 942, 183, 183, 943, 183, 879, 918, 944, 183, 183, 843, 752, 183, 843, 183, 920, 183, 876, 951, 183, 876, 941, 183, 183, 183, 183, 942, 183, 183, 943, 183, 921, 918, 944, 183, 183, 945, 183, 183, 922, 183, 946, 183, 834, 834, 834, 834, 947, 948, 183, 949, 183, 950, 183, 183, 952, 183, 921, 954, 958, 183, 960, 945, 183, 127, 127, 183, 946, 127, 964, 966, 127, 988, 947, 948, 127, 949, 183, 950, 965, 183, 952, 127, 967, 954, 958, 127, 960, 127, 127, 968, 969, 127, 922, 976, 964, 966, 976, 988, 937, 977, 970, 974, 920, 263, 965, 980, 984, 263, 967, 981, 263, 263, 982, 985, 989, 968, 969, 983, 983, 983, 983, 889, 889, 889, 889, 977, 970, 974, 891, 990, 991, 891, 984, 263, 992, 987, 993, 994, 995, 996, 989, 908, 1005, 183, 908, 1005, 923, 997, 919, 923, 924, 821, 917, 924, 183, 990, 991, 183, 1012, 915, 992, 183, 993, 994, 995, 996, 821, 183, 998, 183, 1014, 999, 183, 997, 183, 183, 1013, 926, 183, 1013, 183, 183, 916, 183, 1012, 183, 1015, 183, 1000, 806, 892, 183, 183, 183, 998, 888, 1014, 999, 183, 1001, 183, 183, 183, 183, 183, 183, 1010, 183, 1002, 183, 183, 183, 1015, 1016, 1000, 1007, 183, 183, 183, 1017, 183, 183, 1003, 183, 183, 1001, 1018, 183, 183, 183, 183, 183, 1010, 1020, 934, 183, 183, 934, 1022, 1016, 1025, 1026, 183, 1027, 1028, 1017, 183, 183, 1003, 183, 183, 1029, 1018, 183, 1030, 1031, 183, 1034, 1035, 1020, 1021, 1021, 1021, 1021, 1022, 1037, 1025, 1026, 962, 1027, 1028, 962, 263, 127, 1039, 127, 127, 1029, 127, 127, 1030, 1031, 1043, 1034, 1035, 127, 885, 263, 1041, 1047, 1044, 1037, 1062, 1040, 1045, 263, 263, 1048, 1049, 1046, 127, 1051, 127, 976, 1051, 1050, 976, 1053, 1043, 1055, 1053, 1052, 1055, 263, 1041, 1054, 1044, 884, 1062, 1040, 1045, 1056, 1056, 1056, 1056, 1046, 1057, 127, 263, 1057, 1060, 1050, 983, 983, 983, 983, 1059, 1052, 1063, 1059, 1064, 1058, 1061, 1061, 1061, 1061, 1065, 1066, 1067, 1068, 1076, 183, 1005, 1076, 1077, 1005, 1079, 1077, 1080, 1079, 1082, 1080, 183, 1082, 1063, 183, 1064, 1058, 1069, 183, 1071, 183, 1065, 1066, 1067, 1068, 183, 183, 183, 1072, 183, 1013, 183, 1070, 1013, 183, 1084, 183, 183, 183, 183, 183, 1073, 1085, 1069, 183, 183, 183, 1086, 263, 1075, 1106, 183, 1087, 183, 1072, 183, 183, 183, 1070, 183, 183, 1084, 183, 183, 183, 183, 1089, 1073, 1085, 883, 881, 183, 1090, 1086, 183, 1075, 1081, 183, 1087, 1092, 1093, 1095, 183, 1096, 1097, 183, 1098, 1099, 1100, 183, 1101, 878, 1089, 1021, 1021, 1021, 1021, 752, 1090, 127, 183, 1103, 1081, 183, 1103, 1092, 1093, 1095, 127, 1096, 1097, 127, 1098, 1099, 1100, 1105, 1101, 127, 1114, 127, 1108, 1111, 1111, 1111, 1111, 1112, 1112, 1112, 1112, 779, 777, 1109, 1113, 1113, 1113, 1113, 1051, 1115, 852, 1051, 1053, 1105, 1116, 1053, 1114, 1116, 1108, 1055, 1120, 1121, 1055, 1056, 1056, 1056, 1056, 1057, 1059, 1109, 1057, 1059, 1122, 1118, 1119, 1115, 1118, 1061, 1061, 1061, 1061, 1123, 1124, 1125, 1126, 183, 1120, 1121, 1136, 183, 1129, 183, 1127, 1137, 1076, 748, 183, 1076, 1122, 183, 183, 1077, 183, 183, 1077, 183, 835, 1123, 1124, 1125, 183, 183, 806, 1133, 1136, 183, 1133, 183, 1127, 1137, 1139, 183, 183, 1130, 183, 183, 183, 183, 183, 183, 1143, 183, 1131, 1131, 1131, 1131, 183, 1079, 183, 1080, 1079, 183, 1080, 1134, 183, 1132, 1139, 183, 1082, 1130, 183, 1082, 1145, 183, 1146, 183, 1143, 1148, 183, 1138, 1138, 1138, 1138, 1149, 183, 1140, 1141, 183, 1140, 826, 183, 1132, 1151, 1119, 1103, 1151, 127, 1103, 1145, 1154, 1146, 183, 1154, 1148, 183, 263, 263, 1152, 1155, 1149, 127, 263, 127, 1158, 1153, 1111, 1111, 1111, 1111, 1156, 1112, 1112, 1112, 1112, 1113, 1113, 1113, 1113, 127, 1116, 1162, 1160, 1116, 263, 1163, 1161, 1159, 1164, 1118, 1119, 1153, 1118, 816, 1167, 183, 1156, 1167, 1131, 1131, 1131, 1131, 1133, 1169, 183, 1133, 183, 1162, 1160, 183, 1173, 1163, 1166, 1159, 1164, 183, 1174, 183, 183, 1172, 1141, 183, 1172, 1175, 1170, 1176, 1140, 1141, 183, 1140, 183, 183, 183, 1178, 1179, 183, 1173, 1180, 1166, 814, 1180, 183, 1174, 183, 183, 1138, 1138, 1138, 1138, 1175, 1170, 1176, 1151, 1119, 183, 1151, 127, 183, 1154, 1178, 1179, 1154, 1182, 127, 263, 1182, 1184, 1185, 1185, 1185, 1185, 1189, 1188, 1190, 1183, 1188, 1191, 183, 1186, 1191, 1192, 183, 1167, 1193, 1196, 1167, 1193, 1196, 183, 1197, 1199, 1195, 183, 1172, 1141, 183, 1172, 1189, 1200, 1190, 1183, 127, 1180, 183, 1186, 1180, 263, 183, 1202, 1182, 813, 263, 1182, 1206, 183, 1197, 1199, 1195, 183, 127, 1203, 183, 1207, 1205, 1200, 1204, 1204, 1204, 1204, 1185, 1185, 1185, 1185, 1188, 1191, 1193, 1188, 1191, 1193, 1209, 1209, 1209, 1209, 1211, 183, 1212, 1203, 1210, 1207, 1205, 1196, 1213, 1218, 1196, 127, 183, 1221, 1223, 183, 1214, 1214, 1214, 1214, 1204, 1204, 1204, 1204, 798, 692, 1211, 183, 1212, 1216, 1210, 263, 774, 1224, 1213, 1218, 765, 745, 183, 1221, 1223, 183, 1217, 1217, 1217, 1217, 1219, 1219, 1219, 1219, 1209, 1209, 1209, 1209, 183, 1216, 1214, 1214, 1214, 1214, 1217, 1217, 1217, 1217, 1226, 183, 1227, 183, 183, 659, 743, 1220, 1219, 1219, 1219, 1219, 741, 263, 183, 1230, 183, 183, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1229, 1226, 183, 645, 183, 183, 643, 723, 1220, 1232, 1232, 1232, 1232, 692, 713, 183, 707, 704, 183, 1233, 1233, 1233, 1233, 1232, 1232, 1232, 1232, 1233, 1233, 1233, 1233, 44, 44, 44, 44, 44, 44, 44, 44, 44, 128, 128, 161, 699, 693, 161, 161, 161, 658, 161, 168, 168, 656, 168, 639, 168, 623, 168, 183, 183, 611, 183, 609, 183, 600, 183, 237, 237, 237, 591, 237, 237, 237, 237, 237, 238, 585, 238, 507, 577, 540, 507, 533, 507, 526, 507, 507, 524, 523, 512, 423, 388, 359, 358, 231, 332, 182, 303, 302, 300, 299, 298, 127, 263, 160, 126, 124, 231, 197, 182, 158, 160, 127, 126, 124, 1234, 17, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234 } ; static yyconst flex_int16_t yy_chk[3968] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 33, 24, 3, 3, 24, 33, 3, 3, 13, 13, 13, 13, 14, 14, 14, 14, 20, 20, 20, 20, 1228, 13, 22, 22, 1227, 14, 22, 22, 31, 20, 22, 33, 3, 4, 4, 4, 4, 4, 4, 26, 1226, 4, 4, 31, 30, 4, 4, 21, 21, 21, 21, 28, 28, 26, 1223, 58, 26, 30, 58, 29, 21, 34, 1222, 28, 29, 76, 28, 30, 29, 31, 34, 4, 5, 5, 5, 5, 5, 5, 28, 26, 5, 5, 26, 30, 5, 5, 32, 37, 36, 28, 29, 76, 28, 30, 29, 78, 34, 35, 1221, 32, 32, 38, 35, 36, 37, 81, 38, 82, 36, 1216, 5, 6, 6, 6, 6, 6, 6, 41, 41, 6, 6, 78, 1212, 6, 6, 32, 32, 1203, 35, 36, 37, 81, 38, 82, 36, 45, 45, 45, 45, 95, 98, 95, 95, 98, 41, 512, 1201, 512, 45, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 48, 48, 40, 40, 48, 48, 79, 40, 48, 11, 11, 40, 11, 11, 11, 83, 79, 84, 11, 40, 11, 11, 11, 80, 80, 11, 11, 11, 11, 40, 1198, 103, 79, 40, 103, 1192, 11, 40, 11, 11, 11, 83, 79, 84, 11, 40, 11, 11, 11, 80, 80, 11, 11, 11, 11, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 19, 19, 19, 19, 42, 1189, 19, 85, 105, 125, 19, 42, 125, 19, 19, 108, 19, 19, 19, 19, 109, 110, 19, 1179, 19, 19, 19, 19, 1177, 19, 19, 19, 19, 85, 105, 19, 46, 46, 46, 46, 19, 108, 19, 19, 19, 19, 109, 110, 19, 46, 19, 19, 19, 19, 39, 19, 19, 19, 19, 39, 1175, 19, 42, 111, 19, 47, 47, 47, 47, 39, 112, 87, 63, 39, 39, 87, 63, 1173, 47, 51, 51, 51, 51, 63, 107, 39, 63, 1169, 107, 111, 113, 1163, 51, 64, 115, 39, 112, 87, 63, 39, 39, 87, 63, 93, 64, 93, 93, 64, 170, 63, 107, 170, 63, 93, 107, 64, 113, 51, 55, 64, 115, 55, 1160, 1153, 88, 88, 88, 88, 55, 116, 64, 119, 65, 64, 55, 55, 55, 88, 132, 132, 55, 64, 55, 65, 55, 65, 65, 55, 55, 55, 55, 89, 89, 89, 89, 116, 96, 119, 65, 96, 55, 55, 55, 96, 89, 132, 55, 1150, 55, 65, 55, 65, 65, 55, 55, 55, 55, 61, 61, 1147, 1146, 61, 61, 61, 61, 61, 61, 61, 66, 61, 61, 130, 66, 67, 68, 71, 117, 67, 130, 66, 145, 77, 66, 71, 67, 68, 71, 67, 68, 71, 68, 117, 77, 145, 66, 77, 96, 61, 66, 67, 68, 71, 117, 67, 130, 66, 1144, 77, 66, 71, 67, 68, 71, 67, 68, 71, 68, 117, 77, 145, 1142, 77, 61, 62, 62, 1141, 1137, 62, 62, 62, 62, 62, 62, 62, 1134, 62, 62, 129, 62, 69, 129, 86, 1129, 69, 91, 91, 91, 91, 1126, 62, 69, 86, 62, 69, 136, 86, 86, 91, 101, 101, 101, 101, 1125, 62, 62, 69, 129, 86, 114, 69, 136, 101, 106, 114, 135, 62, 69, 86, 62, 69, 138, 86, 86, 106, 134, 131, 106, 1122, 62, 70, 134, 172, 135, 70, 114, 138, 136, 118, 106, 114, 70, 118, 134, 70, 131, 118, 123, 123, 70, 106, 123, 123, 106, 118, 123, 70, 134, 172, 135, 70, 133, 138, 1120, 118, 133, 141, 70, 118, 134, 70, 131, 118, 1119, 1109, 70, 74, 133, 181, 74, 118, 181, 121, 121, 121, 121, 122, 122, 122, 122, 141, 133, 74, 74, 74, 121, 137, 137, 74, 122, 74, 173, 74, 133, 140, 74, 74, 74, 74, 124, 124, 124, 124, 139, 139, 1101, 141, 143, 74, 74, 74, 142, 140, 137, 74, 144, 74, 173, 74, 146, 150, 74, 74, 74, 74, 142, 143, 147, 146, 142, 139, 147, 148, 156, 144, 148, 149, 150, 140, 147, 154, 153, 149, 151, 1098, 151, 147, 152, 1095, 152, 156, 142, 143, 153, 146, 142, 151, 147, 174, 154, 144, 148, 155, 150, 175, 147, 176, 155, 149, 163, 163, 151, 147, 163, 163, 152, 156, 163, 235, 153, 235, 235, 151, 177, 174, 154, 160, 160, 160, 160, 175, 1094, 176, 155, 162, 162, 162, 162, 164, 164, 164, 164, 165, 165, 165, 165, 171, 162, 178, 177, 1092, 164, 179, 180, 183, 165, 200, 171, 201, 184, 171, 1090, 202, 203, 204, 183, 1086, 179, 183, 523, 184, 523, 171, 184, 178, 1084, 164, 184, 179, 180, 183, 185, 200, 171, 201, 184, 171, 186, 202, 203, 204, 183, 185, 179, 183, 185, 184, 187, 186, 184, 1083, 186, 186, 184, 205, 188, 642, 185, 187, 642, 1071, 187, 206, 186, 187, 189, 188, 209, 185, 188, 524, 185, 524, 187, 186, 190, 189, 186, 186, 189, 205, 188, 189, 210, 187, 191, 190, 187, 206, 190, 187, 189, 188, 209, 707, 188, 191, 707, 190, 191, 211, 190, 189, 191, 1064, 189, 192, 193, 189, 210, 193, 191, 190, 748, 192, 190, 748, 192, 193, 213, 192, 193, 191, 196, 190, 191, 211, 208, 194, 191, 194, 208, 192, 193, 196, 207, 193, 196, 1058, 194, 192, 196, 194, 192, 193, 213, 192, 193, 199, 196, 207, 214, 212, 208, 194, 1046, 194, 208, 215, 199, 196, 207, 199, 196, 212, 194, 216, 196, 194, 195, 195, 217, 218, 219, 199, 220, 207, 214, 212, 221, 195, 195, 223, 195, 215, 199, 222, 224, 199, 225, 212, 226, 216, 227, 222, 195, 195, 217, 218, 219, 228, 220, 226, 1043, 1040, 221, 195, 195, 223, 195, 1038, 236, 222, 224, 236, 225, 1036, 226, 236, 227, 222, 229, 229, 229, 229, 239, 228, 240, 226, 232, 232, 232, 232, 234, 229, 234, 234, 241, 242, 244, 243, 245, 232, 234, 246, 1033, 247, 248, 249, 250, 242, 239, 243, 240, 251, 252, 253, 255, 1032, 257, 258, 259, 260, 241, 242, 244, 243, 245, 256, 254, 246, 236, 247, 248, 249, 250, 242, 254, 243, 256, 251, 252, 253, 255, 254, 257, 258, 259, 260, 261, 262, 262, 262, 262, 256, 254, 264, 265, 267, 269, 270, 266, 268, 254, 264, 256, 266, 268, 271, 270, 254, 271, 273, 274, 278, 261, 267, 265, 272, 275, 273, 272, 276, 269, 284, 277, 274, 1027, 279, 276, 264, 280, 266, 268, 1024, 270, 278, 271, 275, 279, 281, 1023, 267, 265, 277, 284, 273, 272, 281, 269, 280, 282, 274, 287, 285, 276, 282, 283, 288, 283, 286, 286, 278, 285, 275, 279, 290, 289, 293, 1019, 277, 284, 291, 287, 281, 292, 280, 288, 294, 295, 293, 290, 282, 294, 297, 283, 289, 286, 292, 285, 291, 295, 296, 301, 301, 301, 301, 296, 297, 287, 304, 305, 306, 288, 307, 308, 293, 290, 309, 294, 310, 311, 289, 312, 292, 314, 291, 295, 316, 334, 335, 313, 315, 296, 297, 1016, 304, 305, 306, 313, 307, 308, 1012, 315, 309, 336, 310, 311, 317, 312, 318, 314, 317, 1007, 316, 334, 335, 313, 315, 317, 760, 318, 317, 760, 318, 313, 319, 318, 320, 315, 320, 336, 321, 337, 317, 338, 318, 319, 317, 320, 319, 339, 320, 321, 321, 317, 321, 318, 317, 319, 318, 1002, 319, 318, 320, 526, 320, 526, 321, 337, 322, 338, 323, 319, 995, 320, 319, 339, 320, 321, 321, 322, 321, 323, 322, 319, 323, 333, 322, 340, 324, 325, 326, 323, 341, 342, 322, 324, 323, 333, 326, 324, 325, 326, 324, 325, 326, 322, 343, 323, 322, 325, 323, 333, 322, 340, 324, 325, 326, 323, 341, 342, 327, 324, 328, 333, 326, 324, 325, 326, 324, 325, 326, 327, 343, 328, 327, 325, 328, 344, 329, 330, 328, 345, 346, 347, 348, 349, 327, 331, 328, 329, 330, 330, 329, 330, 350, 329, 351, 327, 331, 328, 327, 331, 328, 344, 329, 330, 328, 345, 346, 347, 348, 349, 352, 331, 353, 329, 330, 330, 329, 330, 350, 329, 351, 354, 331, 355, 356, 331, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 352, 369, 353, 370, 371, 372, 373, 374, 375, 376, 377, 354, 378, 355, 356, 379, 357, 360, 361, 362, 363, 364, 365, 366, 367, 368, 380, 369, 381, 370, 371, 372, 373, 374, 375, 376, 377, 382, 378, 383, 384, 379, 385, 386, 387, 389, 390, 395, 391, 392, 763, 394, 380, 763, 381, 391, 396, 397, 399, 390, 389, 395, 400, 382, 394, 383, 384, 392, 385, 386, 387, 398, 398, 396, 399, 401, 400, 397, 402, 402, 401, 391, 403, 408, 410, 390, 389, 395, 408, 406, 394, 409, 409, 392, 411, 412, 415, 403, 398, 396, 399, 410, 400, 397, 406, 402, 401, 413, 417, 417, 415, 424, 412, 411, 408, 416, 413, 418, 409, 420, 416, 419, 418, 403, 420, 422, 425, 410, 426, 427, 406, 428, 429, 430, 422, 417, 415, 424, 412, 411, 419, 431, 413, 432, 433, 434, 416, 435, 418, 436, 420, 437, 425, 438, 426, 427, 454, 428, 429, 430, 422, 455, 779, 456, 457, 779, 419, 431, 993, 432, 433, 434, 439, 435, 440, 436, 458, 437, 439, 438, 460, 441, 454, 439, 966, 440, 439, 455, 440, 456, 457, 440, 441, 441, 442, 441, 461, 462, 439, 463, 440, 533, 458, 533, 439, 442, 460, 441, 442, 439, 442, 440, 439, 443, 440, 444, 464, 440, 441, 441, 442, 441, 461, 462, 443, 463, 444, 443, 443, 444, 465, 442, 445, 446, 442, 466, 442, 447, 961, 443, 468, 444, 464, 445, 446, 469, 445, 446, 447, 960, 443, 447, 444, 443, 443, 444, 465, 798, 445, 446, 798, 466, 470, 447, 448, 449, 468, 959, 471, 445, 446, 469, 445, 446, 447, 448, 449, 447, 448, 449, 448, 450, 451, 449, 813, 472, 451, 813, 470, 450, 448, 449, 450, 451, 471, 450, 451, 474, 475, 452, 476, 448, 449, 477, 448, 449, 448, 450, 451, 449, 452, 472, 451, 452, 478, 450, 453, 479, 450, 451, 453, 450, 451, 474, 475, 452, 476, 453, 480, 477, 453, 481, 483, 484, 485, 486, 452, 487, 488, 452, 478, 489, 453, 479, 490, 492, 453, 494, 495, 496, 497, 498, 499, 453, 480, 500, 453, 481, 483, 484, 485, 486, 501, 487, 488, 502, 503, 489, 504, 506, 490, 492, 508, 494, 495, 496, 497, 498, 499, 509, 511, 500, 510, 516, 509, 513, 517, 514, 501, 508, 513, 502, 503, 511, 504, 506, 514, 510, 515, 511, 518, 516, 519, 529, 517, 528, 521, 515, 529, 522, 509, 527, 518, 957, 525, 508, 513, 519, 525, 511, 521, 531, 514, 510, 528, 511, 522, 516, 527, 538, 517, 530, 532, 515, 529, 531, 530, 535, 518, 536, 535, 534, 542, 519, 525, 541, 521, 532, 534, 540, 528, 540, 522, 538, 527, 543, 536, 544, 545, 541, 546, 531, 530, 547, 548, 549, 535, 550, 542, 551, 552, 553, 554, 532, 534, 555, 556, 956, 628, 538, 628, 543, 536, 544, 545, 541, 546, 955, 954, 547, 548, 549, 557, 550, 573, 551, 552, 553, 554, 574, 559, 555, 556, 557, 559, 639, 557, 639, 953, 575, 578, 559, 579, 560, 559, 580, 581, 561, 557, 826, 573, 560, 826, 583, 560, 574, 559, 560, 561, 557, 559, 561, 557, 558, 558, 575, 578, 559, 579, 560, 559, 580, 581, 561, 951, 558, 558, 560, 558, 583, 560, 562, 558, 560, 561, 564, 949, 561, 564, 563, 558, 584, 562, 948, 562, 562, 564, 940, 565, 564, 563, 558, 558, 563, 558, 563, 939, 562, 558, 565, 829, 564, 565, 829, 564, 563, 565, 584, 562, 566, 562, 562, 564, 566, 565, 564, 563, 936, 586, 563, 566, 563, 567, 566, 587, 565, 567, 568, 565, 569, 588, 569, 565, 567, 589, 566, 567, 933, 568, 566, 569, 568, 590, 569, 586, 932, 566, 570, 567, 566, 587, 592, 567, 568, 593, 569, 588, 569, 570, 567, 589, 570, 567, 570, 568, 594, 569, 568, 590, 569, 571, 571, 595, 570, 597, 576, 598, 592, 601, 922, 593, 602, 571, 603, 570, 571, 599, 570, 576, 570, 604, 594, 605, 606, 576, 607, 608, 571, 595, 599, 597, 610, 598, 612, 601, 599, 613, 602, 571, 603, 614, 571, 615, 616, 576, 617, 604, 618, 605, 606, 576, 607, 608, 619, 621, 599, 624, 610, 626, 612, 627, 599, 613, 920, 630, 629, 614, 632, 615, 616, 629, 617, 626, 618, 633, 631, 631, 627, 631, 619, 621, 630, 624, 634, 635, 636, 632, 637, 640, 638, 919, 640, 637, 633, 636, 646, 629, 641, 626, 634, 646, 641, 635, 627, 647, 917, 649, 630, 638, 647, 649, 915, 632, 643, 643, 643, 643, 640, 637, 633, 636, 645, 645, 645, 645, 634, 646, 641, 635, 648, 650, 651, 648, 654, 638, 647, 649, 652, 652, 652, 652, 655, 656, 657, 656, 651, 661, 658, 650, 658, 660, 662, 654, 659, 659, 659, 659, 660, 648, 657, 663, 664, 665, 666, 662, 655, 667, 668, 669, 670, 662, 651, 661, 671, 650, 672, 673, 674, 654, 906, 694, 696, 745, 660, 745, 657, 663, 664, 665, 666, 662, 655, 667, 668, 669, 670, 662, 676, 904, 671, 697, 672, 673, 674, 679, 678, 694, 696, 676, 678, 680, 676, 765, 676, 765, 679, 678, 903, 679, 678, 679, 680, 698, 676, 680, 700, 697, 901, 680, 682, 679, 678, 900, 682, 676, 678, 680, 676, 681, 676, 682, 679, 678, 682, 679, 678, 679, 680, 698, 681, 680, 700, 681, 681, 680, 682, 683, 684, 683, 682, 684, 685, 685, 687, 681, 687, 682, 683, 684, 682, 683, 684, 890, 685, 687, 681, 685, 687, 681, 681, 882, 686, 683, 684, 683, 686, 684, 688, 685, 687, 688, 687, 686, 683, 684, 686, 683, 684, 688, 685, 687, 688, 685, 687, 875, 701, 689, 686, 774, 702, 774, 686, 690, 688, 691, 703, 688, 689, 686, 689, 689, 686, 705, 690, 688, 691, 690, 688, 691, 706, 690, 701, 689, 699, 699, 702, 699, 691, 690, 709, 691, 703, 710, 689, 711, 689, 689, 712, 705, 690, 715, 691, 690, 716, 691, 706, 690, 713, 713, 713, 713, 717, 718, 691, 719, 709, 721, 722, 710, 724, 711, 723, 723, 712, 723, 725, 715, 726, 727, 716, 728, 729, 730, 731, 733, 734, 735, 717, 718, 736, 719, 737, 721, 722, 738, 724, 739, 740, 742, 744, 746, 725, 749, 726, 727, 747, 728, 729, 730, 731, 733, 734, 735, 750, 747, 736, 755, 737, 750, 746, 738, 749, 739, 740, 742, 744, 751, 751, 753, 751, 754, 757, 756, 758, 874, 755, 753, 759, 761, 754, 747, 756, 759, 761, 750, 746, 767, 749, 873, 757, 767, 758, 764, 764, 764, 764, 766, 766, 766, 766, 769, 755, 753, 814, 814, 754, 814, 756, 759, 761, 773, 773, 773, 773, 775, 757, 767, 758, 782, 769, 783, 784, 785, 775, 777, 777, 777, 777, 778, 780, 780, 780, 780, 778, 786, 787, 788, 789, 791, 792, 793, 794, 795, 796, 782, 769, 783, 784, 785, 775, 878, 815, 878, 817, 820, 820, 881, 820, 881, 778, 786, 787, 788, 789, 791, 792, 793, 794, 795, 796, 797, 799, 800, 818, 819, 822, 800, 815, 797, 817, 801, 797, 799, 800, 797, 799, 800, 801, 823, 799, 863, 801, 864, 863, 801, 824, 797, 799, 800, 818, 819, 822, 800, 862, 797, 802, 801, 797, 799, 800, 797, 799, 800, 801, 823, 799, 802, 801, 803, 802, 801, 824, 804, 802, 866, 825, 804, 866, 827, 803, 860, 802, 803, 804, 831, 803, 804, 858, 805, 805, 836, 838, 802, 839, 803, 802, 857, 856, 804, 802, 805, 825, 804, 805, 827, 803, 807, 807, 803, 804, 831, 803, 804, 808, 854, 805, 836, 838, 807, 839, 840, 807, 809, 809, 808, 841, 805, 808, 842, 805, 852, 808, 844, 807, 809, 843, 843, 809, 843, 808, 810, 810, 876, 851, 807, 876, 840, 807, 811, 809, 808, 841, 810, 808, 842, 810, 811, 808, 844, 811, 809, 845, 811, 809, 812, 812, 846, 810, 834, 834, 834, 834, 847, 848, 811, 849, 812, 850, 810, 812, 853, 810, 811, 855, 859, 811, 861, 845, 811, 865, 868, 812, 846, 869, 865, 868, 867, 893, 847, 848, 870, 849, 812, 850, 867, 812, 853, 871, 869, 855, 859, 872, 861, 880, 877, 870, 871, 887, 837, 879, 865, 868, 879, 893, 835, 880, 872, 877, 833, 883, 867, 883, 887, 884, 869, 884, 885, 888, 885, 888, 894, 870, 871, 886, 886, 886, 886, 889, 889, 889, 889, 880, 872, 877, 891, 895, 896, 891, 887, 892, 897, 892, 898, 899, 902, 905, 894, 908, 916, 907, 908, 916, 923, 907, 832, 923, 924, 924, 830, 924, 907, 895, 896, 907, 925, 828, 897, 909, 898, 899, 902, 905, 821, 910, 909, 907, 927, 910, 909, 907, 911, 909, 926, 816, 910, 926, 907, 910, 806, 907, 925, 911, 928, 909, 911, 790, 781, 912, 921, 910, 909, 776, 927, 910, 909, 912, 911, 909, 912, 921, 910, 912, 921, 910, 913, 913, 914, 911, 928, 929, 911, 918, 918, 912, 921, 930, 913, 914, 914, 913, 914, 912, 931, 918, 912, 921, 918, 912, 921, 935, 934, 913, 914, 934, 938, 929, 941, 942, 918, 943, 944, 930, 913, 914, 914, 913, 914, 945, 931, 918, 946, 947, 918, 950, 952, 935, 937, 937, 937, 937, 938, 958, 941, 942, 962, 943, 944, 962, 963, 965, 963, 964, 968, 945, 967, 969, 946, 947, 967, 950, 952, 970, 772, 971, 965, 971, 968, 958, 988, 964, 969, 972, 973, 972, 973, 970, 974, 975, 977, 976, 975, 974, 976, 978, 967, 980, 978, 977, 980, 979, 965, 979, 968, 771, 988, 964, 969, 981, 981, 981, 981, 970, 982, 984, 986, 982, 986, 974, 983, 983, 983, 983, 985, 977, 989, 985, 990, 984, 987, 987, 987, 987, 991, 992, 994, 996, 1004, 997, 1005, 1004, 1006, 1005, 1008, 1006, 1009, 1008, 1011, 1009, 997, 1011, 989, 997, 990, 984, 997, 998, 999, 999, 991, 992, 994, 996, 1000, 997, 1001, 1000, 998, 1013, 999, 998, 1013, 999, 1014, 1000, 997, 1001, 1000, 997, 1001, 1015, 997, 998, 1003, 999, 1017, 1042, 1003, 1042, 1000, 1018, 1001, 1000, 998, 1003, 999, 998, 1003, 999, 1014, 1000, 1010, 1001, 1000, 1020, 1001, 1015, 770, 768, 1003, 1022, 1017, 1010, 1003, 1010, 1010, 1018, 1025, 1026, 1028, 1003, 1029, 1030, 1003, 1031, 1034, 1035, 1010, 1037, 762, 1020, 1021, 1021, 1021, 1021, 752, 1022, 1050, 1010, 1039, 1010, 1010, 1039, 1025, 1026, 1028, 1044, 1029, 1030, 1041, 1031, 1034, 1035, 1041, 1037, 1045, 1050, 1052, 1044, 1047, 1047, 1047, 1047, 1048, 1048, 1048, 1048, 743, 741, 1045, 1049, 1049, 1049, 1049, 1051, 1052, 732, 1051, 1053, 1041, 1054, 1053, 1050, 1054, 1044, 1055, 1062, 1063, 1055, 1056, 1056, 1056, 1056, 1057, 1059, 1045, 1057, 1059, 1065, 1060, 1060, 1052, 1060, 1061, 1061, 1061, 1061, 1066, 1067, 1068, 1069, 1069, 1062, 1063, 1085, 1070, 1072, 1072, 1070, 1087, 1076, 720, 1069, 1076, 1065, 1069, 1070, 1077, 1072, 1070, 1077, 1072, 714, 1066, 1067, 1068, 1073, 1069, 708, 1078, 1085, 1070, 1078, 1072, 1070, 1087, 1089, 1073, 1069, 1073, 1073, 1069, 1070, 1075, 1072, 1070, 1093, 1072, 1074, 1074, 1074, 1074, 1073, 1079, 1075, 1080, 1079, 1075, 1080, 1081, 1081, 1075, 1089, 1073, 1082, 1073, 1073, 1082, 1096, 1075, 1097, 1081, 1093, 1099, 1081, 1088, 1088, 1088, 1088, 1100, 1075, 1091, 1091, 1075, 1091, 704, 1081, 1075, 1102, 1102, 1103, 1102, 1105, 1103, 1096, 1106, 1097, 1081, 1106, 1099, 1081, 1104, 1107, 1104, 1107, 1100, 1108, 1110, 1115, 1110, 1105, 1111, 1111, 1111, 1111, 1108, 1112, 1112, 1112, 1112, 1113, 1113, 1113, 1113, 1114, 1116, 1121, 1115, 1116, 1117, 1123, 1117, 1114, 1124, 1118, 1118, 1105, 1118, 695, 1128, 1127, 1108, 1128, 1131, 1131, 1131, 1131, 1133, 1130, 1130, 1133, 1127, 1121, 1115, 1127, 1136, 1123, 1127, 1114, 1124, 1130, 1139, 1132, 1130, 1135, 1135, 1127, 1135, 1143, 1132, 1145, 1140, 1140, 1132, 1140, 1130, 1132, 1127, 1148, 1149, 1127, 1136, 1152, 1127, 693, 1152, 1130, 1139, 1132, 1130, 1138, 1138, 1138, 1138, 1143, 1132, 1145, 1151, 1151, 1132, 1151, 1156, 1132, 1154, 1148, 1149, 1154, 1155, 1159, 1157, 1155, 1157, 1158, 1158, 1158, 1158, 1162, 1161, 1164, 1156, 1161, 1165, 1170, 1159, 1165, 1166, 1166, 1167, 1168, 1171, 1167, 1168, 1171, 1170, 1174, 1176, 1170, 1166, 1172, 1172, 1166, 1172, 1162, 1178, 1164, 1156, 1183, 1180, 1170, 1159, 1180, 1181, 1166, 1181, 1182, 692, 1187, 1182, 1187, 1170, 1174, 1176, 1170, 1166, 1186, 1183, 1166, 1190, 1186, 1178, 1184, 1184, 1184, 1184, 1185, 1185, 1185, 1185, 1188, 1191, 1193, 1188, 1191, 1193, 1194, 1194, 1194, 1194, 1197, 1195, 1199, 1183, 1195, 1190, 1186, 1196, 1200, 1207, 1196, 1205, 1195, 1211, 1213, 1195, 1202, 1202, 1202, 1202, 1204, 1204, 1204, 1204, 677, 675, 1197, 1195, 1199, 1205, 1195, 1215, 653, 1215, 1200, 1207, 644, 625, 1195, 1211, 1213, 1195, 1206, 1206, 1206, 1206, 1208, 1208, 1208, 1208, 1209, 1209, 1209, 1209, 1210, 1205, 1214, 1214, 1214, 1214, 1217, 1217, 1217, 1217, 1218, 1210, 1220, 1220, 1210, 623, 622, 1210, 1219, 1219, 1219, 1219, 620, 1225, 1220, 1225, 1210, 1220, 1224, 1224, 1224, 1224, 1229, 1229, 1229, 1229, 1218, 1210, 611, 1220, 1210, 609, 600, 1210, 1230, 1230, 1230, 1230, 596, 591, 1220, 585, 582, 1220, 1231, 1231, 1231, 1231, 1232, 1232, 1232, 1232, 1233, 1233, 1233, 1233, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1235, 1236, 1236, 1237, 577, 572, 1237, 1237, 1237, 539, 1237, 1238, 1238, 537, 1238, 520, 1238, 505, 1238, 1239, 1239, 493, 1239, 491, 1239, 482, 1239, 1240, 1240, 1240, 473, 1240, 1240, 1240, 1240, 1240, 1241, 467, 1241, 1242, 459, 421, 1242, 414, 1242, 407, 1242, 1242, 405, 404, 393, 303, 263, 237, 233, 230, 197, 182, 167, 166, 159, 158, 157, 128, 127, 120, 104, 102, 90, 72, 59, 49, 43, 27, 25, 23, 17, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234, 1234 } ; /* Table of booleans, true if rule could match eol. */ static yyconst flex_int32_t yy_rule_can_match_eol[104] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, }; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int scdoc_flex_debug; int scdoc_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *scdoctext; #line 1 "SCDoc.l" #line 2 "SCDoc.l" /************************************************************************ * * Copyright 2012 Jonatan Liljedahl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include "SCDoc.h" #include "SCDoc.tab.hpp" int scdoc_start_token = 0; //int colnum; //#define YY_USER_ACTION { scdoclloc.first_column = colnum; colnum=colnum+scdocleng; scdoclloc.last_column=colnum; if(scdoclloc.first_line!=scdoclineno) colnum=1; scdoclloc.first_line = scdoclloc.last_line = scdoclineno;} static int method_caller; #define YY_NO_UNISTD_H 1 #line 1825 "lex.scdoc.cpp" #define INITIAL 0 #define verbatim 1 #define verbatim2 2 #define metadata 3 #define eat 4 #define eat2 5 #define eat3 6 #define method 7 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Accessor methods to globals. These are made visible to non-reentrant scanners for convenience. */ int scdoclex_destroy (void ); int scdocget_debug (void ); void scdocset_debug (int debug_flag ); YY_EXTRA_TYPE scdocget_extra (void ); void scdocset_extra (YY_EXTRA_TYPE user_defined ); FILE *scdocget_in (void ); void scdocset_in (FILE * in_str ); FILE *scdocget_out (void ); void scdocset_out (FILE * out_str ); int scdocget_leng (void ); char *scdocget_text (void ); int scdocget_lineno (void ); void scdocset_lineno (int line_number ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int scdocwrap (void ); #else extern int scdocwrap (void ); #endif #endif static void yyunput (int c,char *buf_ptr ); #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #ifdef __ia64__ /* On IA-64, the buffer size is 16k, not 8k */ #define YY_READ_BUF_SIZE 16384 #else #define YY_READ_BUF_SIZE 8192 #endif /* __ia64__ */ #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO do { if (fwrite( scdoctext, scdocleng, 1, scdocout )) {} } while (0) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( scdocin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( scdocin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, scdocin))==0 && ferror(scdocin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(scdocin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int scdoclex (void); #define YY_DECL int scdoclex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after scdoctext and scdocleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 45 "SCDoc.l" if (scdoc_start_token) { int t = scdoc_start_token; scdoc_start_token = 0; // colnum = 1; if(t==START_METADATA) BEGIN(eat); return t; } #line 2034 "lex.scdoc.cpp" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! scdocin ) scdocin = stdin; if ( ! scdocout ) scdocout = stdout; if ( ! YY_CURRENT_BUFFER ) { scdocensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = scdoc_create_buffer(scdocin,YY_BUF_SIZE ); } scdoc_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of scdoctext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1235 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_current_state != 1234 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_find_action: yy_act = yy_accept[yy_current_state]; YY_DO_BEFORE_ACTION; if ( yy_act != YY_END_OF_BUFFER && yy_rule_can_match_eol[yy_act] ) { int yyl; for ( yyl = 0; yyl < scdocleng; ++yyl ) if ( scdoctext[yyl] == '\n' ) scdoclineno++; ; } do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 59 "SCDoc.l" return CLASS; YY_BREAK case 2: YY_RULE_SETUP #line 60 "SCDoc.l" return TITLE; YY_BREAK case 3: YY_RULE_SETUP #line 61 "SCDoc.l" return SUMMARY; YY_BREAK case 4: YY_RULE_SETUP #line 62 "SCDoc.l" return RELATED; YY_BREAK case 5: YY_RULE_SETUP #line 63 "SCDoc.l" return CATEGORIES; YY_BREAK case 6: YY_RULE_SETUP #line 64 "SCDoc.l" return REDIRECT; YY_BREAK case 7: YY_RULE_SETUP #line 66 "SCDoc.l" return CLASSTREE; YY_BREAK case 8: YY_RULE_SETUP #line 67 "SCDoc.l" return KEYWORD; YY_BREAK case 9: YY_RULE_SETUP #line 69 "SCDoc.l" return PRIVATE; YY_BREAK case 10: YY_RULE_SETUP #line 70 "SCDoc.l" return SECTION; YY_BREAK case 11: YY_RULE_SETUP #line 71 "SCDoc.l" return SUBSECTION; YY_BREAK case 12: YY_RULE_SETUP #line 72 "SCDoc.l" return COPYMETHOD; YY_BREAK case 13: YY_RULE_SETUP #line 73 "SCDoc.l" method_caller = YY_START; BEGIN(method); return METHOD; YY_BREAK case 14: YY_RULE_SETUP #line 74 "SCDoc.l" return ARGUMENT; YY_BREAK case 15: /* rule 15 can match eol */ YY_RULE_SETUP #line 76 "SCDoc.l" return DESCRIPTION; YY_BREAK case 16: /* rule 16 can match eol */ YY_RULE_SETUP #line 77 "SCDoc.l" return CLASSMETHODS; YY_BREAK case 17: /* rule 17 can match eol */ YY_RULE_SETUP #line 78 "SCDoc.l" return INSTANCEMETHODS; YY_BREAK case 18: /* rule 18 can match eol */ YY_RULE_SETUP #line 79 "SCDoc.l" return EXAMPLES; YY_BREAK case 19: /* rule 19 can match eol */ YY_RULE_SETUP #line 81 "SCDoc.l" return RETURNS; YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP #line 82 "SCDoc.l" return DISCUSSION; YY_BREAK case 21: /* rule 21 can match eol */ YY_RULE_SETUP #line 84 "SCDoc.l" return LIST; YY_BREAK case 22: /* rule 22 can match eol */ YY_RULE_SETUP #line 85 "SCDoc.l" return TREE; YY_BREAK case 23: /* rule 23 can match eol */ YY_RULE_SETUP #line 86 "SCDoc.l" return NUMBEREDLIST; YY_BREAK case 24: /* rule 24 can match eol */ YY_RULE_SETUP #line 87 "SCDoc.l" return DEFINITIONLIST; YY_BREAK case 25: /* rule 25 can match eol */ YY_RULE_SETUP #line 88 "SCDoc.l" return TABLE; YY_BREAK case 26: /* rule 26 can match eol */ YY_RULE_SETUP #line 89 "SCDoc.l" return FOOTNOTE; YY_BREAK case 27: /* rule 27 can match eol */ YY_RULE_SETUP #line 90 "SCDoc.l" return WARNING; YY_BREAK case 28: /* rule 28 can match eol */ YY_RULE_SETUP #line 91 "SCDoc.l" return NOTE; YY_BREAK case 29: YY_RULE_SETUP #line 93 "SCDoc.l" BEGIN(verbatim); return LINK; YY_BREAK case 30: YY_RULE_SETUP #line 94 "SCDoc.l" BEGIN(verbatim); return ANCHOR; YY_BREAK case 31: YY_RULE_SETUP #line 95 "SCDoc.l" BEGIN(verbatim); return IMAGE; YY_BREAK case 32: /* rule 32 can match eol */ YY_RULE_SETUP #line 96 "SCDoc.l" BEGIN(verbatim); return SOFT; YY_BREAK case 33: /* rule 33 can match eol */ YY_RULE_SETUP #line 97 "SCDoc.l" BEGIN(verbatim); return STRONG; YY_BREAK case 34: /* rule 34 can match eol */ YY_RULE_SETUP #line 98 "SCDoc.l" BEGIN(verbatim); return EMPHASIS; YY_BREAK case 35: YY_RULE_SETUP #line 99 "SCDoc.l" BEGIN(verbatim); return CODE; YY_BREAK case 36: YY_RULE_SETUP #line 100 "SCDoc.l" BEGIN(verbatim); return TELETYPE; YY_BREAK case 37: /* rule 37 can match eol */ YY_RULE_SETUP #line 102 "SCDoc.l" BEGIN(verbatim2); return CODEBLOCK; YY_BREAK case 38: /* rule 38 can match eol */ YY_RULE_SETUP #line 103 "SCDoc.l" BEGIN(verbatim2); return TELETYPEBLOCK; YY_BREAK case 39: /* rule 39 can match eol */ YY_RULE_SETUP #line 105 "SCDoc.l" BEGIN(0); return TAGSYM; YY_BREAK case 40: /* rule 40 can match eol */ YY_RULE_SETUP #line 106 "SCDoc.l" BEGIN(0); return TAGSYM; YY_BREAK case 41: /* rule 41 can match eol */ YY_RULE_SETUP #line 107 "SCDoc.l" scdoclval.str = strdup("\n::"); return TEXT; YY_BREAK case 42: /* rule 42 can match eol */ YY_RULE_SETUP #line 108 "SCDoc.l" return BARS; YY_BREAK case 43: /* rule 43 can match eol */ YY_RULE_SETUP #line 109 "SCDoc.l" return HASHES; YY_BREAK case 44: /* rule 44 can match eol */ YY_RULE_SETUP #line 111 "SCDoc.l" scdoclval.str = strdup("\n"); return TEXT; YY_BREAK case 45: /* rule 45 can match eol */ YY_RULE_SETUP #line 112 "SCDoc.l" scdoclval.str = strdup(" "); return TEXT; YY_BREAK case 46: /* rule 46 can match eol */ YY_RULE_SETUP #line 113 "SCDoc.l" return NEWLINE; YY_BREAK case 47: /* rule 47 can match eol */ YY_RULE_SETUP #line 114 "SCDoc.l" return EMPTYLINES; YY_BREAK case 48: YY_RULE_SETUP #line 116 "SCDoc.l" scdoclval.str = strdup(scdoctext); return COMMA; YY_BREAK case 49: YY_RULE_SETUP #line 118 "SCDoc.l" scdoclval.str = strdup("||"); return TEXT; YY_BREAK case 50: YY_RULE_SETUP #line 119 "SCDoc.l" scdoclval.str = strdup("##"); return TEXT; YY_BREAK case 51: YY_RULE_SETUP #line 120 "SCDoc.l" scdoclval.str = strdup("::"); return TEXT; YY_BREAK case 52: YY_RULE_SETUP #line 121 "SCDoc.l" scdoclval.str = strdup(" "); return TEXT; YY_BREAK case 53: YY_RULE_SETUP #line 122 "SCDoc.l" scdoclval.str = strdup(" "); return TEXT; YY_BREAK case 54: YY_RULE_SETUP #line 124 "SCDoc.l" /* eat this */ YY_BREAK case 55: YY_RULE_SETUP #line 126 "SCDoc.l" scdoclval.str = strdup(scdoctext); return URL; YY_BREAK case 56: YY_RULE_SETUP #line 127 "SCDoc.l" scdoclval.str = strdup(scdoctext); return METHODNAME; YY_BREAK case 57: /* rule 57 can match eol */ YY_RULE_SETUP #line 128 "SCDoc.l" scdoclval.str = strdup(scdoctext); return METHODARGS; YY_BREAK case 58: YY_RULE_SETUP #line 129 "SCDoc.l" /* eat this */ YY_BREAK case 59: /* rule 59 can match eol */ YY_RULE_SETUP #line 130 "SCDoc.l" BEGIN(method_caller); return NEWLINE; YY_BREAK case 60: YY_RULE_SETUP #line 131 "SCDoc.l" return BAD_METHODNAME; YY_BREAK case 61: #line 134 "SCDoc.l" case 62: #line 135 "SCDoc.l" case 63: #line 136 "SCDoc.l" case 64: #line 137 "SCDoc.l" case 65: YY_RULE_SETUP #line 137 "SCDoc.l" scdoclval.str = strdup(scdoctext); return TEXT; YY_BREAK case 66: YY_RULE_SETUP #line 139 "SCDoc.l" BEGIN(metadata); return CLASS; YY_BREAK case 67: YY_RULE_SETUP #line 140 "SCDoc.l" BEGIN(metadata); return TITLE; YY_BREAK case 68: YY_RULE_SETUP #line 141 "SCDoc.l" BEGIN(metadata); return SUMMARY; YY_BREAK case 69: YY_RULE_SETUP #line 142 "SCDoc.l" BEGIN(metadata); return RELATED; YY_BREAK case 70: YY_RULE_SETUP #line 143 "SCDoc.l" BEGIN(metadata); return CATEGORIES; YY_BREAK case 71: YY_RULE_SETUP #line 144 "SCDoc.l" BEGIN(metadata); return REDIRECT; YY_BREAK case 72: YY_RULE_SETUP #line 145 "SCDoc.l" BEGIN(metadata); return CLASSTREE; YY_BREAK case 73: YY_RULE_SETUP #line 146 "SCDoc.l" BEGIN(metadata); return KEYWORD; YY_BREAK case 74: YY_RULE_SETUP #line 147 "SCDoc.l" BEGIN(metadata); return PRIVATE; YY_BREAK case 75: YY_RULE_SETUP #line 148 "SCDoc.l" BEGIN(metadata); return SECTION; YY_BREAK case 76: YY_RULE_SETUP #line 149 "SCDoc.l" BEGIN(metadata); return SUBSECTION; YY_BREAK case 77: YY_RULE_SETUP #line 150 "SCDoc.l" BEGIN(metadata); return COPYMETHOD; YY_BREAK case 78: YY_RULE_SETUP #line 151 "SCDoc.l" method_caller = YY_START; BEGIN(method); return METHOD; YY_BREAK case 79: /* rule 79 can match eol */ YY_RULE_SETUP #line 152 "SCDoc.l" BEGIN(eat); return DESCRIPTION; YY_BREAK case 80: /* rule 80 can match eol */ YY_RULE_SETUP #line 153 "SCDoc.l" BEGIN(eat); return CLASSMETHODS; YY_BREAK case 81: /* rule 81 can match eol */ YY_RULE_SETUP #line 154 "SCDoc.l" BEGIN(eat); return INSTANCEMETHODS; YY_BREAK case 82: /* rule 82 can match eol */ YY_RULE_SETUP #line 155 "SCDoc.l" BEGIN(eat); return EXAMPLES; YY_BREAK case 83: /* rule 83 can match eol */ YY_RULE_SETUP #line 156 "SCDoc.l" BEGIN(eat); return NEWLINE; YY_BREAK case 84: YY_RULE_SETUP #line 157 "SCDoc.l" scdoclval.str = strdup(scdoctext); return COMMA; YY_BREAK case 85: #line 159 "SCDoc.l" case 86: #line 160 "SCDoc.l" case 87: #line 161 "SCDoc.l" case 88: YY_RULE_SETUP #line 161 "SCDoc.l" scdoclval.str = strdup(scdoctext); return TEXT; YY_BREAK case 89: YY_RULE_SETUP #line 162 "SCDoc.l" scdoclval.str = strdup("::"); return TEXT; YY_BREAK case 90: YY_RULE_SETUP #line 163 "SCDoc.l" BEGIN(eat2); YY_BREAK case 91: YY_RULE_SETUP #line 164 "SCDoc.l" BEGIN(eat2); YY_BREAK case 92: YY_RULE_SETUP #line 165 "SCDoc.l" BEGIN(eat2); YY_BREAK case 93: /* rule 93 can match eol */ YY_RULE_SETUP #line 166 "SCDoc.l" BEGIN(eat2); YY_BREAK case 94: /* rule 94 can match eol */ YY_RULE_SETUP #line 167 "SCDoc.l" BEGIN(eat2); YY_BREAK case 95: /* rule 95 can match eol */ YY_RULE_SETUP #line 168 "SCDoc.l" BEGIN(eat2); YY_BREAK case 96: YY_RULE_SETUP #line 169 "SCDoc.l" BEGIN(eat2); YY_BREAK case 97: YY_RULE_SETUP #line 170 "SCDoc.l" BEGIN(eat2); YY_BREAK case 98: /* rule 98 can match eol */ YY_RULE_SETUP #line 171 "SCDoc.l" BEGIN(eat3); YY_BREAK case 99: /* rule 99 can match eol */ YY_RULE_SETUP #line 172 "SCDoc.l" BEGIN(eat3); YY_BREAK case 100: /* rule 100 can match eol */ YY_RULE_SETUP #line 173 "SCDoc.l" BEGIN(eat); YY_BREAK case 101: /* rule 101 can match eol */ YY_RULE_SETUP #line 174 "SCDoc.l" BEGIN(eat); YY_BREAK case 102: /* rule 102 can match eol */ YY_RULE_SETUP #line 175 "SCDoc.l" /* empty */ YY_BREAK case 103: YY_RULE_SETUP #line 176 "SCDoc.l" ECHO; YY_BREAK #line 2660 "lex.scdoc.cpp" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(verbatim): case YY_STATE_EOF(verbatim2): case YY_STATE_EOF(metadata): case YY_STATE_EOF(eat): case YY_STATE_EOF(eat2): case YY_STATE_EOF(eat3): case YY_STATE_EOF(method): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed scdocin at a new source and called * scdoclex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = scdocin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( scdocwrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * scdoctext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of scdoclex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ scdocrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; scdocrestart(scdocin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { /* Extend the array by 50%, plus the number we really need. */ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) scdocrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); } (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1235 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 1235 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 1234); return yy_is_jam ? 0 : yy_current_state; } static void yyunput (int c, register char * yy_bp ) { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up scdoctext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; if ( c == '\n' ){ --scdoclineno; } (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ scdocrestart(scdocin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( scdocwrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve scdoctext */ (yy_hold_char) = *++(yy_c_buf_p); if ( c == '\n' ) scdoclineno++; ; return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void scdocrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ scdocensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = scdoc_create_buffer(scdocin,YY_BUF_SIZE ); } scdoc_init_buffer(YY_CURRENT_BUFFER,input_file ); scdoc_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void scdoc_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * scdocpop_buffer_state(); * scdocpush_buffer_state(new_buffer); */ scdocensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; scdoc_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (scdocwrap()) processing, but the only time this flag * is looked at is after scdocwrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void scdoc_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; scdocin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE scdoc_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) scdocalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in scdoc_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) scdocalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in scdoc_create_buffer()" ); b->yy_is_our_buffer = 1; scdoc_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with scdoc_create_buffer() * */ void scdoc_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) scdocfree((void *) b->yy_ch_buf ); scdocfree((void *) b ); } /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a scdocrestart() or at EOF. */ static void scdoc_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; scdoc_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then scdoc_init_buffer was _probably_ * called from scdocrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void scdoc_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) scdoc_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void scdocpush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; scdocensure_buffer_stack(); /* This block is copied from scdoc_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from scdoc_switch_to_buffer. */ scdoc_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void scdocpop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; scdoc_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { scdoc_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void scdocensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)scdocalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in scdocensure_buffer_stack()" ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)scdocrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); if ( ! (yy_buffer_stack) ) YY_FATAL_ERROR( "out of dynamic memory in scdocensure_buffer_stack()" ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE scdoc_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) scdocalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in scdoc_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; scdoc_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to scdoclex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * scdoc_scan_bytes() instead. */ YY_BUFFER_STATE scdoc_scan_string (yyconst char * yystr ) { return scdoc_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to scdoclex() will * scan from a @e copy of @a bytes. * @param yybytes the byte buffer to scan * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE scdoc_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) scdocalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in scdoc_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = scdoc_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in scdoc_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up scdoctext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ scdoctext[scdocleng] = (yy_hold_char); \ (yy_c_buf_p) = scdoctext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ scdocleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int scdocget_lineno (void) { return scdoclineno; } /** Get the input stream. * */ FILE *scdocget_in (void) { return scdocin; } /** Get the output stream. * */ FILE *scdocget_out (void) { return scdocout; } /** Get the length of the current token. * */ int scdocget_leng (void) { return scdocleng; } /** Get the current token. * */ char *scdocget_text (void) { return scdoctext; } /** Set the current line number. * @param line_number * */ void scdocset_lineno (int line_number ) { scdoclineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see scdoc_switch_to_buffer */ void scdocset_in (FILE * in_str ) { scdocin = in_str ; } void scdocset_out (FILE * out_str ) { scdocout = out_str ; } int scdocget_debug (void) { return scdoc_flex_debug; } void scdocset_debug (int bdebug ) { scdoc_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from scdoclex_destroy(), so don't allocate here. */ /* We do not touch scdoclineno unless the option is enabled. */ scdoclineno = 1; (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT scdocin = stdin; scdocout = stdout; #else scdocin = (FILE *) 0; scdocout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * scdoclex_init() */ return 0; } /* scdoclex_destroy is for both reentrant and non-reentrant scanners. */ int scdoclex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ scdoc_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; scdocpop_buffer_state(); } /* Destroy the stack itself. */ scdocfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * scdoclex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *scdocalloc (yy_size_t size ) { return (void *) malloc( size ); } void *scdocrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void scdocfree (void * ptr ) { free( (char *) ptr ); /* see scdocrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 176 "SCDoc.l" SuperCollider-Source/SCDoc/main.cpp000644 000765 000024 00000001771 12321461510 020241 0ustar00crucialstaff000000 000000 #include #include #include #include #include "SCDoc.h" void error(const char *fmt, ...) { fprintf(stderr, "ERROR: "); va_list vargs; va_start(vargs, fmt); vfprintf(stderr, fmt, vargs); fflush(stderr); } void post(const char *fmt, ...) { va_list vargs; va_start(vargs, fmt); vfprintf(stderr, fmt, vargs); fflush(stderr); } int main(int argc, char **argv) { if(argc>1) { DocNode *n; if(argc>2 && strcmp(argv[1],"--partial")==0) n = scdoc_parse_file(argv[2], SCDOC_PARSE_PARTIAL); else if(argc>2 && strcmp(argv[1],"--metadata")==0) n = scdoc_parse_file(argv[2], SCDOC_PARSE_METADATA); else n = scdoc_parse_file(argv[1], SCDOC_PARSE_FULL); if(n) { doc_node_dump(n); doc_node_free_tree(n); } else return 1; } else { fprintf(stderr, "Usage: %s inputfile.schelp\n",argv[0]); } return 0; } SuperCollider-Source/SCDoc/SCDoc.cpp000644 000765 000024 00000012734 12524671172 020265 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jonatan Liljedahl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include #include #include #include "SCDoc.h" DocNode * scdoc_parse_run(int partial); void scdocrestart (FILE *input_file); int scdoclex_destroy(void); const char * scdoc_current_file = NULL; const char * NODE_TEXT = "TEXT"; const char * NODE_NL = "NL"; static int doc_node_dump_level_done[32] = {0,}; // merge a+b and free b char *strmerge(char *a, char *b) { if(a==NULL) return b; if(b==NULL) return a; char *s = (char *)realloc(a,strlen(a)+strlen(b)+1); strcat(s,b); free(b); return s; } static char *striptrailingws(char *s) { char *s2 = strchr(s,0); while(--s2 > s && isspace(*s2)) { *s2 = 0; } return s; } DocNode * doc_node_create(const char *id) { DocNode *n = (DocNode *)malloc(sizeof(DocNode)); n->id = id; n->text = NULL; n->n_childs = 0; n->children = NULL; return n; } // takes ownership of child DocNode * doc_node_add_child(DocNode *n, DocNode *child) { if(child) { n->children = (DocNode **)realloc(n->children, (n->n_childs+1) * sizeof(DocNode*)); n->children[n->n_childs] = child; n->n_childs++; } return n; } // takes ownership of text /*DocNode * doc_node_add_text(DocNode *n, char *text) { if(n->text) { char *str = strmergefree(n->text,text); n->text = str; printf("NODE: Adding text '%s'\n",text); } else { n->text = text; } return n; }*/ // moves the childs from src doc_node to n void doc_node_move_children(DocNode *n, DocNode *src) { if(src) { free(n->children); n->children = src->children; n->n_childs = src->n_childs; // src->children = NULL; // src->n_childs = 0; free(src->text); free(src); } } DocNode * doc_node_make(const char *id, char *text, DocNode *child) { DocNode *n = doc_node_create(id); n->text = text; doc_node_add_child(n, child); return n; } DocNode * doc_node_make_take_children(const char *id, char *text, DocNode *src) { DocNode *n = doc_node_make(id, text, NULL); doc_node_move_children(n, src); return n; } void doc_node_free_tree(DocNode *n) { int i; if(!n) return; free(n->text); for(i=0;in_childs;i++) { doc_node_free_tree(n->children[i]); } free(n->children); free(n); } void doc_node_fixup_tree(DocNode *n) { int i; if(n->id != NODE_TEXT && n->text) { n->text = striptrailingws(n->text); } if(n->n_childs) { DocNode *last = n->children[n->n_childs-1]; if(last->id==NODE_NL) { free(last); // NL has no text or children n->n_childs--; } last = NULL; for(i = 0; i < n->n_childs; i++) { DocNode *child = n->children[i]; if((child->id==NODE_TEXT || child->id==NODE_NL) && last && last->id==NODE_TEXT) { if(child->id==NODE_NL) { last->text = (char*)realloc(last->text,strlen(last->text)+2); strcat(last->text," "); } else { last->text = strmerge(last->text,child->text); } free(child); // we took childs text and it has no children n->children[i] = NULL; } else { doc_node_fixup_tree(child); last = child; } } int j = 0; for(i = 0; i < n->n_childs; i++) { if(n->children[i]) { n->children[j++] = n->children[i]; } } n->n_childs = j; } } static void _doc_node_dump(DocNode *n, int level, int last) { int i; for(i=0;iid); if(n->text) printf(" \"%s\"",n->text); printf("\n"); for(i = 0; i < n->n_childs; i++) { _doc_node_dump(n->children[i], level+1, i==n->n_childs-1); } doc_node_dump_level_done[level] = 0; } void doc_node_dump(DocNode *n) { _doc_node_dump(n,0,1); } extern void error(const char *fmt, ...); DocNode * scdoc_parse_file(const char *fn, int mode) { FILE *fp; DocNode *n; fp = fopen(fn,"r"); if(!fp) { error("scdoc_parse_file: could not open '%s'\n",fn); return NULL; } scdoc_current_file = fn; scdocrestart(fp); n = scdoc_parse_run(mode); if(n) { doc_node_fixup_tree(n); } fclose(fp); scdoclex_destroy(); scdoc_current_file = NULL; return n; } SuperCollider-Source/SCDoc/SCDoc.h000644 000765 000024 00000001421 12756531745 017731 0ustar00crucialstaff000000 000000 #ifndef SCDOC_H #define SCDOC_H #include #define SCDOC_PARSE_FULL 0 #define SCDOC_PARSE_PARTIAL 1 #define SCDOC_PARSE_METADATA 2 extern const char * NODE_TEXT; extern const char * NODE_NL; typedef struct DocNode { const char *id; char *text; int n_childs; struct DocNode **children; } DocNode; char *strmerge(char *a, char *b); DocNode * doc_node_make_take_children(const char *id, char *text, DocNode *src); DocNode * doc_node_make(const char *id, char *text, DocNode *child); DocNode * doc_node_add_child(DocNode *n, DocNode *child); DocNode * doc_node_create(const char *id); void doc_node_free_tree(DocNode *n); DocNode * scdoc_parse_file(const char *fn, int mode); void doc_node_dump(DocNode *n); extern const char * scdoc_current_file; #endif SuperCollider-Source/SCDoc/SCDoc.l000644 000765 000024 00000016665 12321461510 017731 0ustar00crucialstaff000000 000000 %{ /************************************************************************ * * Copyright 2012 Jonatan Liljedahl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include "SCDoc.h" #include "SCDoc.tab.hpp" int scdoc_start_token = 0; //int colnum; //#define YY_USER_ACTION { scdoclloc.first_column = colnum; colnum=colnum+yyleng; scdoclloc.last_column=colnum; if(scdoclloc.first_line!=yylineno) colnum=1; scdoclloc.first_line = scdoclloc.last_line = yylineno;} static int method_caller; %} %option noyywrap never-interactive nounistd yylineno %x verbatim %x verbatim2 %x metadata %x eat %x eat2 %x eat3 %x method %% %{ if (scdoc_start_token) { int t = scdoc_start_token; scdoc_start_token = 0; // colnum = 1; if(t==START_METADATA) BEGIN(eat); return t; } %} (?i:[ \t]*class::[ \t]*) return CLASS; (?i:[ \t]*title::[ \t]*) return TITLE; (?i:[ \t]*summary::[ \t]*) return SUMMARY; (?i:[ \t]*related::[ \t]*) return RELATED; (?i:[ \t]*categories::[ \t]*) return CATEGORIES; (?i:[ \t]*redirect::[ \t]*) return REDIRECT; (?i:[ \t]*classtree::[ \t]*) return CLASSTREE; (?i:[ \t]*keyword::[ \t]*) return KEYWORD; (?i:[ \t]*private::[ \t]*) return PRIVATE; (?i:[ \t]*section::[ \t]*) return SECTION; (?i:[ \t]*subsection::[ \t]*) return SUBSECTION; (?i:[ \t]*copymethod::[ \t]*) return COPYMETHOD; (?i:[ \t]*method::[ \t]*) method_caller = YY_START; BEGIN(method); return METHOD; (?i:[ \t]*argument::[ \t]*) return ARGUMENT; (?i:[ \t]*description::[ \t\n\r]*) return DESCRIPTION; (?i:[ \t]*classmethods::[ \t\n\r]*) return CLASSMETHODS; (?i:[ \t]*instancemethods::[ \t\n\r]*) return INSTANCEMETHODS; (?i:[ \t]*examples::[ \t\n\r]*) return EXAMPLES; (?i:[ \t]*returns::[ \t\n\r]*) return RETURNS; (?i:[ \t]*discussion::[ \t\n\r]*) return DISCUSSION; (?i:[ \t]*list::[ \t\n\r]*) return LIST; (?i:[ \t]*tree::[ \t\n\r]*) return TREE; (?i:[ \t]*numberedlist::[ \t\n\r]*) return NUMBEREDLIST; (?i:[ \t]*definitionlist::[ \t\n\r]*) return DEFINITIONLIST; (?i:[ \t]*table::[ \t\n\r]*) return TABLE; (?i:[ \t]*footnote::[ \t\n\r]*) return FOOTNOTE; (?i:[ \t]*warning::[ \t\n\r]*) return WARNING; (?i:[ \t]*note::[ \t\n\r]*) return NOTE; (?i:link::[ \t]*) BEGIN(verbatim); return LINK; (?i:anchor::[ \t]*) BEGIN(verbatim); return ANCHOR; (?i:image::[ \t]*) BEGIN(verbatim); return IMAGE; (?i:soft::[ \t\n\r]*) BEGIN(verbatim); return SOFT; (?i:strong::[ \t\n\r]*) BEGIN(verbatim); return STRONG; (?i:emphasis::[ \t\n\r]*) BEGIN(verbatim); return EMPHASIS; (?i:code::[ \t]*) BEGIN(verbatim); return CODE; (?i:teletype::[ \t]*) BEGIN(verbatim); return TELETYPE; (?i:[ \t]*code::[ \t]*\n+) BEGIN(verbatim2); return CODEBLOCK; (?i:[ \t]*teletype::[ \t]*\n+) BEGIN(verbatim2); return TELETYPEBLOCK; [ \t\n\r]*:: BEGIN(0); return TAGSYM; \n[ \t\n\r]*:: BEGIN(0); return TAGSYM; \n[ \t]*\\:: scdoclval.str = strdup("\n::"); return TEXT; [ \t]*\|\|[ \t\n\r]* return BARS; [ \t]*\#\#[ \t\n\r]* return HASHES; \n scdoclval.str = strdup("\n"); return TEXT; \n+ scdoclval.str = strdup(" "); return TEXT; \n return NEWLINE; \n([ \t\r]*\n)+ return EMPTYLINES; [ \t]*,[ \t]* scdoclval.str = strdup(scdoctext); return COMMA; \\\|\| scdoclval.str = strdup("||"); return TEXT; \\\#\# scdoclval.str = strdup("##"); return TEXT; \\:: scdoclval.str = strdup("::"); return TEXT; \t scdoclval.str = strdup(" "); return TEXT; [ \t]+ scdoclval.str = strdup(" "); return TEXT; <*>\r /* eat this */ [a-zA-Z]+:\/\/[^ \t\n\r:,]+ scdoclval.str = strdup(scdoctext); return URL; [a-z][a-zA-Z0-9_]*|[-<>@|&%*+/!?=]+ scdoclval.str = strdup(scdoctext); return METHODNAME; \([^()]+\) scdoclval.str = strdup(scdoctext); return METHODARGS; [ \r\t]+ /* eat this */ \n BEGIN(method_caller); return NEWLINE; . return BAD_METHODNAME; [a-zA-Z]+ | [.!?(){}\[\]'"0-9]+ | [^:\\\t\n\r ]+ | [^:\\\n\r] | . scdoclval.str = strdup(scdoctext); return TEXT; (?i:[ \t]*class::[ \t]*) BEGIN(metadata); return CLASS; (?i:[ \t]*title::[ \t]*) BEGIN(metadata); return TITLE; (?i:[ \t]*summary::[ \t]*) BEGIN(metadata); return SUMMARY; (?i:[ \t]*related::[ \t]*) BEGIN(metadata); return RELATED; (?i:[ \t]*categories::[ \t]*) BEGIN(metadata); return CATEGORIES; (?i:[ \t]*redirect::[ \t]*) BEGIN(metadata); return REDIRECT; (?i:[ \t]*classtree::[ \t]*) BEGIN(metadata); return CLASSTREE; (?i:[ \t]*keyword::[ \t]*) BEGIN(metadata); return KEYWORD; (?i:[ \t]*private::[ \t]*) BEGIN(metadata); return PRIVATE; (?i:[ \t]*section::[ \t]*) BEGIN(metadata); return SECTION; (?i:[ \t]*subsection::[ \t]*) BEGIN(metadata); return SUBSECTION; (?i:[ \t]*copymethod::[ \t]*) BEGIN(metadata); return COPYMETHOD; (?i:[ \t]*method::[ \t]*) method_caller = YY_START; BEGIN(method); return METHOD; (?i:[ \t]*description::[ \t\n\r]*) BEGIN(eat); return DESCRIPTION; (?i:[ \t]*classmethods::[ \t\n\r]*) BEGIN(eat); return CLASSMETHODS; (?i:[ \t]*instancemethods::[ \t\n\r]*) BEGIN(eat); return INSTANCEMETHODS; (?i:[ \t]*examples::[ \t\n\r]*) BEGIN(eat); return EXAMPLES; \n BEGIN(eat); return NEWLINE; [ \t]*,[ \t]* scdoclval.str = strdup(scdoctext); return COMMA; [a-zA-Z]+ | [0-9]+ | [^:\\\n\r,]+ | . scdoclval.str = strdup(scdoctext); return TEXT; \\:: scdoclval.str = strdup("::"); return TEXT; (?i:link::[ \t]*) BEGIN(eat2); (?i:anchor::[ \t]*) BEGIN(eat2); (?i:image::[ \t]*) BEGIN(eat2); (?i:soft::[ \t\n\r]*) BEGIN(eat2); (?i:strong::[ \t\n\r]*) BEGIN(eat2); (?i:emphasis::[ \t\n\r]*) BEGIN(eat2); (?i:code::[ \t]*) BEGIN(eat2); (?i:teletype::[ \t]*) BEGIN(eat2); (?i:[ \t]*code::[ \t]*\n+) BEGIN(eat3); (?i:[ \t]*teletype::[ \t]*\n+) BEGIN(eat3); [ \t\n\r]*:: BEGIN(eat); \n[ \t\n\r]*:: BEGIN(eat); .|\n /* empty */ %%SuperCollider-Source/SCDoc/SCDoc.tab.cpp000644 000765 000024 00000275224 12756531745 021047 0ustar00crucialstaff000000 000000 /* A Bison parser, made by GNU Bison 3.0.2. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.0.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Substitute the variable and function names. */ #define yyparse scdocparse #define yylex scdoclex #define yyerror scdocerror #define yydebug scdocdebug #define yynerrs scdocnerrs #define yylval scdoclval #define yychar scdocchar #define yylloc scdoclloc /* Copy the first part of user declarations. */ #line 1 "SCDoc.y" /* yacc.c:339 */ /************************************************************************ * * Copyright 2012 Jonatan Liljedahl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include #include #include #include "SCDoc.h" //#define YYLEX_PARAM &yylval, &yylloc int scdocparse(); extern int scdoclineno; extern char *scdoctext; extern int scdoc_start_token; extern FILE *scdocin; //extern struct YYLTYPE scdoclloc; //int scdoc_metadata_mode; static const char * method_type = NULL; static DocNode * topnode; void scdocerror(const char *str); extern void error(const char *fmt, ...); extern void post(const char *fmt, ...); static inline bool stringEqual(const char * a, const char * b) { return strcmp(a, b) == 0; } #line 129 "SCDoc.tab.cpp" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 1 #endif /* In a future release of Bison, this section will be replaced by #include "SCDoc.tab.hpp". */ #ifndef YY_SCDOC_SCDOC_TAB_HPP_INCLUDED # define YY_SCDOC_SCDOC_TAB_HPP_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int scdocdebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { END = 0, CLASS = 258, TITLE = 259, SUMMARY = 260, RELATED = 261, CATEGORIES = 262, REDIRECT = 263, CLASSTREE = 264, COPYMETHOD = 265, KEYWORD = 266, PRIVATE = 267, SECTION = 268, SUBSECTION = 269, METHOD = 270, ARGUMENT = 271, DESCRIPTION = 272, CLASSMETHODS = 273, INSTANCEMETHODS = 274, EXAMPLES = 275, RETURNS = 276, DISCUSSION = 277, LIST = 278, TREE = 279, NUMBEREDLIST = 280, DEFINITIONLIST = 281, TABLE = 282, FOOTNOTE = 283, NOTE = 284, WARNING = 285, CODE = 286, LINK = 287, ANCHOR = 288, SOFT = 289, IMAGE = 290, TELETYPE = 291, STRONG = 292, EMPHASIS = 293, CODEBLOCK = 294, TELETYPEBLOCK = 295, TAGSYM = 296, BARS = 297, HASHES = 298, TEXT = 299, URL = 300, COMMA = 301, METHODNAME = 302, METHODARGS = 303, NEWLINE = 304, EMPTYLINES = 305, BAD_METHODNAME = 306, START_FULL = 307, START_PARTIAL = 308, START_METADATA = 309 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE YYSTYPE; union YYSTYPE { #line 56 "SCDoc.y" /* yacc.c:355 */ intptr_t i; const char *id; char *str; DocNode *doc_node; #line 232 "SCDoc.tab.cpp" /* yacc.c:355 */ }; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE scdoclval; extern YYLTYPE scdoclloc; int scdocparse (void); #endif /* !YY_SCDOC_SCDOC_TAB_HPP_INCLUDED */ /* Copy the second part of user declarations. */ #line 101 "SCDoc.y" /* yacc.c:358 */ //int scdoclex (YYSTYPE * yylval_param, struct YYLTYPE * yylloc_param ); int scdoclex (void); #line 265 "SCDoc.tab.cpp" /* yacc.c:358 */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; YYLTYPE yyls_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + 2 * YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 68 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 429 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 55 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 55 /* YYNRULES -- Number of rules. */ #define YYNRULES 132 /* YYNSTATES -- Number of states. */ #define YYNSTATES 191 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 309 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { 0, 108, 108, 109, 112, 118, 122, 130, 131, 134, 135, 138, 139, 140, 143, 144, 145, 146, 149, 150, 151, 152, 155, 156, 159, 160, 161, 164, 164, 165, 168, 169, 172, 173, 174, 177, 180, 181, 184, 185, 186, 189, 196, 202, 207, 208, 219, 230, 231, 234, 243, 244, 247, 248, 251, 252, 255, 256, 259, 260, 263, 264, 272, 273, 276, 277, 278, 281, 282, 285, 286, 287, 288, 289, 290, 291, 294, 295, 298, 299, 302, 303, 304, 305, 306, 309, 310, 311, 312, 313, 314, 315, 318, 319, 322, 323, 324, 327, 328, 331, 332, 335, 338, 339, 342, 343, 346, 347, 350, 357, 358, 361, 362, 365, 366, 369, 370, 373, 374, 377, 378, 381, 382, 385, 386, 389, 390, 393, 394, 395, 396, 399, 400 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 1 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "\"end of file\"", "error", "$undefined", "CLASS", "TITLE", "SUMMARY", "RELATED", "CATEGORIES", "REDIRECT", "CLASSTREE", "COPYMETHOD", "KEYWORD", "PRIVATE", "SECTION", "SUBSECTION", "METHOD", "ARGUMENT", "DESCRIPTION", "CLASSMETHODS", "INSTANCEMETHODS", "EXAMPLES", "RETURNS", "DISCUSSION", "LIST", "TREE", "NUMBEREDLIST", "DEFINITIONLIST", "TABLE", "FOOTNOTE", "NOTE", "WARNING", "CODE", "LINK", "ANCHOR", "SOFT", "IMAGE", "TELETYPE", "STRONG", "EMPHASIS", "\"CODE block\"", "\"TELETYPE block\"", "\"::\"", "\"||\"", "\"##\"", "\"text\"", "URL", "COMMA", "\"method name\"", "\"arguments string\"", "\"newline\"", "\"empty lines\"", "\"bad method name\"", "START_FULL", "START_PARTIAL", "START_METADATA", "$accept", "start", "document", "eateol", "dochead", "headline", "headtag", "sectiontag", "optsections", "sections", "section", "$@1", "optsubsections", "subsections", "subsection", "optsubsubsections", "subsubsections", "subsubsection", "optMETHODARGS", "methodname", "methnames", "methodbody", "optbody", "optargs", "args", "arg", "optreturns", "optdiscussion", "body", "blockA", "blockB", "bodyelem", "prose", "proseelem", "inlinetag", "blocktag", "listtag", "rangetag", "listbody", "tablerow", "tablebody", "tablecells", "defterms", "deflistrow", "deflistbody", "anywordurl", "anyword", "words", "words2", "eol", "eoleof", "anywordnl", "wordsnl", "nocommawords", "commalist", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309 }; # endif #define YYPACT_NINF -129 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-129))) #define YYTABLE_NINF -3 #define yytable_value_is_error(Yytable_value) \ 0 /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { -11, 42, 222, 137, 11, 111, -129, -129, 137, -129, -17, -17, 91, 91, -129, -8, -129, -129, -129, -129, -129, -129, -129, 14, 38, 338, -129, -129, -129, -129, -129, -129, 71, -129, -129, -129, -129, -129, -129, -129, -129, -129, -129, 264, 70, -129, 7, -129, -129, 338, 370, -129, 380, -129, -17, 58, 41, 338, -129, -129, -129, -129, 91, 91, -129, 180, -129, 71, -129, -129, 180, -129, 25, 58, -129, -129, 93, 16, 16, 71, -129, -129, 3, 338, 85, -129, 62, 338, -129, 78, 32, -129, -129, -129, -31, 71, -129, 20, -129, 7, -129, -129, -129, 380, -129, -129, 9, -129, -129, -129, -13, 338, 83, 55, 30, 30, -129, -129, 70, 49, -129, -129, -129, -129, -129, -129, -129, -129, 91, -129, -129, 49, -8, -129, 42, -129, 338, 338, -129, -129, -129, -129, -12, -129, -129, -129, -129, -129, 49, -129, -129, -129, -129, -129, -129, 338, -129, -129, -129, -129, 93, 264, -129, 338, -129, -129, 338, 306, -129, -129, -129, 84, -129, -129, 7, 58, 27, 84, -129, 58, 338, 338, 98, -129, 338, -129, -129, 338, -129, -129, -129 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 8, 0, 0, 0, 0, 119, 120, 0, 7, 0, 0, 0, 0, 27, 0, 20, 18, 19, 21, 94, 95, 96, 0, 0, 0, 98, 97, 89, 85, 91, 87, 0, 90, 86, 88, 92, 93, 113, 81, 114, 84, 76, 31, 5, 25, 26, 39, 40, 62, 63, 66, 68, 79, 0, 0, 0, 0, 80, 14, 15, 16, 0, 0, 17, 23, 10, 0, 1, 3, 23, 116, 0, 0, 129, 130, 132, 0, 0, 0, 46, 48, 44, 0, 0, 110, 0, 51, 103, 0, 0, 112, 118, 111, 0, 0, 29, 30, 33, 34, 24, 38, 65, 67, 64, 78, 0, 123, 124, 126, 0, 0, 0, 0, 0, 0, 9, 6, 22, 0, 4, 122, 115, 121, 74, 42, 127, 128, 0, 75, 43, 0, 0, 45, 0, 107, 51, 0, 72, 109, 105, 50, 101, 71, 102, 83, 77, 117, 0, 32, 82, 73, 125, 100, 70, 0, 69, 13, 12, 11, 131, 31, 47, 51, 108, 106, 51, 37, 99, 28, 41, 53, 104, 35, 36, 0, 59, 52, 55, 0, 0, 0, 61, 54, 51, 57, 58, 0, 49, 56, 60 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { -129, -129, -129, -129, 117, -44, -129, -129, 76, 151, -41, -129, -6, -129, 57, -129, -38, -40, -129, 24, -129, -129, -128, -129, -129, -20, -129, -129, -5, -129, -129, 99, 110, -43, -129, -129, -129, -129, -129, 73, -129, -129, -129, 77, -129, -87, -9, -7, -55, -1, 74, 50, -129, 36, 5 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { -1, 4, 5, 8, 65, 66, 67, 43, 117, 118, 45, 79, 96, 97, 98, 173, 46, 47, 134, 81, 82, 170, 140, 176, 177, 178, 182, 188, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 112, 88, 89, 142, 84, 85, 86, 92, 58, 72, 94, 123, 124, 109, 110, 76, 77 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { 9, 71, 71, 100, 73, 99, 101, 147, 164, 105, 146, 68, 119, 38, 91, 40, 121, 11, 78, 13, 90, 116, 15, 93, 131, 121, 116, 38, 151, 40, 166, 38, 147, 40, 95, 171, 6, 7, 172, 80, 148, 1, 2, 3, 147, 71, 107, 106, 181, 132, 150, 133, 113, 38, 108, 40, 189, 83, 93, 101, 105, 147, 128, 122, 122, 6, 7, 114, 115, 38, 93, 40, 125, 145, 6, 7, 128, 100, 135, 6, 7, 87, 141, 14, 111, 93, 93, 16, 17, 18, 19, 6, 7, 38, 91, 40, 156, 122, 6, 7, 175, 107, 38, 138, 40, 83, 153, 6, 7, 108, 93, -2, 69, 157, 158, 38, 91, 40, 159, 143, 187, 87, 93, 99, 154, 70, 155, 136, 137, 174, 161, 141, 165, 163, 101, 74, 75, 126, 127, 93, 59, 60, 61, 62, 63, 64, 120, 167, 102, 104, 168, 129, 130, 44, 149, 169, 162, 183, 141, 103, 152, 141, 144, 139, 160, 0, 71, 0, 179, 0, 122, 0, 0, 0, 180, 185, 186, 0, 184, 141, 0, 0, 190, 59, 60, 61, 62, 63, 64, 10, 11, 12, 13, 14, 0, 15, 0, 16, 17, 18, 19, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 0, 0, 0, 38, 39, 40, 0, 0, 41, 42, 10, 11, 12, 13, 14, 0, 15, 0, 16, 17, 18, 19, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 0, 0, 0, 38, 39, 40, 0, 0, 41, 42, 10, 11, 12, 13, 0, 95, 15, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 0, 0, 0, 38, 39, 40, 0, 0, 41, 42, 10, 11, 12, 13, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 10, 0, 12, 38, 39, 40, 0, 0, 41, 42, 0, 0, 0, 0, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 10, 0, 12, 38, 39, 40, 0, 0, 41, 42, 0, 0, 0, 0, 20, 21, 22, 23, 24, 0, 26, 27, 0, 0, 0, 0, 32, 0, 0, 25, 36, 37, 28, 29, 30, 31, 0, 33, 34, 35, 0, 42, 0, 0, 0, 38, 39, 40, 0, 0, 41 }; static const yytype_int16 yycheck[] = { 1, 10, 11, 44, 11, 43, 46, 94, 136, 52, 41, 0, 67, 44, 45, 46, 0, 10, 13, 12, 25, 65, 15, 32, 79, 0, 70, 44, 41, 46, 42, 44, 119, 46, 14, 163, 49, 50, 166, 47, 95, 52, 53, 54, 131, 54, 55, 54, 21, 46, 41, 48, 57, 44, 55, 46, 184, 43, 67, 99, 103, 148, 46, 72, 73, 49, 50, 62, 63, 44, 79, 46, 73, 41, 49, 50, 46, 118, 83, 49, 50, 43, 87, 13, 43, 94, 95, 17, 18, 19, 20, 49, 50, 44, 45, 46, 41, 106, 49, 50, 16, 110, 44, 41, 46, 43, 111, 49, 50, 110, 119, 0, 1, 114, 115, 44, 45, 46, 119, 41, 22, 43, 131, 161, 41, 8, 43, 42, 43, 167, 131, 136, 137, 134, 174, 44, 45, 44, 45, 148, 3, 4, 5, 6, 7, 8, 70, 148, 49, 50, 155, 77, 78, 2, 97, 161, 132, 177, 163, 49, 110, 166, 89, 86, 128, -1, 175, -1, 175, -1, 179, -1, -1, -1, 175, 180, 181, -1, 179, 184, -1, -1, 187, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1, 15, -1, 17, 18, 19, 20, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, 44, 45, 46, -1, -1, 49, 50, 9, 10, 11, 12, 13, -1, 15, -1, 17, 18, 19, 20, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, 44, 45, 46, -1, -1, 49, 50, 9, 10, 11, 12, -1, 14, 15, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, -1, -1, -1, 44, 45, 46, -1, -1, 49, 50, 9, 10, 11, 12, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 9, -1, 11, 44, 45, 46, -1, -1, 49, 50, -1, -1, -1, -1, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 9, -1, 11, 44, 45, 46, -1, -1, 49, 50, -1, -1, -1, -1, 23, 24, 25, 26, 27, -1, 29, 30, -1, -1, -1, -1, 35, -1, -1, 28, 39, 40, 31, 32, 33, 34, -1, 36, 37, 38, -1, 50, -1, -1, -1, 44, 45, 46, -1, -1, 49 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 52, 53, 54, 56, 57, 49, 50, 58, 104, 9, 10, 11, 12, 13, 15, 17, 18, 19, 20, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 44, 45, 46, 49, 50, 62, 64, 65, 71, 72, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 101, 3, 4, 5, 6, 7, 8, 59, 60, 61, 0, 1, 59, 101, 102, 102, 44, 45, 108, 109, 109, 66, 47, 74, 75, 43, 97, 98, 99, 43, 94, 95, 83, 45, 100, 101, 103, 14, 67, 68, 69, 71, 65, 72, 86, 87, 86, 88, 102, 101, 104, 106, 107, 43, 93, 83, 109, 109, 60, 63, 64, 103, 63, 0, 101, 104, 105, 104, 44, 45, 46, 105, 105, 103, 46, 48, 73, 83, 42, 43, 41, 98, 77, 83, 96, 41, 94, 41, 41, 100, 103, 69, 41, 41, 106, 83, 41, 43, 41, 104, 104, 104, 108, 104, 74, 104, 77, 83, 42, 104, 83, 67, 76, 77, 77, 70, 71, 16, 78, 79, 80, 102, 104, 21, 81, 80, 104, 83, 83, 22, 82, 77, 83 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 55, 56, 56, 57, 57, 57, 58, 58, 59, 59, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 64, 64, 64, 66, 65, 65, 67, 67, 68, 68, 68, 69, 70, 70, 71, 71, 71, 72, 72, 72, 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 84, 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 90, 90, 91, 91, 91, 92, 92, 93, 93, 94, 95, 95, 96, 96, 97, 97, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 108, 108, 109, 109 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 2, 4, 2, 3, 1, 0, 2, 1, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 1, 1, 0, 5, 2, 1, 0, 2, 1, 1, 4, 1, 0, 2, 1, 1, 5, 3, 3, 0, 1, 1, 3, 1, 4, 1, 0, 1, 0, 2, 1, 4, 3, 2, 0, 2, 0, 1, 1, 2, 2, 1, 2, 1, 3, 3, 3, 3, 3, 3, 3, 1, 3, 2, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 1, 3, 1, 3, 2, 3, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 2, 1, 1, 3, 1 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. If N is 0, then set CURRENT to the empty location which ends the previous symbol: RHS[0] (always defined). */ #ifndef YYLLOC_DEFAULT # define YYLLOC_DEFAULT(Current, Rhs, N) \ do \ if (N) \ { \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ while (0) #endif #define YYRHSLOC(Rhs, K) ((Rhs)[K]) /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* YY_LOCATION_PRINT -- Print the location on the stream. This macro was not mandated originally: define only if we know we won't break user code: when these are the locations we know. */ #ifndef YY_LOCATION_PRINT # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL /* Print *YYLOCP on YYO. Private, do not rely on its existence. */ YY_ATTRIBUTE_UNUSED static unsigned yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) { unsigned res = 0; int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; if (0 <= yylocp->first_line) { res += YYFPRINTF (yyo, "%d", yylocp->first_line); if (0 <= yylocp->first_column) res += YYFPRINTF (yyo, ".%d", yylocp->first_column); } if (0 <= yylocp->last_line) { if (yylocp->first_line < yylocp->last_line) { res += YYFPRINTF (yyo, "-%d", yylocp->last_line); if (0 <= end_col) res += YYFPRINTF (yyo, ".%d", end_col); } else if (0 <= end_col && yylocp->first_column < end_col) res += YYFPRINTF (yyo, "-%d", end_col); } return res; } # define YY_LOCATION_PRINT(File, Loc) \ yy_location_print_ (File, &(Loc)) # else # define YY_LOCATION_PRINT(File, Loc) ((void) 0) # endif #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value, Location); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) { FILE *yyo = yyoutput; YYUSE (yyo); YYUSE (yylocationp); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); YY_LOCATION_PRINT (yyoutput, *yylocationp); YYFPRINTF (yyoutput, ": "); yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule) { unsigned long int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) , &(yylsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, yylsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp) { YYUSE (yyvaluep); YYUSE (yylocationp); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN switch (yytype) { case 44: /* "text" */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1367 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 45: /* URL */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1373 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 46: /* COMMA */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1379 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 47: /* "method name" */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1385 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 48: /* "arguments string" */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1391 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 57: /* document */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1397 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 59: /* dochead */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1403 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 60: /* headline */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1409 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 63: /* optsections */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1415 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 64: /* sections */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1421 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 65: /* section */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1427 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 67: /* optsubsections */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1433 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 68: /* subsections */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1439 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 69: /* subsection */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1445 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 70: /* optsubsubsections */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1451 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 71: /* subsubsections */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1457 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 72: /* subsubsection */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1463 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 73: /* optMETHODARGS */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1469 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 74: /* methodname */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1475 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 75: /* methnames */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1481 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 76: /* methodbody */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1487 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 77: /* optbody */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1493 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 78: /* optargs */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1499 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 79: /* args */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1505 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 80: /* arg */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1511 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 81: /* optreturns */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1517 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 82: /* optdiscussion */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1523 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 83: /* body */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1529 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 84: /* blockA */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1535 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 85: /* blockB */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1541 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 86: /* bodyelem */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1547 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 87: /* prose */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1553 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 88: /* proseelem */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1559 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 93: /* listbody */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1565 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 94: /* tablerow */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1571 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 95: /* tablebody */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1577 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 96: /* tablecells */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1583 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 97: /* defterms */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1589 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 98: /* deflistrow */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1595 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 99: /* deflistbody */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1601 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 100: /* anywordurl */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1607 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 101: /* anyword */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1613 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 102: /* words */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1619 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 103: /* words2 */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1625 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 106: /* anywordnl */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1631 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 107: /* wordsnl */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1637 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 108: /* nocommawords */ #line 99 "SCDoc.y" /* yacc.c:1257 */ { free(((*yyvaluep).str)); } #line 1643 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; case 109: /* commalist */ #line 98 "SCDoc.y" /* yacc.c:1257 */ { doc_node_free_tree(((*yyvaluep).doc_node)); } #line 1649 "SCDoc.tab.cpp" /* yacc.c:1257 */ break; default: break; } YY_IGNORE_MAYBE_UNINITIALIZED_END } /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Location data for the lookahead symbol. */ YYLTYPE yylloc # if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL = { 1, 1, 1, 1 } # endif ; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. 'yyls': related to locations. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; /* The location stack. */ YYLTYPE yylsa[YYINITDEPTH]; YYLTYPE *yyls; YYLTYPE *yylsp; /* The locations where the error started and ended. */ YYLTYPE yyerror_range[3]; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; YYLTYPE yyloc; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yylsp = yyls = yylsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ yylsp[0] = yylloc; goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; YYLTYPE *yyls1 = yyls; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yyls1, yysize * sizeof (*yylsp), &yystacksize); yyls = yyls1; yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); YYSTACK_RELOCATE (yyls_alloc, yyls); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; yylsp = yyls + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END *++yylsp = yylloc; goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; /* Default location. */ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: #line 108 "SCDoc.y" /* yacc.c:1646 */ { topnode = (yyvsp[0].doc_node); } #line 1937 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 3: #line 109 "SCDoc.y" /* yacc.c:1646 */ { topnode = NULL; doc_node_free_tree((yyvsp[-1].doc_node)); } #line 1943 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 4: #line 113 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_create("DOCUMENT"); doc_node_add_child((yyval.doc_node), (yyvsp[-1].doc_node)); doc_node_add_child((yyval.doc_node), (yyvsp[0].doc_node)); } #line 1953 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 5: #line 119 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("BODY",NULL,(yyvsp[0].doc_node)); } #line 1961 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 6: #line 123 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_create("DOCUMENT"); doc_node_add_child((yyval.doc_node), (yyvsp[-1].doc_node)); doc_node_add_child((yyval.doc_node), (yyvsp[0].doc_node)); } #line 1971 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 9: #line 134 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 1977 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 10: #line 135 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("HEADER",NULL,(yyvsp[0].doc_node)); } #line 1983 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 11: #line 138 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make((yyvsp[-2].id),(yyvsp[-1].str),NULL); } #line 1989 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 12: #line 139 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("CATEGORIES",NULL,(yyvsp[-1].doc_node)); } #line 1995 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 13: #line 140 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("RELATED",NULL,(yyvsp[-1].doc_node)); } #line 2001 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 14: #line 143 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "TITLE"; } #line 2007 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 15: #line 144 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "TITLE"; } #line 2013 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 16: #line 145 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "SUMMARY"; } #line 2019 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 17: #line 146 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "REDIRECT"; } #line 2025 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 18: #line 149 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "CLASSMETHODS"; method_type = "CMETHOD"; } #line 2031 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 19: #line 150 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "INSTANCEMETHODS"; method_type = "IMETHOD"; } #line 2037 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 20: #line 151 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "DESCRIPTION"; method_type = "METHOD"; } #line 2043 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 21: #line 152 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "EXAMPLES"; method_type = "METHOD"; } #line 2049 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 23: #line 156 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("BODY",NULL,NULL); } #line 2055 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 24: #line 159 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2061 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 25: #line 160 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("BODY",NULL,(yyvsp[0].doc_node)); } #line 2067 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 26: #line 161 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("BODY",NULL,(yyvsp[0].doc_node)); } #line 2073 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 27: #line 164 "SCDoc.y" /* yacc.c:1646 */ { method_type = "METHOD"; } #line 2079 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 28: #line 164 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("SECTION",(yyvsp[-2].str),(yyvsp[0].doc_node)); } #line 2085 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 29: #line 165 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children((yyvsp[-1].id), NULL,(yyvsp[0].doc_node)); } #line 2091 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 31: #line 169 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2097 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 32: #line 172 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2103 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 33: #line 173 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(SUBSECTIONS)",NULL,(yyvsp[0].doc_node)); } #line 2109 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 35: #line 177 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("SUBSECTION", (yyvsp[-2].str), (yyvsp[0].doc_node)); } #line 2115 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 37: #line 181 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2121 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 38: #line 184 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2127 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 39: #line 185 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(SUBSUBSECTIONS)",NULL,(yyvsp[0].doc_node)); } #line 2133 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 40: #line 186 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("(SUBSUBSECTIONS)",NULL,(yyvsp[0].doc_node)); } #line 2139 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 41: #line 190 "SCDoc.y" /* yacc.c:1646 */ { (yyvsp[-3].doc_node)->id = "METHODNAMES"; (yyval.doc_node) = doc_node_make(method_type,(yyvsp[-2].str),(yyvsp[-3].doc_node)); doc_node_add_child((yyval.doc_node), (yyvsp[0].doc_node)); // doc_node_add_child($2, $3); } #line 2150 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 42: #line 196 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make( stringEqual(method_type, "CMETHOD") ? "CCOPYMETHOD" : (stringEqual(method_type, "IMETHOD") ? "ICOPYMETHOD" : "COPYMETHOD"), (yyvsp[-1].str), NULL ); } #line 2161 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 43: #line 202 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children( stringEqual(method_type, "CMETHOD") ? "CPRIVATE" : "IPRIVATE", NULL, (yyvsp[-1].doc_node)); } #line 2169 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 44: #line 207 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = NULL; } #line 2175 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 45: #line 209 "SCDoc.y" /* yacc.c:1646 */ { // $$ = doc_node_make("ARGSTRING",$1,NULL); (yyval.str) = (yyvsp[0].str); if(!stringEqual(method_type, "METHOD")) { yyerror("METHOD argument string is not allowed inside CLASSMETHODS or INSTANCEMETHODS"); YYERROR; } } #line 2188 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 46: #line 220 "SCDoc.y" /* yacc.c:1646 */ { char *p = (yyvsp[0].str)+strlen((yyvsp[0].str))-1; if(*p=='_') { post("WARNING: SCDoc: In %s\n Property setter %s should be documented without underscore.\n", scdoc_current_file, (yyvsp[0].str)); *p = '\0'; }; (yyval.str) = (yyvsp[0].str); } #line 2201 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 47: #line 230 "SCDoc.y" /* yacc.c:1646 */ { free((yyvsp[-1].str)); (yyvsp[-1].str) = NULL; (yyval.doc_node) = doc_node_add_child((yyvsp[-2].doc_node), doc_node_make("STRING",(yyvsp[0].str),NULL)); } #line 2207 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 48: #line 231 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(METHODNAMES)",NULL,doc_node_make("STRING",(yyvsp[0].str),NULL)); } #line 2213 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 49: #line 235 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("METHODBODY",NULL,(yyvsp[-3].doc_node)); doc_node_add_child((yyval.doc_node), (yyvsp[-2].doc_node)); doc_node_add_child((yyval.doc_node), (yyvsp[-1].doc_node)); doc_node_add_child((yyval.doc_node), (yyvsp[0].doc_node)); } #line 2224 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 51: #line 244 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2230 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 53: #line 248 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2236 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 54: #line 251 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2242 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 55: #line 252 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("ARGUMENTS",NULL,(yyvsp[0].doc_node)); } #line 2248 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 56: #line 255 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("ARGUMENT", (yyvsp[-2].str), (yyvsp[0].doc_node)); } #line 2254 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 57: #line 256 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("ARGUMENT", NULL, (yyvsp[0].doc_node)); } #line 2260 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 58: #line 259 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("RETURNS",NULL,(yyvsp[0].doc_node)); } #line 2266 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 59: #line 260 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2272 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 60: #line 263 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("DISCUSSION",NULL,(yyvsp[0].doc_node)); } #line 2278 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 61: #line 264 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2284 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 64: #line 276 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2290 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 65: #line 277 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2296 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 66: #line 278 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(SECTIONBODY)",NULL,(yyvsp[0].doc_node)); } #line 2302 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 67: #line 281 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2308 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 68: #line 282 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(SECTIONBODY)",NULL,(yyvsp[0].doc_node)); } #line 2314 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 69: #line 285 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children((yyvsp[-2].id),NULL,(yyvsp[-1].doc_node)); } #line 2320 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 70: #line 286 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children((yyvsp[-2].id),NULL,(yyvsp[-1].doc_node)); } #line 2326 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 71: #line 287 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("TABLE",NULL,(yyvsp[-1].doc_node)); } #line 2332 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 72: #line 288 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("DEFINITIONLIST",NULL,(yyvsp[-1].doc_node)); } #line 2338 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 73: #line 289 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make((yyvsp[-2].id),(yyvsp[-1].str),NULL); } #line 2344 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 74: #line 290 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("CLASSTREE",(yyvsp[-1].str),NULL); } #line 2350 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 75: #line 291 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("KEYWORD",NULL,(yyvsp[-1].doc_node)); // printf("keyword '%s'\n",$2->children[0]->text); } #line 2358 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 76: #line 294 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = NULL; } #line 2364 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 77: #line 295 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("IMAGE",(yyvsp[-1].str),NULL); } #line 2370 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 78: #line 298 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node), (yyvsp[0].doc_node)); } #line 2376 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 79: #line 299 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("PROSE",NULL,(yyvsp[0].doc_node)); } #line 2382 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 80: #line 302 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make(NODE_TEXT,(yyvsp[0].str),NULL); } #line 2388 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 81: #line 303 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("LINK",(yyvsp[0].str),NULL); } #line 2394 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 82: #line 304 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make((yyvsp[-2].id),(yyvsp[-1].str),NULL); } #line 2400 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 83: #line 305 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("FOOTNOTE",NULL,(yyvsp[-1].doc_node)); } #line 2406 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 84: #line 306 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_create(NODE_NL); } #line 2412 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 85: #line 309 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "LINK"; } #line 2418 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 86: #line 310 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "STRONG"; } #line 2424 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 87: #line 311 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "SOFT"; } #line 2430 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 88: #line 312 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "EMPHASIS"; } #line 2436 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 89: #line 313 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "CODE"; } #line 2442 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 90: #line 314 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "TELETYPE"; } #line 2448 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 91: #line 315 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "ANCHOR"; } #line 2454 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 92: #line 318 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "CODEBLOCK"; } #line 2460 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 93: #line 319 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "TELETYPEBLOCK"; } #line 2466 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 94: #line 322 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "LIST"; } #line 2472 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 95: #line 323 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "TREE"; } #line 2478 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 96: #line 324 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "NUMBEREDLIST"; } #line 2484 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 97: #line 327 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "WARNING"; } #line 2490 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 98: #line 328 "SCDoc.y" /* yacc.c:1646 */ { (yyval.id) = "NOTE"; } #line 2496 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 99: #line 331 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-2].doc_node), doc_node_make_take_children("ITEM",NULL,(yyvsp[0].doc_node))); } #line 2502 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 100: #line 332 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(LISTBODY)",NULL, doc_node_make_take_children("ITEM",NULL,(yyvsp[0].doc_node))); } #line 2508 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 101: #line 335 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("TABROW",NULL,(yyvsp[0].doc_node)); } #line 2514 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 102: #line 338 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2520 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 103: #line 339 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(TABLEBODY)",NULL,(yyvsp[0].doc_node)); } #line 2526 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 104: #line 342 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-2].doc_node), doc_node_make_take_children("TABCOL",NULL,(yyvsp[0].doc_node))); } #line 2532 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 105: #line 343 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(TABLECELLS)",NULL, doc_node_make_take_children("TABCOL",NULL,(yyvsp[0].doc_node))); } #line 2538 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 106: #line 346 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-2].doc_node),doc_node_make_take_children("TERM",NULL,(yyvsp[0].doc_node))); } #line 2544 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 107: #line 347 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(TERMS)",NULL,doc_node_make_take_children("TERM",NULL,(yyvsp[0].doc_node))); } #line 2550 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 108: #line 351 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make_take_children("DEFLISTITEM", NULL, (yyvsp[-2].doc_node)); doc_node_add_child((yyval.doc_node), doc_node_make_take_children("DEFINITION", NULL, (yyvsp[0].doc_node))); } #line 2559 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 109: #line 357 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_add_child((yyvsp[-1].doc_node),(yyvsp[0].doc_node)); } #line 2565 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 110: #line 358 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(DEFLISTBODY)",NULL,(yyvsp[0].doc_node)); } #line 2571 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 115: #line 369 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = strmerge((yyvsp[-1].str),(yyvsp[0].str)); } #line 2577 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 117: #line 373 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = strmerge((yyvsp[-1].str),(yyvsp[0].str)); } #line 2583 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 124: #line 386 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = strdup("\n"); } #line 2589 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 125: #line 389 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = strmerge((yyvsp[-1].str),(yyvsp[0].str)); } #line 2595 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 127: #line 393 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = strmerge((yyvsp[-1].str),(yyvsp[0].str)); } #line 2601 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 128: #line 394 "SCDoc.y" /* yacc.c:1646 */ { (yyval.str) = strmerge((yyvsp[-1].str),(yyvsp[0].str)); } #line 2607 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 131: #line 399 "SCDoc.y" /* yacc.c:1646 */ { free((yyvsp[-1].str)); (yyvsp[-1].str)=NULL; (yyval.doc_node) = doc_node_add_child((yyvsp[-2].doc_node),doc_node_make("STRING",(yyvsp[0].str),NULL)); } #line 2613 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; case 132: #line 400 "SCDoc.y" /* yacc.c:1646 */ { (yyval.doc_node) = doc_node_make("(COMMALIST)",NULL,doc_node_make("STRING",(yyvsp[0].str),NULL)); } #line 2619 "SCDoc.tab.cpp" /* yacc.c:1646 */ break; #line 2623 "SCDoc.tab.cpp" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; *++yylsp = yyloc; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } yyerror_range[1] = yylloc; if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval, &yylloc); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; yyerror_range[1] = yylsp[1-yylen]; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yyerror_range[1] = *yylsp; yydestruct ("Error: popping", yystos[yystate], yyvsp, yylsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END yyerror_range[2] = yylloc; /* Using YYLLOC is tempting, but would change the location of the lookahead. YYLOC is available though. */ YYLLOC_DEFAULT (yyloc, yyerror_range, 2); *++yylsp = yyloc; /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval, &yylloc); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp, yylsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } #line 403 "SCDoc.y" /* yacc.c:1906 */ DocNode * scdoc_parse_run(int mode) { int modes[] = {START_FULL, START_PARTIAL, START_METADATA}; if(mode<0 || mode>=sizeof(modes)) { error("scdoc_parse_run(): unknown mode: %d\n",mode); } scdoc_start_token = modes[mode]; /* scdoc_start_token = START_FULL; scdoc_metadata_mode = 0; if(mode==SCDOC_PARSE_PARTIAL) { scdoc_start_token = START_PARTIAL; } else if(mode==SCDOC_PARSE_METADATA) { scdoc_metadata_mode = 1; }*/ topnode = NULL; method_type = "METHOD"; if(scdocparse()!=0) { return NULL; } return topnode; } void scdocerror(const char *str) { error("In %s:\n At line %d: %s\n\n",scdoc_current_file,scdoclineno,str); /* FIXME: this does not work well, since the reported linenumber is often *after* the actual error line fseek(scdocin, 0, SEEK_SET); int line = 1; char buf[256],*txt; while(line!=scdoclineno && !feof(scdocin)) { int c = fgetc(scdocin); if(c=='\n') line++; } txt = fgets(buf, 256, scdocin); if(txt) fprintf(stderr," %s\n-------------------\n", txt); */ } SuperCollider-Source/SCDoc/SCDoc.tab.hpp000644 000765 000024 00000007007 12756531745 021044 0ustar00crucialstaff000000 000000 /* A Bison parser, made by GNU Bison 3.0.2. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_SCDOC_SCDOC_TAB_HPP_INCLUDED # define YY_SCDOC_SCDOC_TAB_HPP_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int scdocdebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { END = 0, CLASS = 258, TITLE = 259, SUMMARY = 260, RELATED = 261, CATEGORIES = 262, REDIRECT = 263, CLASSTREE = 264, COPYMETHOD = 265, KEYWORD = 266, PRIVATE = 267, SECTION = 268, SUBSECTION = 269, METHOD = 270, ARGUMENT = 271, DESCRIPTION = 272, CLASSMETHODS = 273, INSTANCEMETHODS = 274, EXAMPLES = 275, RETURNS = 276, DISCUSSION = 277, LIST = 278, TREE = 279, NUMBEREDLIST = 280, DEFINITIONLIST = 281, TABLE = 282, FOOTNOTE = 283, NOTE = 284, WARNING = 285, CODE = 286, LINK = 287, ANCHOR = 288, SOFT = 289, IMAGE = 290, TELETYPE = 291, STRONG = 292, EMPHASIS = 293, CODEBLOCK = 294, TELETYPEBLOCK = 295, TAGSYM = 296, BARS = 297, HASHES = 298, TEXT = 299, URL = 300, COMMA = 301, METHODNAME = 302, METHODARGS = 303, NEWLINE = 304, EMPTYLINES = 305, BAD_METHODNAME = 306, START_FULL = 307, START_PARTIAL = 308, START_METADATA = 309 }; #endif /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE YYSTYPE; union YYSTYPE { #line 56 "SCDoc.y" /* yacc.c:1909 */ intptr_t i; const char *id; char *str; DocNode *doc_node; #line 117 "SCDoc.tab.hpp" /* yacc.c:1909 */ }; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif /* Location type. */ #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED typedef struct YYLTYPE YYLTYPE; struct YYLTYPE { int first_line; int first_column; int last_line; int last_column; }; # define YYLTYPE_IS_DECLARED 1 # define YYLTYPE_IS_TRIVIAL 1 #endif extern YYSTYPE scdoclval; extern YYLTYPE scdoclloc; int scdocparse (void); #endif /* !YY_SCDOC_SCDOC_TAB_HPP_INCLUDED */ SuperCollider-Source/SCDoc/SCDoc.y000644 000765 000024 00000033526 12756531745 017765 0ustar00crucialstaff000000 000000 %{ /************************************************************************ * * Copyright 2012 Jonatan Liljedahl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include #include #include #include "SCDoc.h" //#define YYLEX_PARAM &yylval, &yylloc int scdocparse(); extern int scdoclineno; extern char *scdoctext; extern int scdoc_start_token; extern FILE *scdocin; //extern struct YYLTYPE scdoclloc; //int scdoc_metadata_mode; static const char * method_type = NULL; static DocNode * topnode; void scdocerror(const char *str); extern void error(const char *fmt, ...); extern void post(const char *fmt, ...); static inline bool stringEqual(const char * a, const char * b) { return strcmp(a, b) == 0; } %} %locations %error-verbose %union { intptr_t i; const char *id; char *str; DocNode *doc_node; } // single line header tags that take text %token CLASS TITLE SUMMARY RELATED CATEGORIES REDIRECT // single line body tags that take text %token CLASSTREE COPYMETHOD KEYWORD PRIVATE // single line structural tags that take text, with children %token SECTION SUBSECTION METHOD ARGUMENT // single line structural tags with no text, with children %token DESCRIPTION CLASSMETHODS INSTANCEMETHODS EXAMPLES RETURNS DISCUSSION // nestable range tags with no text, with children %token LIST TREE NUMBEREDLIST DEFINITIONLIST TABLE FOOTNOTE NOTE WARNING // modal range tags that take multi-line text %token CODE LINK ANCHOR SOFT IMAGE TELETYPE STRONG EMPHASIS %token CODEBLOCK "CODE block" TELETYPEBLOCK "TELETYPE block" // symbols %token TAGSYM "::" BARS "||" HASHES "##" // text and whitespace %token TEXT "text" URL COMMA METHODNAME "method name" METHODARGS "arguments string" %token NEWLINE "newline" EMPTYLINES "empty lines" %token BAD_METHODNAME "bad method name" %token END 0 "end of file" %type headtag sectiontag listtag rangetag inlinetag blocktag %type anyword words anywordnl wordsnl anywordurl words2 nocommawords optMETHODARGS methodname %type document arg optreturns optdiscussion body bodyelem %type optsubsections optsubsubsections methodbody %type dochead headline optsections sections section %type subsections subsection subsubsection subsubsections %type optbody optargs args listbody tablebody tablecells tablerow %type prose proseelem blockA blockB commalist %type deflistbody deflistrow defterms methnames %token START_FULL START_PARTIAL START_METADATA %start start %destructor { doc_node_free_tree($$); } %destructor { free($$); } %{ //int scdoclex (YYSTYPE * yylval_param, struct YYLTYPE * yylloc_param ); int scdoclex (void); %} %% start: document { topnode = $1; } | document error { topnode = NULL; doc_node_free_tree($1); } ; document: START_FULL eateol dochead optsections { $$ = doc_node_create("DOCUMENT"); doc_node_add_child($$, $3); doc_node_add_child($$, $4); } | START_PARTIAL sections { $$ = doc_node_make_take_children("BODY",NULL,$2); } | START_METADATA dochead optsections { $$ = doc_node_create("DOCUMENT"); doc_node_add_child($$, $2); doc_node_add_child($$, $3); } ; eateol: eol | /* empty */ ; dochead: dochead headline { $$ = doc_node_add_child($1,$2); } | headline { $$ = doc_node_make("HEADER",NULL,$1); } ; headline: headtag words2 eol { $$ = doc_node_make($1,$2,NULL); } | CATEGORIES commalist eol { $$ = doc_node_make_take_children("CATEGORIES",NULL,$2); } | RELATED commalist eol { $$ = doc_node_make_take_children("RELATED",NULL,$2); } ; headtag: CLASS { $$ = "TITLE"; } /* no need for the separate class:: tag actually. */ | TITLE { $$ = "TITLE"; } | SUMMARY { $$ = "SUMMARY"; } | REDIRECT { $$ = "REDIRECT"; } ; sectiontag: CLASSMETHODS { $$ = "CLASSMETHODS"; method_type = "CMETHOD"; } | INSTANCEMETHODS { $$ = "INSTANCEMETHODS"; method_type = "IMETHOD"; } | DESCRIPTION { $$ = "DESCRIPTION"; method_type = "METHOD"; } | EXAMPLES { $$ = "EXAMPLES"; method_type = "METHOD"; } ; optsections: sections | { $$ = doc_node_make("BODY",NULL,NULL); } ; sections: sections section { $$ = doc_node_add_child($1,$2); } | section { $$ = doc_node_make("BODY",NULL,$1); } | subsubsections { $$ = doc_node_make_take_children("BODY",NULL,$1); } /* allow text before first section */ ; section: SECTION { method_type = "METHOD"; } words2 eol optsubsections { $$ = doc_node_make_take_children("SECTION",$3,$5); } | sectiontag optsubsections { $$ = doc_node_make_take_children($1, NULL,$2); } ; optsubsections: subsections | { $$ = NULL; } ; subsections: subsections subsection { $$ = doc_node_add_child($1,$2); } | subsection { $$ = doc_node_make("(SUBSECTIONS)",NULL,$1); } | subsubsections ; subsection: SUBSECTION words2 eol optsubsubsections { $$ = doc_node_make_take_children("SUBSECTION", $2, $4); } ; optsubsubsections: subsubsections | { $$ = NULL; } ; subsubsections: subsubsections subsubsection { $$ = doc_node_add_child($1,$2); } | subsubsection { $$ = doc_node_make("(SUBSUBSECTIONS)",NULL,$1); } | body { $$ = doc_node_make_take_children("(SUBSUBSECTIONS)",NULL,$1); } ; subsubsection: METHOD methnames optMETHODARGS eol methodbody { $2->id = "METHODNAMES"; $$ = doc_node_make(method_type,$3,$2); doc_node_add_child($$, $5); // doc_node_add_child($2, $3); } | COPYMETHOD words eol { $$ = doc_node_make( stringEqual(method_type, "CMETHOD") ? "CCOPYMETHOD" : (stringEqual(method_type, "IMETHOD") ? "ICOPYMETHOD" : "COPYMETHOD"), $2, NULL ); } | PRIVATE commalist eoleof { $$ = doc_node_make_take_children( stringEqual(method_type, "CMETHOD") ? "CPRIVATE" : "IPRIVATE", NULL, $2); } ; optMETHODARGS: { $$ = NULL; } | METHODARGS { // $$ = doc_node_make("ARGSTRING",$1,NULL); $$ = $1; if(!stringEqual(method_type, "METHOD")) { yyerror("METHOD argument string is not allowed inside CLASSMETHODS or INSTANCEMETHODS"); YYERROR; } } ; methodname: METHODNAME { char *p = $1+strlen($1)-1; if(*p=='_') { post("WARNING: SCDoc: In %s\n Property setter %s should be documented without underscore.\n", scdoc_current_file, $1); *p = '\0'; }; $$ = $1; } ; methnames: methnames COMMA methodname { free($2); $2 = NULL; $$ = doc_node_add_child($1, doc_node_make("STRING",$3,NULL)); } | methodname { $$ = doc_node_make("(METHODNAMES)",NULL,doc_node_make("STRING",$1,NULL)); } ; methodbody: optbody optargs optreturns optdiscussion { $$ = doc_node_make_take_children("METHODBODY",NULL,$1); doc_node_add_child($$, $2); doc_node_add_child($$, $3); doc_node_add_child($$, $4); } ; optbody: body | { $$ = NULL; } ; optargs: args | { $$ = NULL; } ; args: args arg { $$ = doc_node_add_child($1,$2); } | arg { $$ = doc_node_make("ARGUMENTS",NULL,$1); } ; arg: ARGUMENT words eol optbody { $$ = doc_node_make_take_children("ARGUMENT", $2, $4); } | ARGUMENT eol body { $$ = doc_node_make_take_children("ARGUMENT", NULL, $3); } ; optreturns: RETURNS body { $$ = doc_node_make_take_children("RETURNS",NULL,$2); } | { $$ = NULL; } ; optdiscussion: DISCUSSION body { $$ = doc_node_make_take_children("DISCUSSION",NULL,$2); } | { $$ = NULL; } ; /* body contains a list of bodyelem's (A) and prose (B) such that the list can start and end with either A or B, and A can repeat while B can not */ body: blockA | blockB ; blockA: blockB bodyelem { $$ = doc_node_add_child($1,$2); } | blockA bodyelem { $$ = doc_node_add_child($1,$2); } | bodyelem { $$ = doc_node_make("(SECTIONBODY)",NULL,$1); } ; blockB: blockA prose { $$ = doc_node_add_child($1,$2); } | prose { $$ = doc_node_make("(SECTIONBODY)",NULL,$1); } ; bodyelem: rangetag body TAGSYM { $$ = doc_node_make_take_children($1,NULL,$2); } | listtag listbody TAGSYM { $$ = doc_node_make_take_children($1,NULL,$2); } | TABLE tablebody TAGSYM { $$ = doc_node_make_take_children("TABLE",NULL,$2); } | DEFINITIONLIST deflistbody TAGSYM { $$ = doc_node_make_take_children("DEFINITIONLIST",NULL,$2); } | blocktag wordsnl TAGSYM { $$ = doc_node_make($1,$2,NULL); } | CLASSTREE words eoleof { $$ = doc_node_make("CLASSTREE",$2,NULL); } | KEYWORD commalist eoleof { $$ = doc_node_make_take_children("KEYWORD",NULL,$2); // printf("keyword '%s'\n",$2->children[0]->text); } | EMPTYLINES { $$ = NULL; } | IMAGE words2 TAGSYM { $$ = doc_node_make("IMAGE",$2,NULL); } ; prose: prose proseelem { $$ = doc_node_add_child($1, $2); } | proseelem { $$ = doc_node_make("PROSE",NULL,$1); } ; proseelem: anyword { $$ = doc_node_make(NODE_TEXT,$1,NULL); } // one TEXT for each word | URL { $$ = doc_node_make("LINK",$1,NULL); } | inlinetag words TAGSYM { $$ = doc_node_make($1,$2,NULL); } | FOOTNOTE body TAGSYM { $$ = doc_node_make_take_children("FOOTNOTE",NULL,$2); } | NEWLINE { $$ = doc_node_create(NODE_NL); } ; inlinetag: LINK { $$ = "LINK"; } | STRONG { $$ = "STRONG"; } | SOFT { $$ = "SOFT"; } | EMPHASIS { $$ = "EMPHASIS"; } | CODE { $$ = "CODE"; } | TELETYPE { $$ = "TELETYPE"; } | ANCHOR { $$ = "ANCHOR"; } ; blocktag: CODEBLOCK { $$ = "CODEBLOCK"; } | TELETYPEBLOCK { $$ = "TELETYPEBLOCK"; } ; listtag: LIST { $$ = "LIST"; } | TREE { $$ = "TREE"; } | NUMBEREDLIST { $$ = "NUMBEREDLIST"; } ; rangetag: WARNING { $$ = "WARNING"; } | NOTE { $$ = "NOTE"; } ; listbody: listbody HASHES body { $$ = doc_node_add_child($1, doc_node_make_take_children("ITEM",NULL,$3)); } | HASHES body { $$ = doc_node_make("(LISTBODY)",NULL, doc_node_make_take_children("ITEM",NULL,$2)); } ; tablerow: HASHES tablecells { $$ = doc_node_make_take_children("TABROW",NULL,$2); } ; tablebody: tablebody tablerow { $$ = doc_node_add_child($1,$2); } | tablerow { $$ = doc_node_make("(TABLEBODY)",NULL,$1); } ; tablecells: tablecells BARS optbody { $$ = doc_node_add_child($1, doc_node_make_take_children("TABCOL",NULL,$3)); } | optbody { $$ = doc_node_make("(TABLECELLS)",NULL, doc_node_make_take_children("TABCOL",NULL,$1)); } ; defterms: defterms HASHES body { $$ = doc_node_add_child($1,doc_node_make_take_children("TERM",NULL,$3)); } | HASHES body { $$ = doc_node_make("(TERMS)",NULL,doc_node_make_take_children("TERM",NULL,$2)); } ; deflistrow: defterms BARS optbody { $$ = doc_node_make_take_children("DEFLISTITEM", NULL, $1); doc_node_add_child($$, doc_node_make_take_children("DEFINITION", NULL, $3)); } ; deflistbody: deflistbody deflistrow { $$ = doc_node_add_child($1,$2); } | deflistrow { $$ = doc_node_make("(DEFLISTBODY)",NULL,$1); } ; anywordurl: anyword | URL ; anyword: TEXT | COMMA ; words: words anyword { $$ = strmerge($1,$2); } | anyword ; words2: words2 anywordurl { $$ = strmerge($1,$2); } | anywordurl ; eol: NEWLINE | EMPTYLINES ; eoleof: eol | END ; anywordnl: anyword | eol { $$ = strdup("\n"); } ; wordsnl: wordsnl anywordnl { $$ = strmerge($1,$2); } | anywordnl ; nocommawords: nocommawords TEXT { $$ = strmerge($1,$2); } | nocommawords URL { $$ = strmerge($1,$2); } | TEXT | URL ; commalist: commalist COMMA nocommawords { free($2); $2=NULL; $$ = doc_node_add_child($1,doc_node_make("STRING",$3,NULL)); } | nocommawords { $$ = doc_node_make("(COMMALIST)",NULL,doc_node_make("STRING",$1,NULL)); } ; %% DocNode * scdoc_parse_run(int mode) { int modes[] = {START_FULL, START_PARTIAL, START_METADATA}; if(mode<0 || mode>=sizeof(modes)) { error("scdoc_parse_run(): unknown mode: %d\n",mode); } scdoc_start_token = modes[mode]; /* scdoc_start_token = START_FULL; scdoc_metadata_mode = 0; if(mode==SCDOC_PARSE_PARTIAL) { scdoc_start_token = START_PARTIAL; } else if(mode==SCDOC_PARSE_METADATA) { scdoc_metadata_mode = 1; }*/ topnode = NULL; method_type = "METHOD"; if(scdocparse()!=0) { return NULL; } return topnode; } void scdocerror(const char *str) { error("In %s:\n At line %d: %s\n\n",scdoc_current_file,scdoclineno,str); /* FIXME: this does not work well, since the reported linenumber is often *after* the actual error line fseek(scdocin, 0, SEEK_SET); int line = 1; char buf[256],*txt; while(line!=scdoclineno && !feof(scdocin)) { int c = fgetc(scdocin); if(c=='\n') line++; } txt = fgets(buf, 256, scdocin); if(txt) fprintf(stderr," %s\n-------------------\n", txt); */ } SuperCollider-Source/SCDoc/SCDocPrim.cpp000644 000765 000024 00000005706 12756531745 021126 0ustar00crucialstaff000000 000000 /************************************************************************ * * Copyright 2012 Jonatan Liljedahl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ************************************************************************/ #include "GC.h" #include "PyrKernel.h" #include "PyrPrimitive.h" #include "PyrSymbol.h" #include "SCBase.h" #include "SC_DirUtils.h" #include #include #include #include //extern "C" { #include "SCDoc.h" //} PyrSymbol *s_scdoc_node; static void _doc_traverse(struct VMGlobals* g, DocNode *n, PyrObject *parent, PyrSlot *slot) { PyrObject *result = instantiateObject( g->gc, s_scdoc_node->u.classobj, 0, false, true ); SetObject(slot, result); if(parent) { assert(isKindOf(parent, class_array)); g->gc->GCWriteNew(parent, result); // we know result is white so we can use GCWriteNew parent->size++; } // initialise the instance vars PyrSymbol *id = getsym(n->id); SetSymbol(result->slots, id); // id // text if(n->text) { PyrObject *str = (PyrObject*) newPyrString(g->gc, n->text, 0, true); SetObject(result->slots+1, str); g->gc->GCWriteNew(result, str); // we know str is white so we can use GCWriteNew } // children if(n->n_childs) { PyrObject *array = newPyrArray(g->gc, n->n_childs, 0, true); SetObject(result->slots+2, array); g->gc->GCWriteNew(result, array); // we know array is white so we can use GCWriteNew for(int i=0; in_childs; i++) { _doc_traverse(g, n->children[i], array, array->slots+i); } } // makeDiv, notPrivOnly, sort remain nil for now } int prSCDoc_ParseFile(struct VMGlobals* g, int numArgsPushed) { PyrSlot *a, *b, *c; char filename[PATH_MAX]; int mode, err; a = g->sp - 2; b = g->sp - 1; c = g->sp; err = slotStrVal(b, filename, PATH_MAX); if (err) return err; err = slotIntVal(c, &mode); if (err) return err; DocNode *n = scdoc_parse_file(filename, mode); if(n) { // doc_node_dump(n); _doc_traverse(g, n, NULL, a); doc_node_free_tree(n); } else { SetNil(a); } return errNone; } void initSCDocPrimitives() { int base, index = 0; s_scdoc_node = getsym("SCDocNode"); base = nextPrimitiveIndex(); definePrimitive(base, index++, "_SCDoc_ParseFile", prSCDoc_ParseFile, 3, 0); } SuperCollider-Source/SCDoc/SCDocPrim.h000644 000765 000024 00000000126 12321461510 020536 0ustar00crucialstaff000000 000000 #ifndef _SCDOCPRIM_H_ #define _SCDOCPRIM_H_ void initSCDocPrimitives(void); #endif SuperCollider-Source/SCClassLibrary/backwards_compatibility/000755 000765 000024 00000000000 13007315613 025366 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Common/000755 000765 000024 00000000000 13007315613 021724 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/DefaultLibrary/000755 000765 000024 00000000000 13007315613 023405 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/deprecated/000755 000765 000024 00000000000 13007315613 022574 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/JITLib/000755 000765 000024 00000000000 13007315613 021551 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/Platform/000755 000765 000024 00000000000 13007315613 022260 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/SCDoc/000755 000765 000024 00000000000 13007315613 021427 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/scide_scqt/000755 000765 000024 00000000000 13007315613 022615 5ustar00crucialstaff000000 000000 SuperCollider-Source/SCClassLibrary/scide_scqt/ScIDE.sc000644 000765 000024 00000051472 12766171707 024063 0ustar00crucialstaff000000 000000 ScIDE { classvar subListSorter; classvar <>currentPath; classvar 0) { this.send(id, res); }; } *completeClassMethod { |id, text| var class, methods, res; class = text.asSymbol.asClass; if (class.notNil) { methods = IdentityDictionary(); class = class.class; while { class.notNil } { class.methods.do { |method| // methods include operators like "+", but those are // actually not valid in the method call syntax if (method.name.asString[0].isAlpha && methods[method.name].isNil) { methods.put(method.name, method); }; }; class = class.superclass; }; res = methods.values.collect { |m| this.serializeMethod(m) }; if (res.size > 0) { this.send(id, res) }; } } *completeMethod { |id, text| var res = []; Class.allClasses.do { |class| class.methods.do { |method| var signature; var definition; if (method.name.asString.beginsWith(text)) { res = res.add( this.serializeMethod(method) ); }; }; }; if (res.size > 0) { this.send(id, res) }; } *findMethod { |id, text| var cname, mname, tokens, res; var class, method; tokens = text.split($.); if (tokens.size > 1) { cname = tokens[0]; mname = tokens[1]; }{ mname = tokens[0]; }; if (mname.size < 1) { ^this }; if (cname.size > 0) { class = cname.asSymbol.asClass; if (class.isNil) { warn("No class named" + cname.asString); ^this; }; method = class.class.findRespondingMethodFor(mname.asSymbol); if (method.isNil) { warn("No such method:" + cname.asString ++ "." ++ mname.asString); ^this; }; this.send(id, [this.serializeMethod(method)]); }{ res = []; this.allMethodsDo { |method| if (method.name.asString == mname) { res = res.add( this.serializeMethod(method) ); }; }; if (res.size > 0) { this.send(id, res) }{ warn("No such method:" + mname.asString); ^this; }; } } *serializeMethod { arg method; var data = [method.ownerClass.name, method.name]; if (method.argNames.size > 1) { data = data ++ [ method.argNames.as(Array), method.prototypeFrame.collect { |val| val !? val.cs } ].lace [2..]; }; ^data; } *serializeMethodDetailed { arg method; var args, data; args = []; if (method.argNames.size > 1) { args = args ++ [ method.argNames.as(Array), method.prototypeFrame.collect { |val| val !? { if (val.class === Float) { val.asString } { val.cs } } }; ].lace [2..]; }; data = [ method.ownerClass.name, method.name, method.filenameSymbol, method.charPos, args ]; ^data; } *allMethodsDo { arg func; Class.allClasses.do { |class| class.methods.do { |method| func.value(method); }; }; } *findReferencesToSymbol {|requestId, symbol| var methods; var result = SortedList(8, subListSorter); var references = Class.findAllReferences(symbol.asSymbol); if (references.notNil) { methods = IdentitySet.new; references.do { | funcDef | var homeContext; homeContext = if(funcDef.context.isNil) {funcDef} {funcDef.context.homeContext}; if (homeContext.isKindOf(Method)) { methods.add(homeContext); }; }; methods.do { | method | result.add([ method.ownerClass.name, method.name, method.filenameSymbol.asString, method.charPos + 1 ]) } }; this.send(requestId, [symbol, result.asArray]) } *openHelpUrl { |url| this.processUrl(url, { |processedUrl| this.send("openHelpUrl", processedUrl.asString) }); } *cmdPeriod { docRoutine.play(AppClock) } *processUrl { |urlString, doneAction| // NOTE: Copied and modified from HelpBrower:-goTo var url, brokenFunc; brokenFunc = { |fragment| var brokenUrl = URI.fromLocalPath( SCDoc.helpTargetDir++"/BrokenLink.html" ); brokenUrl.fragment = fragment; brokenUrl; }; url = URI(urlString); if (docRoutine.notNil) { docRoutine.stop }; docRoutine = Routine { try { url = SCDoc.prepareHelpForURL(url) ?? { brokenFunc.(urlString) }; doneAction.value(url); } {|err| err.throw; }; CmdPeriod.remove(this); docRoutine = nil; }.play(AppClock); CmdPeriod.add(this); } // Document Support ////////////////////////////////////////////////// *newDocument {|title="Untitled", string="", id| this.send(\newDocument, [title, string, id]); } *open { |path, charPos = 0, selectionLength = 0, id| this.send(\openFile, [path, charPos, selectionLength, id]) } *getQUuid { _ScIDE_GetQUuid this.primitiveFailed } *getTextByQUuid {|quuid, funcID, start = 0, range = -1| this.send(\getDocumentText, [quuid, funcID, start, range]); } *setTextByQUuid {|quuid, funcID, text, start = 0, range = -1| this.send(\setDocumentText, [quuid, funcID, text, start, range]); } *setSelectionByQUuid {|quuid, start, length| this.send(\setDocumentSelection, [quuid, start, length]); } *setEditablebyQUuid {|quuid, editable| this.send(\setDocumentEditable, [quuid, editable]); } *setPromptsToSavebyQUuid {|quuid, prompts| this.send(\setDocumentPromptsToSave, [quuid, prompts]); } *setCurrentDocumentByQUuid {|quuid| this.send(\setCurrentDocument, [quuid]); } *removeDocUndoByQUuid {|quuid| this.send(\removeDocUndo, [quuid]); } *close {|quuid| this.send(\closeDocument, [quuid]); } *setDocumentTitle {|quuid, newTitle| this.send(\setDocumentTitle, [quuid, newTitle]); } *setDocumentKeyDownEnabled {|quuid, bool| this.send(\enableDocumentKeyDownAction, [quuid, bool]); } *setDocumentKeyUpEnabled {|quuid, bool| this.send(\enableDocumentKeyUpAction, [quuid, bool]); } *setDocumentGlobalKeyDownEnabled {|bool| this.send(\enableDocumentGlobalKeyDownAction, [bool]); } *setDocumentGlobalKeyUpEnabled {|bool| this.send(\enableDocumentGlobalKeyUpAction, [bool]); } *setDocumentMouseDownEnabled {|quuid, bool| this.send(\enableDocumentMouseDownAction, [quuid, bool]); } *setDocumentMouseUpEnabled {|quuid, bool| this.send(\enableDocumentMouseUpAction, [quuid, bool]); } *setDocumentTextChangedEnabled {|quuid, bool| this.send(\enableDocumentTextChangedAction, [quuid, bool]); } *setDocumentTextMirrorEnabled {|bool| this.send(\enableDocumentTextMirror, [bool]); } *send { |id, data| defer { this.prSend(id, data) } } // PRIVATE /////////////////////////////////////////////////////////// *prSend {|id, data| _ScIDE_Send this.primitiveFailed } *prConnect {|ideName| _ScIDE_Connect this.primitiveFailed } } Document { classvar current; classvar initAction; classvar <>autoRun = true; classvar toFrontAction, <>endFrontAction, <>onClose, = 0 } } { start = start - 1 }; while { str[end] !== Char.nl and: { end < max } } { end = end + 1 }; ^str.copyRange(start + 1, end); } // document setup path_ { |apath| this.notYetImplemented } dir { var path = this.path; ^path !? { path.dirname } } name { this.deprecated(thisMethod, Document.findMethod(\title)); ^this.title } name_ { |aname| this.deprecated(thisMethod, Document.findMethod(\title_)); this.title_(aname) } // envir stuff envir_ { | ev | envir = ev; if (this.class.current == this) { if(envir.isNil) { this.restoreCurrentEnvironment } { if (savedEnvir.isNil) { this.saveCurrentEnvironment } } } } restoreCurrentEnvironment { if (savedEnvir.notNil) { currentEnvironment = savedEnvir; savedEnvir = nil; } } saveCurrentEnvironment { if (envir.notNil) { savedEnvir = currentEnvironment; currentEnvironment = envir; } } selectLine { | line | var text, breaks, numLines, start = 0, end; if(line < 1, { line = 1 }); text = this.text; breaks = text.findAll("\n"); numLines = breaks.size + 1; line = min(line, numLines); if(line > 1, { start = breaks[line - 2] + 1}); end = breaks[line - 1] ?? { text.size }; this.selectRange(start, end - start); } selectRange { | start=0, length=0 | this.prSetSelectionMirror(quuid, start, length); // set the backend mirror ScIDE.setSelectionByQUuid(quuid, start, length); // set the IDE doc } editable_ { | bool=true | editable = bool; ScIDE.setEditablebyQUuid(quuid, bool); } promptToSave_ { | bool | promptToSave = bool; ScIDE.setPromptsToSavebyQUuid(quuid, bool); } removeUndo { ScIDE.removeDocUndoByQUuid(quuid); } // probably still needed for compatibility *implementationClass { ^this } } SuperCollider-Source/SCClassLibrary/SCDoc/Help.sc000644 000765 000024 00000002245 12756534417 022670 0ustar00crucialstaff000000 000000 Help { // These classvars and vars are part of the deprecated Help.tree stuff. When that stuff is removed from the classlib, this can be removed too. classvar cachePath; var tree, fileslist, path, // document "path" without basedir and extension, like "Classes/SinOsc" <>title, <>summary, <>redirect, <>categories, // a list of categories <>related, // a list of related docs <>docimethods, // a set of documented methods <>doccmethods, // a set of documented methods <>docmethods, // a set of documented methods <>privcmethods, // a set of private methods <>privimethods, // a set of private methods <>undoccmethods, <>undocimethods, <>keywords, // a list of keywords <>additions, <>isExtension, <>mtime, <>fullPath, <>oldHelp; var <>isClassDoc; var <>klass, <>implKlass, <>implements; var <>isUndocumentedClass; printOn {|stream| stream << "SCDocEntry(" << path.cs << ", " << title.cs << ", " << summary.cs << ")"; } prJSONString {|stream, key, x| if(x.isNil) { x = "" }; stream << "'" << key << "': \"" << x.escapeChar(34.asAscii) << "\",\n"; } prJSONList {|stream, key, v| if(v.isNil) { v = "" }; stream << "'" << key << "': [ " << v.collect{|x|"\""++x.escapeChar(34.asAscii)++"\""}.join(",") << " ],\n"; } toJSON {|stream| stream << "\"" << path.escapeChar(34.asAscii) << "\": {\n"; this.prJSONString(stream, "title", title); this.prJSONString(stream, "path", path); this.prJSONString(stream, "summary", summary); this.prJSONString(stream, "installed", if(isExtension,"extension","standard")); //FIXME: also 'missing'.. better to have separate extension and missing booleans.. this.prJSONString(stream, "categories", if(categories.notNil) {categories.join(", ")} {""}); // FIXME: export list instead this.prJSONList(stream, "keywords", keywords); this.prJSONList(stream, "related", related); this.prJSONList(stream, "methods", this.makeMethodList); if(oldHelp.notNil) { this.prJSONString(stream, "oldhelp", oldHelp); }; if(klass.notNil) { klass.superclasses !? { this.prJSONList(stream, "superclasses", klass.superclasses.collect {|c| c.name.asString }) }; klass.subclasses !? { this.prJSONList(stream, "subclasses", klass.subclasses.collect {|c| c.name.asString }) }; implKlass !? { this.prJSONString(stream, "implementor", implKlass.name.asString); } }; stream << "},\n"; } *new {|node,path| ^super.new.init(node,path); } *newUndocClass {|name| var doc = super.new.init(nil,"Classes/"++name.asString); var f, cats, implements, c; doc.klass = name.asSymbol.asClass; doc.isClassDoc = true; doc.isUndocumentedClass = true; doc.title = name.asString; f = doc.klass.filenameSymbol.asString; doc.mtime = 0; doc.isExtension = f.beginsWith(Platform.classLibraryDir).not; doc.undoccmethods = doc.klass.class.methods.collectAs({|m|m.name.asGetter},IdentitySet); doc.undocimethods = doc.klass.methods.collectAs({|m|m.name.asGetter},IdentitySet); if((implements=doc.klass.tryPerform(\implementsClass)).class===Symbol) { (c = implements.asClass) !? { doc.implements = c; doc.summary = "Implements "++implements; doc.categories = ["Redirect Class Implementors"]; ^doc; }; }; doc.summary = "(Undocumented class)"; cats = ["Undocumented classes"]; if(SCDoc.classHasArKrIr(doc.klass)) { cats = cats.add("UGens>Undocumented"); }; if(doc.klass.respondsTo('categories') and: {doc.klass.categories.notNil}) { cats = cats ++ doc.klass.categories; }; doc.categories = cats; ^doc; } init {|node,aPath| var hdr, bdy; // 'path' variable is used as a key for SCDoc.documents dictionary. // Make sure it always uses forward slashes. // FIXME: implement & use a generic path conversion method? path = aPath.replace("\\","/"); if(node.isNil) {^this}; #hdr, bdy = node.children; isExtension = false; isUndocumentedClass = false; doccmethods = IdentitySet(); docimethods = IdentitySet(); docmethods = IdentitySet(); privcmethods = IdentitySet(); privimethods = IdentitySet(); undoccmethods = IdentitySet(); undocimethods = IdentitySet(); hdr.children.do {|n| switch(n.id, \TITLE, { title = n.text }, \CLASS, { title = n.text }, // not used anymore? \SUMMARY, { summary = n.text }, \REDIRECT, { redirect = n.text }, \CATEGORIES, { categories = n.children.collect {|child| child.text} }, \RELATED, { related = n.children.collect {|child| child.text} }, ); }; this.prScanMethodsKeywords(bdy); if(title.isNil) { warn("SCDoc:"+path+"has no title!"); title = "(Untitled)"; }; if(isClassDoc = (path.dirname=="Classes")) { klass = title.asSymbol.asClass; //if(klass.isNil) { //warn("SCDoc:"+path++": No such class!"); //}; if(title != path.basename ) { warn("SCDoc:"+path++": Title and filename mismatch. Must be same for class docs!"); }; }; if(categories.isNil) { warn("SCDoc:"+path+"has no categories!"); categories = ["Uncategorized"]; }; if(summary.isNil) { warn("SCDoc:"+path+"has no summary!"); summary = "(Missing summary)"; }; } destPath { ^SCDoc.helpTargetDir +/+ path ++ ".html"; } makeMethodList { var list; //FIXME: no need for the extra _ char.. docimethods.do {|name| list = list.add("_-"++name.asString); }; doccmethods.do {|name| list = list.add("_*"++name.asString); }; undocimethods.do {|name| list = list.add("?-"++name.asString); }; undoccmethods.do {|name| list = list.add("?*"++name.asString); }; docmethods.do {|name| list = list.add("_."++name.asString); }; ^list; } setAdditions {|a| var x; additions = a; a.do {|f| (x = SCDoc.parseFilePartial(f)) !? { this.prScanMethodsKeywords(x); } } } indexUndocumentedMethods { var ignoreMethods = IdentitySet[\categories, \init, \checkInputs, \new1, \argNamesInputsOffset, \initClass, \storeArgs, \storeOn, \printOn]; var syms, name, mets, l = Array.new; var docmets = IdentitySet.new; if(klass.isNil) { ^this }; if(redirect.notNil) { try { implKlass = klass.perform(redirect.asSymbol) }; } { implKlass = nil; }; docmets = docimethods | privimethods | ignoreMethods; (mets = klass.methods) !? { mets.collectAs({|m|m.name.asGetter},IdentitySet).do {|name| if(docmets.includes(name).not) { undocimethods = undocimethods.add(name); }; }; }; docmets = doccmethods | privcmethods | ignoreMethods; (mets = klass.class.methods) !? { mets.collectAs({|m|m.name.asGetter},IdentitySet).do {|name| if(docmets.includes(name).not) { undoccmethods = undoccmethods.add(name); }; }; }; } prAddMethodNames {|node, list| node.children.do {|n| list = list.add(n.text.asSymbol); } ^list; } prAddCopyMethod {|node, list| ^list.add(node.text.split($ )[1].drop(1)) } prScanMethodsKeywords {|node| if(node.isNil) { //warn("FIXME: for some reason prScanMethodsKeywords was called on a nil node") ^this; }; switch(node.id, \METHOD, { docmethods = this.prAddMethodNames(node.children[0], docmethods) }, \CMETHOD, { doccmethods = this.prAddMethodNames(node.children[0], doccmethods) }, \IMETHOD, { docimethods = this.prAddMethodNames(node.children[0], docimethods) }, \COPYMETHOD, { docmethods = this.prAddCopyMethod(node,docmethods) }, \CCOPYMETHOD, { doccmethods = this.prAddCopyMethod(node,doccmethods) }, \ICOPYMETHOD, { docimethods = this.prAddCopyMethod(node,docimethods) }, \CPRIVATE, { privcmethods = this.prAddMethodNames(node, privcmethods) }, \IPRIVATE, { privimethods = this.prAddMethodNames(node, privimethods) }, \KEYWORD, { node.children.do {|n| keywords = keywords.add(n.text); } }, { node.children.do {|n| this.prScanMethodsKeywords(n); } } ); } } SCDocNode { var <>id, <>text, <>children, <>makeDiv, notPrivOnly, <>sort; printOn {|stream| stream << "SCDocNode(" << id << ", " << text.cs << ", " << children << ")"; } findChild {|id| ^children.detect {|node| node.id===id} } notPrivOnly { if(notPrivOnly.isNil) { notPrivOnly = (children.detect {|x| x.id != \CPRIVATE and: {x.id != \IPRIVATE}}.notNil) }; ^notPrivOnly } addDivAfter {|id, div, title, childs| var node = this.findChild(id); var mets = SCDocNode() .id_(\SUBSECTION) .text_(title) .children_(childs) .makeDiv_(div); if(node.isNil) { //no subtree, create one children = children.add( node = SCDocNode().id_(id) ); }; node.children = node.children.add(mets); } sortClassDoc { var x = 0; // FIXME: does this work correctly for prose before first section, etc? children.do {|n| switch(n.id, \DESCRIPTION, { n.sort = 10 }, \CLASSMETHODS,{ n.sort = 11 }, \INSTANCEMETHODS, { n.sort = 12 }, \EXAMPLES,{ n.sort = 13 }, \SECTION, { n.sort = 14 + x = x + 1 }, { n.sort = x = x + 1 } ); }; children = children.sort {|a,b| a.sortverbosity = 1; classvar <>renderer; classvar documents; classvar helpSourceDirs; *parseFileFull {|path| ^this.prParseFile(path, 0) } *parseFilePartial {|path| ^this.prParseFile(path, 1) } *parseFileMetaData {|dir,path| var fullPath = dir +/+ path; var subpath = path.drop(-7); var entry, x = this.prParseFile(fullPath, 2); if(x.isNil) {^nil}; entry = SCDocEntry(x, subpath); entry.isExtension = (dir != this.helpSourceDir); entry.fullPath = fullPath; entry.mtime = File.mtime(fullPath); if(dir.beginsWith(Platform.userExtensionDir +/+ "quarks")) { entry.categories = entry.categories ++ ["Quarks>"++dir.dirname.basename]; }; ^entry; } *prParseFile {|path, mode| _SCDoc_ParseFile ^this.primitiveFailed } *indexOldHelp { var f = {|x,cat="Old Helpfiles",indent=0| var a,b,doc; x.pairsDo {|k,v| if(v.isKindOf(Dictionary)) { k = k.asString; a = 0; b = k.size-1; while({ $[ == k[a]},{a=a+1}); while({ $] == k[b]},{b=b-1}); k = k.copyRange(a,b); f.(v,cat++">"++k.asString,indent+1); } { if(v.size>0) { doc = SCDocEntry(nil,"Old Help"+/+v); doc.oldHelp = URI.fromLocalPath(v).asString; doc.title = v.basename; doc.summary = "(not yet converted to new help format)"; doc.categories = [cat]; doc.isExtension = true; SCDoc.documents[doc.path] = doc; } } } }; Help.rebuildTree; f.(Help.tree); } *indexAllDocuments { |clearCache=false| var now = Main.elapsedTime; var key, doc; var nonHelpFiles; var undocClasses = Class.allClasses.reject(_.isMetaClass).collectAs({|c|c.name},IdentitySet); var additions = Dictionary(); this.checkVersion(clearCache); this.postMsg("Indexing help-files...",0); documents = Dictionary(); // or use IdDict and symbols as keys? helpSourceDirs = nil; // force re-scan of HelpSource folders this.helpSourceDirs.do {|dir| PathName(dir).filesDo {|f| case {f.fullPath.endsWith(".ext.schelp")} { f = f.fullPath; key = f[dir.size+1 ..].drop(-11).replace("\\","/"); additions[key] = additions[key].add(f); } {f.extension=="schelp"} { doc = this.parseFileMetaData(dir, f.fullPath.drop(dir.size+1)); doc !? { documents[doc.path] = doc; if(doc.isClassDoc) { undocClasses.remove(doc.title.asSymbol); } } } { f = f.fullPath; nonHelpFiles = nonHelpFiles.add([f,f.drop(dir.size+1)]); }; } }; this.postMsg("Handling"+additions.size+"document additions...",1); additions.pairsDo {|key, val| doc = documents[key]; if(doc.notNil) { doc.setAdditions(val); } { warn("SCDoc: Additions % for non-existent help file".format(val)); } }; this.postMsg("Indexing undocumented methods...",1); documents.do {|d| if(d.isClassDoc) { d.indexUndocumentedMethods }; }; this.postMsg("Adding entries for"+undocClasses.size+"undocumented classes...",1); undocClasses.do {|x| doc = SCDocEntry.newUndocClass(x); documents[doc.path] = doc; }; this.postMsg("Copying"+nonHelpFiles.size+"non-help files...",1); nonHelpFiles.do {|x| var dest = SCDoc.helpTargetDir+/+x[1]; var folder = dest.dirname; File.mkdir(folder); if(File.exists(dest).not or: {File.mtime(x[0]) > File.mtime(dest)}) { File.delete(dest); File.copy(x[0],dest); }; }; if(Help.respondsTo('tree')) { this.postMsg("Indexing old helpfiles..."); this.indexOldHelp; }; this.postMsg("Exporting docmap.js...",1); this.exportDocMapJS(this.helpTargetDir +/+ "docmap.js"); this.postMsg("Indexed % documents in % seconds".format(documents.size,round(Main.elapsedTime-now,0.01)),0); NotificationCenter.notify(SCDoc, \didIndexAllDocs); } *didIndexDocuments { ^documents.notNil } *documents { if(documents.isNil) { this.indexAllDocuments; }; ^documents; } *helpSourceDirs { var find, rootPaths; if(helpSourceDirs.isNil) { this.postMsg("locating HelpSource folders...",2); helpSourceDirs = [helpSourceDir]; // Note: an array will keep the order. find = {|dir| dir.folders.do {|f| if(f.folderName=="HelpSource") { helpSourceDirs = helpSourceDirs.add(f.fullPath.withoutTrailingSlash); } { find.(f); }; } }; rootPaths = [thisProcess.platform.userExtensionDir, thisProcess.platform.systemExtensionDir]; rootPaths = rootPaths.addAll(LanguageConfig.includePaths); rootPaths.do {|dir| find.(PathName(dir)); }; }; ^helpSourceDirs } *exportDocMapJS {|path| var f = File.open(path,"w"); f << "docmap = {\n"; this.documents.do {|doc| doc.toJSON(f); }; f << "}\n"; f.close; } *helpSourceDir_ {|path| helpSourceDir = path.standardizePath; } *helpTargetDir_ {|path| //if(path!=helpTargetDir) {didRun = false}; helpTargetDir = path.standardizePath; helpTargetUrl = URI.fromLocalPath(helpTargetDir).asString; } *postMsg {|txt, lvl=0| if(verbosity>lvl) { postln("SCDoc: "++txt); }; if(thisThread.isKindOf(Routine)) { 0.yield; } } *parseDoc {|doc| var add, root; (root = this.parseFileFull(doc.fullPath)) !? { doc.additions.do {|f| (add = this.parseFilePartial(f)) !? { root.children[1].merge(add); } }; this.handleCopyMethods(root,doc); }; ^root; } *parseAndRender {|doc| var dest = doc.destPath; var root = this.parseDoc(doc); root !? { this.postMsg("% -> %".format(doc.fullPath, dest),2); this.renderer.renderToFile(dest, doc, root); } } *prepareHelpForURL {|url| var path, targetBasePath, pathIsCaseInsensitive; var subtarget, src, c, cmd, doc, destExist, destMtime; var verpath = this.helpTargetDir +/+ "version"; path = url.asLocalPath; // detect old helpfiles and wrap them in OldHelpWrapper if(url.scheme == "sc") { ^URI(SCDoc.findHelpFile(path)); }; // just pass through remote url's if(url.scheme != "file") {^url}; targetBasePath = SCDoc.helpTargetDir; if (thisProcess.platform.name === \windows) { targetBasePath = targetBasePath.replace("/","\\") }; pathIsCaseInsensitive = thisProcess.platform.name === \windows; // detect old helpfiles and wrap them in OldHelpWrapper if( /* // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions. // we could use File.realpath(path) below but that would double the execution time, // so let's just assume any local file outside helpTargetDir is an old helpfile. block{|break| Help.do {|key, path| if(url.endsWith(path)) { break.value(true) } }; false }*/ compare( path [..(targetBasePath.size-1)], targetBasePath, pathIsCaseInsensitive ) != 0 ) { ^SCDoc.getOldWrapUrl(url) }; if(destExist = File.exists(path)) { destMtime = File.mtime(path); }; if(path.endsWith(".html")) { subtarget = path.drop(this.helpTargetDir.size+1).drop(-5).replace("\\","/"); doc = this.documents[subtarget]; doc !? { if(doc.isUndocumentedClass) { if(doc.mtime == 0) { this.renderUndocClass(doc); doc.mtime = 1; }; ^url; }; if(File.mtime(doc.fullPath)>doc.mtime) { // src changed after indexing this.postMsg("% changed, re-indexing documents".format(doc.path),2); this.indexAllDocuments; ^this.prepareHelpForURL(url); }; if(destExist.not or: {doc.mtime>destMtime} or: {doc.additions.detect {|f| File.mtime(f)>destMtime}.notNil} or: {File.mtime(this.helpTargetDir +/+ "scdoc_version")>destMtime} or: {doc.klass.notNil and: {File.mtime(doc.klass.filenameSymbol.asString)>destMtime}} ) { this.parseAndRender(doc); }; ^url; }; }; if(destExist) { ^url; }; warn("SCDoc: Broken link:" + url.asString); ^nil; } *initClass { this.helpSourceDir_(thisProcess.platform.classLibraryDir.dirname +/+ "HelpSource"); this.helpTargetDir_(thisProcess.platform.userAppSupportDir +/+ "Help"); renderer = SCDocHTMLRenderer; } *classHasArKrIr {|c| ^#[\ar,\kr,\ir].collect {|m| c.class.findRespondingMethodFor(m).notNil }.reduce {|a,b| a or: b}; } *checkVersion {|clearCache=false| var f, path = this.helpTargetDir +/+ "scdoc_version"; if(clearCache or: {path.load != version}) { this.postMsg("refreshing scdoc version timestamp",1); // this will update the mtime of the version file, triggering re-rendering of files older than now File.mkdir(this.helpTargetDir); f = File.open(path,"w"); f.write(version.asCompileString); f.close; ^true; }; ^false; } *renderAll {|includeExtensions=true| this.postMsg("Rendering all documents"); this.documents.do {|doc| if(doc.oldHelp.isNil and: {includeExtensions or: {doc.isExtension.not}}) { if(doc.isUndocumentedClass) { this.renderUndocClass(doc); } { this.parseAndRender(doc); } } }; this.postMsg("Done!"); } *makeClassTemplate {|doc| var name = doc.title; var cats = doc.categories; var class = doc.klass; var n, m, f, c; f = {|cm| var txt,c,m,l,last,sym; if(cm) { txt = "\nCLASSMETHODS::\n\n"; n = doc.undoccmethods; c = class.class; } { txt = "\nINSTANCEMETHODS::\n\n"; n = doc.undocimethods; c = class; }; n.do {|x| txt = txt ++ "METHOD::" + x ++ "\n(describe method here)\n\n"; sym = x.asSymbol; m = c.findRespondingMethodFor(sym.asSetter); m = m ?? {c.findRespondingMethodFor(sym)}; m !? { l = m.argNames; last = l.size-1; l.do {|a,i| if (i>0) { //skip 'this' (first arg) txt = txt ++ "ARGUMENT:: "; if(i==last and: {m.varArgs}) { txt = txt ++ " ... "; }; txt = txt ++ a ++ "\n(describe argument here)\n\n"; } } }; txt = txt ++ "returns:: (describe returnvalue here)\n\n"; }; txt; }; ^ "TITLE::"+name ++"\nsummary:: (put short description here)\n" ++"categories::"+cats.join(", ") ++"\nrelated:: Classes/SomeRelatedClass, Reference/SomeRelatedStuff, etc.\n\n" ++"DESCRIPTION::\n(put long description here)\n\n" ++ f.(true) ++ f.(false) ++"\nEXAMPLES::\n\ncode::\n(some example code)\n::\n"; } *renderUndocClass {|doc| var node, desc, body; node = SCDocNode().id_(\DOCUMENT).children_([ SCDocNode().id_(\HEADER).children_([ // the header content is already in the SCDocEntry.. ]), body = SCDocNode().id_(\BODY).children_([ SCDocNode().id_(\DESCRIPTION).children_([ desc = SCDocNode().id_(\PROSE) ]) ]) ]); if(doc.implements.notNil) { this.postMsg("Generating class redirect implementor doc: % for %".format(doc.title,doc.implements.name),2); desc.children = [ SCDocNode().id_(\TEXT).text_("Implements "), SCDocNode().id_(\LINK).text_("Classes/"++doc.implements.name) ]; } { this.postMsg("Undocumented class: "++doc.title++", generating stub and template",2); desc.children = [ SCDocNode().id_(\TEXT).text_("This class is missing documentation.") ]; body.children = body.children.add( SCDocNode().id_(\SECTION).text_("Help template").children_([ SCDocNode().id_(\PROSE).children_([ SCDocNode().id_(\TEXT).text_("Copy and paste the text below and save to HelpSource/Classes/"++doc.title++".schelp") ]), SCDocNode().id_(\CODEBLOCK).text_(this.makeClassTemplate(doc)) ]) ); }; this.renderer.renderToFile(doc.destPath, doc, node); } *getMethodDoc {|classname,methodname| var doc, id, node, mname; var findmet = {|n| if((n.id == id) and: {n.children[0].children.detect{|x|x.text==mname}.notNil}) { n; } { block {|break| n.children.do {|n2| n2 = findmet.(n2,id); if(n2.notNil) { break.value(n2); } }; nil; } } }; var err = {|txt| warn("SCDoc.getMethodDoc(%, %): %".format(classname,methodname,txt)); }; doc = this.documents["Classes/"++classname]; if(doc.isNil or: {doc.fullPath.isNil}) { err.("class document not found"); ^nil; }; id = switch(methodname[0], $*, \CMETHOD, $-, \IMETHOD, $., \METHOD, { err.("methodname must be prefixed with '*', '-' or '.'"); ^nil; } ); mname = methodname.drop(1); node = this.parseDoc(doc); if(node.isNil) { err.("could not parse class document"); ^nil; }; node = findmet.(node); if(node.isNil) { err.("method not found"); ^nil; }; ^node; } *handleCopyMethods {|node,doc| var found = {|n| var name, met, x; #name, met = n.text.findRegexp("[^ ,]+").flop[1]; x = this.getMethodDoc(name, met); if(x.isNil) { warn("from: %".format(doc.fullPath)); }; x; }; node.children.do{|n,i| switch(n.id, \CCOPYMETHOD, { n = found.(n); n !? {n.id_(\CMETHOD); node.children[i] = n} }, \ICOPYMETHOD, { n = found.(n); n !? {n.id_(\IMETHOD); node.children[i] = n} }, \COPYMETHOD, { n = found.(n); n !? {n.id_(\METHOD); node.children[i] = n} }, { this.handleCopyMethods(n,doc); } ); }; } *findHelpFile {|str| var old, sym, pfx = SCDoc.helpTargetUrl; if(str.isNil or: {str.isEmpty}) { ^pfx ++ "/Help.html" }; if(this.documents[str].notNil) { ^pfx ++ "/" ++ str ++ ".html" }; sym = str.asSymbol; if(sym.asClass.notNil) { ^pfx ++ (if(this.documents["Classes/"++str].isUndocumentedClass) { (old = if(Help.respondsTo('findHelpFile'),{Help.findHelpFile(str)})) !? { "/OldHelpWrapper.html#"++old++"?"++SCDoc.helpTargetUrl ++ "/Classes/" ++ str ++ ".html" } } ?? { "/Classes/" ++ str ++ ".html" }); }; if(str.last == $_) { str = str.drop(-1) }; ^pfx ++ if("^[a-z][a-zA-Z0-9_]*$|^[-<>@|&%*+/!?=]+$".matchRegexp(str)) { "/Overviews/Methods.html#" } { "/Search.html#" } ++ str; } *getOldWrapUrl {|url| var urlString, className, newUrl; urlString = url.asString; newUrl = URI.fromLocalPath( SCDoc.helpTargetDir +/+ "OldHelpWrapper.html" ); newUrl.fragment = urlString; newUrl.query = SCDoc.helpTargetUrl ++ if((className=urlString.basename.split($.).first).asSymbol.asClass.notNil) {"/Classes/" ++ className ++ ".html"} {"/Guides/WritingHelp.html"} ^newUrl; } } URI { /* NOTE: This class attempts compliance with specification Uniform Resource Identifier (URI): Generic Syntax (RFC 3986) http://datatracker.ietf.org/doc/rfc3986/ If you intend to modify it, please consult the specification! */ classvar parseRegexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; var <>scheme, <>authority, <>path, <>query, <>fragment; *new { |validUriString| ^super.new.init(validUriString) } *fromLocalPath { |string| var uri = super.new; uri.scheme = "file"; uri.authority = ""; uri.path = string; if (thisProcess.platform.name === \windows) { uri.path = uri.path.replace("\\","/"); if (uri.path.size >= 2 and: {uri.path[1] == $:}) { uri.path = "/" ++ uri.path; } } ^ uri; } *tolerant { |string| var uri; if (thisProcess.platform.name === \windows and: { string.size >= 2 and: { string[1] == $:} } ) { ^ this.fromLocalPath(string); }; uri = this.new(string); if (uri.scheme.isNil) { uri.scheme = "file"; if (uri.authority.isNil) { uri.authority = "" } }; ^ uri; } init { |string| var result; if (string.notNil) { string = string.replace("%20"," "); result = string.findRegexp( parseRegexp ).flop[1]; if (result[1].size > 0) { scheme = result[2] }; if (result[3].size>0) { authority = result[4] }; path = result[5]; if (result[6].size > 0) { query = result[7] }; if (result[8].size > 0) { fragment = result[9] }; }; } asLocalPath { var localPath; if (scheme != "file") { ^nil }; if (thisProcess.platform.name === \windows) { localPath = path; if (localPath.beginsWith("/")) { localPath = localPath.drop(1) }; localPath = localPath.replace("/","\\"); ^localPath; } ^ path.copy; } asString { var str = ""; if (scheme.notNil) { str = str ++ scheme ++ ":" }; if (authority.notNil) { str = str ++ "//" ++ authority }; str = str ++ path; if (query.notNil) { str = str ++ "?" ++ query }; if (fragment.notNil) { str = str ++ "#" ++ fragment }; ^str; } } + String { stripWhiteSpace { var ws = [$\n, $\r, $\t, $\ ]; var a=0, b=this.size-1; while({ ws.includes(this[a])},{a=a+1}); while({ ws.includes(this[b])},{b=b-1}); ^this.copyRange(a,b); } unixCmdGetStdOutLines { var pipe, lines, line; pipe = Pipe.new(this, "r"); lines = Array.new; line = pipe.getLine; while({line.notNil}, {lines = lines.add(line); line = pipe.getLine; }); pipe.close; ^lines; } } + Method { isExtensionOf {|class| ^( (this.filenameSymbol != class.filenameSymbol) and: if((class!=Object) and: (class!=Meta_Object), {class.superclasses.includes(this.ownerClass).not}, {true}) ); } } SuperCollider-Source/SCClassLibrary/SCDoc/SCDocRenderer.sc000644 000765 000024 00000055616 13007174002 024410 0ustar00crucialstaff000000 000000 /* HTML renderer */ SCDocHTMLRenderer { classvar currentClass, currentImplClass, currentMethod, currArg; classvar currentNArgs; classvar footNotes; classvar noParBreak; classvar currDoc; classvar minArgs; classvar baseDir; *escapeSpecialChars {|str| var x = ""; var beg = -1, end = 0; str.do {|chr, i| switch(chr, $&, { x = x ++ str.copyRange(beg, i-1) ++ "&"; beg = i+1; }, $<, { x = x ++ str.copyRange(beg, i-1) ++ "<"; beg = i+1; }, $>, { x = x ++ str.copyRange(beg, i-1) ++ ">"; beg = i+1; }, { end = i } ); }; if(beg<=end) { x = x ++ str[beg..end]; }; ^x; } *escapeSpacesInAnchor { |str| ^str.replace(" ", "%20") } *htmlForLink {|link,escape=true| var n, m, f, c, doc; // FIXME: how slow is this? can we optimize #n, m, f = link.split($#); // link, anchor, label if(m.size > 0) { m = this.escapeSpacesInAnchor(m); }; ^if ("^[a-zA-Z]+://.+".matchRegexp(link) or: (link.first==$/)) { if(f.size<1) {f=link}; c = if(m.size>0) {n++"#"++m} {n}; if(escape) { f = this.escapeSpecialChars(f) }; ""++f++""; } { if(n.size>0) { c = baseDir+/+n; doc = SCDoc.documents[n]; // link to other doc (might not be rendered yet) if(doc.notNil) { c = c ++ ".html"; } { // link to ready-made html (Search, Browse, etc) if(File.exists(SCDoc.helpTargetDir+/+n++".html")) { c = c ++ ".html"; } { // link to other file? if(File.exists(SCDoc.helpTargetDir+/+n).not) { "SCDoc: In %\n" " Broken link: '%'" .format(currDoc.fullPath, link).warn; }; }; }; } { c = ""; // link inside same document }; if(m.size>0) { c = c ++ "#" ++ m }; // add #anchor if(f.size<1) { // no label if(n.size>0) { f = if(doc.notNil) {doc.title} {n.basename}; if(m.size>0) { f = f++": "++m; } } { f = if(m.size>0) {m} {"(empty link)"}; }; }; if(escape) { f = this.escapeSpecialChars(f) }; ""++f++""; }; } *makeArgString {|m, par=true| var res = ""; var value; var l = m.argNames; var last = l.size-1; l.do {|a,i| if (i>0) { //skip 'this' (first arg) if(i==last and: {m.varArgs}) { res = res ++ " " ++ "... " ++ a; } { if (i>1) { res = res ++ ", " }; res = res ++ "" ++ a; (value = m.prototypeFrame[i]) !? { value = if(value.class===Float) { value.asString } { value.cs }; res = res ++ ": " ++ value; }; }; res = res ++ ""; }; }; if (res.notEmpty and: par) { ^("("++res++")"); }; ^res; } *renderHeader {|stream, doc| var x, cats, m, z; var folder = doc.path.dirname; var undocumented = false; if(folder==".",{folder=""}); // FIXME: use SCDoc.helpTargetDir relative to baseDir baseDir = "."; doc.path.occurrencesOf($/).do { baseDir = baseDir ++ "/.."; }; stream << "" << doc.title << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" << "\n" // FIXME: remove? << "\n" << "\n" << "\n" << "\n"; stream << "