Control MA3 onPC with Akai APCmini mk2 (OSC) ArtGateOne

BECOME PART OF THE COMMUNITY - Sign up here
  • Hello - today I am presenting my solution for controlling MA3 onPC using the Akai APC mini mk2 MIDI controller.

    My previous solutions were based on web remote communication, but that is no longer possible because MA3 uses a video stream.

    For communication, I use my Node.js code, which handles sending and receiving OSC messages and MIDI control. On the MA3 side, there is a plugin running that sends OSC messages (thank you, Andreas!).

    With this setup, I have managed to achieve what I did with dot2 and MA2, which is controlling Action Buttons across multiple pages.

    To accomplish this, I created a view composed of several playbacks, displaying only the bottom buttons for each wing 1-6.

    The exception is Wing 1, which also displays the faders.

    I don't know if there is something in MA3 like in dot2, which allows a global fix (but one that can be applied only to a specific group of buttons/faders?), so the faders are FIXed so that you can still control them after switching the PAGE. This issue doesn't exist in my solution for BCF2000, as it has motorized faders that update elegantly.

    The program is very simple and free.

    Currently, I have achieved feedback for LED controls, control of Executors by specific number rather than sequence, and of course, control of the Grand Master and BO, as well as switching PAGEs 1-8, which is quite a lot.

    If Andreas can tell me how to get information about the color of Appearances and pages, I will add automatic coloring of the keys on the Akai side, just like I did for dot2 and MA2!

    Feel free to test it out.

    ma3 Akai apc mini mk2 - YouTube



    And this is PLUGIN

    local executor_table = {101,102,103,104,105,106,107,108,116,117,118,119,120,121,122,123,131,132,133,134,135,136,137,138,146,147,148,149,150,151,152,153,161,162,163,164,165,166,167,168,176,177,178,179,180,181,182,183,201,202,203,204,205,206,207,208}
    local osc_config = 2
    local history_fader, history_status = {}, {}
    local osc_template = 'SendOSC %i "/%s%i,i,%i"'
    local enabled = false
    local Printf, Echo, GetExecutor, Cmd, ipairs, mfloor = Printf, Echo, GetExecutor, Cmd, ipairs, math.floor

    local function send_osc(etype, exec_no, value)
     -- Printf(osc_template:format(osc_config, etype, exec_no, value))
     Cmd(osc_template:format(osc_config, etype, exec_no, value))
    end

    local function poll(exec_no)
     local exec = GetExecutor(exec_no)
     local value = exec and mfloor(exec:GetFader{} * 1.27) or -1
     local last_value = history_fader[exec_no]
     local status

     if not exec then
       status = -1
     else
       status = exec.Object and exec.Object:HasActivePlayback() and 1 or 0
     end

     local last_status = history_status[exec_no] 
     if value ~= last_value then
       send_osc('Fader', exec_no, value)
       history_fader[exec_no] = value
     end
     if status ~= last_status then
       send_osc('Key', exec_no, status)
       history_status[exec_no] = status
     end
    end

    local function mainloop() 
     while enabled do
       for _, exec_no in ipairs(executor_table) do poll(exec_no) end
       coroutine.yield(0.1)
     end
    end

    local function maintoggle() 
     if enabled then
       enabled = false
     else
       enabled = true
       history_fader, history_status = {}, {}
       mainloop()
     end
    end

    return maintoggle 

  • Hello Ladies and Gentlemen,

    I have just successfully completed my "program" for controlling the MA3 with the Akai APC Mini MK2.

    This is another release - this time we have a color version, which means our controller will show the appearance colors on our buttons!

    Happy testing!

    Remember - this is a free program!

    ArtGateOne/ma3apcmini: apcmini control ma3 osc midi (github.com)

  • This is a color osc plugin

    -- Define a table containing the executor numbers to be monitored
    local executor_table = {
    101, 102, 103, 104, 105, 106, 107, 108, 116, 117, 118, 119, 120, 121, 122, 123, 
    131, 132, 133, 134, 135, 136, 137, 138, 146, 147, 148, 149, 150, 151, 152, 153, 
    161, 162, 163, 164, 165, 166, 167, 168, 176, 177, 178, 179, 180, 181, 182, 183, 
    201, 202, 203, 204, 205, 206, 207, 208
    }

    -- Configuration for the OSC (Open Sound Control)
    local osc_config = 2

    -- Tables to keep track of the status and color
    local history_status, history_color = {}, {}

    -- Global variable to store the current page number
    local current_page = -1

    -- Template for the OSC message for executor status and color
    local osc_template = 'SendOSC %i "/%s%i,is,%i,%s"'

    -- Template for the OSC message for page number
    local osc_page_template = 'SendOSC %i "/%s,i,%i"'

    -- Flag to control the main loop
    local enabled = false

    -- Assign global functions to local variables for ease of use
    local Printf, Echo, GetExecutor, Cmd, ipairs, mfloor = Printf, Echo, GetExecutor, Cmd, ipairs, math.floor

    -- Function to pause the script for a given number of seconds
    local function pause(seconds)
    local start = os.clock()
    while os.clock() - start < seconds do end
    end

    -- Function to send OSC messages for key changes
    local function send_osc(exec_no, status, color)
    -- Format and send the OSC message for status and color changes
    Cmd(osc_template:format(osc_config, "Key", exec_no, status, color))
    end

    -- Function to send OSC messages for page changes
    local function send_osc_page(page)
    -- Format and send the OSC message for page changes
    Cmd(osc_page_template:format(osc_config, "Page", page))
    end

    -- Function to get color information for an executor
    local function get_color(exec_no)
    -- Default color is black
    local color = "#000000"

    -- Get the executor object
    local exec = GetExecutor(exec_no)
    if exec then
    local assigned_object = exec.Object
    if assigned_object then
    local appearance_object = assigned_object.Appearance
    if appearance_object then
    -- Format the color as a hexadecimal string
    color = string.format("#%02X%02X%02X", appearance_object.ImageR, appearance_object.ImageG, appearance_object.ImageB)
    end
    end
    end
    return color
    end

    -- Function to get the current page number
    local function get_current_page()
    local page = -1 -- Default page number if not available

    -- Use pcall to call CurrentExecPage safely
    local success, page_object = pcall(CurrentExecPage)
    if success then
    -- Ensure page_object is a string before processing
    local page_string = tostring(page_object)

    -- Extract the page number from the string "Page X"
    page = tonumber(page_string:match("Page (%d+)")) or page
    else
    Printf("Error retrieving current page number via CurrentExecPage.")
    end

    return page
    end


    -- Function to poll the executor and send updates if status, color, or page number has changed
    local function poll(exec_no)
    -- Retrieve the executor object
    local exec = GetExecutor(exec_no)
    local status

    if exec then
    -- Determine the status (1 if active playback, 0 otherwise)
    status = exec.Object and exec.Object:HasActivePlayback() and 1 or 0
    else
    -- If executor is not found, set status to -1
    status = -1
    end

    -- Retrieve the previous status and color from history
    local last_status = history_status[exec_no] or -1
    local last_color = history_color[exec_no] or "#000000"

    -- Get the current color of the executor
    local current_color = get_color(exec_no)

    -- Check if either status or color has changed
    if status ~= last_status or current_color ~= last_color then
    -- Send OSC message with current status and color
    send_osc(exec_no, status, current_color)
    -- Update history with current status and color
    history_status[exec_no] = status
    history_color[exec_no] = current_color
    end
    end

    -- Main loop to continuously poll executors and check for page changes
    local function mainloop() 
    while enabled do
    -- Check for page change
    local new_page = get_current_page()
    if new_page ~= -1 and new_page ~= current_page then
    send_osc_page(new_page)
    current_page = new_page
    end
       
    -- Poll each executor
    for _, exec_no in ipairs(executor_table) do
    poll(exec_no)
    end

    -- Pause for 0.1 seconds
    pause(0.1)
    end
    end

    -- Function to toggle the main loop on and off
    local function maintoggle() 
    if enabled then
    -- Disable the loop and clear history when turning off
    enabled = false
    history_status, history_color = {}, {}
    current_page = -1 -- Reset the page number
    else
    -- Enable the loop and start it when turning on
    enabled = true
    mainloop()
    end
    end

    -- Return the toggle function for external control
    return maintoggle

  • The following function hurts my brain, heart and soul:;(

    -- Function to pause the script for a given number of seconds
    local function pause(seconds)
      local start = os.clock()
      while os.clock() - start < seconds do end
    end

    to see how you actually are torturing you Lua engine, please change the function to:

    -- Function to pause the script for a given number of seconds
    local total = 0
    local function pause(seconds)
      local start = os.clock()
      local count = 0
      while os.clock() - start < seconds do count=count+1 end
      total = total + count
      Echo('to slow down the rest of the script I have just called os.clock %i times, totally so far: %i times', count, total) 
    end

    please please, pause your code by yielding the time back to the Lua engine, not by wasting processing-time inside your own script.

    local function pause(seconds)
      coroutine.yield(seconds)
    end

  • Small adjustments and additions to MA3 and APC Mini

    I have added code to support the older version of the APC Mini controller.

    I have added support for PAGE - now if you change the page on MA3, it will automatically refresh on the MIDI controller as well and highlight the appropriate page dot.

    The APC Mini OSC plugin supports basic 2-color functionality (it can be used with both the older and the MK2 versions of the APC), while the APC MK2 Color plugin is exclusively for MK2.

    Three main files:

    - For APC Mini basic version

    - For APC Mini MK2 with two colors

    - For APC Mini MK2 with multicolor support

  • v1.0.5

    Update for MA3 and APC mini - I have added a small modification that was previously available only in the version for dot2 - specifically, the Temp Fader. All the buttons above the faders now function as Temp Faders - with the difference that, upon release, the fader value returns to the previous value instead of being set to 0, as it happens in MA3, which annoys some users. So now you have additional functionality not available in the MA3 software

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!