Die Inhalte auf dieser Seite stehen unter diesem Creative Commens License Dingsbums. Also fröhlich kopieren und weiterverteilen. Bitte abweichende Copyright-Hinweise in anderen Blogs respektiveren.

Donnerstag, 1. Oktober 2020

Oddy Sequencer MaxForLive device

Abstract

 I had a idea for a new kind of step sequencer named "Oddy Sequencer". In this article i wanna focus on the timing of the note ons in this sequencer concept because i face a problem and request your help.

Sequencer definitions

The Step Sequencer provides 8 different sequences.

Each sequence has it's indivudal tempo. 

The sequences are switched automatically by a pattern.

A pattern has 8 sequences arranged to patternfragments.

Each patternfragments has assigned a sequence 

Each patternfragment has assigned a length "l".

The patternfragment plays "l" steps of it's sequence. This is defined as "tick".

When the all ticks of a patternfragment length l are played,

the sequencer switches to the next pattern fragment immediately.

TestCase 1

Here is a sample how it could look like:


Bf  1     2     3     4     1

    x  x  x  x  x  x  x  x  x      <= sa 

    x     x     x     x     x      <= sb  


Row Bf marks 1/4 bars.

Each x marks a note on.

Sequence sa has set tempo 1/8.

Sequence sb has set tempo 1/4.

That looks familar like a normal step sequencer.

TestCase 2

Now Patternfragment fa is set to sequence sa with length of 8.

And Patternfragment fb is set to sequence sb with length of 4.

Then the sequencer plays like:


Bf 1     2     3     4     1     2     3     4     1

   x  x  x  x  x  x  x  x                                 <= fa 

                           x     x     x     x            <= fb  


It plays sa in the defined length of 8 ticks for fa. 

Each tick produces a note on. 

Each tick is 1/8 bar long.

When the 8 ticks are over it switches to fb and plays 4 ticks, which are now 1/4 bar long.

After that the sequencer starts with the first patternfragment.

That still looks familar like a normal step sequencer.

TestCase 3

Now Patternfragment fa is set to tempo 8 and sequence sa with length of 7.

And Patternfragment fb is set to tempo 4 sequence sb with length of 4.

Then the sequencer plays like:


Bf 1     2     3     4     1     2     3     4     1

   x  x  x  x  x  x  x                                    <= fa 

                        x     x     x     x     x         <= fb  

You see that the sb sequence starts not on the first bar, as usual for step sequencers but immediately after the first patternfragment is finished.

PatternSync 

In the prototype i implemented several different ways to force an additional pattern-sync which switches to the first patternfragment immediately,

- PatternSync on x bars.

- PatternSync on note on detected on device in.

- PatternSync on positive controller edge

etc.

But this Pattern sync is just a detail, not relevant for my actual problem:

The Problem: Syncing the clock

It's a bit tricky to sync the clock with tempos 1/2/4/8/16/32/64/128. 

But it should work.

But now imagine we wanna add triplets and dotted notes for the tempo.

The problem i now really face is how to sync the clock.

Can you define a strategy to sync the clock when supporting triplets and dotted notes in this sequencer concept?

I think when i just set a timer on the defined X (Note on) points this will work some time but the longer it plays it might get out of sync slightly. My problem is to find the points to sync to master clock when pattern sync is disabled and the sequencer plays a long time.

The solution:

A fallback solution to add a sync which occurs all x bars and restarts the sequencer from the very beginning.

Here is a s sample sequence created with the device.

Here is a screenshot of the current gui:



Freitag, 1. Mai 2020

A dynamic signal flow graph implementation in max for live

Sourcecode on GitHub

Introduction

So after years i decided to open a blog and when i went to blogger.com i stumpled over the old blog i started years ago. Good luck for me so i don't need to create a new account and had a chance to view my old brain emisisons - did I write this?!

This time i wanna release my thoughts about creating a variable audio channel strip. Everything started when i wanted to have a better overview over my ableton live routings. I created this device. It consists of three samplers and a predefined signal chain where custom audio processing plugins can be loaded. The implementation is as stupid as it could be - i just copied the objects: Not a good exercise. A more dynamic approach would be nice. I researched a bit and stumpled over various advanced issues i wanna document here.

20200501: Graph meta definition

So the first issue when we wanna create a dyamic signal flow is to find a meta definition data structure to define the layout of the graph. Max provides the matrixctrl object that represents a 2d matrix consisting of rows and colums where the user can set dots on each cell. This is what i wanna use to define the signal flow graph, as such matrix controllers are common for mastering studios i think. Here they are called mastering patch bays or mastering matrix. A virtual version of this is what i wanna do.
20150501: Image: Signal flow matrix example with internal routings

