diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index d02d4aa3931..0e96c2fa1cb 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -235,6 +235,7 @@ jobs: SHARED_LIBSCSYNTH: ${{ matrix.shared-libscsynth }} ARTIFACT_FILE: 'SuperCollider-${{ needs.lint.outputs.sc-version }}-${{ matrix.artifact-suffix }}.dmg' DEVELOPER_DIR: '/Applications/Xcode_${{ matrix.xcode-version }}.app/Contents/Developer' + MACOSX_DEPLOYMENT_TARGET: '${{ matrix.deployment-target }}' steps: - uses: actions/checkout@v2 with: @@ -274,14 +275,47 @@ jobs: - name: build libsndfile # to make it compatible with older OSes (lower deployment target) if: matrix.build-libsndfile == true run: | - brew uninstall --ignore-dependencies libsndfile - brew install automake mpg123 + brew uninstall --ignore-dependencies libsndfile libvorbis libogg flac opus + brew install automake + cd $GITHUB_WORKSPACE/.. + curl -L https://gitlab.xiph.org/xiph/ogg/-/archive/v1.3.5/ogg-v1.3.5.tar.bz2 --output ogg.tar.bz2 + tar xfz ogg.tar.bz2 + cd ogg*/ + echo "*** building libogg ***" + mkdir build && cd build + cmake -G"Unix Makefiles" -DBUILD_FRAMEWORK=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra" -DCMAKE_INSTALL_PREFIX=/usr/local .. + cmake --build . --target install + cd $GITHUB_WORKSPACE/.. + curl -L https://github.com/xiph/flac/archive/refs/tags/1.3.3.tar.gz --output flac.tar.xz + tar xfz flac.tar.xz + cd flac*/ + echo "*** building flac ***" + cd build # build directory already exists + cmake -G"Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra" -DCMAKE_INSTALL_PREFIX=/usr/local .. + cmake --build . --target install + cd $GITHUB_WORKSPACE/.. + curl -L https://github.com/xiph/opus/archive/refs/tags/v1.3.1.tar.gz --output opus.tar.gz + tar xfz opus.tar.gz + cd opus*/ + echo "*** building opus ***" + mkdir build && cd build + cmake -G"Unix Makefiles" -DBUILD_SHARED_LIBS=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra" -DCMAKE_INSTALL_PREFIX=/usr/local .. + cmake --build . --target install + cd $GITHUB_WORKSPACE/.. + curl -L https://github.com/xiph/vorbis/releases/download/v1.3.7/libvorbis-1.3.7.tar.gz --output libvorbis.tar.gz + tar xfz libvorbis.tar.gz + cd libvorbis*/ + echo "building *** libvorbis ***" + mkdir build && cd build + cmake -G"Unix Makefiles" -DBUILD_FRAMEWORK=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS="-Wall -Wextra" -DCMAKE_INSTALL_PREFIX=/usr/local .. + cmake --build . --target install cd $GITHUB_WORKSPACE/.. curl -L https://github.com/libsndfile/libsndfile/releases/download/1.0.31/libsndfile-1.0.31.tar.bz2 --output libsndfile.tar.bz2 - tar xfvz libsndfile.tar.bz2 + tar xfz libsndfile.tar.bz2 cd libsndfile*/ + echo "building libsndfile" mkdir build && cd build - cmake -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.deployment-target }} -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_C_FLAGS="-Wall -Wextra" -DCMAKE_INSTALL_PREFIX=/usr/local .. + cmake -G"Unix Makefiles" -DBUILD_SHARED_LIBS=ON -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_C_FLAGS="-Wall -Wextra" -DCMAKE_INSTALL_PREFIX=/usr/local .. cmake --build . --target install - name: install system libraries if: env.USE_SYSLIBS == 'true' @@ -311,7 +345,7 @@ jobs: echo "EXTRA_CMAKE_FLAGS:" $EXTRA_CMAKE_FLAGS - cmake -G"Xcode" -DRULE_LAUNCH_COMPILE=ccache -DCMAKE_OSX_DEPLOYMENT_TARGET=${{ matrix.deployment-target }} -DSUPERNOVA=ON $EXTRA_CMAKE_FLAGS .. --debug-output + cmake -G"Xcode" -DRULE_LAUNCH_COMPILE=ccache -DSUPERNOVA=ON $EXTRA_CMAKE_FLAGS .. --debug-output - name: build run: cmake --build $BUILD_PATH --config Release --target install - name: create archive @@ -325,7 +359,7 @@ jobs: # the following assumes that we end up with the build in the folder SuperCollider # hdiutil sometimes fails with "create failed - Resource busy" # when that happens, we run it again - hdiutil create -srcfolder SuperCollider -format UDZO $ARTIFACT_FILE || hdiutil create -srcfolder SuperCollider -format UDZO $ARTIFACT_FILE + hdiutil create -srcfolder SuperCollider -format UDZO -fs HFS+ $ARTIFACT_FILE || hdiutil create -srcfolder SuperCollider -format UDZO -fs HFS+ $ARTIFACT_FILE - name: upload artifacts uses: actions/upload-artifact@v2 if: matrix.artifact-suffix @@ -451,9 +485,9 @@ jobs: ASIO_PATH: ${{ env.LIBS_DOWNLOAD_PATH }}/asio_sdk run: | mkdir -p $ASIO_PATH && cd $ASIO_PATH - curl -L https://www.steinberg.net/sdk_downloads/asiosdk2.3.zip -o asio.zip + curl -L https://www.steinberg.net/asiosdk -o asio.zip 7z x asio.zip -y - mv ASIOSDK2.3 $GITHUB_WORKSPACE/external_libraries/portaudio/asiosdk + mv asiosdk_* $GITHUB_WORKSPACE/external_libraries/portaudio/asiosdk - name: configure shell: bash run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c5a4de9ed8..ec87866a605 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,7 +41,15 @@ Release dates of 3.x versions: - 3.9: 2018-01-13 - 3.10: 2018-11-24 - 3.11: 2020-03-08 -- 3.12: 2020-08-02 +- 3.12: 2021-08-02 + +3.12.1 (2021-09-05) +=================== + +The 3.12.1 release fixes compatibility with older macOS systems (10.13 and below) + +### General: Fixed +Builds for older macOS systems ([#5537](https://github.com/supercollider/supercollider/pull/5537)) 3.12.0 (2021-08-02) =================== @@ -105,6 +113,7 @@ macOS builds include a custom build of libsndfile to support older macOS version ### UGens: Fixed PanAz: initialize amps in Ctor ([#4973](https://github.com/supercollider/supercollider/pull/4973)) + EnvGen fixes ([#5217](https://github.com/supercollider/supercollider/pull/5217), [#4921](https://github.com/supercollider/supercollider/pull/4921), [#4793](https://github.com/supercollider/supercollider/pull/4793)) ### IDE: Fixed diff --git a/HelpSource/Classes/Server.schelp b/HelpSource/Classes/Server.schelp index 266a243894f..41a492b4ffb 100644 --- a/HelpSource/Classes/Server.schelp +++ b/HelpSource/Classes/Server.schelp @@ -28,6 +28,8 @@ code:: s.serverRunning // returns true if it is true :: +Some insights about common Server issues can be found on the FAQ link::Guides/UserFAQ#Server Issues#Server Issues:: + ClassMethods:: private:: initClass diff --git a/HelpSource/Classes/SynthDef.schelp b/HelpSource/Classes/SynthDef.schelp index 978ecbaf601..89678bba700 100644 --- a/HelpSource/Classes/SynthDef.schelp +++ b/HelpSource/Classes/SynthDef.schelp @@ -11,6 +11,8 @@ The SynthDef class encapsulates the client-side representation of a given def, a SynthDef is one of the more complicated classes in SC and an exhaustive explanation of it is beyond the scope of this document. As such, the examples at the bottom of this document and those found in the various tutorials accessible from link::Help:: may be necessary to make some aspects of its use clear. +Some insights about common SynthDef issues can be found on the FAQ link::Guides/UserFAQ#SynthDef Issues#SynthDef Issues:: + subsection:: UGen Graph Functions and Special Argument Forms The core of a def is its link::Classes/UGen##unit generator:: graph function. diff --git a/HelpSource/Guides/GUI-Introduction.schelp b/HelpSource/Guides/GUI-Introduction.schelp index 72e2baa8683..b92a853edfc 100644 --- a/HelpSource/Guides/GUI-Introduction.schelp +++ b/HelpSource/Guides/GUI-Introduction.schelp @@ -390,4 +390,6 @@ Routine{ }.play(SystemClock) :: -As mentioned above, using the GUI system is also not allowed in code performed directly in response to OSC messages (this includes functions given to all kinds of OSC responder classes). The same solutions as above apply: +As mentioned above, using the GUI system is also not allowed in code performed directly in response to OSC messages (this includes functions given to all kinds of OSC responder classes). The same solutions as above apply. + +Another example for addressing this issue can be found in the FAQ link::Guides/UserFAQ#Language (client) Issues#Language (client) Issues:: diff --git a/HelpSource/Guides/News-3_12.schelp b/HelpSource/Guides/News-3_12.schelp index 6c783ebc547..51c409a55ec 100644 --- a/HelpSource/Guides/News-3_12.schelp +++ b/HelpSource/Guides/News-3_12.schelp @@ -2,7 +2,7 @@ title:: News in 3.12 summary:: A summary of news in SC 3.12 categories:: News -The 3.12.0 release brings new features, countless bugfixes, as well as project and documentation updates. See the repository for all the changes. A big thank you to all developers for your contributions! +The 3.12 release brings new features, countless bugfixes, as well as project and documentation updates. See the repository for all the changes. A big thank you to all developers for your contributions! Change log highlights: @@ -26,6 +26,9 @@ Move CI from Travis/AppVeyor to GitHub Actions (#5261, #5273 #5371, #5377) Run TestSuite in CI (#5332) +section:: General: Fixed +Builds for older macOS systems (#5537) + section:: sclang: Changed Exclude default paths: change from command line parameter to language file flag (#3733) @@ -61,6 +64,7 @@ macOS builds include a custom build of libsndfile to support older macOS version section:: UGens: Fixed PanAz: initialize amps in Ctor (#4973) + EnvGen fixes (#5217, #4921, #4793) section:: IDE: Fixed diff --git a/HelpSource/Guides/UserFAQ.schelp b/HelpSource/Guides/UserFAQ.schelp new file mode 100644 index 00000000000..2b0e0bb05b6 --- /dev/null +++ b/HelpSource/Guides/UserFAQ.schelp @@ -0,0 +1,410 @@ +title:: User FAQ +summary:: Some FAQ and common errors +categories:: FAQ + + +anchor::ERROR Primitive BasicNew failed Index not an Integer:: + +SECTION:: ERROR: Primitive 'BasicNew' failed. Index not an Integer + +subsection:: If you're writing a SynthDef + +It's quite likely that the error means you're trying to dynamically change the number of channels inside a SynthDef, which is something you can't do - SynthDefs need to have a fixed layout. +For example, this is a simple attempt to make pink noise over a variable number of channels: + +code:: +( +SynthDef(\thiswillfail, { |out=0, numChannels=2| + Out.ar(out, {PinkNoise.ar}.dup(numChannels)) +}).add +) +:: + +It fails because we're trying to make the number of pink noise generators involved, actually changeable. +You can't do that - when the SynthDef is compiled, the language needs to know strong::exactly:: how many UGens will be involved and how they are connected. This is because a SynthDef represents an efficient fixed-layout synth that the server can instantiate. + +subsection:: So what to do instead? + +Think of SynthDefs as tiny fixed reusable components, and design your logic to reuse them in whatever combinations are needed. + +To go back to the simple example above (the pink noise generator), you could simply do: + +code:: +( +SynthDef(\simplepink, { |out=0| + Out.ar(out, PinkNoise.ar) +}).add +) +:: + +and create one code::\simplepink:: synth for each channel. Or you could create one SynthDef for each number of channels you expect to use. +For example if you might use between 1 and 5 channels: + +code:: +( +(1..5).do{ |n| +SynthDef("simplepink_%".format(n).asSymbol, { |out=0| + Out.ar(out, {PinkNoise.ar}.dup(n)) +}).add +} +) +:: + +Then you'd need to invoke code::\simplepink_4:: or whatever, as appropriate. + + +anchor::Language (client) Issues:: + +SECTION:: Language (client) issues + +subsection:: Calling gui primitives from a SystemClock routine + +When calling gui primitives from a SystemClock routine will cause an error: + +code:: +SystemClock.sched(0,{ Window.new.front }) +:: + +code:: +ERROR: Qt: You can not use this Qt functionality in the current thread. Try scheduling on AppClock instead. +ERROR: Primitive '_QWindow_AvailableGeometry' failed. +:: + +To avoid this issue use the AppClock: + +code:: +AppClock.sched(0,{ Window.new.front }) +:: + +or the defer method: + +code:: +SystemClock.sched(0,{ { Window.new.front }.defer }) +:: + + +subsection:: Binary operations order + +Because of the way SuperCollider evaluates expressions, the usual order of execution of mathematical expressions is not respected. +In SuperCollider everything is an object, and evaluation happens from left to right, so: + +code:: +5 + 3 * 2 +:: + +will evaluate as (5 + 3 ) * 2. + +This happens because the expression becomes: + +code:: +5.performBinaryOpOnSimpleNumber('+',3).performBinaryOpOnSimpleNumber('*',2) +:: + +Therefore, in algebraic expressions parenthesis must be used when left to right orders is not what is desired: + +code:: +5 + (3 * 2) +:: + + +anchor::SynthDef Issues:: + +SECTION:: SynthDef Issues + +subsection:: "If" statements inside a SynthDef + +It's only a matter of time before a user tries to write something like this in a code::SynthDef:: + +code:: +SynthDef(\kablooie, { |x = 0| + var signal; + if(x > 0) { + signal = SinOsc.ar + } { + signal = Saw.ar + }; +}); +:: + +... with the disturbing result: code::ERROR: Non Boolean in test.:: + +"Non Boolean in test"? But strong::x > 0:: is a comparison, and surely should produce a Boolean, right? + +This should be the first clue that Boolean logic in the server is a very different animal from the so-called "normal" use of conditionals on the client side (in the language). + +subsection:: What is a Boolean in the server? + +In fact, there is no such thing. The server handles floating-point numbers. It doesn't have strong::true:: or strong::false:: entities. + +Since everything in the server is a number, the result of the comparison must also be a number. The server follows the same convention as other DSP environments (Max/MSP, pd etc.): + +- code::True:: is represented by 1.0 +- code::False:: is represented by 0.0 + +subsection:: Why is x > 0 "non-Boolean" in the "test"? + +This goes back to the general issue of handling operators in the server. +Math operators in a SynthDef are not calculations to do strong::right now::. +They strong::describe:: calculations that will be done strong::in the future::, many thousands of times. + +code:: +var x = 1; +x > 0; +// -> true +:: + +code:: +SynthDef(\kablooie, { |x = 0| + "x: ".post; x.postln; + "(x > 0): ".post; (x > 0).postln; +}); +:: + +code:: +x: an OutputProxy +(x > 0): a BinaryOpUGen +:: + +The precise value of strong::x:: is unknown at the time you execute the SynthDef code. +strong::x:: actually represents an unlimited number of values, which will be provided to Synths using argument lists. So, it's meaningless to determine, once and for all, whether strong::x > 0:: or not. strong::x:: may be strong::> 0:: now and strong::< 1:: a split second later. So, instead of producing a Boolean, strong::x > 0:: produces a strong::Binary Operator UGen:: that repeatedly executes the comparison. + +Going back to this: + +code:: +if (aBinaryOpUGen) { ... } { ... }; +:: + +To do this, the language must know which function (true or false) to execute. But there is no way to know which one the BinaryOpUGen will be. +So, SuperCollider throws an error. + +subsection:: If you can't branch, what good is a comparison in the server? + +Comparisons have a lot of uses, actually. + +- strong::Choosing one of two signals::: This is the closest we can get to strong::if-then-else:: in the server. Both strong::then:: and strong::else:: must be running continuously. That's a requirement of how the server works: the number and arrangement of unit generators within a single Synth cannot change. Instead, you can choose strong::which of those signals makes it downstream::. One will be used and the other ignored. +Since true is 1 and false is 0, you can use a conditional to index into an array using Select. + +code:: +Select.kr(aKrSignal > anotherKrSignal, [false_signal, true_signal]); +:: + +- strong::Generating triggers::: A trigger occurs whenever a signal is <= 0, and then becomes > 0. Extending this to comparisons, it means that strong::a trigger occurs when a comparison is false for a while, and then becomes true::. Comparing a signal to a threshold may then be used anywhere that a trigger is valid. +For a simple example, take the case of sending a message to the language when the microphone input's amplitude crosses a threshold. + +code:: +var mic = In.ar(8, 1), amplitude = Amplitude.kr(mic); +SendTrig.kr(amplitude > 0.2, 0, amplitude); +:: + +- strong::Passing or suppressing triggers::: You might need to generate triggers continuously, but permit the triggers to take effect only when a condition is met. Multiplication handles this nicely: +strong::condition * trigger::. Since the condition evaluates as 0 when false, the trigger will be replaced by 0 and nothing happens, as desired. + +For a simple case, let's refine the mic amplitude example by suppressing triggers that occur within 1/4 second after the previous. + +code:: +var mic = In.ar(8, 1), + amplitude = Amplitude.kr(mic), + trig = amplitude > 0.2, + timer = Timer.kr(trig), // how long since the last trigger? + filteredTrig = (timer > 0.25) * trig; + +SendTrig.kr(filteredTrig, 0, amplitude); +:: + +subsection:: Logical operators: And, Or, Not, Xor + +Logical operators have simple arithmetic equivalents. + +- strong::And = multiplication::: strong::(x > 0) * (y > 0):: means both conditions must be true (nonzero) for the result to be nonzero. + +- strong::Or = addition::: strong::(x > 0) + (y > 0):: means nonzero in either condition is enough to make the result nonzero. + +NOTE:: +If both are true, then the result will be 2, not 1. In some cases, the 2 may not be acceptable. That can be fixed by wrapping the Or in another comparison -- strong::((x > 0) + (y > 0)) > 0:: -- because 2 > 0 evaluates to 1! +:: + +- strong::Not::: I prefer to negate a condition by comparing it to zero: +strong::condition <= 0::. 0 <= 0 is 1 (i.e., not 0), and 1 <= 0 is 0 (not 1). +If you're certain the logical expression will only ever be 0 or 1 exactly, you can also negate by subtraction: strong::1 - condition::. + +- strong::Xor::: Exclusive-or is true if one or the other condition is true, but not both. We can add the two conditions and compare it to 1. The syntax is a little bit tricky because code::==:: doesn't turn into a BinaryOpUGen automatically. +We have to create the BinaryOpUGen by hand. + +code:: +BinaryOpUGen('==', (x > 0) + (y > 0), 1) +:: + + +subsection:: ERROR: SynthDef not found + +Sending a SynthDef to the server requires a little bit of time, which means that running a block of code with both SynthDef definitions and instances of those SynthDefs won't be guaranteed to work unless this slight delay is accounted for. There are two main ways to do this: + +First way: put the SynthDefs and the main code in a Task and put some kind of code::.wait:: time between them. + +code:: +Task({ + // put your SynthDefs here + 0.2.wait; + // put the rest of your code here +}).play; +:: + +Second way: use code::.sync::: + +code:: +Routine({ + // put your SynthDefs here + s.sync; // assuming that 's' is the server + // put the rest of your code here +}).play +:: + +subsection:: FAILURE /s_new alloc failed, increase server's memory allocation + +strong::What it means::: While initializing the unit generators in a new Synth node, the server ran out of real-time memory. + +strong::Solution::: Increase the amount of real-time memory available to the server. This size is set, as the error message says, in the +code::ServerOptions:: object associated with the server. It is a server startup option; you must quit the server and reboot it, or the new +setting will not take effect. + +code:: +myServer.quit; +myServer.options.memSize = 65536; // e.g., could be different for you +myServer.boot; +:: + +code::myServer.options.memSize:: is given in KB. The default is 8192KB, or 8MB. + +strong::What it really means::: Many unit generators require internal memory buffers, such as delay lines, comb filters, allpass delays, some FFT manipulators, reverb units etc. +These internal buffers are not allocated directly from the operating system, but rather from a "real-time memory pool." +This is because direct allocation from the OS, by functions such as code::malloc()::, is not real-time safe. +The OS may take too long to return the new block, causing glitches in the audio. +To solve this problem, the server allocates a chunk of memory when it starts up and parcels it out to unit generators as needed. + +If you use a large number of delays, the server may run out of real-time memory. The default code::8192KB:: setting can support 47.55 seconds of delay at a sampling rate of 44.1 kHz. +This goes away quickly when using lots of synths with multiple channels of delay. + +strong::Alternate solution::: For delay units, you may use preallocated delay buffers -- code::Buffer.alloc():: -- and the "Buf" delay units: +code::BufDelayN::, code::BufDelayL::, code::BufDelayC::, code::BufCombL:: etc. +code::Buffer.alloc():: does not use the real-time pool and is not subject to the memSize limitation. This approach will not help with FFT units. + +subsection:: Array arguments + +Sometimes, you need to send an array to a series of Control inputs in a SynthDef (often called "_array arguments_"). + +code:: +Synth(\xyz, [freqs: [300, 400, 500]]); +:: + +There are two primary ways to do this: + +- Supply a literal array -- code::\#[1, 2, 3]:: -- as the default for the argument name in the function. +This is discussed in link::Classes/SynthDef::'s help file. + +code:: +SynthDef(\xyz, { |freqs = #[1, 2, 3]| + // ... +}) +:: + +- Or, use code::NamedControl::. +This is the only way to do it if you want to construct the array's size dynamically, or based on a variable. See link::Classes/NamedControl::. + +code:: +SynthDef(\xyz, { + var freqs = NamedControl.kr(\freqs, #[1, 2, 3]); + // ... +}); +:: + +subsection:: Why does it have to be a literal array? + +The reason comes from the process of building a SynthDef: + +1. First, look at the function arguments to figure out what the Control inputs should be. +2. Then create Control units (usually just one, if they're all normal arguments without prefixes or special rates). Each channel is represented by an code::OutputProxy::. +3. Then run the SynthDef function, passing the output proxies to the arguments. +4. Then sort the UGens into the right order, etc. etc. + +To do steps \#1 and \#2, the SynthDef builder has to know the size of an array argument strong::before:: running the function. That's possible only if it's a literal array: code::\#[1, 2, 3, 4, 5]::. Any other array notation creates the array strong::while running the function:: (step \#3). But then it's too late -- the SynthDef builder already created a non-array control channel for it! + +code:: +SynthDef(\notArray, { |a = (1..5)| + a.debug("a is"); +}); +:: +code::a is: an OutputProxy:: + +code:: +SynthDef(\array, { |a = #[1, 2, 3, 4, 5]| + a.debug("a is"); +}); +:: +code::a is: [ an OutputProxy, an OutputProxy, an OutputProxy, an OutputProxy, an OutputProxy ]:: + +(Note, if 'a' printed as [ 1, 2, 3, 4, 5 ], then you wouldn't be able to change the values in a Synth using code::.set::!) + + +anchor::Server Issues:: + +SECTION:: Server issues + +subsection:: How to trigger a function from the server + +The first and most important point: strong::Functions are client-side only::. +The server doesn't know what functions are, doesn't understand them and has no way to execute them. +strong::Only the client can execute a function::. + +Therefore, if you want a function to execute when something happens in the server, the only way is for the server to tell the client to take the action. + +The server can communicate messages back to the client using one of two unit generators: code::SendTrig:: and code::SendReply::. +code::SendTrig:: is simpler and less flexible (it can send only a code::/tr:: message, and only one data value). +code::SendReply:: allows you to name the message anything you like, and can send arrays with the message. +We'll use SendReply here because of its greater flexibility. + +Within the language, you also need an object to receive the message and act on it. Usually this is code::OSCFunc:: or code::OSCdef::. In this example, code::OSCdef:: filters messages not just on the name code::/bleep:: but also on the synth's ID. This way, you could have multiple triggering synths, with a different responder and a different action per synth. + +code:: +( +a = { + var trig = Dust.kr(8), + decay = Decay2.kr(trig, 0.01, 0.1), + sig = SinOsc.ar(TExpRand.kr(200, 600, trig), 0, 0.1) * decay; + SendReply.kr(trig, '/bleep', trig); + sig ! 2 +}.play; + +o = OSCdef(\bleepResponder, { |msg| + msg.postln; +}, '/bleep', s.addr, argTemplate: [a.nodeID]); +) + +a.free; o.remove; +:: + +subsection:: Helpfile references: + +- link::Classes/SendTrig::, link::Classes/SendReply:: + +- link::Classes/OSCresponderNode::, link::Classes/OSCpathResponder::, link::Classes/OSCresponder::, link::Guides/OSC_communication:: + + +subsection:: Error: failed to open UDP socket: address in use + +Sometime when booting the server one gets a message: code::Error: failed to open UDP socket: addess in use::. + +This is usually caused by an instance of scsynth that as hanged but has not released the osc port, perhaps because SuperCollider crashed. +You can use SuperCollider (sclang) to kill all running servers by running code::Server.killAll::. +You can also kill scsynth using a terminal or your operating system's task manager. + + +anchor::Other Issues:: + +SECTION:: Other issues + +subsection:: Error while loading shared libraries: libsclang.so: cannot open shared object file + +This usually happens after building on Linux and it means that your system is unaware of newly installed shared libraries. Running ldconfig +(as root) solves the problem: + +code::/sbin/ldconfig:: diff --git a/HelpSource/Help.schelp b/HelpSource/Help.schelp index 1a3b785e228..95f7fcd617e 100644 --- a/HelpSource/Help.schelp +++ b/HelpSource/Help.schelp @@ -19,9 +19,10 @@ These are useful starting points for getting help on SuperCollider: definitionlist:: ## link::Tutorials/Getting-Started/00-Getting-Started-With-SC##Getting Started tutorial series:: || Get started with SuperCollider ## link::Guides/Glossary:: || Glossary -## link::Guides/ClientVsServer:: || Explaining the client vs server architecture. +## link::Guides/ClientVsServer:: || Explaining the client vs server architecture ## link::Guides/More-On-Getting-Help:: || How to find more help -## link::Browse.html#Tutorials#All tutorials:: || Index of all help files categorized under "Tutorials." +## link::Browse.html#Tutorials#All tutorials:: || Index of all help files categorized under "Tutorials" +## link::Guides/UserFAQ:: || Common Errors and FAQ :: SECTION::Documentation indexes diff --git a/SCVersion.txt b/SCVersion.txt index 7cf796f71f2..d1f469963b8 100644 --- a/SCVersion.txt +++ b/SCVersion.txt @@ -3,7 +3,7 @@ set(SC_VERSION_MAJOR 3) set(SC_VERSION_MINOR 12) -set(SC_VERSION_PATCH 0) +set(SC_VERSION_PATCH 1) set(SC_VERSION_TWEAK "") set(SC_VERSION ${SC_VERSION_MAJOR}.${SC_VERSION_MINOR}.${SC_VERSION_PATCH}${SC_VERSION_TWEAK})