mozaic_include_migration_mananger

Mozaic: Include Snippet - Migration Manager

The Migration Manager (Include) is a code snippet that allows to migrate script parameters between different script versions. You just need to add 2 event calls and define 4 events for callbacks.

One can easily state-safe a script and reload its full settings including the scripts source into another Mozaic instance - but if you load a newer version of the script or minimaly change the source and do an 'upload', all your precious settings are lost. The Migration Manager allows to recover all settings from another instance.

  • Before loading a new script version, save the to-be-preseved configuration to a new preset name (either in the host or in Mozaic)
  • Update the script to the new version by loading the script - this will come up with the scripts default settings
  • Turn the IMPORT knob of the script
  • Open a second Moazic instance and load the saved configuration, you have ten seconds to do this
  • The new version will pick up the configuration and you are ready to go

If you are a script dev, you can use this feature to fast-restre your settings after you minimally changed code and hit 'UPLOAD'. Just keep the 'sender' instance open and reload it when importing to the receiver.

  • Your script should have many parmeters, more than you would like to dial in manually either when updating or for every test during development the script
  • Updating of the script should be intended or likely


You can either grab the snippet from one of the example scripts where you find the to-be-included snippet below the line

  >>>>>>>> MIGRATION MANAGER INCLUDE <<<<<<<<

at the end of the example - check that you found the current v1.2 snippet code.

Or you copy the code from the large code block at the end of this page to the end of your own script.

  • In the @OnLoad, right at the start call @MigrationManagerInit and at the end setup your unique script's id and call @MigrationManagerOnLoad.
  • Add an 'IMPORT' knob in your scripts GUI and call @MigrationManagerOnImport to start importing if the knob is turned.
  • Your scipt also needs to define the 4 event functions @MigrateSend, @MigrateRead, @MigrateImportDone,@MigrateExportDone that will be called by the Migration Manager.

Right at the start of this event function add

Call @MigrationManagerInit

to initialize all variables.

At the end of your @OnLoad, setup you scripts unique id and

Call @MigrationManagerOnLoad

for the optinal sending of data

There are three types of scripts

  1. ) Your script doesn't define an own OnTimer
  2. ) Your script defines an own OnTimer, which is already running at this point and which has an intervall less than 200
  3. ) Your script defines an own OnTimer, but its either with a slower interval (>200) or it only runs conditional

Only scripts of type 3) need to add the IF block after the Call @MigrationManagerOnLoad that temporary sets up a faster timer timer interval and start the timer if upon this 'upload' another instance is waiting for a transmission.
After migration is finished (takes several timer events), the @MigrateExportDone event is called, where you can undo these temporary changes

  mmScriptId    = 0xDEAA0 // Please choose an new unique number up to 24bits !
  mmScriptTimer = YES     // YES if script defines an own timer. Remove the line or 
                          // set to NO if Migration Manager should manage the timer
  Call @MigrationManagerOnLoad 
  if mmIsMigrating
    // This code is of type 3) (own slower timer, and not yet running)
    SetTimerInterval 50
    StartTimer
  endif

Each script needs to use an own unique mmScriptId. There could be several totally different scripts including the Migration Manager Snippet loaded in a single AUv3 host session, therefore the scripts unique id is used to identify other instances of this specific script and to ensure the scripts ‚own‘ data is received. The id can be understood as „sender/receiver name or address“ of a script, the Migration Manager only connects scripts with identical mmScriptId. A later change of the id for a script already in use is not advisable as the data of older saved instances can no longer be imported. The maximum value for mmScriptId is 24bits or 6 hex chars (0x000100 to 0xFFFF80)


Reserved mmScriptId‘s

The following mmScriptId ranges are already in use by other scripts and should be avoided:

mmScriptId end of range script
0x4200 0x420F MS6 SysEx Performance Editor and Spatial Processor
0xDEAA0 0xDEAAF Migration Manager Demo
0x4D4D43 0x4D4D4F Midi Multicast
0x50C001 0x50C01F MutatoR

When your script uses an own timer like in type b) or c), make sure to wrap your original OnTimer code into an IF block like shown below.

During both migration directions (send of read part) the timer needs to be running and calling the Migration Manger