So here are some definitions for our matrix:
















  • Left side are inputs 1..n
  • top side are outputs 1..n
  • In1/Out1 is the main input/output of the device
  • The rest of the in/outs are internal routings
  • The internal output is connected to the appropriate internal input
  • So for n > 1 applies: out[n] is connected to in[n]
  • The object represented by one dot in the matrix we call node.
  • Each node in general consists of a audio processing plugin, 
  • Maybe other controls may be there like in the 24 subdevices of the Kickmachine device


  • This is why feedback loops may occur if the wrong routing is activated by setting the dot in the matrix. The first thing we wanna deal with is the detection of feedback loops. (See next chapter)
    But back to the definition of the graph. It's as simple the graph is defined by a list of integer values (0, 1) which represents the activation state of all the nodes in the matrix. The index of a vlue is equal to the cellindex. Meaning first cellindex will be the dot on the top left, continuing from left to right and then line by line.

    This layout is yet provided by the matrixctrls using getrow message for each row. We continue using this definition in the feedbackloopdetector patch. The only thing we have to do is request the single rows from the matrixctrl and join the lists together so we have one list which contains the value of the whole matrix in contrast to the values of a single row.
    The result of the feedback detector may be several lists of cell-indexes which represent the paths of the feedback loop. But for the first step i did not implement this. Instead the algorithm gets triggered for one cell whichs enabled state shall be calculated and returns just a bool value 0,1 which represents the enabled state. The parent patcher triggers this routine for each cell in the matrix uppon changing a value in the matrix.

    Gui: Matrix

    The gui for the device shall make use of the matrixctrl object. Different modes for the matrix adjust the behaviour when clicking a button. The basic mode allready implemented in the prototype for feedback detection is to activate routings.
    Others modes may exist so we have in total following modes:


















  • Routing activation
  • Delete Plugin
  • Show Plugin Gui
  • Load plugin (from filesystem path)
  • Layer which shows green or red color for signal level clipping


  • 20200501: Feedback Detection

    By setting the matrix routings "wrong" you can produce feedback loops. Also in max this results in an awfull beeping noise in the audio output. And currently there is no detection of feedback loops. This is what i wanna do.

    20150501: Image: Signal flow matrix example with feedback loop



    You may have it guessed this is a recursive issue. A few hours should be enough to implement this on a programming language of my choice but i took the hard way and implemented it in max for live. The result of the feedback loop detector is used to disable cells to avoid the user configuring the matrix to contain feedback loops.


    The prototype of the algorithm can be found here. It works pretty well but only inside the max editor since ableton prohibites the recursions and reacts with an stack overflow error.



    .   20150501: Video: Signal flow matrix gui disables feedback loops.

    20200511: CLR Adapter

    After some investigation i decided to use the Max SDK and write a max object in C#. Following are some resources to get the C to C# Adapter running:











  • https://bountify.co/call-c-dll-from-c-application
  • NuGetPackageManager Command: Install-Package UnmanagedExports -Version 1.2.7



  • The sample project of the Max-C#-Adapter looks like this: Here are some inlets and outlets configured and some data repeated to the outlet.

    namespace CbChannelStrip
    {
    using System.IO;
    using System.Drawing;
    using CbMaxClrAdapter.Jitter;
    using CbMaxClrAdapter;
    {
    public sealed class CChannelStrip : CMaxObject
    this.IntInlet = new CIntInlet(this)
    public CChannelStrip() { {
    this.IntOutlet = new CIntOutlet(this);
    Action = this.OnIntInlet };
    Action = this.OnListInlet
    this.ListInlet = new CListInlet(this) { };
    this.MatrixInlet = new CMatrixInlet(this)
    this.ListOutlet = new CListOutlet(this); { Action = this.OnMatrixInlet };
    /// this.LeftInlet.SingleItemListEnabled = true; TODO-TestMe
    this.MatrixOutlet = new CMatrixOutlet(this); this.LeftInlet.Support(CMessageTypeEnum.Symbol);
    this.LeftInlet.SetPrefixedListAction("load_image", this.OnLoadImage);
    this.LeftInlet.SetSymbolAction("clear_matrix", this.OnClearMatrix); this.LeftInlet.Support(CMessageTypeEnum.List); } internal readonly CIntInlet IntInlet;
    internal readonly CMatrixInlet MatrixInlet;
    internal readonly CIntOutlet IntOutlet; internal readonly CListInlet ListInlet; internal readonly CListOutlet ListOutlet; internal readonly CMatrixOutlet MatrixOutlet;
    this.MatrixOutlet.Message.Value.SetImage(Image.FromFile(aFileInfo.FullName));
    private void OnLoadImage(CInlet aInlet, string aSymbol, CReadonlyListData aParams) { var aFileInfo = new FileInfo(aParams.ElementAt(0).ToString().Replace("/", "\\")); this.MatrixOutlet.Message.Value.PrintMatrixInfo(this, "ImageMatrix");
    this.IntOutlet.Message.Value = aInt.Value;
    this.MatrixOutlet.Send(); } private void OnClearMatrix(CInlet aInlet, CSymbol aSymbol) { this.MatrixOutlet.Message.Value.Clear(); this.MatrixOutlet.Send(); } private void OnIntInlet(CInlet aInlet, CInt aInt) {
    this.MatrixOutlet.Message.Value = aMatrix.Value;
    this.IntOutlet.Send(); } private void OnListInlet(CInlet aInlet, CList aList) { this.ListOutlet.Message.Value = aList.Value; this.ListOutlet.Send(); } private void OnMatrixInlet(CInlet aInlet, CMatrix aMatrix) { this.MatrixOutlet.Send();
    } }
    }

    This is the class diagram of the Adapter-Classes: (Download the image to view full size)
    - Improvments not included herein: class MultiTypeOutlet




    20200512: Gui: Graph

    Another view would be a graph view we can create using graph wiz. With the image map generator of graph wiz and the apropriate image map object of max we can even create a limited interactive behaviour of the graph image.

    In the meantime i made the graph view running in the version with the CLR-Adapter (see below). Here's a demo:

    20200512: Video: Graph view visualizing the matrix state.

    20200512: Latency Compensation

    So each node can store one audio processing plugin. Depending on what the plugin does there may be no latency (for example a compressor) to a delay of several seconds (for example a phase linear eq) So when signals are processed in paralell and after the prcessing mixed together again there must be a strategy to compensate this latency. Otherwise it will result in unwanted phenomens starting from phasing problems up to a audible recognizeable delay in the signal. I put a sample signal flow here. This shall be the data for the first testcase. so the required output delay of a node will be: thiscomp = maxdelay - thisdelay. where max delay is the maximum delay of all paralell signal paths and this delay is the delay of the actual signal paths and thiscomp is the delay applied to the ringbuffer to realize latency compensation.

    Here is the graph view with Latency Compensation. For the testcase i set Latency=IoNumber.



    20200512: Video: Graphview with latency time displayed.


    20200514: GraphView: Improved

    I improved the graph view a bit so that Nodes which are not connected are displayed gray. Also Latency is not recognized for such nodes. Beside i changed the shapes for input, output and nodes. Also the scaling is improved.

    20200512: Video: GraphView with improved layout.

    20200514: GraphView: Animated (Beta)

    I wrote some code to draw the graph via Vector2d API instead of dumping a bitmap. This allows to add some animation. Still the edges (the lines between the nodes) are missing. 


    20200514: Video: Animated GraphView (Edges missing)

    20200514: GraphView: Animated (Edges+Tips)

    Here's the complete graph animated to morph between different states.

    20200514: Video: Animated Graph View (With Edges+Tips)

    20200515: GraphView: Animated (ColorMorph)

    Here i added to morph colors, taking place when old color and new color differs.

    20200515: Video: Animated Graph View (ColorMorph)







    20200517: GraphView: Mouse & Keyboard Interaction

    So i'm still was not satisfied with the user interface. So i removed the matrix view and added a drag & drop editor and keyboard commands. On top you see the final channel editor boxes with the buttons to open and show VST-Plugins. 

    20200517: Video: Animated Graph View with Keyboard and MouseInteraction

    20200518: Full-featured Gui Draft

    Today i implemented the intermediatelly final layout for the gui and did a lot of improvements for the graph view. Behind the scenes the latency managment is nearly finished. No more long to go :)

    20150518: Video: Full featured GUI


    20150520: MixerMatrix with Latency Compensation running

    So finally the latency compensation for vst plugins and the max device internal mc.send~ / mc.receive~ pairs is running. The plugin latency is received from the vst~ object and for the latency mc.send~ / mc.receive~we assume a hardcoded value of 1 sample per pair. 

    All together for 11 channels we need 11 input buffers per channel and 11*11 + 2 send/receive objects. (2 for main in and main out). That results in 123 send/receive pairs. Actually we don't use that much since there are feedback loops which are not possible. But since max doesnt support dynamic alloction we need to place and allocate a send receive pair and a buffer for every location it can take place.

    I turns out that max requires about 60-80 % cpu load and inside ableton live the cpu load is 150%. I still need to check this but it seems the cpu consumption comes from the send/receive pairs and the buffers.

    So to sum that up, the pferormance is too weak. Maybe i gonna dig into multichannel audio buffer/mixer matrix programming and code that in c/c++. This should be faster since there is no send/receive object of max involved and everything can be solved in one set c/c++ stack frames without having max calls in between.

    20150520: Image:First version with latency compensation and mixer matrix running.

    20150522: Need for Optimization

    A few days ago i put the max patcher into a ableton live max device and got shoked since the device which takes about 60% cpu load in the max editor uses 150% cpu load in max and hence is useless. A big discussion about possibilities for optimization followed here.

    I allready started to set up a c++ project where i planed to implement the routing and latency compensation buffers on my own - without the overhead of max object and system calls in between. Surely implementing the buffers etc. in c++ would be a nice practice to get familar with audio processing but then another apporach came up, to connect the max objects dynamically at runtime.  So i'm not sure from device point of view it will be worth the effort to do a c++ buffer/routing implementation. I will decide in the next days which way to go. 


    20150524: Optimization completed.

    i extended the clr adapter with some classes that allow manipulating the patchers in c#. Using this mechanism the external for the mixer matrix now creates a hardwired max-graph that reflects the graph designed in the gui. By hardwiring the graph the matrix~, send~ and receive~ objects needed for dynamically switching the configuration of the routings are obsolete. Doing so the cpu load within max for live used for the graph routings goes down from 160% to nearly 0%. Now this is what we call a effective optimization... XD

    20210201: Planned: C#-MaxObjectHost
    It would be nice, to host a max object from c#, meaning not only create it in the patcher and wiring it but using it's inlets and outlets from c# code. This way i could extend the vst~ object with a unload function and also provide a native support for Shell Dlls.

    20210201: Planned: C#-CodeGenerator
    It would be nice, to analyze the max class registry and generate c# code from it so one can send specific messages to a concrete max object by calling a generated function.

    20210201: Planned: Dynamic Resize Matrix
    Add, remove nodes and resize matrix dynamically by keeping old connections.


    20210201: Planned: CbVst~
    Extended vst~ object supporting Unload and ShowShellDllPluginChooserDialog.


    Freitag, 25. März 2011

    SessionPerAppInstance

    VerweisAufWeakRefDelegate, WeakWithEvents

    Donnerstag, 22. April 2010

    2010-04-23 Definitions for an application core

    Under construction

    Some definitions for an application-core under .NET framework using WPF/ORM-Framework/SQL-Server

    Lifetime service

    The framework supplies object initialization and termination in hirarchically organized ownership models. It can optionally track lifing objects. It manages recursive termination of all child objects when a parent object is terminated.

    Service Container features for Dependency Injection [DICont]

    The framework supplies various implementations of dependency injection containers to supply services [DiService] identified by a System.Type.

    local service dependency injection container [LocalDICont].

    This is the most simple implementation of a service container which is just a mapping from an SystemType object representing a service interface to an system.object which represents the service implementing the interface.

    virtual services dependency injection container [VirtualDICont].

    A special [DiCont] implementation allows to make services available for all child objects. Using this feature services can be routed through object hirarchies from a root-level service provider to a nested-level service user where objects in the middle do not neet do declare code to forward services to child objects. Using this features various dependencies and delegation code can be elimanted.

    redirected service dependency injection container [RedirectedDICont].

    A special [DiCont] implementation allows to install redirectors for services. So if you request a type of service this object is not registered directly as a service in the container but an supplier object is registered which grants access to the service object. this is used for on demand loading of services.

    service container fasade feature [RedirectedDICont].

    The facade [Facade] composes the [LocalDICont], [VirtualDICont] and [RedirectedDICont] making it transparent to the client wether the service her requests is a local, virtual or redirected service.

    [CmdExecCalc], [CmdAvailCalc], [CmdErrCalc]

    [todo]

    Property-Object feature [Prop], [PropObj]

    The framework supplies a generic property which can be configured to implement various property strategies. VArious properties can be arranged to a property object. The framework can connect to any property so no special base class is required to use for objects can be bound to the framework. This feature is required for the [OrmAdapter]

    Property's object model [PropOM]

    Properties can contain objects of other [PropObj] objects. The framework supports managing such [PropOM] object models.

    Propertiys dynamic implementation feature [PropDyn]

    The property implementations can run in dynamically allocated property objects.

    propertys code generation feature [PropGen]

    All code for properties can be generated to replace dynamically [PropDyn] objects.

    Property's buffer feature: [PropBuf]

    A property can be configured to use a buffer.

    Property's service feature: [ServicePropBuf]

    A [PropBuf] can be connected to a service. The framework will then set the [PropBuf] to a service received from a [DICont].

    Property's r/w feature: [PropRead] [PropWrite]

    A Property can be configured to supply read and/or write operations.

    Property's change notification feature. [PropObserve]

    The property can be configured to generate code for change notification which includes code to adapt the Microsoft Windows Presentation foundation observer implemenation. (System.ComponentModel.INotifyPropertyChanged). This feature is available for [PropR] and [PropW] properties.

    Property's lazy load feature: [PropLazyLoad]

    The [Prop] can be configured to implement a lazy load strategy where a user defined calculation routine [PropInternalCalc] can be connected. The [PropInternalCalc] is called whenever a client requests the value of a property whichs buffer is set to 'not loaded'. [PropBufNotLoaded], [PropBufLoaded]

    Property's auto-refresh feature: [PropRefresh]

    The framework implements a input-value-dependency-recorder [IVDR]. The recorder is activated whenever the [PropRead] interceptor catches such events.

    There are following conditions:

    • The property was called from an external client (for example a graphical user interface connected to a view-model) In this case the [IVDR] will record nothing.
    • The property was called from a [PropInternalCalc] routine In this case the [IVDR] will record a property to use an input value.

    Whenever a recorded input value is changed using [PropOBserve] the calculated properties buffer is reset to [PropBufNotLoaded] Afterward a change-event is sent via [PropObserve]. If a client is observing the property it will request the property value which again causes calling the [PropInternalCalc] routine to recalculate the property value.

    Propertiys user calculation routine [PropUDCalc]

    By default the [PropInternalCalc] is connected to a user defined calculation routine used to calculate values for properties. For example a [PropUDCalc] can be implement to calculate the total amount of a bill.

    Properties default value ffeature [PropDefCalc]

    Properties can be configured to use to use a routine for calculating default values. The [PropDefCalc] routine is called from [PropInternalCalc] if a domain object was newly created on the user interface. For example a [PropDefCalc] can implement a number generator to supply a value for a new customer.

    Properties new declaration feature [PropNewCalc]

    Properties can be configured always to contain a valid object avoiding Null-reference exceptions. This feature comes close to the 'New' declaration in vb6. (See the difference to the new-declaration in vb.net: In vb.net a object will not be re-created after it was set to nothing. The difference to the vb-language feautre is that the user can implement a [PropUDNewCalc] method for user defined creating objects.

    Propertie's inheritance feature [PropInherit]

    Properties can be automatically inherited from lower level objects. For example in a typical application looking at [PropObj] objects you have at least model layer and a view-model layer. [MVVM] In a typicall enterprise application you have an additional [ORMLayer]. Now the framework can inherit properties to generate code for your view model to read values from the model layer which again reads them from the [ORM]-layer. Doing so you get an application which provides a user interface to edit, load and save data from/to a relational database. For this you do not have to write code to redifne properties in the view-model or in the model.

    Properties validation feature [PropValCalc]

    Propertys can be configured to call a user defined property value validation rule. [PropValCalc] This validation rule is called by the framework in various cases. For example it is called before a property value is written. However, depending on the client some values don't have to be checked. Consider a graphical user interface where a user can select values from a predefined list. [PreDefList] In this case the validation rule for the value needs to be included in the list is not required to be executed. Now consider a data import from another system. In this case you should run all available validation rules to ensure the data imported will not cause your system or your business-workflow to be corrupted. Similar cases apply to date values which can/must contain or not contain various details. For example a date/time must may or must not contain a time but (only) a date. If you use Date/Time gui editors friend to the framework these checks are not necessarry. More complex and more expensive checks will occur when looking at business objects like an order, a shipping or things like that.

    Propertys predefined list feature [PreDefList]

    A special validation rule [PropValidate] exists to check for predefined values. However, these lists can be automatically mapped to the user interface.

    Propertys validation rule forwarding

    (todo)

    operation abstraction [OP]

    There exists an abstraction layer for all calculation routines ([PropInternCalc], [PropUDCalc], [PropNewCalc], [PropValCalc] (...)) This abstraction layer includes also command routines [CmdExecCalc], [CmdAvailCalc], [CmdErrCalc].

    Asynchronous [OP] feature.

    This whole section is proprietary. Especially problems arising from combining various [AsyncMirror]-Modes must be identified. The feature matrix may not include all [AsyncMirror]-Modes described herein.

    any [OP] operation can be declared to run asynchronously. [AsyncOp] In this case a property-client will trigger the process in the client-thread [ClientThread] when it invokes an [OP] on the supplier object. [AsyncSupObj] The framework will open up a thread-context for a background-worker [BwThread] in which the [Op] is executed.

    Have a look at the difference between Backgroundworker oriented Multithreaded programme [BwMultiThreading] [MicrosoftBWPhiliosphy] and message-oriented//state-based multithreaded programming [MsgMultiThreading]. The framework supports a combinatation of both paradigmas. MsgMultiThreading is primarly used in [ProgressAsyncPropMirror] where it is implemented by [BwMultiThreading] However to implement [InstructionAsyncPropMirror] a [message queue] has to be implemented.

    Before the [BWThread] context is opened various mirror objects will be created. Each mirror object in the [BWThread] represents a mirrorred object from the client thread. [MirrorObj] [MirroredObj] This mirror objects will be passed to the [BWThread] context so the [OP] executed asynchronously can use them. There is no on demand requesting mirrored objects by the [BWThread] from the [ClientThread] planned for now as it is not required in the concept, however, this would require the Framework implementation to use [MsgMultiThreading]

    Async-mirroring of Services [DIservice]

    The [BWThread] context contains mirrored representations of any service used by the calculation routine. [IVDR], [ServicePropBuf] To support this operation, services must implement the ICreateAsyncServiceMirror interface.

    The standard use case for this the service which manages the [OrmObjContext]. The ICreateAsyncServiceMirror will need to clone the object and copy the connection string. [DbConString] This allows to open new ORM-Object-Context [OrmObjContext] in the [BWThread].

    Async mirroring of [PropObj] objects. [PropAsyncMirror]

    First there will be a [clone] of the [AsyncSupObj] which will be sent to the [BWThread] for execution.

    There are serveral strategies a [Prop] can be mirrored:

    • No-Prop-Mirror

      In this case it is not possible to read or write an value from this property in the [BWThread].

      recalculated asnyc property mirror [RecalcAsyncPropMirror]

      In this case the properties in the [BWThread] will remain in [PropBufNotLoaded] state causing a [PropInternCalc] in the [BWThread]. This may load values from the [Db] which is quite critical in order you may get inconsistent states. It has to be verified if [RecalcPropMirror] is implemented.

      If this mode is exclusive and not combined with [ProgressAsyncPropMirror] property values can only be read in the [BWContext].

    • copy-loaded-async prop mirror [CopyLoadedAsyncPropMirror]

      In this case property values used by the calculation routine will be calculated in the [ClientThread] and transported to the [BWThread]. There may be conditions in the [PropInternCalc] routine which in various cases requires different input values. We need to know all input values to be copied to the [BwThread] context. Either the depending properties may be manually defined or a learning routine may use the [IVDR] executed within a testcase to learn all properties need to be copied to the [BWThread].

      However, in this mode only properties with [PropBufLoaded] state are copied. Other propertie's [PropInternCalc] are assumed to calculate the same value [PropInternCalc] or a value that is adequate in a asynchronous process.

      If this mode is exclusive and not combined with [ProgressAsyncPropMirror] property values can only be read in the [BWContext].

    • client-loaded async prop mirrior [CopyForceClientCalcAsyncPropMirror]

      This mode is similar to [CopyLoadedAsyncPropMirror] with the only difference, that [PropBufNotLoaded] values are loaded in the [ClientThread]. This is required for values calculated depending on input values from a view model. However, also this can be learned from [IVDR] executed from within a testcase.

      If this mode is exclusive and not combined with [ProgressAsyncPropMirror] property values can only be read in the [BWContext].

    • progress-asnyc-prop-mirror [ProgressAsyncPropMirror]

      In this mode property progress-values [ProgressVal] can be written in the [BWContext]. The new value effects the [PropBuf] of the [MirrorObj] which may cause recalc of other properties [PropRefresh] all running in the [BWThread]. The new value is also sent to the [ClientThread] where it will effect the [PropBuf] state of the [MirroredObj]. Analog [PropRefresh] sequences may be triggered in the [ClientThread].

      So writting a [ProgressVal] in the [BwThread] will first effect the state of the [MirrorObj] and (a little later) the state of the [MirroredObj]. [MirrorState], [MirroredState]. [AsyncStateInconsistent] can occur during these operations.

    • Instruction-async-prop-mirror [InstructionAsyncPropMirror]

      In this mode to the [MirroredState] will be transmitted to the [BWThread]. (reverse to the [ProgressAsyncPropMirror]. Again the [AsyncStateInconsistent] may occur.

    [AsyncStateInconsistent]

    In [ProgressAsyncPropMirror] there is a special case where a user has modified the [MirroredState] while the [ProgressVal] was calculated. This may cause the writting the [ProgressVal] to the [MirrorObj] to succedd but writting the [ProgressVal] to the [MirroredObj] will fail. A similar case causes this state during [InstructionAsyncPropMirror] operations.

    [AsyncStateInconsistentBwAbort]

    In case of [AsyncStateInconsistent] the [BWThread] has to be aborted and no more [ProgressVals] can be accepted to effect the [PropBuf] of the [MirroredObj].

    [AsyncStateInconsistentSavePrevention]

    In [AsyncStateInconsistent] optionally the [MirroredObj] can be set to a inconsistent state [MirroredObjInconsistent] where it is not allowed to be saved or modify persistent objects. However, if persistent objects have allready been modified they must be optionally prevented from beeing saved until the [BWTherad] terminated successfully. Defining these rules are very application specific and it is error prone for application developers to do this.

    [AsyncStateInconsistentNoPersistModifyPrevention]

    The framework may support to detect cases where [ProgressVal] effect the persistent state of an object and disallow this. This will avoid problems arising from missing [AsyncStateInconsistentSavePrevention]. This will cause the [AsyncStateInconsistentBwAbort] to take effect.

    Bi-directional Active object support [ActObj], [BiDiActObj]

    Active objects require a state machine in order to work properly. These state machines may be composed using the folliwing events:

    • Property [Prop].AsyncReadIsPending

      this property designates wether the property value is currently asyncronously laoded. [AsyncOp][PropInternCalc]

    • Property [Prop].AsyncWriteIsPending

      this property designates wehter the property value is currently transmitted to the other thread using [

    • [todo] events

    Active-object networks

    A simple case is an active object star-network [NetworkTopologies]. When nodes of the star start to open up [BiDiActObj] communications in a mesh or fully connected network this is very hard to control at some point. When doing so problems like deadlooks and race conditions start to become error causes. Thus such a terminology is not recommended and should not be required in our system. Compare the [BwMultiThreading].

    [OrmAdapter]

    [Todo]

    Literature

    [DICont] Microsoft tutorial for dependency injection
    [ORM] Wiki-article for object relational mapping
    Some well described object-relational design patterns
    [MVVM] blog article for how to use model-view-view-model architecture in microsoft presentation foundation guis
    [OrmAdapter] Wiki Article for the adapter pattern
    [Interceptor] Wiki article for the interceptor design pattern (Note we don't use it asynchrounously)
    [Observer] Wiki article for the observer pattern
    Description of the event keyword in visual basic
    [LazyLoad] Wiki article for the lazy load pattern
    [DbConString]Connection string examples
    [OrmObjContext] The .NET DataContext class
    [CLone]Wiki Article for the prototype pattern
    [Db]Wiki Article for Microsoft SQL-Server
    [BwMultiThreading] Microsoft article of how to use BackgroundWorker
    [MsgMultiThreading]Some links for massively asynchronous, message based multithreading
    [ActObj]Wiki Article for the Active-Object pattern
    [NetwiorkToplogies]Wiki Article for network topologies
    [Facade]Wiki Article for the facade pattern

    Montag, 29. März 2010

    2010-03-29-Vb20xx-Bottlenecks and traps using Linq with expensive select-expressions

    VersionDescription
    2010-03-29 T15:51:00Corrected formula for number of calls to new.

    Description:

    Implement Lazy-Load pattern for IEnumerator.Item[Get].

    Problem:

    If you are a linq-beginner there is something you should really be aware of before using it. Otherwise some day you may wonder about strange bugs or bad performance of your linq application.

    Starting with linq some months ago I meanwhile like it very much and went deeply in using Linq-querys for various use cases. I used the select expression also to instantiate objects as shown in the below code snippet. Doing so i walked in a trap because i was not aware, that the select expression is evaluated each time the object set is enumerated. Also complex queries may be evaluated very often which increases runtime costs when the result tree is not copied.

    Consider the following Vb.Net code:

     Dim aCount As Integer = (From aNum In New Integer() {1,2,3} Select New Object).Count

    This query seems ok, but the problem is, that new objects are instantiated each time the list is iterated and even if one uses the Count-extension-method. This results in a number of calls to new of n * c + n * i where n is the number of items in the list, c is the number of requests to the count method and i is the number of iterations. The required number of calls to new is more less equal to n.

    I now use following extension method to solve this problem and get the desired number of n calls to new:


     Module MyExtensions
      <System.Runtime.CompilerServices.Extension()>_
      Friend Function EvaluateItems(Of T)(ByVal aItems As IEnumerable(Of Func(Of T))) As IEnumerable(Of T)
       Dim aArray As T()
       Dim aCount As Integer = aItems.Count
       ReDim aArray(aCount - 1)
       Dim aIndex As Integer
       Dim aItem As Func(Of T)
       For Each aItem In aItems
        aArray(aIndex) = aItem()
        aIndex = aIndex + 1
        Next
       Return aArray
      End Function
     End Module

     Dim aQuery As IEnumerable(Of Func(Of Object)) = (From aNum In New Integer() {1,2,3} Select Function() New Object)  Dim aCount1 As Integer = aQuery.Count
     Dim aObjects As IEnumerable(Of Object) = aQuery.EvaluateItems
     Dim aCount2 As Integer = aObjects.Count

    With the obove code only n constructors calls occur where n is the number of objects in the list.

    However, i have one suggestions here.

    Of course it is necessarry that the select expression is evaluated each time the item is requested. However, this does not apply if the list is only enumerated using IEnumerator.MoveNext without using IEnumerator.Item[Get]. The Interface design is suitable for implementing a lazy load here but (linq)-implementations of IEnumerable do not follow this.

    I also wrote a extension method to (deep)-copy any IEnumerable tree for optimizing complex queries where updating is handled by the owner of the query result. The implementation quite tricky and not not so good so i don't post it here yet. Maybe Microsoft could provide a default extension method or a code snippet to do this.

    Beside of this i'd like to suggest linq to implement a lazy load in IEnumerator.Item.Get to allow iteration without evaluating the select expression. For example this is done when counting items or when requesting an item at the end of the object set using ElementAt. For some use cases (for example implementing paging) this behaviour is required.

    Solution:

    1a. Implement lazy load in certain IEnumerator.Item[Get] implementations. (For example Linq)

    Or

    1b. provide extension method to create a ghost-list.

    2. Provide a IEnumerable-Extension method which deep-copys items in an ienumerable (to an array) to avoid unneccesarry evaluations of the select expression.

    TestCase:


     Class C
      Public Sub New()
       InstanceCount = InstanceCount + 1
      End Sub
      Public Shared InstanceCount As Integer
     End Class

     Module Test

      Function MyCount(ByVal a As IEnumerable) As Integer
       Dim aCount As Integer
       Dim aEnumerator As IEnumerator = a.GetEnumerator
       While aEnumerator.MoveNext
        aCount = aCount + 1
       End While
       Return aCount
      End Function

      Sub Test
       Debug.Assert(3 = MyCount((From aNum In New Integer() {1,2,3} Select New C).CreateGhostList)
       Dim aSuggestionImplemented As Boolean = True
       If aSuggestionImplemented Then
        ' This will fail with Vb.Net 2010
        Debug.Assert(0 = C.InstanceCount)
       Else
        ' In Vb.Net 2010 using IEnumerator.MoveNext evaluates the Select expression of a linq-query.
        Debug.Assert(3 = C.InstanceCount)
       End If
      End Sub

      End Module

    Freitag, 5. März 2010

    Language integration of well know Design-Patterns

    Since the mid 70s or so design patterns have become a powerfull way of standardizing the static object model of a software application.

    I manage that there seems to be less awareness or understanding that for certain patterns there exist language integrations.

    For example since Microsoft Visual Basic 6 there exists the Keyword "Event". Using this single keyword you can define an observable object, and with another keyword (in vb.net it is 'Handles') you can define an Observer pattern in ~3 lines of code. Some years ago in c++ you may have written some hundred lines of code to do so.

    Look at the Decorator pattern. This pattern in fundamental way does just the same thing which you can implement in Aspect oriented languages which gives you much more power than standard implementations of the pattern could provide.

    Well, this whole thing is quite amazing. It boosts compactness of code to a quite high level. Compared to the code reduction you get generating Assembler code for a function or object this is quantum jump in the ongoing process of defining higher languages.

    I hope that more language integrations for well known patterns will become popular and some day we'll have language-integration lists for various patterns.

    The homogenity of languages goes on. Some years ago and nowadays industrial software projects may contain a dozens of proprietary interface definition languages and each step between languages or systems requires a lot of marshalling code which is not always generated. Think how many design patterns you use in one software project. May there be each or at least some design patterns implemented using a domain specific language or a special keyword? Well, using .NET Plattform you allready do it. Using Aspect J you allready do it.

    I'm thinking of a list of language integrations of well known patterns but compared to the number of patterns there seem to exist not too much for now.

    PatternLanguage integration
    GOF-ObserverMicrosoft VisualBasic "Event" Keyword/other clr-syntaxes
    GOF-DecoratorAspect oriented languages
    GOF-StateUML-Statemachine/other statemachines
    Reflection -Reflection-APIs of various languages (.NET/CLR, Java,c++ rtti ...)
    -Dynamic languages (in restricted way)

    Mittwoch, 24. Februar 2010

    2010-02-24-Vb20xx-reflapi-Karl-Michael Beck To LW

    Keywords

    • Type safe reflection api.
    • Inheriting from Generic-type-arguments

    version: 2010-02-24T23:15

    Hi L,
    I would suggest to implement an extended type system for compiletime checked type safety of code generators and other code using reflection.

    1. Problem: Reflection APi not type safe.

    A language integrated code generator and code based on reflection may want to use a reflection-api that supports compile-time checks. Using reflection is not type safe. If you accept an type object there are very often constraints to type objects valid for specific use cases. These constraints can be checked at runtime but there is no compiletime check for it.

    2. Problem: Inherit from generic-template-arguments

    As in c++ a class can be inherited from template arguments users may want to inherit from generic type parameters in vb. As vb supports type constraints for generic type arguments working with base type members inherited from generic type arguments can be compile-time checked.

    2. Solution: Provide a type safe reflection api.

    ' Begin Vb20xx
    Class B
    End Class
    Class C
      Inherits B
    End Class
    Class Demo
      Sub S
       Dim ob As B = New C ' valid cast: C is kind of B
       Dim oc As C = New B ' compiler error: B is not kind of C
       Dim tc As Type = GetType(B)
       Dim tb As Type(Of B) = GetType(C) ' Valid cast: C is kind of B
       Dim tc As Type(Of C) = GetType(B) ' Compiler error: B is not kind of C
      End Sub
    End Class
    ' End Vb20xx

    2. Solution: Inherit from generic-type-arguments.

    The mechanism needed to implement solution 1 has something todo with the ability to inherit from generic-type-arguments. This feature may also be public for the users. However, there must be some new layers for type-system implemented for the final type system requires to use this service.

    ' Begin Vb20xx
    Class C
    End Class
    Class G(Of T As C)
      Inherits T ' inherits any member in C and any member in T.
      Sub New()
       Dim c As C = Me ' Valid cast: T is constrained to C.
      End Sub
    End Class
    ' End Vb20xx

    Note: A Problem arising here is, that each member in the generic type must be implicitely declared as shadows. But i guess, together with a homogenous naming system this case is quite strange.