[Cs-dev] Channel API
Date | 2013-03-30 05:41 |
From | Andres Cabrera |
Subject | [Cs-dev] Channel API |
Attachments | None None |
Hi, I've been working on cleaning up the channel API, and it's looking much better now (I think). I'd like some thoughts on how its going and if there are any ideas (in particular from people like Steven, Rory and Oeyvind who are heavy users of the API).http://csound.sourceforge.net/doc/html/group__CONTROLEVENTS.html Andrés |
Date | 2013-03-30 09:42 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
This looks great Andres. So the new type specific channel methods are all thread safe now? And csoundSetCallback() only works for keyboard events, but isn't called something like csoundSetKeyboardCallback because it could be extended in the future? Fair enough. It would be nice if instead of passing an int index to csoundSetPvsChannel users could use a named channel. It seems a little at odds with the rest of the functions there. (I thought Victor had addressed this already?). I've had to use the in/outvalue callback methods recently with Processing, so that I can sync up Csound to trigger visuals. Without this callback mechanism a lot of events would be missed by Processing which use a much slower sample rate of around 30fps. It's kind of frustrating to have these two channel systems. The chnget/chnset API methods are far simpler to use, so most people starting out with the API (I included) will favour them because of their ease of use. The knock on effect of this is that a lot of frontends will support them over the in/outvalue system, although in the long run this system offers far more flexibility. Is there any way callbacks could be registered for the chnget/chnset mechanism, or at least provide the option of registering callbacks? The generic setter/getter sounds great and I understand your concerns about passing larger types back and fourth. Am I right in assuming that with an asynchronous messaging system one would register a message listener method that would get triggered by Csound. And the data that would be passed to this message queue from another thread would be safe to work with. Then when one has altered the data you would pass it back to the message queue, and then on to Csound. Is it correct to think that his system would be a little slower than brute force sharing of memory, but on hte other hand absolutely thread safe? Sorry for all the questions, I'm just trying to get my head around how this would work. The one thing that is most clear however, is that you have my total trust on this matter! ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-03-31 06:59 |
From | Andres Cabrera |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
Hi Rory,
On Sat, Mar 30, 2013 at 2:42 AM, Rory Walsh <rorywalsh@ear.ie> wrote: This looks great Andres. So the new type specific channel methods are Yes, but this is all Victor's work. If you compile using gcc, control channels are accessed atomically, so there are no locks. In other cases, the channel lock is used. And csoundSetCallback() only works for keyboard I haven't touched that, but I am tempted to remove csoundSetCallback(). I don't think we need generic callbacks, as we might need specific function types or number of arguments, so it might not be worth keeping IMO. It would be Absolutely right. I'm looking into this.
I've modified this internally so that all the mechanisms actually access the same channels, so you can set with outvalue and query with chnget. I actually supported both methods in CsoundQt, but of course the channels were independent. I still need to finish integrating chani/chano into this unified system. All of this is actually backward incompatible behavior, because the three bus systems would have their own independent channel sets, whereas there is a single one now. However, I don't think anyone actually mixed these systems, so I'm not worried that this change will have impact.
I'm thinking that the listener handling would be internal to the queue, so when you call a setter or getter, the function will block until the message has been passed to Csound and processed. Sorry for all the questions, I'm just trying to get my head around how Thanks, and please keep the suggestions coming. It would be great if you can review all the API and comment. Cheers, Andrés
|
Date | 2013-03-31 17:50 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
I've been keeping an eye on developments across the entire API. Things are looking much better than before. One thing that I find rather frustrating is having to maintain a list of opcode syntax descriptors. Most frontend developers will run some kind of script on the help docs to generate this info, but something like this would be nice: char* csoundGetOpcodeSyntaxDescriptor(char* opcodeName) which when passed oscil for example would return the following: aout oscil xamp, xfreq, ifn It would make life a little easier but perhaps it should remain something for frontend developers to maintain. ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-03-31 18:16 |
From | Victor Lazzarini |
Subject | Re: [Cs-dev] Channel API |
This is difficult because it means maintaining more than one list of opcode descriptions and it can be confusing if the two are not in sync. The opcode list doesn't really know anything about the names of parameters, only about their types. So it might be potentially possible to return something like this struct opcode_description { char *name; char *inputs; char *outputs; } => name = "oscil" inputs = "kkio" outputs = "s" where the types are k, i, o (optional i-rate) and s (= k or a) Victor On 31 Mar 2013, at 17:50, Rory Walsh wrote: > I've been keeping an eye on developments across the entire API. Things > are looking much better than before. One thing that I find rather > frustrating is having to maintain a list of opcode syntax descriptors. > Most frontend developers will run some kind of script on the help docs > to generate this info, but something like this would be nice: > > char* csoundGetOpcodeSyntaxDescriptor(char* opcodeName) > > which when passed oscil for example would return the following: > > aout oscil xamp, xfreq, ifn > > It would make life a little easier but perhaps it should remain > something for frontend developers to maintain. > > ------------------------------------------------------------------------------ > Own the Future-Intel(R) Level Up Game Demo Contest 2013 > Rise to greatness in Intel's independent game demo contest. Compete > for recognition, cash, and the chance to get your game on Steam. > $5K grand prize plus 10 genre and skill prizes. Submit your demo > by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 > _______________________________________________ > Csound-devel mailing list > Csound-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/csound-devel Dr Victor Lazzarini Senior Lecturer Dept. of Music NUI Maynooth Ireland tel.: +353 1 708 3545 Victor dot Lazzarini AT nuim dot ie ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-03-31 18:28 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
That's what i thought. I guess it would be easier to just maintain a list! Now with regards to the channel system, I wonder could an additional optional string parameter can be added to chnexport. The idea being that frontend can then grab this text and do something with it. You could call it an attribute string. So potentially some like this might be possible: giTotalNumberOfControls init 100 gkVal[] init giTotalNumberOfControls; 100 slider controls instr 1 iCnt init 0 Init_Loop: SChan sprintf "slider%d", iCnt SAttributes sprintf "pos(10, %d), colour(\"red\")", iCnt*60 gkVal[iCnt] chnexport SChan, 3, 0, 0, 0, 1, SAttributes loop_lt iCnt, 1, giTotalNumberOfControls, Init_Loop endin instr 2 amix init 0 kChanDataCnt init 0 kOutputCnt init 0 Get_Channe_Data_Loop: SChan sprintf "slider%d", iCnt gkVal[kCnt] chnget SChan aout oscili 1/giTotalNumberOfControls, gkVal[kCnt], 1 amix = amix+aout loop_lt kChanDataCnt, 1, giTotalNumberOfControls, Get_Channe_Data_Loop outs amix, amix endin Is there any obvious problems with placing chnexport's into an instrument body? If so, I guess a frontend could do a quick performance and grab all the channel info, do what it needs with it, (in this case create 100 sliders), then rewind and begin performance from the start with everything set up? ------------------------------------------------------------------------------ Own the Future-Intel(R) Level Up Game Demo Contest 2013 Rise to greatness in Intel's independent game demo contest. Compete for recognition, cash, and the chance to get your game on Steam. $5K grand prize plus 10 genre and skill prizes. Submit your demo by 6/6/13. http://altfarm.mediaplex.com/ad/ck/12124-176961-30367-2 _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-03-31 18:45 |
From | Andres Cabrera |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
Hi, This is actually a nice idea and can do most of what is desired here:http://sourceforge.net/apps/mediawiki/csound/index.php?title=RFC_2-Widget_API I haven't checked but maybe you can use chn_k to set attributes in the header, that way hosts don't need to start performance and stop to get the GUI details. I'm not sure if this would conflict later with chnexport. Does instr 0 get evaluated on orc compile? Cheers, Andrés On Sun, Mar 31, 2013 at 10:28 AM, Rory Walsh <rorywalsh@ear.ie> wrote: That's what i thought. I guess it would be easier to just maintain a |
Date | 2013-03-31 18:57 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
It's an involved as Matt's original proposal, but should allow us to do quite a lot. Yeah, we could some additional hint types: gival chnexport Sname, imode[, iValType, idflt, imin, imax, iType, iX, iY, iWidth, iHeight, SAttributes] iType would be an int hinting the type of control a frontend could create such as: 1 = horizontal slider 2 = vertical slider 3 = button With hints for x, y, width and height one would hardly need the SAttributes string at all. The best thing about this, and it's something Matt and I were keen to promote when we first started this discussion, is the sharing of instruments across frontends. That would be really cool I think. Of course it would makes prototyping GUI very quick. On 31 March 2013 18:45, Andres Cabrera |
Date | 2013-03-31 19:06 |
From | Andres Cabrera |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
I think this is a good idea. Of course only basic widgets can be shared this way, but it might be a great way to build interfaces on OS X and Android too. BTW, is there an opcode to know what system one is on? Andrés On Sun, Mar 31, 2013 at 10:57 AM, Rory Walsh <rorywalsh@ear.ie> wrote: It's an involved as Matt's original proposal, but should allow us to |
Date | 2013-03-31 19:17 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
I think it's important that it's for basic stuff only. A simple, light and powerful system will work best. More complex controls should be the responsibility of the frontend. It will certainly save me a lot of typing the next time I have to create an instrument with a 16x16 matrix of buttons! On 31 March 2013 19:06, Andres Cabrera |
Date | 2013-04-07 21:36 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
Btw, I use a pretty simple string parsing class in Cabbage to parse strings of simple identifiers. For example bounds(x,y,width,height) range(0, 1, 0) etc. The code could easily be rewritten using more C-style conventions. We could then parse strings and fill the controlChannelHints_s with all the relevant information. The info could then be passed to the front end through various member variables of the extended controlChannelHints_s structure. Now if we could update these variables during performance that would be pretty sweet. I'm thinking of not only controlling frontend parameters with Csound, but also their actual look, if the frontend supports it. This is something else Matt was thinking of in his original idea if I'm not mistaken. So what we could do is provide an extra, optional string parameter to chnset: chnset kval, Sname, SAttributes Let's say you have a row of simple toggle buttons that you want to use as a pattern matrix. You might like to light each one up in turn as the beat moves across the row. Something like this might then be possible: kBeat init 0 iButtons = 16 ;turn all buttons the same colour for a moment COLOUR_BUTTONS: kStatus chnget sChannels[kCnt] chnset kStatus, sChannels[kCnt], "colour(0, 0, 0)" loop_lt kCnt, 1, iButtons, COLOUR_BUTTONS ;now update the button which lands under the beat kStatus chnget sChannels[kBeat] chnset kStatus, sChannels[kBeat], "colour(0, 1, 0)" kBeat = (kBeat>15 ? 0 : kBeat+1) Of course you could also have control over fading in and out of different colours by constructing different strings each time. As well as start moving controls across the screen all of their own accord! Users could dynamically alter the layout of the their instruments during performance. That would be neat. I don't mind adopting another type of syntax, or modifying the one I have. But I do like the idea of having very simple, easy to read identifiers. Let me know what you think. On 31 March 2013 19:17, Rory Walsh |
Date | 2013-04-07 23:13 |
From | Oeyvind Brandtsegg |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
Sorry for the late reply, and yes, it looks very nice and much cleaner. I especially like the unification of the different bus systems, and find it very elegant that you have been able to clean it up while keeping backwards compatibility. Very very nice.
best Oeyvind 2013/3/30 Andres Cabrera <mantaraya36@gmail.com>
Oeyvind Brandtsegg Professor of Music Technology NTNU 7491 Trondheim Norway Cell: +47 92 203 205 http://flyndresang.no/ http://www.partikkelaudio.com/ http://soundcloud.com/brandtsegg http://soundcloud.com/t-emp |
Date | 2013-04-08 05:31 |
From | Andres Cabrera |
Subject | Re: [Cs-dev] Channel API |
Hi, There is no internal reason why the ChannelHints can't be changed dynamically. There is not opcode yet for that, which could be the "setter" for the chnparams opcode "getter". The only issue is how to let the host know that the hints have changed... But I would suggest not using a string to set parameters, because this can lead to fragmentation, and a csd that works in one front end then doesn't in another, just because they use a different format. I would suggest keeping the channel hints very simple, or to extend it in a way that is defined inside the Csound API, so that it can be supported directly by frontends. However, it would also be great if we could have some extensible and more versatile framework (you can't have xy widgets because you need two channels...), but then it would have to look more like what Matt is suggesting, a set of opcodes and different GUI backends for running with FLTK, Cabbage, Qt, over the network, on your phone, etc... Cheers, Andrés On Sun, Apr 7, 2013 at 1:36 PM, Rory Walsh |
Date | 2013-04-08 05:37 |
From | Andres Cabrera |
Subject | Re: [Cs-dev] Channel API |
Thanks. There's still some work to be done, but it's getting there. There are a few things that had to change for this. For example, all the mechanisms had a separate set of channels, and now all the opcodes share the same set. But I doubt anyone implemented more than one of the systems in their software... The other change I've done is that for the chani/chano opcodes, the input and output sets were separate, so an input channel called "level" would not conflict with an output channel "level". I'm still pondering whether to leave this as is, but this would be less ideal because I would have to use something like namespaces which complicates things a bit for users. And other minor things like the pvs channels now will share the same pool with the other channels, so pvs channel "1" can conflict with another previously defined channel called "1". Same issue, can add namespaces, but would prefer not to... Cheers, Andrés On Sun, Apr 7, 2013 at 3:13 PM, Oeyvind Brandtsegg |
Date | 2013-04-08 10:08 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
But Matt's suggestion also advocates the use of strings to set widget attributes? I'm not fussed about what format they are presented in, whether it's "colour(1, 0, 1, 0)", OR, "colour: 1, 1, 0, 1" The main advantage of using strings is that you only have to set the attributes you want to change. And the identifiers used should be standardised and each hint accessible through the ControlParams structure. Letting the front-ends know about a change is the biggest issue. Is there no way an optional callback could be registered for chnset? If frontends want to use chnset in a callback capacity they register a callback, if not they don't register a callback. If a callback is registered chnset switches operation mode to outvalue, if not it operates as it does now. I'm not sure how this could be implemented, or if it could, but it certainly would be nice. The idea of adding another new channel specification is enticing, but only if the existing mechanism really can't cut it. I guess we could also add a chnupdate opcode to the chnget/set family of opcodes that would trigger a callback in the host and update control hints? This nice thing about this is it could run a different update speeds to the chnset opcode. chnupdate "channel1", "colour:1, 0, 0, 1" To be honest, I'm more than happy with extending the hints structure to include width, height and x and y. I'm just thinking about possible future directions! ------------------------------------------------------------------------------ Minimize network downtime and maximize team effectiveness. Reduce network management and security costs.Learn how to hire the most talented Cisco Certified professionals. Visit the Employer Resources Portal http://www.cisco.com/web/learning/employer_resources/index.html _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-04-09 03:00 |
From | Andres Cabrera |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
Hi, You're right, there would need to be some form of text there. But we could all work together to try to interoperate where possible.Andrés On Mon, Apr 8, 2013 at 2:08 AM, Rory Walsh <rorywalsh@ear.ie> wrote: But Matt's suggestion also advocates the use of strings to set widget |
Date | 2013-04-09 08:35 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
> You're right, there would need to be some form of text there. But we could > all work together to try to interoperate where possible. Sure, we need only decide on a set syntax for this? > I think a callback to inform the host that there has been a change in a > channel's parameters or that a new channel has been registered might be > nice, although it will demand that the host not block inside this > callback... Declaring new channels/controls on the fly would be nice, but I think it might be safer to just set control visibility. > And there's also the issue of multiple windows, it might be great if each > instrument or group could put its widgets in the right window, otherwise > widgets can start just piling up if you are reusing code. Maybe using > something like "effect::level" as channel name can be interpreted as > namespace::channel? This would be nice, I guess we just need to unified syntax for these messages? ------------------------------------------------------------------------------ Precog is a next-generation analytics platform capable of advanced analytics on semi-structured data. The platform includes APIs for building apps and a phenomenal toolset for data science. Developers can use our toolset for easy data analysis & visualization. Get a free account! http://www2.precog.com/precogplatform/slashdotnewsletter _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-04-10 16:30 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
Crazy idea, and of course might not be possible, but I'll throw it out there anyway. Can we not just force all frontends to register callbacks for channel messages from Csound 6 onwards. It seems that we are investing a lot of effort into improving the chnset/chnget methods when perhaps we should instead be extending Matt's original callback system. Moving forward I think it's more and more essential that host's are notified when krate variables are updated in Csound. If a callback system is the best then perhaps we should invest more time into that. ------------------------------------------------------------------------------ Precog is a next-generation analytics platform capable of advanced analytics on semi-structured data. The platform includes APIs for building apps and a phenomenal toolset for data science. Developers can use our toolset for easy data analysis & visualization. Get a free account! http://www2.precog.com/precogplatform/slashdotnewsletter _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-04-10 16:34 |
From | Steven Yi |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
I haven't followed this thread too closely, but there is a design in use for Android and iOS using CsoundValueCacheable. It's a generic system where the host can register multiple callback handlers. This gives the option for the developer to develop individual bindings or a single master binding that does a larger bit of code. It essentially uses an object for the purposes of callbacks, and has a defined lifecycle. Maybe this is worth considering in all this?
On Wed, Apr 10, 2013 at 4:30 PM, Rory Walsh <rorywalsh@ear.ie> wrote: Crazy idea, and of course might not be possible, but I'll throw it out |
Date | 2013-04-10 16:36 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
Absolutely. I think it's good to throw all the cards on the table with this one. Can you give a short example of how yours might look in C/C++? I find it hard to follow the java stuff! On 10 April 2013 16:34, Steven Yi |
Date | 2013-04-10 16:52 |
From | Steven Yi |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
Something like this in C++: class CachedSlider : CsoundValueCacheable { ... args } void CachedSlider::setup(CSOUND* csound) {
//alloc memory, cache pointers from csound, etc. } void CachedSlider::updateValuesFromCsound(CSOUND* csound) { //read values from csound
} void CachedSlider::updateValuesToCsound(CSOUND* csound) { //write to csound } void CachedSlider::cleanup(CSOUND* csound) {
//free up memory, remove any listeners, etc. } CachedSlider cached(); csoundCPP.addValueCacheable(cached); csoundCPP.start();
or something like this in C: struct _cacheable { void* data; void *(setup)(CSOUND*, void*); void *(updateValueFromCsound)(CSOUND*, void*);
void *(updateValuesToCsound)(CSOUND*, void*); void *(cleanup)(CSOUND*, void*); } CS_VALUE_CACHEABLE; void setupSlider(CSOUND* csound, void* data) {
} void updateSliderFromCsound(CSOUND* csound, void* data) { } void updateSliderToCsound(CSOUND* csound, void* data) { } void cleanupSlider(CSOUND* csound, void* data) {
} CS_VALUE_CACHEABLE* slider1 = csound->Malloc(csound, sizeof(CS_VALUE_CACHEABLE); slider1->data = someUIWidget;
slider1->setup = setupSlider; slider1->updateValuesFromCsound = updateSliderFromCsound; slider1->updateValuesToCsound = updateSliderToCsound; slider1->cleanup = cleanupSlider; csound->AddValueCacheable(csound, slider1); int keepPerforming = 1; do { for(i = 0; i < valueCacheablesLength; I++) {
valueCacheables->updateValueToCsound(csound, valueCacheables->data);. } keepPerforming = csoundPerformKsmps(csound); for(i = 0; i < valueCacheablesLength; I++) {
valueCacheables->updateValueFromCsound(csound, valueCacheables->data);. } } while(keepPerforming); Just some speculative code.
On Wed, Apr 10, 2013 at 4:36 PM, Rory Walsh <rorywalsh@ear.ie> wrote: Absolutely. I think it's good to throw all the cards on the table with |
Date | 2013-04-10 17:03 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
But you have to be careful when to access the cached values, or are they safe? I'm still a little confused by this I have to admit. ------------------------------------------------------------------------------ Precog is a next-generation analytics platform capable of advanced analytics on semi-structured data. The platform includes APIs for building apps and a phenomenal toolset for data science. Developers can use our toolset for easy data analysis & visualization. Get a free account! http://www2.precog.com/precogplatform/slashdotnewsletter _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |
Date | 2013-04-10 17:17 |
From | Steven Yi |
Subject | Re: [Cs-dev] Channel API |
Attachments | None None |
The cached value structs are like objects. The for-loop that calls csoundPerformKsmps shows that the structs' function pointers for updating values to and from csound happen before/after csoundPerformKsmps is called. So the code is called at the block boundaries. The functions in the struct can in turn be whatever you'd like. Now, the value cacheable layer does not necessarily mean you have to do I/O with your host layer directly from those calls. You can in turn just cache a value to read from later by your host. For example, in the callback set on a value cacheable, you could do some logic to only make a further call to your host every 10 k-passes. Or, you could have in another thread your UI layer do some kind of polling of the values, say, every 30 fps. So you can have the valueCacheable notify your host that a value is updated, or you can design the host to read the values arbitrarily. The design is somewhat generic and flexible in that regards, so you can have fine synchronization with the Csound engine, or make the access more coarse (i.e. "give me the latest value", "write my current value", rather than "update now this kpass").
On Wed, Apr 10, 2013 at 5:03 PM, Rory Walsh <rorywalsh@ear.ie> wrote: But you have to be careful when to access the cached values, or are |
Date | 2013-04-10 17:26 |
From | Rory Walsh |
Subject | Re: [Cs-dev] Channel API |
Actually this is more or less what I do with Cabbage. Man, it took me a while to get that! ------------------------------------------------------------------------------ Precog is a next-generation analytics platform capable of advanced analytics on semi-structured data. The platform includes APIs for building apps and a phenomenal toolset for data science. Developers can use our toolset for easy data analysis & visualization. Get a free account! http://www2.precog.com/precogplatform/slashdotnewsletter _______________________________________________ Csound-devel mailing list Csound-devel@lists.sourceforge.net |