-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ability to traverse generator graph #207
Comments
@morganpackard I'm considering the following approach and I'd to get your thoughts on it, if it's possible to follow my techno-babbling. Added to Generator_ typedef void (Generator_::*GeneratorSetter)(Generator gen);
std::map<string, Generator> inputGenerators_;
std::map<string, Generator_::GeneratorSetter> inputGeneratorSetters_;
void Generator_::setInputGenerator(string name, Generator gen)
{
std::map<string, Generator_::GeneratorSetter>::iterator it = inputGeneratorSetters_.find(name);
if (it != inputGeneratorSetters_.end())
{
Generator_::GeneratorSetter setter = it->second;
(this->*setter)(gen);
inputGenerators_[name] = gen;
}
else
{
// fatal exception
error("Input generator not registered for name \"" + name + "\". Did you use TONIC_INIT_GEN_INPUT?", true);
}
} Changes to Macros The requirement is that
#define TONIC_INIT_GEN_INPUT(propertyName, setterFunctionPointer, initialValue) \
{ \
inputGenerators_[#propertyName] = initialValue; \
Generator_::GeneratorSetter setter = static_cast<Generator_::GeneratorSetter>(setterFunctionPointer); \
inputGeneratorSetters_[#propertyName] = setter; \
}
#define TONIC_MAKE_GEN_SETTERS(generatorClassName, propertyName) \
\
generatorClassName& propertyName(Generator arg){ \
this->gen()->setInputGenerator(#propertyName, arg); \
return static_cast<generatorClassName&>(*this); \
} \
\
generatorClassName& propertyName(float arg){ \
return propertyName( FixedValue(arg) ); \
} \
\
generatorClassName& propertyName(ControlGenerator arg){ \
return propertyName( FixedValue().setValue(arg) ); \
} Example In TONIC_INIT_GEN_INPUT(freq, &TableLookupOsc_::setFreqGen, FixedValue(440)) In the class declaration for TONIC_MAKE_GEN_SETTERS(TableLookupOsc, freq); I've tested this for a few generators and it seems to work correctly on OSX at least. I'm not 100% sure it will work on all compilers, though, due to some weird member function pointer inheritance business (see this: http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible) Also, this pattern is sort of weird, and I'm not sure it's really easy to figure out for someone wanting to create a new generator. Thoughts? |
Also works on iOS. Haven't tested windows or linux. |
Will check it out when I get a minute. Sent from my iPhone On Aug 13, 2013, at 6:01 PM, "Nick D." [email protected] wrote: Also works on iOS. Haven't tested windows or linux. — |
Haven't had a clear chunk of time to think this through, and may not for days. But a couple things:
|
I'm not sure I follow what you mean here. Just because they have the same names, I'm not sure how you could bridge the name of the instance variable from the underscore class to the parameter setters int the smart pointer using one macro. And c++ has no capability for string-to-variable-name introspection. Also don't forget that some input setters have other side effects, for example changing whether an effect processes as stereo or mono, and I think it's important to keep that logic in the underscore class and out of the smart pointer - the smart pointer implementation should be as thin as possible.
Global static initialization happens prior to main(), but in no guaranteed order. I considered that as an option too, but I'm not sure it's possible to use static initialization to initialize instance-specific information such as a list of inputs. Memory offsets are not well-defined at compile time for non-POD objects. |
Or I suppose, not well-defined at all - AFAIK it's not possible to reliably use |
Ok. Are you really eager to move quickly on this or can we marinate on it a bit? Sent from my Speak & Spell On Aug 13, 2013, at 10:18 PM, "Nick D." [email protected] wrote:
|
Btw--the band limited stuff is AWESOME! Sent from my Speak & Spell On Aug 13, 2013, at 10:18 PM, "Nick D." [email protected] wrote:
|
Sweet! Glad you like it. I'm not in a hurry. We can marinate until the flavor is just right. Your feedback actually gave me another idea that might be a bit simpler. |
So I did a bit more research on C++ instance construction, and as far as I can tell, there is literally no way to modify an instance of an object at the exact time of its construction, except for in the constructor. Static member variables of a class are initialized in the global initialization phase, before main(), but have no knowledge of the class itself or any instance thereof. Unless there is some really really tricky indirection that we haven't discovered yet, I'm leaning toward a three-fold macro approach to make "generic" generator creation easier. Basically you still have to remember to use the macros correctly, but IMO that's better than requiring hand-coding for everything. Obviously there will be specific cases that fall outside the capabilities of generic macros, but I feel like that's a less-common use case. Here's what I'm thinking:
|
Was just pondering this, after having been away from the problem, and perhaps not remembering all the details of it. In my own words, here's the issue:
I think we can handle #1 with some member function pointer wizardry / ugliness in the setter macros. Surely I've missed something. I'll go back and read and see where I'm being stupid. |
After having spent probably 12+ hours on problem 1) using the function pointer wizardry approach, I'm pretty unconvinced that it's the way to go. I had a semi-working implementation but it required the use of at least 2 or 3 macros and a lot of casting assumptions (member function pointer definitions + inheritance = weird). I also think any sort of "hack" that's obfuscated away into a macro is not a best-practice solution - it relies too heavily on unclear logic and hackery to be easily understood, and there's no way to enforce the usage of a macro at compile time. That being said, I'm prepared to be wrong if you have an approach in mind. I think having something akin to a "protocol" to which generators should conform is the right approach. In c++ that's either unimplemented or pure virtual inherited methods that should be implemented in a subclass (e.g. For 2), tick may indeed be a good way to do that. I think we could probably refactor it to pass down a "message" struct or something in order to prompt generators to do a number of things:
Excellent suggestion. |
Also FYI my comment previous to your most recent one outlines the semi-functional approach I had worked out. |
Ok. Here's a new idea. Commited some initial code into https://github.com/TonicAudio/Tonic/tree/MP-Deep_Copy Abstract ParameterCopier class:
The Generator_ holds a map of pointers to ParameterCopiers
Define subclasses of the ParameterCopier inside the macro-generated setter functions:
CreateCopy method:
|
Beautiful. I dig it. |
I made a few comments on your commit as well. I'm not sure how to solve the type issue. Is the goal to be able to have Not sure if it's relevant, but apparently you can't use templates in locally-defined classes (defined within a function): |
If I do think that it probably should return the correct generator subtype though. And requiring that the GeneratorSub type be passed to the template would also take care of the problem of instantiating the copy. |
We already do that, though, right? If I follow, you're saying that Maybe I'm misunderstanding. |
You're right, we do need a |
Maybe |
Yeah, the smart pointer makes it tough. Not too hard to do with standard instances: |
Maybe we have The
One thing to keep in mind as this starts taking shape is that many |
Maybe I'm misunderstanding the covariant return type stuff, but it looks to On Mon, Oct 7, 2013 at 11:00 AM, Nick D. [email protected] wrote:
Morgan Packard |
They need to be pointer types, apparently. I tried a quick test and it would not compile when returning the smart pointer by value. Returning a pointer instead to a new heap instance did successfully compile, but obviously we don't want that. |
Hi @morganpackard @ndonald2 It would be soooo cool to get it working |
Hi Lev,
I’m so happy to see that some folks are still using Tonic! I haven’t so
much as glanced at or thought about the code in years and don’t think I can
be much help. Good luck!
-Morgan
…On Thu, May 16, 2024 at 1:56 PM Lev Panov ***@***.***> wrote:
Ok. Here's a new idea. Commited some initial code into
https://github.com/TonicAudio/Tonic/tree/MP-Deep_Copy
Hi @morganpackard <https://github.com/morganpackard> @ndonald2
<https://github.com/ndonald2>
I'm currenltly trying to see what's possbile to do with the Generator
cloning.
Was hoping to see find some starting point in the mentioned branch,
however it doesn't seem to be in the repo:(
Any tips on where to look for the proof of concept code for Generator
cloning?
—
Reply to this email directly, view it on GitHub
<#207 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAHWSZN4GPUJS6X2NHVBF73ZCTXLVAVCNFSM4AHGKEV2U5DIOJSWCZC7NNSXTN2JONZXKZKDN5WW2ZLOOQ5TEMJRGU4DMOJZHEYA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Related to #183
The ability to actually keep track of the connections between generators and traverse the graph would open up a lot of possibilities.
How to make this somewhat automatic is proving to be a challenge.
The text was updated successfully, but these errors were encountered: