Loopy Pro: Create music, your way.

What is Loopy Pro?Loopy Pro is a powerful, flexible, and intuitive live looper, sampler, clip launcher and DAW for iPhone and iPad. At its core, it allows you to record and layer sounds in real-time to create complex musical arrangements. But it doesn’t stop there—Loopy Pro offers advanced tools to customize your workflow, build dynamic performance setups, and create a seamless connection between instruments, effects, and external gear.

Use it for live looping, sequencing, arranging, mixing, and much more. Whether you're a live performer, a producer, or just experimenting with sound, Loopy Pro helps you take control of your creative process.

Download on the App Store

Loopy Pro is your all-in-one musical toolkit. Try it for free today.

Any apps that can read Ableton .als files?

1235

Comments

  • Which Software? What format? You can send me the project for analyzing? (Only if it is Groovebox, as i do not have Gadget)
    If it is Gadget can you set one up in Groovebox and link that here?

  • edited December 2019

    @MrBlaschke said:
    Which Software? What format? You can send me the project for analyzing? (Only if it is Groovebox, as i do not have Gadget)
    If it is Gadget can you set one up in Groovebox and link that here?

    PMed (as you know :))

  • edited December 2019

    @SpookyZoo
    Ok - got it. I identified that issue.
    Problem - The MIDIUtil library has no support for such stuff.
    Solution - I have to do time calculations for the notes/bars/and stuff.

    It is not impossible but i need some time for that. I now know what the issue is and have a theory how to deal with it.

    That is why the 2nd section is added on top of the first, because when it starts it is basically again at position „0“ - it does not really know in which section it is. That is where i have to generate hooks to act on.

    The most easy solution would be to write each section to a new track so one has to re-order them manually...that is not the nicest solution so i just use it as a fallback.

    Hang on there - it might work out the next days.

  • @MrBlaschke said:
    Which Software? What format? You can send me the project for analyzing? (Only if it is Groovebox, as i do not have Gadget)
    If it is Gadget can you set one up in Groovebox and link that here?

    @MrBlaschke said:
    @SpookyZoo
    Ok - got it. I identified that issue.
    Problem - The MIDIUtil library has no support for such stuff.
    Solution - I have to do time calculations for the notes/bars/and stuff.

    It is not impossible but i need some time for that. I now know what the issue is and have a theory how to deal with it.

    That is why the 2nd section is added on top of the first, because when it starts it is basically again at position „0“ - it does not really know in which section it is. That is where i have to generate hooks to act on.

    The most easy solution would be to write each section to a new track so one has to re-order them manually...that is not the nicest solution so i just use it as a fallback.

    Hang on there - it might work out the next days.

    All good.

    Amazing functionality as it stands already.

    Great work! :)

  • -Woop- -Woop- Thanks @White :smile:

  • @SpookyZoo
    Man - that was a thing. As i had no clue of the internal Ableton data this needed a complete rewrite of the parsing engine.
    Literally you can now export the whole song to a separate MIDI file. I can not place cuts for the individual scenes as that is not supported in the library but you can chop that up in your MIDI editor of choice i guess.
    Maybe i can find some way to annotate cuts - i have to investigate that.

    New code is ready to be cleaned and coming later tonight - i guess.

    I think the new version got it right:

    Scene1:

    Switching to Scene2:

    Scene2:

    Converted and imported to Xequence

    As we deal with XML-standards this should work just fine with Gadget-files also - actually with any standard Ableton XML export, no matter where it comes from.

    @rs2000 @_ki @White @Svetlovska

  • edited December 2019

    Here you go (again)

    The new version supporting scenes inside clips. Should do a complete song export.
    Errors and/or problems -> get in touch. I‘ll see what i can do.

    @_ki Would you please update the WIKI again. *prettypleasewithcheeseontop* :smile:

    # Ableton MIDI clip zip export to MIDI file converter
    # Original script by MrBlaschke
    # Usability enhancements by rs2000
    # Dec 11, 2019, V.04
    #
    # greatly enhanced version that handles multiple scenes and clip offsets
    # resulted in new parser engine
    # request by @SpookyZoo
    #
    # Original request and idea by Svetlovska
    
    import sys
    import os
    import tempfile
    import xml.etree.ElementTree as ET
    import xml.etree as XTree
    from xml.etree.ElementTree import fromstring, ElementTree
    import console
    import io
    import appex
    import ui
    from zipfile import ZipFile
    from zipfile import BadZipfile
    import gzip
    import binascii
    from time import sleep
    #custom (newer) version - ahead of the Pythonista version
    #get the code from: https://github.com/MarkCWirt/MIDIUtil/blob/develop/src/midiutil/MidiFile.py
    #switch to the "RAW" mode and copy all you see on that big text-page
    #place it in the "Python Modules/site-packages-3" directory
    #in a new file called "midiutil_v1_2_1.py"
    from midiutil_v1_2_1 import MIDIFile
    
    
    
    def main():
        if not appex.is_running_extension():
            print('This script is intended to be run from the sharing extension.')
            return
    
        # Catch zip file from external "Open in..." dialog
        inputFile = appex.get_file_path()
        outfile = os.path.splitext(os.path.basename(inputFile))[0] + ".mid"
        targetCC = -1
    
        #some global cleverness - digital post-it's
        haveZIP = False
        haveGadget = False
        try:
            with ZipFile(inputFile) as zf:
                print("Info: we have a real ZIP archive")
                haveZIP = True
        except BadZipfile:
            print("Info: It is an ALS or Gadget file")
    
        if inputFile.endswith(".zip") and haveZIP == True:
            print("Importing ZIP archive...")
            with ZipFile(inputFile, 'r') as ablezip:
    
                # Iterate over the list of file names in given archive
                # filter out possible hidden files in "__MACOSX" directories for manually created ZIPs, etc
                listOfiles = ablezip.namelist()
                for elem in listOfiles:
                    if not elem.startswith("__") and elem.endswith(".als"):
                        #print('Found:', elem, end=' ')
                        infile = ablezip.extract(elem)
        elif inputFile.endswith(".als"):
            infile = inputFile
            with open(infile, 'rb') as test_f:
                #Is true if file is gzip
                if binascii.hexlify(test_f.read(2)) == b'1f8b':
                    print("Input is Gadget ALS file")
                    haveGadget = True
                    with gzip.open(inputFile, 'rb') as f:
                        gadgetContents = f.read().decode("utf-8")
                else:
                    print("Input is plain ALS file")
        else:
            print("filetype not supported...")
            sys.exit()
    
    
        track           = 0
        channel         = 0
        time            = 0     # In beats
        duration        = 1     # In beats
        tempo           = 60    # In BPM
        volume          = 100   # 0-127, as per the MIDI standard
    
        toffset                 = 0         # for calculating time-offsets in multi scenes
        timeoff                 = 0         # store for temp offsets
    
        #Parse the data/file because parsing strings will not clean up bad characters in XML
        if haveGadget == True:
            #some people need always special treatment - handle them with care...
            tree = ElementTree(fromstring(gadgetContents))
        else:
            tree = ET.parse(str(infile))
    
        root = tree.getroot()
        #getting the tempo/bpm (rounded) from the Ableton file
        for master in root.iter('Tempo'):
            for child in master.iter('FloatEvent'):
                tempo = int(float(child.get('Value')))
    
        #get amount of tracks to be allocated
        for tracks in root.iter('Tracks'):
            numTracks = len(list(tracks.findall('MidiTrack')))
            print('Found',str(numTracks),'track(s) with', tempo, 'BPM')
    
        #Preparing the target MIDI-file
        MyMIDI = MIDIFile(numTracks, adjust_origin=True)        #tempo track is created automatically
        MyMIDI.addTempo(track, time, tempo)
    
        #Give me aaaallll you've got
        for miditrack in root.findall('.//MidiTrack'):
            #resetting the time offset data
            toffset = 0
            timeoff = 0
    
            #getting track data (name, etc)
            for uname in miditrack.findall('.//UserName'):
                trackname = uname.attrib.get('Value')
                print('\nProcessing track: ', trackname)
                MyMIDI.addTrackName(track, 0, trackname)
    
            for clipslot in miditrack.findall('.//MainSequencer/ClipSlotList/ClipSlot'):
                #looping the amount of clips
                for midiclip in clipslot.findall('.//ClipSlot/Value/MidiClip'):
                    #raising the time offset for the next clip inside this track
                    toffset = toffset + timeoff
    
                    #get the clip-length
                    for loopinfo in midiclip.findall('.//Loop'):
                        le = loopinfo.find('LoopEnd')
                        #store the next time offset
                        timeoff = float(le.attrib.get('Value'))
    
                    for noteinfo in midiclip.findall('.//Notes/KeyTracks'):
                        print('\tAmount of note events: ', len(noteinfo.getchildren()))
    
                        for keytracks in noteinfo:
                            for key in keytracks.findall('.//MidiKey'):
                                keyt = int(key.attrib.get('Value'))
                                print('\t\tProcessing key: ', str(keyt))
                            #getting the notes
                            for notes in keytracks.findall('.//Notes/MidiNoteEvent'):
                                tim = float(notes.attrib.get('Time')) + float(toffset)
                                dur = float(notes.attrib.get('Duration'))
                                vel = int(notes.attrib.get('Velocity'))
                                MyMIDI.addNote(track, channel, keyt, tim, dur, vel)
    
                    #getting automation data
                    for envelopes in midiclip.findall('.//Envelopes/Envelopes'):
                        for clipenv in envelopes:
                            #get the automation internal id
                            autoid = int(clipenv.find('.//EnvelopeTarget/PointeeId').attrib.get('Value'))
                            if autoid == 16200:            #pitchbend
                                targetCC = 0
                                print('\tFound CC-data for: Pitch')
                            elif autoid == 16203:          #mod-wheel
                                targetCC = 1
                                print('\tFound CC-data for: Modulation')
                            elif autoid == 16111:          #cutoff?
                                targetCC = 74
                                print('\tFound CC-data for: Cutoff')
                            else:
                                targetCC = -1
                                print('\n!! Found unhandled CC data. Contact developer for integration. Thanks!')
    
                            #get the automation values for each envelope
                            for automs in clipenv.findall('.//Automation/Events'):
                                for aevents in automs:
                                    eventvals = aevents.attrib
                                    ccTim = float(eventvals.get('Time'))
                                    ccVal = int(eventvals.get('Value'))
                                    if ccTim < 0:
                                        ccTim = 0   
    
                                    #writing pitchbend informations
                                    if targetCC == 0:
                                        MyMIDI.addPitchWheelEvent(track, channel, ccTim, ccVal)
    
                                    #writing other CC values
                                    if targetCC != -1 and targetCC != 0:
                                        MyMIDI.addControllerEvent(track, channel, ccTim, targetCC, ccVal)
            track = track + 1
    
        with tempfile.NamedTemporaryFile(suffix='.mid') as fp:
            MyMIDI.writeFile(fp)
            fp.seek(0)
            fp.read()
            # Open the MIDI file in your app of choice - aka 'bring out the gimp'
            console.open_in(str(fp.name))
            #closing and deleting the temporary file
            fp.close()
            print ('done.')
    
    if __name__ == '__main__':
        main()
    
    

    Have fun!
    -MrBlaschke

  • _ki_ki
    edited December 2019

    @MrBlaschke You don't have to ask. I started with the wiki page and feel responsible to keep it up to date :)

    Using the wiki is no magic at all, every forum user can log into it using the same username and pass as on the forum.
    Goto the page and press edit. On that page the source code is wrapped inside a <file py ALS_to_MIDI.py> ... ... </file>. Just clear everything between these tags and then insert the new raw code, enter 'Script updated' as edit comment and press 'Save' (Or if you want to be sure, first use the preview button) - and done.

  • No, no - thank you for this cool script and putting work and time into it 👍🏻

    BTW i din‘t find time yet to do more Gadget exports, but weekend is comming...

  • @MrBlaschke said:
    @SpookyZoo
    Man - that was a thing. As i had no clue of the internal Ableton data this needed a complete rewrite of the parsing engine.
    Literally you can now export the whole song to a separate MIDI file. I can not place cuts for the individual scenes as that is not supported in the library but you can chop that up in your MIDI editor of choice i guess.
    Maybe i can find some way to annotate cuts - i have to investigate that.

    New code is ready to be cleaned and coming later tonight - i guess.

    I think the new version got it right:

    Great work! This whole thread is just awesome. :)

  • @MrBlaschke : wow, a credit in software for me! Thank you. Trust me when I say that is the only way my name is ever getting anywhere near computer code. I’m honoured! (Blushing). Thank you all for your amazing work on this, it has been a joy to behold. :)

  • Late to the show here but

    Thank You for this.

    Seriously, @MrBlaschke and @Svetlovska and everyone who jumped in and encouraged this madness.

    I had been lurking these forums for a couple months and came across this a few weeks back (with same problem) by like the 2nd page I stopped everything and went to sign up here.

    It’s pretty nerdy but ppl here will understand- how great it was reading the way this unfolded. This is a good place.

    So I hate to ask this because I think out of principal I will get pythonista and try to learn how to set this up. But being someone who knows next to nothing about coding, would it be easier if I could get my hands on Ableton light? My brother is a more serious producer and he’s got Ableton and so much gear I feel like there is probably a free demo somewhere.
    I have no problem at all paying the $9 for pythonista I’m more concerned about my ability to get even basic code setup properly ( although I followed the thread closely so I get the general steps )

    Anyway, this was an awesome thing to watch happen and the least I can do is try to figure out how to make use of this code.

    Having access to my groovebox projects as midi files would be my number 1 wish if a little Steve Jobs genie appeared out of my lightning connector port right now and this was pretty close to that. Thanks!

  • @LowMoses
    Don't be afraid to set this up. It is really easy. Just follow the few steps and you're good to go. You do not need to code or understand the code.

  • @MrBlaschke Thanks! I’m going to do it

  • So I just discovered this amazing amazing engineering feat by you guys!!!!
    this is awesome made my night now I can export some sweet midi from groove box and get my funk on. you guys rock.

  • Hey @onerez So you’ve got it up and running? Good stuff!

  • Must of missed this news last year looks a cool way of exporting midi around apps.

  • @SpookyZoo said:
    Hey @onerez So you’ve got it up and running? Good stuff!

    Yes took me a bit as the wiki I was not getting at fist. But I have a tendency to skim read. LOL. It’s great.

  • Great thread!
    The ABL2MIDI - Ableton Export to MIDI Converter: Discchord link looks useful. Thanks for making this!

  • edited October 2020

    iPad apps that can export Ableton Live Set (*.als) files:

    There's an outdated list on the Ableton site.

    • Ampify/Novation Blocs Wave Apple App Store: Exports audio only, to Files Apps, etc.
    • Ampify/Novation Groovebox Apple App Store: Exports both audio and MIDI, to Files Apps, etc.
    • Dmitrij Pavlov Groove Rider GR-16 Apple App Store: Exports audio only, to Files Apps, etc.
    • Korg Gadget 2 Apple App Store: Exports audio or MIDI, not both at once, and only to Dropbox or iTunes File Sharing, which is inconvenient and takes too long. Each individual audio clip is exported, even if they're identical.
    • Olympia Noise Co Patterning 2 Apple App Store
  • Whose the heck happenin hu
    Yeah my developedmentor is away studying for a real job
    So I have to do all this math myself & I’m too old & off the cuff to interpret- regardless I so appreciate you all & quadrilliotlie appreciate the work … butt a hu ? There’s not a simpler way to get what was paid for …. & actually “states” it …well …, , it’LL {will} do ???(come on old school punk rocker here ??!! ) wwhy don’t we hit them all at once for not providing what they say there app oll do ? ) [just food for thought ] (it does say render ‘midi” only though ….just sayin … don’t wanna stir up any unwanted decent ;hint,hint — it’s not like hundreds of people ignorant of how or what they were paying for ;nudge , nudge ,know what I mean : wink ,wink ; not like we were coerced into paying for something that it says it will do and didn’t …………WINK,wink …do you know what I mean “

    All in good fun {but not ;if you know what I mean ;wink,wink ,Nudge nudge , com’mon ……way too common}

  • @MrBlaschke or some of the other great minds in here…. I have been spending a lot of time on my new MAC and been using Logic a lot!!…. But I would love to be able to convert the Groovebox ALS file on my mac instead of doing shortcut here and then sending the midi over to MAC. Is there a way other then ableton to get the midi out on desktop?

    Thanks!

  • @onerez
    As this is based on Python you should be good to go on your Mac using the exact same thing with some OS specific changes - but i am sure they are minimal.
    If i remember correctly macOS still has a python included - if not there are macOS installers available from the python site.

  • Haven’t go patterning, does it export als with midi> @MrBlaschke said:

    @onerez
    As this is based on Python you should be good to go on your Mac using the exact same thing with some OS specific changes - but i am sure they are minimal.
    If i remember correctly macOS still has a python included - if not there are macOS installers available from the python site.

    Pythonista will also run on M1 Macs although I haven’t tried the script on there yet.

  • @GrimLucky said:
    Haven’t go patterning, does it export als with midi> @MrBlaschke said:

    Yep…

  • Stumbled upon this thread yesterday and had a go at converting an .als from Groovebox to MIDI. Ended up getting an error that may be related to the step of, “select site-package-3 as output folder and press 'Create'”. In this step there is only site-package folder with numerous other folders in it, so I just used the site-packages main folder. Wondering if anyone can help figure out what I did wrong.

    The error I get is:
    Info: we have a real ZIP archive
    Importing ZIP archive...
    Found 4 track(s) with 96 BPM

    Processing track: Horizon MIDI
    Traceback (most recent call last):
    File "/private/var/mobile/Containers/Shared/AppGroup/DD7D5B44-3EF8-4B46-87E6-81E54F278568/Pythonista3/Documents//ALS_to_MIDI.py", line 200, in
    main()
    File "/private/var/mobile/Containers/Shared/AppGroup/DD7D5B44-3EF8-4B46-87E6-81E54F278568/Pythonista3/Documents//ALS_to_MIDI.py", line 140, in main
    print('\tAmount of note events: ', len(noteinfo.getchildren()))
    AttributeError: 'xml.etree.ElementTree.Element' object has no attribute 'getchildren'

  • First, try commenting out line 140 with a #

    I had a similar issue when I first tried to use the script and I think that was the only line I needed to comment out to get it working. The script was broken with an updated version of Python in which the getchildren function can no longer be used.

Sign In or Register to comment.