@OnTimer 
  if mmIsMigrating
    Call @MigrationManagerOnTimer  
  else
    // Code you already had in your timer
  endif
@End

If the knob ideally labeled 'IMPORT' is turned, you can add the following code to initiate the receiving of data and additionally support double-tap

   _knob = LastKnob
   _val  = GetKnobValue _knob
   
   if _knob = 1
   ...
   elseif _knob = 2 and _val >= 64    // IMPORT knob with double-tap feature
    SetKnobValue 2, 127              // Turn knob to 'on' position
        
    Call @MigrationManagerOnImport   // Call the import manager

    // For a script of type 3) you need to temporary modify the timer interval and start it
    SetTimerInterval 50
    StartTimer    
  endif  


The transmission happens in the two user events @MigrateSend and @MigrateRead by copying to/from the global98 array, one set of variables on each call.

Internally the MigrationManager uses the global97 array to drive the communication, calling your event functions several times until all data is transmitted.

Input: pIdx
Output: pType, global98

The pIdx identifies the parameter to be transfered, the index starts with your unique script-id and is incremented on every transmission step. You code needs to fill in global98 and copy pIdx into pType - to indicate the end of transmission, set pType to MIGRATION_DONE

@MigrateSend // params: pIdx     output: pType, global98
  pType = pIdx                     // Transfer preset data one by one
  if pIdx = mmScriptId 
    CopyArray data,global98,16     // First transfer 16 entries of 'data'

  elseif pType = mmScriptId +1
    CopyArray things,global98,16   // Then transfer 16 entries of 'things'

  elseif pType = mmScriptId +2
    CopyArray stuff,global98,16    // On third call transfer 16 entries of 'stuff'
  
  elseif pType = mmScriptId +3
    global98[0] = color_code       // On fourth call transfer single entry for colorCode
    
  else
    pType = MIGRATION_DONE         // The last call signals end of transmission
  endif
@End

Input: pType, global98x

The MigrationRead event function is called after the sender updated the data supplying a pType parameter specifiying the content of global98 array.

The MIGRATION_DONE is not forwarded to this event, but instead @MigrateImportDone is called

@MigrateRead // params: pType, global98
  if pType = mmScriptId            // Receive is analogous
    CopyArray global98,data,16     // First call copy into 16 'data' entries

  elseif pType = mmScriptId +1
    CopyArray global98,things,16   // Second call copy into 16 'things' entries

  elseif pType = mmScriptId +2
    CopyArray global98,stuff, 16   // Third call copy into 16 'stuff' entries
  
  elseif pType = mmScriptId +3
    color_code = global98[0]       // Last call restores the colorCode entry
  endif
@End

If you need to transfer more variables, just add them accordingly to both MigrateRead and MigrateSend, using the same offset in both events.

For version updates, only add new variables at the end of the IF-cascade and take care of filling in default values for variables that an older script version might not supply.

At the end of an importing transmission started by a call to @MigrationManagerOnImport, the @MigrateImportDone event is called by the Migration Manager.

If your script is of type 3), then this is the place to undo the temporary timer settings

@MigrateImportDone // param pType (either MIGRATION_DONE or MIGRATION_ERROR)
  if pType = MIGRATION_DONE
    // Call your scripts redraw functions to show the changed state to the user
  endif
  
  // Don't forget to re-position the IMPORT knob
  SetKnobValue 2,0
  
  // This sample code is for type 3) (own slower timer, not running 
  //    after OnLoad), we need to restore the original settings
  SetTimerInterval 1000
  StopTimer 
@End

At the end of an exportingtransmission started by a call to @MigrationManagerOnLoad in the @OnLoad, the @MigrateExportDone event is called by the Migration Manager.

If your script is of type 3), then this is the place to undo the temporary timer settings

@MigrateExportDone // param pType (either MIGRATION_DONE or MIGRATION_ERROR)
  // This sample code is for type c) (own slower timer, not running 
  //    after OnLoad), we need to restore the original settings
  SetTimerInterval 1000
  StopTimer
@End



