I don't see the point of doing option A if there is concensus that
option B will eventually supercede it. So I propose doing option B in
two parts.
Basically start with what is on the wiki right now. Calling the
script library midi-mapping-scripts.js or something descriptive (.js
so editors do highlighting correctly).
Put all functions for all controllers in that file (initially there
shouldn't be much there).
In phase 2 implement an optional script block within each controller
xml file (change option type to script-binding) and fetch script from
there and the midi-mapping-scripts.js. Apart from the paranoia I
share with Albert about scripts living inside XML getting mangled and
so on, there are other wrinkles to consider like namespace of
functions across controllers (someday we'll probably want to support
multiple controller set-ups), and no doubt other things...
I'll see if I can find some time to update the proposal tonight or
tomorrow. Until I get around to it please continue to chatter / feed
me ideas I can play off.
-G
On 11/25/08, Albert Santoni <[EMAIL PROTECTED]> wrote:
> Hi guys,
>
> To keep things moving along:
>
> RJ and Robin have raised some interesting issues with the proposed
> design, but in the worst/laziest case, most of these points don't seem
> to be huge flaws (if I understand them correctly).
>
> However, it would be good to address the point RJ raised earlier about
> deciding where the "library" of QtScript will be stored. I'd like to
> propose the two following options:
>
> Option A)
> * We have a generic "common.script" file sitting in the midi
> directory, which is loaded no matter what controller you're using.
> * For each MIDI mapping of the name "blah.midi.xml", we attempt to
> load a "blah.midi.script" file, which will contain the QtScript
> functions that are specific to that "blah" controller.
>
> Option B)
> * We have some <script>your QtScript here</script> block inside the
> top-level <controller> tags in the .midi.xml file (ie. what RJ
> proposed).
> * (Lemma) We still have the generic "common.script" so we can share
> code between script files.
>
> I'm personally inclined to go with Option A for two (weak) reasons.
> The first is because of our terrible experiences with XML parsing in
> the library (try creating a file called <track>.mp3 and see what
> happens), and the second being fear of the unknown - I just don't know
> what having the QtScript embedded in that file would do for the flow
> of the program. Where is the MIDI XML file parsed? Is it going to be
> sane from an OO design point of view to get it from our MIDI XML
> parser into the Midi script engine (or whatever)?
>
> I will admit these are crappy reasons to favour Option A, especially
> when (as RJ pointed out) it'll probably end up being a bigger pain in
> the ass to have separate .script for each controller. Someone who's
> more knowledgeable on this stuff (and knows how to code it) needs to
> make a decision here (ASAP), because I'm not familiar enough with the
> MIDI code.
>
> Lastly, keep in mind our design might not turn out to work as well in
> the real world as we hope, so take the proposed design to be an
> exploratory first attempt. Let's get working on this scriptable MIDI
> stuff as soon as we can, and we'll deal with issues as they come up.
>
> Thanks,
> Albert
>
>
>
> On 24-Nov-08, at 1:31 AM, Adam Davison wrote:
>
>> Hi,
>>
>> I was actually thinking, although I haven't had time to properly
>> comment on the design. Of having some kind of function registry on the
>> C++ side that allows you to mix and match C++ code and script code,
>> the idea being that there are sort of 3 levels your
>> action/option/function progresses through:
>>
>> 1. Your controller doesn't work with Mixxx so you write a custom
>> handler in your own file
>> 2. Other people have similar issues so we move it to a common file
>> somewhere
>> 3. We port it to C++ and compile it in
>>
>> My guess being that not invoking the interpreter is probably a good
>> thing where possible, especially for slower systems.
>>
>> Adam
>>
>> 2008/11/24 Russell Ryan <[EMAIL PROTECTED]>:
>>>
>>>
>>>
>>>
>>> Garth Dahlstrom wrote:
>>>>
>>>> The idea of having the script embedded in the XML does appeal to
>>>> me for
>>>> the aspects of making distribution simpler. I think it *might*
>>>> make the
>>>> job of maintaining the XML file programatically more difficult,
>>>> but I'm not
>>>> really sure nor am I sure it would make it that much more
>>>> difficult that it
>>>> wouldn't be worth it.
>>>>
>>>> I guess the thing to consider with respect to the "MIDI Learning"
>>>> code is
>>>> only scoped to map a controller signal to some function, you will
>>>> not be
>>>> able to teach Mixxx what to do through with that signal (it is not
>>>> some
>>>> fancy macro recording language or anything like that). So, no
>>>> matter how
>>>> you do the "MIDI Learning", you are still going to have to go in
>>>> by hand and
>>>> edit some QtScript to enhance behaviours beyond the currently
>>>> compiled-in
>>>> functions. Ah shit, I wish his branch was merged already... then
>>>> people
>>>> could just see how it works and where it ends.
>>>>
>>>
>>> Right ... a general purpose "Do What the User Means" feature is
>>> impossible
>>> :).
>>>
>>> One issue with the current proposal is that the name of the
>>> javascript to
>>> call is embedded in the <key> child of the <control> group. If a
>>> MIDI-Learn
>>> is to present different options for what <key> should be, then it
>>> will have
>>> to introspect all the methods of QtScript "HerculesMk2" object and
>>> decide
>>> which ones are appropriate to present as options to the user. This
>>> seems
>>> like it will be difficult. Perhaps a simple and easy way to get
>>> around that
>>> is to represent hooks into the QtScript by an 'action', like this:
>>>
>>> Separate a device's mappings into 'actions' you can perform,
>>> scripts which
>>> are called by those actions, and controls that map to those
>>> actions, then
>>> the sole job of MIDI-Learn would be to modify the MIDI Note/Control
>>> ->
>>> Action mapping, which is simple XML munging. Having a list of
>>> conceptual
>>> actions for a controller allows you to present the actions to a
>>> user with
>>> human readable names for the action.
>>>
>>> An example:
>>>
>>> <controller name="Hercules MK2" version="1.0">
>>> <script>
>>> HerculesMk2.deck1_fx_cue_loop_mode = function(msg) { ... };
>>> HerculesMk2.deck1_playpause = function(msg) { ... };
>>> HerculesMk2.deck1_stop = function(msg) { ... };
>>> HerculesMk2.deck1_reverse = function(msg) { ... };
>>> </script>
>>>
>>> <action id="deck1_fx_cue_loop_mode" name="Deck 1: Toggle Fx/Cue/
>>> Loop Mode">
>>> <script>HerculesMk2.deck1_fx_cue_loop_mode(this);</script>
>>> </action>
>>>
>>>
>>> <control>
>>> <miditype>Ctrl</miditype>
>>> <midino>0x07</miditype>
>>> <action>deck1_fx_cue_loop_mode</action>
>>> </control>
>>> </controller>
>>>
>>> (Please ignore any inconsistencies in the example .. I'm just
>>> trying to show
>>> the separation I'm talking about)
>>>
>>> (A note about the <script> tag inside of <action>. My idea was that
>>> this
>>> snippet is executed with 'this' bound to the msg that the handlers
>>> are
>>> supposed to take in the example)
>>>
>>> So then the only thing the GUI has to do is say
>>> 1) (listening for midi input) Hit a button on your MIDI console.
>>> (user hits
>>> a button)
>>> 2) You hit Ctrl:0x07 ... please select an action to map this button
>>> to:
>>> (shows list of all action nodes by their human-readable 'name'
>>> attribute).
>>> 3) (user selects an action)
>>> 4) Write the selected action as the new <action> child of the
>>> <control>
>>> corresponding to Ctrl:0x07.
>>>
>>> I've never used QtScript before so maybe it's much more powerful at
>>> introspection than I'm imagining, but my guess is this would make
>>> things a
>>> lot easier.
>>>
>>> Does this make sense?
>>> RJ
>>>
>>>> So having script embedded in the XML means that humans and
>>>> machines will
>>>> both be editing the same file. Maybe that isn't a problem
>>>> though. Maybe
>>>> we should do it this way...
>>>>
>>>>
>>>> On Mon, Nov 24, 2008 at 12:20 AM, Russell Ryan <[EMAIL PROTECTED]
>>>> <mailto:[EMAIL PROTECTED]>> wrote:
>>>>
>>>>
>>>> I have a few comments and questions on this this spec draft:
>>>>
>>>> http://mixxx.org/wiki/doku.php/midi#midi_extension_proposal_2008-11-23_draft
>>>>
>>>> 1) Where is the 'library' of QtScript stored? Is it one giant
>>>> library
>>>> for all controllers, or is it a script file per device?
>>>>
>>>> Would it be more simple to have the script for a device stored
>>>> inside
>>>> the same XML file for the device?
>>>>
>>>> i.e.
>>>>
>>>> <controller>
>>>> <script>
>>>> ... QTScript definitions for controller ...
>>>> </script>
>>>> <control>
>>>> <group>[Channel1]</group>
>>>> ...
>>>> </control>
>>>> <control>
>>>> ...
>>>> </control>
>>>> ... etc ...
>>>> </controller>
>>>>
>>>>
>>>> That way, the entire controller definition is self contained and
>>>> much
>>>> easier to understand because everything is in one place.
>>>>
>>>> Imagine the use case of a new controller definition that isn't
>>>> included
>>>> in the release yet.
>>>>
>>>> If someone posted it to the forums, then they would have to
>>>> include an
>>>> updated version of the library that had the relevant script.
>>>> (and if
>>>> someone had customized their library or added other definitions,
>>>> then
>>>> they would have to hand merge the two libraries, yuck!).
>>>>
>>>> If there are two files for one device (one script, one xml),
>>>> then the
>>>> mapping author has to post two files, and you have to make sure
>>>> two
>>>> files make it into your Mixxx distribution. One file just makes
>>>> things
>>>> much easier / simpler.
>>>>
>>>> 2) Hopefully Tom's MIDI rewrite/rework and this work that is
>>>> going on
>>>> will last Mixxx far into the future in terms of the hardware of
>>>> tomorrow. I think that allowing scripting like this is a safe and
>>>> extensible way to add lots of flexibility.
>>>>
>>>> A good example of the 'hardware of tomorrow' is the JazzMutant
>>>> Lemur :
>>>> http://www.jazzmutant.com/lemur_overview.php
>>>> Basically, what is the next new thing and how can we future proof
>>>> against it?
>>>>
>>>> 3)
>>>> My only worry for MIDI-Learn is something like this:
>>>>
>>>> My FooBaz controller already does X in mode A, Y in mode B, and
>>>> Z in
>>>> mode C. I want to change what it does in mode C only. How are we
>>>> going
>>>> to support something like that? That isn't a terribly unreasonable
>>>> thing
>>>> to want. Especially in the case of a single turntable control
>>>> surface
>>>> which has a button to switch from being turntable 1 to turntable
>>>> 2, so
>>>> the entire device is mode-based.
>>>>
>>>>
>>>> That's all! Good job everybody it's really exciting to see all
>>>> of the
>>>> great things on the road ahead.
>>>>
>>>> Cheers,
>>>> RJ
>>>>
>>>> Adam Davison wrote:
>>>>> Hi,
>>>>>
>>>>> I think I was one of the original people criticising the idea of
>>>>> making the parsing of the XML more dynamic. My reasoning for
>>>> this was
>>>>> that you're basically about to go and implement an interpreter and
>>>>> every time we need an additional feature, the interpreter gets more
>>>>> complicated, until you have basically a programming language. At
>>>> that
>>>>> point we've spent all this time where we could have used an
>>>>> existing
>>>>> language and we probably also didn't design our interpreter as
>>>> well as
>>>>> the ones that already exist either.
>>>>>
>>>>> Try to think of this design as an extension of the existing options
>>>>> block. Where currently you're choosing from a list of builtin
>>>>> functions, here you would be choosing from some combination of
>>>> builtin
>>>>> functions and script you wrote yourself.
>>>>>
>>>>> This is a very simple extension of the current midi mapping scheme,
>>>>> allows for a lot of new behaviour but without too much work to be
>>>>> done.
>>>>>
>>>>> Obviously this doesn't have to be the end of it but I'm not sure
>>>> that
>>>>> any of us really has a complete understanding of how the final
>>>>> solution to this problem should look. So it's a good stepping
>>>> stone to
>>>>> seeing how a really good API for MIDI mapping might look. And
>>>> for now
>>>>> you can theoretically stuff basically infinite complexity down it's
>>>>> throat too, pretty or otherwise.
>>>>>
>>>>> Adam
>>>>>
>>>>> 2008/11/23 Robin Sheat <[EMAIL PROTECTED]
>>>> <mailto:[EMAIL PROTECTED]>>:
>>>>>
>>>>>> On Monday 24 November 2008 06:57:25 Garth Dahlstrom wrote:
>>>>>>
>>>>>>> 1. do as little work as possible within the internals of
>>>> Mixxx, yet be as
>>>>>>> flexible as possible (for all controllers, the first real
>>>> controller will
>>>>>>> be something like the Stanton SCS.3d)
>>>>>>>
>>>>>> What happens if you gain your flexibility by doing work in
>>>> Mixxx? (or, wait,
>>>>>> do you mean CPU work or programmer work? My idea doesn't
>>>> impinge on CPU at all
>>>>>> really)
>>>>>>
>>>>>>
>>>>>>> 2. avoid anything that would break the midi learning stuff or
>>>> make it or
>>>>>>> tool-based another mapping approach significantly more
>>>>>>> complicated
>>>>>>>
>>>>>> My thinking is that scripting would make tool-based mapping a
>>>> lot harder.
>>>>>> Programs generating ECMAScript? I think of it like this:
>>>> without actually
>>>>>> emulating a device, could you have a program show you all the
>>>> possible buttons
>>>>>> and modes a device can handle? With script, you can't. With
>>>> declarative XML,
>>>>>> you could have something that pops up a display showing a
>>>> picture of the
>>>>>> device, and all the possible functions any button could perform.
>>>>>>
>>>>>>
>>>>>>> So... now it's my turn to ask some questions and explain how
>>>> the current
>>>>>>> proposal dodges them... :D
>>>>>>>
>>>>>> OK :)
>>>>>>
>>>>>>
>>>>>>> I understand mixing content and presentation, but I don't
>>>> follow how it
>>>>>>> applies here.
>>>>>>>
>>>>>> A bad analogy on my part I think.
>>>>>>
>>>>>>
>>>>>>> We aren't mixing mapping with behaviour, the two are still
>>>> very much
>>>>>>>
>>>>>> You have MIDI codes in the script. That is the essence of
>>>> mixing them :)
>>>>>>
>>>>>>
>>>>>>> Where does the behaviour that powers "mappingschange" get
>>>> defined? Has to
>>>>>>> either be an internal compiled-in behaviour or a script of
>>>> some kind...
>>>>>>>
>>>>>> Compiled in, definitely. Now, I'm assuming that the MIDI code
>>>> in mix reads
>>>>>> through the XML and fills variables/objects with the mapping
>>>> information. I'm
>>>>>> thinking that when a mode change occurs, you reinterpret the
>>>> XML with a
>>>>>> different mapping view selected, so in the things with
>>>> selectable mapping,
>>>>>> different button->function bindings get inserted into the data
>>>> structure that
>>>>>> holds that (or the objects that hold that info understand
>>>> mappings, and you
>>>>>> tell them what their new one should be and they just update.
>>>> That would
>>>>>> probably be cleaner).
>>>>>>
>>>>>>
>>>>>>> What if company XYZ comes out with a new device that uses a
>>>> slider to
>>>>>>> change mapping modes based on different ranges (0..31 = fx,
>>>> 32..63 =
>>>>>>> bankswitch, 64.. 97 = loop, 98 .. 127 = cue point)?
>>>>>>>
>>>>>> We handle the standard cases, guessing a bit, but say:
>>>>>> * herc style button to cycle,
>>>>>> * /n/-position knob (which is either implemented like a
>>>> special-case slider,
>>>>>> or like the herc pitch knob, so a direction control - depending
>>>> on the
>>>>>> hardware),
>>>>>> * multiple separate buttons.
>>>>>> for anything else, we thunk to script. If we find scripts are
>>>> being used for
>>>>>> certain things a lot, we pull that functionality into mixxx.
>>>>>>
>>>>>>
>>>>>>> The proposed extension handles this by dumping the raw midi
>>>> event to a
>>>>>>> script, the script is still equally messy, maybe more so, but
>>>> there is no
>>>>>>> trace of that mess in the XML file.
>>>>>>>
>>>>>> But it has to be somewhere, and it will cause maintenance
>>>> headaches. Say you
>>>>>> implement it for the 3-state cycling button. Now you have
>>>> support for that,
>>>>>> but only for the herc, you can't reuse that code for another
>>>> device, or for a
>>>>>> 4-state cycle. If you design it in a declarative way, you just
>>>> need to add a
>>>>>> new mapping name and button->function bindings, and the code
>>>> that backs this
>>>>>> will work across all controllers.
>>>>>>
>>>>>>
>>>>>>> HerculesMk2.fx_cue_loop_button
>>>>>>> HerculesMk2.fx_cue_loop_mode
>>>>>>>
>>>>>> That seems clunky to me :(
>>>>>>
>>>>>>
>>>>>>> Where would the state for this get stored in Mixxx? How will
>>>> control
>>>>>>> mapping XML know what state its in?
>>>>>>>
>>>>>> Basically, for every mapping group, it has a simple state. Just
>>>> an iterator
>>>>>> that can be told to cycle through the defined values.
>>>>>>
>>>>>>
>>>>>>>> <control mapping="fx">
>>>>>>>> <!-- stuff to apply to the button '1' when the mapping
>>>> mode is
>>>>>>>> 'fx' -->
>>>>>>>> </control>
>>>>>>>>
>>>>>>> The guts of this are _extremely important_ for the
>>>> implications of the
>>>>>>> functions need to be compiled-in to support them...
>>>>>>>
>>>>>> Not in this case, I was thinking of having it exactly like the
>>>> current '1'
>>>>>> definition, except calling the function appropriate for 'fx' mode.
>>>>>>
>>>>>>
>>>>>>> Would their be some kind of reference to a compiled-in function?
>>>>>>> Inflexible, needs recompile to change/extend...
>>>>>>>
>>>>>> You can still have scripts. I think they're likely to be
>>>> required. I just
>>>>>> think that common cases should be declared rather than written,
>>>> and that if we
>>>>>> design our XML format around this idea now, it'll be easier
>>>> than if we wait
>>>>>> longer and there are lots of third party mapping file all over
>>>> the place.
>>>>>>
>>>>>>
>>>>>>> Would their be some <IF> type tags in there defining what to
>>>> do? (mixing
>>>>>>> mapping and behaviour? reusable across different controllers?)
>>>>>>>
>>>>>> No. The idea of turning a declarative structure (the XML) into
>>>> a procedural
>>>>>> one (with 'if' and such) makes be twitch a little. Think of it
>>>> like Prolog.
>>>>>>
>>>>>>
>>>>>>> If so, we'd have to write some kind of interpreter to compile
>>>> this to
>>>>>>> script for execution or we'd have to represent this in some
>>>> kind of logical
>>>>>>> tree thingy I'm guessing. We could present the user some kind
>>>>>>> of
>>>>>>> excel-like-function-wizard...
>>>>>>>
>>>>>> Tree thingy is what I was thinking of. I'm assuming you load
>>>> the XML and use
>>>>>> it to populate a data structure. You just make that data
>>>> structure aware of
>>>>>> the mappings. When you switch mappings, and look up that
>>>> structure to see what
>>>>>> happens when button X is pressed, you interpret what it
>>>> responds based on the
>>>>>> context of the mapping, or alternately, it knows about the
>>>> mapping, and so
>>>>>> gives you the right response.
>>>>>>
>>>>>> Another way is that whenever the mode is changed, that
>>>> structure is updated
>>>>>> with the new mappings, but that seems less elegant and slower too.
>>>>>>
>>>>>>
>>>>>>>> Alternately, you could wrap all the controls in a 'map'
>>>> element, so that
>>>>>>>> each
>>>>>>>> control and light doesn't have to know its own mapping. That
>>>> makes some
>>>>>>>> sense.
>>>>>>>>
>>>>>>> Where would the logic live? What would it look like?
>>>>>>>
>>>>>> It would only be a small difference in interpretation when the
>>>> XML is loaded.
>>>>>>
>>>>>>
>>>>>>> There is no avoiding having people learn to program in order
>>>> to program
>>>>>>> midi state... The question is, do they learn C++,
>>>> excel-function-wizard,
>>>>>>> XML script, or QtScript/EMCAScript/Javascript?
>>>>>>>
>>>>>> Programming is a strong word here :) I wouldn't consider XML
>>>> scripting
>>>>>> programming, in this case. You're just outlining the buttons,
>>>> and in some
>>>>>> cases allowing options based on something else.
>>>>>>
>>>>>> Of course, when you want properly complex, turing-completish
>>>> behaviour, then
>>>>>> you hook into a script. But I don't think it's needed for most
>>>> simple cases.
>>>>>>
>>>>>>
>>>>>>> As usual the devil's in the details.
>>>>>>>
>>>>>> Yep :)
>>>>>>
>>>>>> --
>>>>>> Robin <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>>
>>>> JabberID: <[EMAIL PROTECTED]
>>>> <mailto:[EMAIL PROTECTED]>>
>>>>>> http://www.kallisti.net.nz/blog |||
>>>> http://identi.ca/eythian
>>>>>>
>>>>>> PGP Key 0xA99CEB6D = 5957 6D23 8B16 EFAB FEF8 7175 14D3 6485
>>>> A99C EB6D
>>>>>>
>>>>>>
>>>>>>
>>>>
>>>> -------------------------------------------------------------------------
>>>>>> This SF.Net email is sponsored by the Moblin Your Move
>>>> Developer's challenge
>>>>>> Build the coolest Linux based applications with Moblin SDK &
>>>> win great prizes
>>>>>> Grand prize is a trip for two to an Open Source event anywhere
>>>> in the world
>>>>>> http://moblin-contest.org/redirect.php?banner_id=100&url=/
>>>> <http://moblin-contest.org/redirect.php?banner_id=100&url=/>
>>>>>> _______________________________________________
>>>>>> Mixxx-devel mailing list
>>>>>> [email protected]
>>>> <mailto:[email protected]>
>>>>>> https://lists.sourceforge.net/lists/listinfo/mixxx-devel
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>
>>>>
>>>> -------------------------------------------------------------------------
>>>>> This SF.Net email is sponsored by the Moblin Your Move
>>>> Developer's challenge
>>>>> Build the coolest Linux based applications with Moblin SDK & win
>>>> great prizes
>>>>> Grand prize is a trip for two to an Open Source event anywhere
>>>> in the world
>>>>> http://moblin-contest.org/redirect.php?banner_id=100&url=/
>>>> <http://moblin-contest.org/redirect.php?banner_id=100&url=/>
>>>>> _______________________________________________
>>>>> Mixxx-devel mailing list
>>>>> [email protected]
>>>> <mailto:[email protected]>
>>>>> https://lists.sourceforge.net/lists/listinfo/mixxx-devel
>>>>>
>>>>
>>>>
>>>>
>>>> -------------------------------------------------------------------------
>>>> This SF.Net email is sponsored by the Moblin Your Move Developer's
>>>> challenge
>>>> Build the coolest Linux based applications with Moblin SDK & win
>>>> great prizes
>>>> Grand prize is a trip for two to an Open Source event anywhere in
>>>> the world
>>>> http://moblin-contest.org/redirect.php?banner_id=100&url=/
>>>> <http://moblin-contest.org/redirect.php?banner_id=100&url=/>
>>>> _______________________________________________
>>>> Mixxx-devel mailing list
>>>> [email protected]
>>>> <mailto:[email protected]>
>>>> https://lists.sourceforge.net/lists/listinfo/mixxx-devel
>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> __
>>>> --- == __/ t.O ==--
>>>> http://stacktrace.org/
>>>
>>>
>>
>> -------------------------------------------------------------------------
>> This SF.Net email is sponsored by the Moblin Your Move Developer's
>> challenge
>> Build the coolest Linux based applications with Moblin SDK & win
>> great prizes
>> Grand prize is a trip for two to an Open Source event anywhere in
>> the world
>> http://moblin-contest.org/redirect.php?banner_id=100&url=/
>> _______________________________________________
>> Mixxx-devel mailing list
>> [email protected]
>> https://lists.sourceforge.net/lists/listinfo/mixxx-devel
>
>
--
Sent from Gmail for mobile | mobile.google.com
__
--- == __/ t.O ==--
http://stacktrace.org/
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Mixxx-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mixxx-devel