ossia / score

ossia score, an interactive sequencer for the intermedia arts
https://ossia.io
Other
1.48k stars 103 forks source link

[feature-request] permanent & pattern-matching mappings (of values) #347

Open pchdev opened 7 years ago

pchdev commented 7 years ago

two different questions/ideas on the mapping processes, based on the reflections we had about the websocket feature request (issue #312 )

should we implement a function that maps permanently a parameter to another one (potentially in a parallel device), and should we add some user-friendly pattern matching (c-switch or rust-like) function in order to do more precise and complex operations (i.e. midi note 64 triggers sample n°3 in another device).

I of course realize this is already possible with the javascript processes, but then again, it might be interesting to have a "non-coder" pattern matching available?

bltzr commented 7 years ago

could you give an (more elaborated) example ?

bltzr commented 7 years ago

why not doing this as a simple mapping in the main constraint ?

pchdev commented 7 years ago

okay, so question 1: I have a permanent mapping between 2 parameters that I don't want to draw manually with a mapping process that would have the length of the entire scenario, and I don't want it to be displayed either with an infinite trigger, because... it's not really visible and it occupies some unnecessary space.

as for the pattern matching: let's say I have a simple midi device, I want to precisely map (temporarily or permanently) the note received to a sample trigger in another device. That would be possible with a simple switch-case or pattern matching function like: match MidiDevice:/note_on 64 => { OSCDevice:/sample_trig 0 ;} 68 => { OSCDevice:/sample_trig 3 ; } 71 => { OSCDevice/sample_trig 21 ; } etc.

bltzr commented 7 years ago

well, there are indeed two separate problems in your issue: question 1 is mainly a problem of displaying stuff in the racks/slots, and it's currently already possible (even if cumbersome) to show/hide processes from the main process, so maybe it's just a question of making this better ?

about the pattern-matching, from what you describe I don't really see that as pattern-matching (even though pattern-matching could be useful in other cases...) but as a simple integer bijection that could be better expressed better in a two-column table than in a XY curve - in the case you mention that would be: src: MidiDevice:/note_on dst: OSCDevice:/sample_trig mapping: 64 0 68 3 71 21 does that make sense ?

pchdev commented 7 years ago

yes, something like that, but that was really an example, the integer translation was not the intended general case, but a syntax closer to the one proposed in other languages like rust, but even simpler: https://doc.rust-lang.org/book/patterns.html

bltzr commented 7 years ago

well, which part of this (looooong) page would apply ? or maybe, even better, what would you like in i-score, more specifically ? (take the time to cross situations and examples, nothing urges...)

pchdev commented 7 years ago

At first, I think the simple, multiple & destructuring parts would be relevant:

the simple one applied to the previous midi example

the multiple would be: src: MidiDevice:/note_on dst: OSCDevice:/sample_trig mapping 64 | 68 | 71 => 0 64 && 65 && 66 => 1 _ => 3

and destructuring for arrays / dataspaces involving multiple values

color{0.5,0.5,0.4} => sample_trigger 0 color{1.0,1.0,1.0} => sample_trigger 47 even maybe color{1.0,0.8,?} => sample_trigger 45 the "?" being a wildcard or something like that.

etc.

bltzr commented 7 years ago

that's interesting, thanks! we should see how we can generalize this... maybe, for now, managing this with js could be a good start... and when this becomes generic enough, we could think about creating a process doing this (and potentially more...)

jcelerier commented 7 years ago

yeah, I think the simplest would be to just allow to code it. Maybe with a library such as this one ? https://github.com/natefaubion/sparkler (for now the only way to use it would be to copy paste everything, I should look into some kind of js package import...)

@bltzr an introduction to pattern matching: http://caml.inria.fr/pub/docs/oreilly-book/html/book-ora016.html

pchdev commented 7 years ago

cool ! didn't know about sparkler

jcelerier commented 7 years ago

@pchdev what would you think of having a panel where you could declare "global" javascript functions / libraries that would be shared by all the instances of the javascript process in the score ?

Also currently all the JS processes live in their own context (e.g. setting a global variable in one would not affect the others). Should it stay like this or would you be interested in sharing them ? e.g. process A and B use JS context 1, process C and D use JS context 2. Both approaches could be possible : shared and not shared.

pchdev commented 7 years ago

oww, interesting! I'd say a big yes on principle

bltzr commented 7 years ago

what about this one ? is this related in any way to (or could be managed with) QML ?

jcelerier commented 7 years ago

it needs some design. ideally, we talked with @blueyeti a long time ago about being able to handle a whole "vertical" point (e.g. trigger, time node, events, conditions, states... the whole stuff) entirely through the behaviour of a single script, but it's a big model change which would take a lot of work.

A relatively easy way today to do this is to just use a JS state. Maybe someone could think of the potential syntax a QML object would have to be able to handle this ?

e.g.

{
    Ossia.Mapping {
        match: "MidiDevice:/note_on"
        with: [ 
                   [ 64, "OSCDevice:/sample_trig 0" ], 
                   [ 36, "OSCDevice:/sample_trig 1" ] 
        ]
    }
}

This would not be as good as a dedicated language but more easily achievable.

pchdev commented 7 years ago

having a dedicated process/language would be great indeed, but meanwhile this looks perfectly good to me!

bltzr commented 7 years ago

as I don't understand most of what you're talking about, guys, and even less how complicated this is to implement, I'll let you set the milestone you find appropriate

jcelerier commented 5 years ago

https://github.com/OSSIA/score-user-library/blob/master/Devices/Mapper/Mapper.qml should be useful for this !

thibaudk commented 4 years ago

Attempting to create a permanent mapping betwen 2 parameters in 2 different devices, i tried this piece of QML

import QtQuick 2.0
import Ossia 1.0 as Ossia

Ossia.Mapper
{
    function createTree() {
        return [
                {
                    name: "Pipe",
                    type: Ossia.Type.Int,
                    bind: "java:/aleas/channel0/start",
                    read: function(orig, v) { return [ { address: "foo:/bar", value : v.value } ];}
                }
        ];
    }
}

But it dosen't work.

A few crashes occurs with this message

pure virtual method called
terminate called without an active exception
Abandon (core dumped)

and this warning keeps showing up

Warning: QObject: Cannot create children for a parent that is in a different thread.
(Parent is ossia::net::mapper_protocol(0x66305f0), parent's thread is QThread(0x6630648), current thread is QThread(0x35a21c0) (:0)

Refreshing the namespace returns

Debug: Updating invalid node (:0)

I also had a few actual errors involving "mutex" but I can't reproduce them now. Thoes tend to crop up fairly arbitraryly