// ╔╦╗┬┌─┐┬─┐┌─┐┌┬┐┬┌─┐┌┐┌  ╔╦╗┌─┐┌┐┌┌─┐┌─┐┌─┐┬─┐
// ║║║││ ┬├┬┘├─┤ │ ││ ││││  ║║║├─┤│││├─┤│ ┬├┤ ├┬┘
// ╩ ╩┴└─┘┴└─┴ ┴ ┴ ┴└─┘┘└┘  ╩ ╩┴ ┴┘└┘┴ ┴└─┘└─┘┴└─
// =================== V 1.2 ======================

@MigrationManagerInit
  MIGRATION_RUNNING = -1     // mmState and message type
  MIGRATION_ERROR   = -2
  MIGRATION_DONE    = -7
   
  MM_MAGIC  = 0              // Offsets in global97[ ]
  MM_READER = 1
  MM_SCRIPT = 2
  MM_TYPE   = 3
  MM_ACK    = 4
  MM_SENDER = 5
  
  MM_MAGIC_ID = 0x15EEC0DE   // Magic number for MigrationManager

  mmActive   = NO
  mmRead     = NO
  mmState    = MIGRATION_DONE
  mmInstance = Random 1, 1000
  if Unassigned mmScriptTimer
    mmScriptTimer = NO
  endif
  mmIsMigrating = NO  
@End

@MigrationManagerOnLoad
  if Unassigned mmScriptId
    Log {📦 MigrationManager v1.2: ‼️ mmScriptId not initialized}
  elseif Unassigned mmIsMigrating
    Log {📦 MigrationManager v1.2: ‼️ @MigrationManagerInit not called before @MigrationManagerOnLoad}    
  else
    mmIsMigrating = NO 
  
    // Starting with about 7 hex digits, Mozaic can no longer correctly add small
    // values due to its limited internal number range
    // As the unique script id is later incremented for each message, better test
    // beforehand, if the value is still in range for math operations
    mmIdx = mmScriptId +1
    if mmIdx - mmScriptId <> 1
      Log {📦 MigrationManager v1.2: ‼️ mmScriptId value too high}
    else        
      mmIdx = mmScriptId      
      
      if global97[MM_MAGIC]<>MM_MAGIC_ID
        Log {📦 MigrationManager v1.2: OnLoad - No receiver waiting}  
      elseif global97[MM_SCRIPT]<>mmScriptId
        Log {📦 MigrationManager v1.2: OnLoad - Wrong receiver waiting}
      elseif global97[MM_SENDER]<>0 or global97[MM_TYPE]<>0
        Log {📦 MigrationManager v1.2: OnLoad - Another migration ongoing}
      else    
        global97[MM_SENDER] = mmInstance
        mmState   = MIGRATION_RUNNING
        mmActive  = YES
        mmRead    = NO 
        mmTimeout = SystemTime + 500

        mmIsMigrating = YES
        if mmScriptTimer = NO
          Log {📦 MigrationManager v1.2: Start Migration with own timer event}            
          SetTimerInterval 50
          StartTimer
        else
          Log {📦 MigrationManager v1.2: Start Migration using scripts timer event}    
        endif        
      endif
    endif
  endif
@End

@MigrationManagerOnImport
  if Unassigned mmScriptId
    Log {📦 MigrationManager v1.2: ‼️ mmScriptId not initialized}
  elseif Unassigned mmIdx
    Log {📦 MigrationManager v1.2: ‼️ @MigationManagerOnLoad was not called}
  
  elseif mmState<>MIGRATION_RUNNING
    FillArray global97, 0
    FillArray global98, 0
    global97[MM_MAGIC]  = MM_MAGIC_ID
    global97[MM_READER] = mmInstance
    global97[MM_SCRIPT] = mmScriptId
    // MM_SENDER, MM_TYPE and MM_ACK are zero fromm the FillArray above
    
    mmActive  = YES
    mmRead    = YES
    mmState   = MIGRATION_RUNNING
    mmTimeout = SystemTime + 10000
    if mmScriptTimer = NO
      Log {📦 MigrationManager v1.2: Waiting for data with own timer event}    
      SetTimerInterval 50
      StartTimer
    else
      Log {📦 MigrationManager v1.2: Waiting for data using scripts timer event}    
    endif  
   mmIsMigrating = YES
  endif
  
  if not mmActive
    mmIsMigrating = NO
    pType = MIGRATION_ERROR
    Call @MigrateImportDone
  endif
