• myQwil

    @alfonso.santimone Sorry it took so long. I finally got around to making win64 builds of my externals. They're all up on my Github page but here's gme(s)~ for the sake of convenience:


    posted in extra~ read more
  • myQwil

    @deframmentazione-geometrica It looks like your select box is trying to prevent repeat values from getting through, so when random outputs the same value as it did previously, select will keep telling random to produce another value until it's different, then it'll assign that to the single number box on the right. The two number boxes at the bottom will retain the duplicate value and continue to reassign the value to each other until it's caught by the stack overflow error.

    Then again, how everything plays out will depend on whether you create the select box before or after creating the looped number boxes at the bottom, because that'll determine what gets triggered first. If you create the select box last, then the number boxes at the bottom will change and it may never even get to the number box on the right.

    posted in technical issues read more
  • myQwil

    MSYS2 is the new standard last time I checked. You can follow along with the purr data build guide to guarantee the right dependencies get installed. You only need to go as far as step 4, and you can also skip the inno setup if you're just building externals.


    I went ahead and built plaits for 32-bit pure data. Hopefully that works for you.


    When building it, I needed to change one thing in the Makefile. See that line where it says:

    cflags = -DTEST -Wno-unused-local-typedefs -I./

    That doesn't work. -I./ needs to be changed to the absolute path that your plaits project happens to be in. For example, mine looked like this:

    cflags = -DTEST -Wno-unused-local-typedefs -I/c/Users/myQwil/Desktop/pd-plaits-master

    posted in extra~ read more
  • myQwil

    @seb-harmonik.ar No, I'm not the creator of the gme library. There's a lot about its behaviour that I don't fully comprehend at this point. One of the first issues I came across was the instant fade. Another was that it would come to a full stop after maybe 2 repetitions or so. I've tried preventing these issues by changing the original code in as minimal a way as possible but there are probably further changes that could make it run more smoothly in pd. Again, the only reason I added that ifndef clause is because it's what worked for me personally. I wanted it to behave the same way across multiple platforms in such a way that it repeated the song forever, leaving the stopping of the track up to the patch itself.

    In gme.zip you should see the folder gme-diff. It contains whatever changes I made to the original code. If you're building your own version of gme, you'll need to incorporate those changes to see where I'm coming from. Either way, it's worth knowing that it behaves differently on your end. What OS are you using, by the way?

    posted in extra~ read more
  • myQwil

    @seb-harmonik.ar That was there because that same issue would happen to me, but under different circumstances depending on if I was using linux or windows. I believe I was using ubuntu studio 64-bit.

    posted in extra~ read more
  • myQwil

    Hi @alfonso-santimone, at this point, none of my externals are built for win64, but I'll look into making those builds

    posted in extra~ read more
  • myQwil

    I've noticed that pd-vanilla and purr-data currently handle pointers differently, making the is.pd object work in pd-vanilla, but not purr-data. I've created another pd-native variation of the external [is] that works in both purr-data and pd-vanilla.

    While the route object in pd-vanilla can detect pointers as a type of symbol, in purr-data, a pointer is detected as a list by the symbol object, but not detected as a list by the route object. So if an atom passing through [route list] gets sent to the rejection outlet, then later reveals to have a string value of "list" when sent to a [symbol] object, we can assume that that atom is a pointer.


    posted in extra~ read more
  • myQwil

    You can also debug with VSCode, which is something I recently just tried out for the first time. You'd need to install the VSCode extension C/C++, then you'd build pd-vanilla based on the instructions given on pd's website and the INSTALL.txt file, and using the --enable-debug option.

    Then open the pure-data folder in VSCode, either by navigating to that folder in a terminal and typing code . or by right-clicking the folder and selecting "Open With->VSCode"

    Then in VSCode, you switch to the debug pane and from a drop-down at the top of the pane, click "Add Configuration" and after selecting a config preset, a file called launch.json will pop up. You'll need to specify where the binary is. In my case, the location was:
    "program": "/home/myqwil/Documents/pure-data/bin/pd",

    Then lastly, and maybe there's a better way of doing this last part but the quick and easy way is just to inject your external into some part of pd's code, change the setup function so that it's static, and make sure the setup function gets called at some point, usually the setup calls are kept inside of one function at the very end of a .c file. Then it's just a matter of adding your breakpoints and re-building pd when changes are made.

    posted in technical issues read more
  • myQwil

    Works very much the same as trigger except that when you use 'a' for creation arguments, lists that consist of only 1 atom will output as the atom itself and not as a list. This also includes pointers. You'll notice that with trigger, a pointer will output as a list, which makes it difficult to type-check.

    The [unpak] object had a similar problem where it would output lists instead of raw atom values, and that has also been changed with unpak's latest update.

    EDIT: I've made it so that floats default to anything outlets and no creation args defaults to 2 anything outlets.


    posted in extra~ read more
  • myQwil

    Similar to [pack ] and [unpack ] but instead of the default atom type being a float, the default type is anything.

    Also comes with a new creation arg 'a' for anything. Numbers and unrecognized types will also default to anything.

    For strict type checking, use f(loat), s(ymbol), and p(ointer).
    The pak object will also store unrecognized types as symbols and interpret 'b' as a 'bang' symbol.

    EDIT: You can now send lists to any of the additional pak inlets and it will store the list values with the inlet as the starting point. For example, sending the message [foo bar 3 baz( to the 2nd inlet of [pak 1 2 3 4] would result in the list: 1 foo bar 3

    EDIT2: pak still has a bug when setting a pointer from any inlet other than the first one. This became more apparent when trying to work with the object in pd-vanilla.

    EDIT3: pak is much more stable now and works in pd-vanilla. The example includes a new object I've created called [x ], which is a kind of trigger object that dehusks lists that consist of only 1 element when you use 'a' for creation args. For pd-vanilla users, the example also requires zexy's [demux].

    EDIT4: You can now use "." to skip inlets and assign only specific ones.
    For example, sending the message [. . 123( would assign 123 to the 3rd inlet and leave the first two values the same as they were. You can also send these messages to any inlet.

    EDIT5: I made it so that the skip arg feature only applies to list and anything type messages, so if you really want to, you can still assign a single period to an inlet by sending it as a symbol. I also needed to make it so the skip arg feature also works on strict-type inlets.
    It's also worth mentioning that the proxy inlets now have their own pointer, float, symbol, and list functions, rather than an anything function that handles all message types by running string comparisons, so it should be a bit faster if only slightly, and overall better coding practice for a pure data external.

    EDIT6: The skip arg feature was only added to pak so I added the same feature to unpak as well. Using a period as an arg will skip the outlet and not send any value through it.

    EDIT7: fixed one more bug in pak, where the first inlet could only receive raw pointers and every other inlet could only receive pointers in lists. I also changed unpak so that when a stored symbol is "bang", it will output as an actual bang message rather than as a bang symbol.
    Added two more objects [@pak] / [@unpak] - reverse pak/unpak. Outputs the lists in reverse order.

    EDIT8: I've changed the pack related objects so that strict-type error messages are muted by default and to unmute them, you need to send [mute 0( to the 1st inlet. The number sent to mute acts as a bit mask for the inlets, so when a bit is turned on, the associated inlet will not output error messages.


    posted in extra~ read more
  • myQwil

    @ingox I recently made a slight change to how the c external works and went ahead and made the same change to your pd external. I just needed to include the rejection outlet of the left route object. is.pd

    posted in extra~ read more
  • myQwil

    Neat! I've used route with custom messages, but it didn't occur to me that it could also be used as a type checker.

    posted in extra~ read more
  • myQwil

    Returns a boolean 1 or 0 if the value sent to the 1st inlet matches the type specified in the creation arg or 2nd inlet.

    You can set the type to be matched against either as a creation argument or with the message [type $1(, or by sending to the 2nd inlet either the type name or an example of the atom whose type you want matched against.

    EDIT: the "type" method needed a bug fix. The help file has also been slightly altered:

    EDIT2: Now the type can be virtually anything, rather than one of 5 possible types. This allows us to check for specific messages. For example, sending the message [foo 1 2 3( to the object [is foo] will return true.

    EDIT3: Defaults to float if no creation argument given. Also added a pointer example to the help file.

    EDIT4: A memory-freeing method was necessary to clear the proxy inlet.


    posted in extra~ read more
  • myQwil

    Allows you to play various game music formats, including:

    AY - ZX Spectrum/Amstrad CPC
    GBS - Nintendo Game Boy
    GYM - Sega Genesis/Mega Drive
    HES - NEC TurboGrafx-16/PC Engine
    KSS - MSX Home Computer/other Z80 systems (doesn't support FM sound)
    NSF/NSFE - Nintendo NES/Famicom (with VRC 6, Namco 106, and FME-7 sound)
    SAP - Atari systems using POKEY sound chip
    SPC - Super Nintendo/Super Famicom
    VGM/VGZ - Sega Master System/Mark III, Sega Genesis/Mega Drive,BBC Micro

    The externals use the game-music-emu library, which can be found here: https://bitbucket.org/mpyne/game-music-emu/wiki/Home

    [gme~] has 2 outlets for left and right audio channels, while [gmes~] is a multi-channel variant that has 16 outlets for 8 voices, times 2 for stereo.
    [gmes~] only works for certain emulator types that have implemented a special class called Classic_Emu. These types include AY, GBS, HES, KSS, NSF, SAP, and sometimes VGM. You can try loading other formats into [gmes~] but most likely all you'll get is a very sped-up version of the song and the voices will not be separated into their individual channels. Under Linux, [gmes~] doesn't appear to work even for those file types.
    Luckily, there's a workaround which involves creating multiple instances of [gme~] and dedicating each one to a specific voice/channel. I've included an example of how that works in the zip file.


    • [ info ( - Post game and song info, and track number in the case of multi-track formats
      • this currently does not include .rsn files, though I plan to make that possible in the future. Since .rsn is essentially a .rar file, you'll need to first extract the .spc's and open them individually.
    • [ path ( - Post the file's full path
    • [ read $1 ( - Reads the path of a file
      • To get gme~ to play music, start by reading in a file, then send either a bang or a number indicating a specific track.
    • [ goto $1 ( - Seeks to a time in the track in milliseconds
      • Still very buggy. It works well for some formats and not so well for others. My guess is it has something to do with emulators that implement Classic_Emu.
    • [ tempo $1 ( - Sets the tempo
      • 0.5 is half speed, while 2 is double. It caps at 4, though I might eventually remove or increase the cap if it's safe to do so.
    • [ track $1 ( - Sets the track without playing it
      • sending a float to gme~ will cause that track number to start playing if a file has been loaded.
    • [ mute $1 ... ( - Mutes the channels specified.
      • can be either one value or a list of values.
    • [ solo $1 ... ( - Mutes all channels except the ones specified.
      • it toggles between solo and unmute-all if it's the same channel(s) being solo'd.
    • [ mask ($1) ( - Sets the muting mask directly, or posts its current state if no argument is given.
      • muting actually works by reading an integer and interpreting each bit as an on/off switch for a channel.
      • -1 mutes all channels, 0 unmutes all channels, 5 would mute the 1st and 3nd channels since 5 in binary is 0101.
    • [ stop ( - Stops playback.
      • start playback again by sending a bang or "play" message, or a float value
    • [ play | bang ( - Starts playback or pauses/unpauses when playback has already started, or restarts playback if it has been stopped.
      • "play" is just an alias for bang in the event that it needs to be interpreted as its own unique message.

    Creation args

    Both externals optionally take a list of numbers, indicating the channels that should be played, while the rest get muted. If there are no creation arguments, all channels will play normally.

    Note: included in the zip are libgme.* files. These files, depending on which OS you're running, might need to accompany the externals. In the case of Windows, libgme.dll almost definitely needs to accompany gme(s)~.dll
    Also, gme can read m3u's, but not directly. When you read a file like .nsf, gme will look for a file that has the exact same name but with the extension m3u, then use that file to determine track names and in which order the tracks are to be played.


    posted in extra~ read more
  • myQwil

    This is a spiritual successor to amPd. It's much more stable and has many more features than amPd:

    • reads/writes metadata to/from patches. This is done by storing the info in the form of comments, in a canvas called [pd meta] or [pd info]. If no such canvas exists, foobar will add it in the top left-hand corner of your patch.

    • comes with a Win32 Dialog UI element, containing sliders, toggles, buttons, and edit-text/button combos to send messages to your patch.

      • foobar looks in your patch for a canvas called [pd mix] and uses the parameters of whatever sliders, bang objects, or toggles it finds there to give your UI controls similar functionality.

    How playback works

    • libpd sends a 1 to vol, then a bang to play.
      • Generally this is where, in your patch, you have an [r play] hooked up to your metro, and an [r vol] connected to a [*~ ] before your output reaches [dac~].
    • the length of the song is arbitrarily set by the user.
      • This affects the trackbar's cursor visibility and ability to set a position.
      • If the length is 0, there will be no trackbar cursor. Otherwise, the cursor, when moved, will send its position in seconds to pos. From there, it's up to your patch to take that information from [r pos] and work it into song events.
    • The patch will not actually stop and move on to the next track until libpd receives a bang from [s stop].

    How the mixer works

    • all mixer controls go inside of [pd mix]
    • horizontal and vertical sliders are turned into slider controls in the UI element
      • labels assigned to sliders in the patch become labels for the UI element's slider controls. The same applies for send symbols.
      • min and max values of sliders on the UI element work in integers only, so if you want a gradual shift from, say, 0 to 1, write "gradient" in the slider's receive symbol, and the slider's range will be broken down into roughly 200+ individual steps.
      • there are currently 7 sliders in the UI element
    • bang objects with no label become simple buttons in the UI
      • their send symbols will be reflected in the button's name and they will send a bang when clicked.
      • there are currently 3 buttons
    • bang objects with a label assigned become message buttons
      • these have an edit text field associated with them, where you can type out any message you want and send it to the destination.
      • the bang's label is placed inside of the edit text field as a suggested message to send.
        • pure data strips commas out of labels, so I'm using apostrophes to denote where commas should go. ex: do this' then this
      • there are currently 2 message buttons, with the 'any' button being a potential 3rd.
    • a bang object with a label written in the format dest : msg will be assigned to the 'any' button.
      • the 'any' button has an editable destination field, giving you access to basically any receive symbol in your patch.
      • also substitutes as a third normal message button, when the other two are already in use
    • toggles become checkboxes
      • each checkbox can have a label and send symbol assigned to it
      • there are currently 4 checkboxes
    • right-clicking a track shows the context menu entry Pd Player -> Load mixer.
      • basically, you can load mixers of tracks not currently playing for some potentially interesting exchanges between patches. After loading the mixer, you still need to hit the Refresh button to show the changes.

    foo_pd's copy of libpd.dll contains only the externals that I needed to run the example patches. If you want your own patches to work with foo_pd, you might need to make another build using MSYS2. If you're not sure which objects aren't instantiating, foobar's console prints all of pd's messages while audio is being processed. I'll also add more externals over time.

    I'll be maintaining foo_pd at https://github.com/myQwil/foo_pd where you can also find the latest builds


    posted in libpd / webpd read more
  • myQwil

    Cool object. This is a late response but I was checking out your code and wound up making a bunch of changes to it to address 3 bugs I found:

    • 1 - [n! ] doesn't instantiate on its own. it needs a prior instantiation of [factorial] to load. Normally to fix that, what you'd do is make a copy of the binary and rename it to n!.pd_darwin, but there still needs to be a setup function with the object's name in it, or a function that's just called "setup", which you should probably try to avoid just because it's not very self-documenting.
    • 2 - It doesn't successfully find the help file. Pd automatically adds "-help" or "-help.pd" on its own. It also automatically creates a help file reference. The sethelpsymbol function is pretty much only good for when you have multiple objects of different classes that need to refer to a common help file.
    • 3 - It freezes and sometimes crashes pd if it's fed a really big number, because it'll start looping endlessly..


    posted in extra~ read more
  • myQwil

    Hot Binops
    Performs binop arithmetic with 2 hot (active) inlets, which means that the usage of either inlet will trigger an output. Some of the objects require the hexloader library to load properly.

    The naming convention is a # symbol, followed by the expression.
    examples: [#+ ] [#- ] [#== ] [#!= ] [#&& ] [#|| ] etc.

    The collection is based on the binop objects found in x_arithmetic.c. This includes:
    binops 1: +, -, *, /, pow, max, min
    binops 2: ==, !=, >, <, >=, <=
    binops 3: &, |, &&, ||, <<, >>, %, mod, div

    Reverse Binops
    Performs binop arithmetic with the inlets having switched roles. Some objects require the hexloader library.

    The naming convention is an @ symbol, followed by the expression.
    examples: [@- ] [@/ ] [@pow ] [@<< ] etc.

    The collection consists of binop objects where the swapping of inlets would have a noticeable difference in results. These include:
    -, /, pow, <<, >>, %, mod, div

    Bitwise Arithmetic
    Consists of two bitwise objects to perform bitwise negation [!~ ] and XOR ([^ ] and [#^ ]). Bitwise negation has another alias of [~ ] but it will not load unless [!~ ] is loaded first, or if the object is placed in pd/extra/!~ and "!~" is added to your list of libraries.


    posted in extra~ read more
  • myQwil

    Based on a patch I made a few years ago, which I then tidied up and implemented externals I hadn't yet made at the time, then tweaked some stuff around to give it a new sound, which reminds me a bit of silent hill music.


    posted in patch~ read more
  • myQwil

    splits and joins the sign, exponent, and mantissa of a float

    accepts bangs and floats
    accepts 1 creation argument for assigning the stored value
    has 1 extra inlet for assigning the stored value
    outputs the sign, exponent, and mantissa of the stored float

    accepts bangs and floats (mantissa is assigned the float)
    accepts 3 creation arguments for assigning the mantissa, exponent, and sign
    has 3 extra inlets for assigning these values
    outputs a float by combining these values together

    help file included


    posted in extra~ read more
  • myQwil

    A number base converter that accepts 1 creation argument to specify which number base to convert to. If nothing is specified, or the number is out of range (1-64), it defaults to 16. The converted number is sent in the form of a symbol type. Much of the code is based on the musl library's vfprintf function.

    The symbol array is as follows:


    Some letters were taken out for looking too similar to numbers or other letters.


    posted in extra~ read more
Internal error.

Oops! Looks like something went wrong!