cycling74 / min-api Goto Github PK
View Code? Open in Web Editor NEWHigh-level C++-language application programming interface for Max
License: MIT License
High-level C++-language application programming interface for Max
License: MIT License
We will want one for the max class but in the case of Jitter we will also want one for the jit class.
Needed to support being done by @robtherich .
My test case for this involves the attribute disable function, but this is indicative of a wider problem when accessing any class member, which could cause a lot of pain for users.
attribute<bool> disable_simple_integer { this, "disable_simple_integer", true,
setter { MIN_FUNCTION {
simple_integer.disable(args[0]);
return { args[0] };
}}
};
attribute<long> simple_integer { this, "simple_integer", 100};
The above code-block causes an error on object construction, because 'simple_integer' is not yet constructed when the setter function is called to set the default value of 'disable_simple_integer'. Obviously it's possible to put checks for this in, but this could end up with a lot of extra boilerplate in setter methods.
Additionally, these kind of errors can be quite hard to spot for inexperienced developers, and also can be introduced from working code merely by re-ordering members in the class definition.
Is it possible to delay the initialisation of attributes with their default value (via their setters) until after object construction?
e.g. if a setter or message should always be deferred to the main thread. Perhaps that should be the default?
Currently it is cumbersome and overwhelming, and highly-repetitive and error-prone, to add/manage new method bindings/signatures to the magic robot code that wraps a Min class for Max.
Additionally the naming of the template classes is not descriptive and thus also the subject of occasional confusion or misunderstanding.
From @gregory-taylor :
Do we want snippets? for where we normally put the Examples?
Setting the readonly property on an attribute has no effect, which makes sense as I can't find any implementation for it. I would add it myself but the 'object_attr_setdisabled' function is missing from the c74::max namespace.
for example, see problems with lossius/atk-max#2
It would be useful if, in addition to the one sample processing method, it was also possible to add an optional block method serving as a vector preprocessor, called just before the processing of a vector starts.
One example where this would be useful would be audio gain and matrix objects. If updated gain values are set as control messages rather than at audio rate, this would make it possible to smooth the transition to the new value over one vector in order to avoid audible clicks.
The JSFX API for developing Reaper plugins has this, and it is rather useful:
http://reaper.fm/sdk/js/js.php#js_intro
Here's an example of how this might be used in a stereo gain object:
// When a new gain value is requested, it updates the value of desiredGain.
/// Block (signal vector) preprocessing
void block()(void) {
inc = (desiredGain - gain) / blocksize;
}
/// Process one sample
samples<2> operator()(sample input1, sample input2) {
gain += inc;
return {{ input1 * gain, input2 * gain }};
}
e.g. digest first letter must be capitalized and have no period.
for example: create list.process @operation 5
need example / test of custom getter mechanism as documented in https://github.com/Cycling74/min-api/blob/master/doc/GuideToWritingObjects.md
Currently an attribute value is assigned when the attribute instance is created, on the stack, as the Min class is constructed. There are several tricky consequences:
Thus attribute defaults should not be assigned in the attribute ctor, but rather pushed onto a queue and then processed together later, e.g. just before attr_args_process()
Currently one must create a "maxclass_setup" method as is done the xfade~
example in order to add metadata such as enum listings or labels.
As @robtherich has rightly pointed-out, we would benefit from specifying this stuff as arguments to the attribute initializer.
c74::max::cpost() works, but sometimes I really do want to post to the Max window. Am I missing something?
... and move toward best-practices in the code by using the more targeted and safe casting operators.
this has currently been done for non-jitter classes, but the code path for jitter classes has not been moved yet...
@robtherich suspects (as I do) that it won't be a problem to move it there also, but we need to confirm...
All constructors, attribute setters, methods, should use a consistent interface for passing data.
Some work has been on this front by @benbrackenc74 for ctors such that they receive args as const atoms& args = {}
. This was previously partially tracked as Cycling74/min-devkit#33.
This new interface means that attributes will not be able to alter the values of their incoming arguments because they are now a const reference -- but that mechanism was also kind of an ugly hack. A better interface is to return the value from the function as it is supposed to be used.
Cleaning up the attribute interface for setters highlights additional looming concerns with the existing ATTRIBUTE
macro:
END
macro which has the same problems but potentially even more prone to collisionThus this work will embody refining the attribute interface in such a way as to address these design problems.
Use variadic template implementation so that any combination of args can be parsed.
Would simplify code currently needed by @darwingrosse .
Currently no way to do that. Maybe we need some flags for the MIN_EXTERNAL macro or something?
In other words an enum attribute where the values are represented as integral constants but the names are exposed to Max symbolically.
The @darwingrosse arpeggiator has immediate use for this feature.
Currently symbol attrs can define a range of symbols. We could do a similar treatment for int attrs if they received a range of symbols. what would this imply?
Have done experiments previously where the enum values are hashed from the symbol (e.g. in Jamoma2). The value don't count sequentially up from zero as is the traditional Max idiom -- the symbol is also not gettable (e.g. reverse-lookup). The compile-time optimization of the hash in Jamoma2 is also potentially not going to buy us anything in Max where everything is determined at runtime anyway. Thus an unordered_map
might make the most sense for the internal representation.
Min is designed as a header-only library.
http://stackoverflow.com/questions/12290639/quantifiable-metrics-benchmarks-on-the-usage-of-header-only-c-libraries
It works great when it is included in * a * source file. But I’ve had a nagging feeling that if it were included in more than one source file that there would be a problem because if there is a symbol defined in one source file (via a header include) and also defined in another source file (via a header include) then you have a the linker symbol conflict situation.
@robtherich experienced precisely this in Cycling74/jit.mo#21 .
There should be a way around this. Perhaps simply with more careful or controlled including of headers. Boost for example is mostly header-only and doesn’t have this problem as far as I know.
thus avoiding ambiguity and conflicts between what is currently the max::method
and the very different min::method
when both namespaces are being used.
Specifically as it relates to the arbitrary cell access. These could also be useful for generating equations based on matrix coords
cell() - gives the current cell coordinates {x,y}
norm() - gives normalized cell coordinates {x/dim.x, y/dim.y}
snorm() - gives signed normalized cell coordinate {2x/dim.x-1,2y/dim.y-1}
dim() - gives the dimensions of the input matrix. Don't really know if necessary, since it's already covered by .width(), .height()
sample(x,y,…) - currently named "in_cell" returns the value of the input cell at given coordinates. In gen, this is linear-interpolated if a subpixel coord is given, but I don't think that's necessary to implement for this. In Gen, it also takes a normalized float coordinate as input, with is a major PITA for neighbor-cell lookups.
I don't think we need to be too beholden to gen conventions, but I could see where someone might be jumping from jit.gen to min-sdk
most likely this is a problem with the type info of the parameter, not just the documentation...
Currently all of our CI and Unit Testing is configured for the Min-DevKit.
The result is that to evaluate changes one has to run tests etc. in the DevKit instead of in the API.
Proposed Solution: have the CI do a clone of the DevKit and run the unit tests on that.
separate from description
Data written to cout or cerr streams from within an object constructor does not appear in the Max window.
To reproduce: enable the code in the min.beat.random
unit test, it does not crash for me on my local machine (neither in Debug nor Release configs) but it does crash claiming an exception from a bad arg to a mutex.
At a minimum we should try to catch the exception.
currently forced to use old-school max::qelem...
need a wrapper class like we do with clocks/timers
As mentioned in the conversation on pr #1 by @impsnldavid :
In terms of unit testing I could create a separate class which forwards the messages to a different destination. Not sure about regression testing unless there's a way to programmatically get the contents of the Max window?
We cannot trap non-error messages to the Max window, so I personally would not worry about that for the initial testing.
In the case of objects which immediately attempt to make a connection with hardware, being constructed and then immediately destroyed could cause issues. Could we provide some flag that can be tested in the object constructor to determine if this is a 'dummy' construction (just for the purposes of wrapping the object)?
When looking at the generated refpages, the dataview listing of attrs and messages will show a shortened version of the description that cuts off after the first period. This causes trouble when displaying float values in a description, like:
"Function frequency (default = 1.0)."
becomes
"Function frequency (default = 1"
It would be good to know the appropriate workaround, or if this is just a bug in the doc gen. Feature?
In a conversation with @darwingrosse this week stemming from #3 it became obvious that there is room for some further enhancement of the stream-based post() mechanism.
While the post() mechanism that @impsnldavid created is far superior to the old c74::max::object_post()
, it would be even better if the syntax was more familiar looking to what is found e.g. in books for people new to C++, since Max is a gateway to learning programming for many people.
Thus it would be nice if the syntax could be cout << "yay" << endl
or cerr << "fooey" << endl
.
The way post()
current works is that it prints when the logger is freed by going out of scope. The Max window can only print one line at a time, so perhaps we could change that such that it prints when receiving << endl
and then the logger would become persistent.
If you really want to post to the OS console instead of the Max console then you can still explicitly do that by using std::cout << ...
.
One potential solution:
currently there is none -- should it be a template parameter like it is done in Jamoma2?
perhaps alphabetically? somehow need to avoid meaningless shuffling...
so that custom xml page is not over-written
When creating an attribute of enum type with an enum_map for user-facing value labels, space characters in a label text causes it to be parsed as multiple items when displayed in the Max inspector.
basically allow symbols to map to the numeric values since we have them stored already anyway
particularly for namespace and template / sfinae ugliness
In the Max C API you could indicate object construction failure by returning null from the new instance method. This was useful in situations where an object needs to load resources at runtime (e.g. access to specific hardware) which can potentially fail.
Is there an equivalent in the Min API, perhaps by throwing an exception during the constructor?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.