@End

@OnTimer
  Call @MigrationManagerOnTimer
@End

@MigrationManagerOnTimer
  if Unassigned mmActive
    mmActive = NO
  endif
  
  if mmActive 
    Call @MMTimerVerifyConnection  
  
    if mmState <> MIGRATION_ERROR
      if mmRead
        Call @MMTimerRead
      else
        Call @MMTimerSend
      endif
    endif

    if SystemTime > mmTimeout
      Log {📦 MigrationManager v1.2: ‼️ Timeout}    
      mmState = MIGRATION_ERROR
      if mmScriptTimer = NO
        StopTimer
      endif
    endif
  
    if mmState <> MIGRATION_RUNNING
      mmIsMigrating = NO          
      if mmRead
        pType = mmState
        Call @MigrateImportDone
      else
        pType = mmState
        Call @MigrateExportDone        
      endif
      
      if mmScriptTimer = NO
        StopTimer
      endif
      
      if mmRead or mmState = MIGRATION_ERROR
        FillArray global97,0
        FillArray global98,0
        mmActive = NO 
      endif
    endif
  endif
@End

@MMTimerVerifyConnection
  if global97[MM_MAGIC]<>MM_MAGIC_ID 
    mmState = MIGRATION_ERROR
    Log {📦 MigrationManager v1.2: ‼️ Communication broken - Magic of msg block changed}

  elseif  global97[MM_SCRIPT]<>mmScriptId
    mmState = MIGRATION_ERROR
    Log {📦 MigrationManager v1.2: ‼️ Communication broken - ScriptId of msg block changed}

  elseif (not mmRead) and global97[MM_SENDER]<>mmInstance
    mmState = MIGRATION_ERROR
    Log {📦 MigrationManager v1.2: ‼️ Communication broken - SenderId of msg block changed}

  elseif mmRead and global97[MM_READER]<>mmInstance
    mmState = MIGRATION_ERROR
    Log {📦 MigrationManager v1.2: ‼️ Communication broken - ReaderId of msg block changed}
  endif
@End

@MMTimerSend   // OnLoad
  if global97[MM_TYPE]=global97[MM_ACK]
  
    pIdx  = mmIdx
    pType = MIGRATION_ERROR
    Call @MigrateSend
    global97[MM_TYPE] = pType
      
    if pType = MIGRATION_ERROR
      mmState = pType
      Log {📦 MigrationManager v1.2: ‼️ MigrateSend didn't set pType for pIdx=},pIdx  
        
    elseif pType = MIGRATION_DONE    
      mmState = pType
      Log {📦 MigrationManager v1.2: Migration succesful}    
      
    else
      Log {📦 MigrationManager v1.2: - Send },mmIdx - mmScriptId
      mmIdx = mmIdx + 1   // Inc clips at 65536 per default    
      mmTimeout   = SystemTime + 250        
    endif
  endif      
@End

@MMTimerRead    // OnImport
  pType = global97[MM_TYPE]
  if pType=MIGRATION_DONE
    mmState = pType
    Log {📦 MigrationManager v1.2: Migration succesful}    
    
  elseif pType=MIGRATION_ERROR
    mmState = pType
    Log {📦 MigrationManager v1.2: ‼️ Communication broken}    

  elseif pType<>0 and pType<>global97[MM_ACK]
    Call @MigrateRead
    global97[MM_ACK] = pType
    Log {📦 MigrationManager v1.2: - Read },pType - mmScriptId
    mmTimeout = SystemTime + 250              
  endif  
@End

// =================== END ============================
// ╔╦╗┬┌─┐┬─┐┌─┐┌┬┐┬┌─┐┌┐┌  ╔╦╗┌─┐┌┐┌┌─┐┌─┐┌─┐┬─┐
// ║║║││ ┬├┬┘├─┤ │ ││ ││││  ║║║├─┤│││├─┤│ ┬├┤ ├┬┘
// ╩ ╩┴└─┘┴└─┴ ┴ ┴ ┴└─┘┘└┘  ╩ ╩┴ ┴┘└┘┴ ┴└─┘└─┘┴└─
  • mozaic_include_migration_mananger.txt
  • Last modified: 2021/07/16 22:20
  • by _ki