Import/Export WAV files to/from Aeros

Forgot to include a more concrete example at the end of my previous brain dump:

[MAGIC_NUMBERx1 = 0x0a]
[TITLExN]
[HEADER x20]
[STEREO_TRACKS_FLAG_TAG = 90 01 01]
[ADDITIONAL_INFO_TAG = 98 01 02]
    [UNDECIPHERED_BYTES = a2 01 02 00 00 8a 06]
    [ORIGINATOR_FIRMWAREx20 = "4.14.108-aeros-4.0.2"]
[PARTS_LIST_TAG = 90 06 06]
    [PART_TAG = 9a 06 XX]
        [TRACK_TAG = 9a 06 XX]
            [UNDECIPHERED_BYTES x4] [OPTIONAL_MEASURE_COUNT x1]
            [CHANNEL_A_UNDECIPHERED_BYTES x8] [CHANNEL_A_FILENAME xN]
            [CHANNEL_B_UNDECIPHERED_BYTES x8] [CHANNEL_B_FILENAME xN]
    [PART_TAG = 9a 06 XX]
        [TRACK_TAG = 9a 06 XX]
            [UNDECIPHERED_BYTES x4] [OPTIONAL_MEASURE_COUNT x1]
            [CHANNEL_A_UNDECIPHERED_BYTES x8] [CHANNEL_A_FILENAME xN]
            [CHANNEL_B_UNDECIPHERED_BYTES x8] [CHANNEL_B_FILENAME xN]

And to tease you, here’s the output of my (python) tool parsing one of my test files:

[INFO ]  --- Analyze meta song_2/.meta
[DEBUG]  Running with song_2/.meta at song_2
[INFO ]  Parts list object found
[INFO ]   - Part object found, 0x60
[INFO ]     - Track object found, 0x2d
[DEBUG]     - Track object has measure count, 2
[INFO ]     - Track object found, 0x2d
[DEBUG]     - Track object has measure count, 2
[INFO ]   - Part object found, 0x60
[INFO ]     - Track object found, 0x2d
[DEBUG]     - Track object has measure count, 2
[INFO ]     - Track object found, 0x2d
[DEBUG]     - Track object has measure count, 2
[INFO ]  Meta file parsed structure:
{'fileHeaderByte': 10,
 'title': 'song_2',
 'metaRaw': b'\x15\x00\x00\xc8B\x1a\x04\x08\x04\x10\x04X\x18h\x01p\x01\x80\x01j',
 'stereo': True,
 'beatsPerMinute': 100.0,
 'fileListIndex': 106,
 'timeSignatureNumerator': 4,
 'timeSignatureDenominator': 4,
 'partsObject': {'header': b'\x90\x06\x06',
                 'filepos': 62,
                 'parts': [{'header': b'\x9a\x06`',
                            'filepos': 65,
                            'tracks': [{'header': b'\x9a\x06-',
                                        'filepos': 68,
                                        'metaRaw': b'\x08q\x18\xc0',
                                        'measureCount': 2,
                                        'expectedChannels': 2,
                                        'channels': [{'filepos': 76,
                                                      'metaRaw': b'R\x12\x08\xc8\xf8\x0c\x12',
                                                      'filename': 'song_2/CHASP1T1.wav'},
                                                     {'filepos': 96,
                                                      'metaRaw': b'Z\x12\x08\xc8\xf8\x0c\x12',
                                                      'filename': 'song_2/CHBSP1T1.wav'}]},
                                       {'header': b'\x9a\x06-',
                                        'filepos': 116,
                                        'metaRaw': b'\x08q\x18\xc0',
                                        'measureCount': 2,
                                        'expectedChannels': 2,
                                        'channels': [{'filepos': 124,
                                                      'metaRaw': b'R\x12\x08\xc8\xf8\x0c\x12',
                                                      'filename': 'song_2/CHASP1T2.wav'},
                                                     {'filepos': 144,
                                                      'metaRaw': b'Z\x12\x08\xc8\xf8\x0c\x12',
                                                      'filename': 'song_2/CHBSP1T2.wav'}]}]},
                           {'header': b'\x9a\x06`',
                            'filepos': 164,
                            'tracks': [{'header': b'\x9a\x06-',
                                        'filepos': 167,
                                        'metaRaw': b'\x08q\x18\xc0',
                                        'measureCount': 2,
                                        'expectedChannels': 2,
                                        'channels': [{'filepos': 175,
                                                      'metaRaw': b'R\x12\x08\xc8\xf8\x0c\x12',
                                                      'filename': 'song_2/CHASP2T1.wav'},
                                                     {'filepos': 195,
                                                      'metaRaw': b'Z\x12\x08\xc8\xf8\x0c\x12',
                                                      'filename': 'song_2/CHBSP2T1.wav'}]},
                                       {'header': b'\x9a\x06-',
                                        'filepos': 215,
                                        'metaRaw': b'\x08q\x18\xc0',
                                        'measureCount': 2,
                                        'expectedChannels': 2,
                                        'channels': [{'filepos': 223,
                                                      'metaRaw': b'R\x12\x08\x9b\xf8\x0c\x12',
                                                      'filename': 'song_2/CHASP2T2.wav'},
                                                     {'filepos': 243,
                                                      'metaRaw': b'Z\x12\x08\x9b\xf8\x0c\x12',
                                                      'filename': 'song_2/CHBSP2T2.wav'}]}]}]},
 'unknownSection1': {'header': b'\x90\x01\x01', 'filepos': 28, 'metaRaw': None},
 'originator': {'header': b'\x98\x01\x02',
                'filepos': 31,
                'metaRaw': b'\xa2\x01\x02\x00\x00\x8a\x06',
                'originatorFirmware': '4.14.108-aeros-4.0.2'}}

I’ve only checked it with quantised 2x2 files so far; but I don’t expect 6x6 or freeform to be wildly different.

I don’t require money for this work (if I want cash for development work, I’ve got my day-job :-)), but the offer is worth a lot more to me. Knowing that it is useful work to other Aeros users is actually the thing that encourages me, so thank you very much for your support and comments.

4 Likes

The first thing my mentor on my first computer programming gig (1965) taught me was to punch sequence numbers in columns 73-80 so that if we dropped a deck we could use the card sorter to put 'em back in order.

My last punched card Cobol program was a Fortran Syntax Analyzer that was 4 boxes long - 3,000 cards. When I developed it on a Burroughs time-shared computer on-line, compile took 5 minutes. When I ported it to a stand-alone IBM SYS360, compile took 25 minutes. That was the difference between Borroughs’ excellent design and IBM’s crap.

Aloha, mi amigo!

This user also appreciates your effort.

It’s a sign of our times with lawyers and bean counters running everything - they can’t seem to understand the concept of Community or collective effort and responsibility.

Even though Cobol was marketed as a “self documenting language”, that was a cruel joke. Incompetent programmers could and did write spaghetti code in Cobol just as easily as they can in Fortran, Java or “C”. In fact, the project I was describing in my other email (3,000 punched cards) was the syntax analyzer section of Autodoc – an “automatic” documentation processor written in COBOL that would take COBOL, Fortran or IBM360 BAL programs as input and produce flowcharts and variable cross reference lists, etc. to satisfy corporate “documentation” requirements. I designed and programmed the analyzers for Fortran and 360BAL in COBOL. COBOL is a lousy language for string manipulations… :wink:

Snobol and Foxpro are MUCH better!

I started college as a computer science major. My first school (1984) was still using punch cards. I have a MS in Geology.

:joy::joy::joy: ours was an IBM… i don’t remember the model number but initially it could not sort!

I took the ONLY computer course at Ga Tech in my last quarter there - Math 441 - learned Algol on a Burroughs B6500.

Enjoyed the programming so much I dropped out and got a full-time job as a programmer in the Physics Dept at Univ of Florida in 1965.

The IBM 082 card sorter was a stand alone and very cool piece of gear.

I used to go into the computer room once in a while with a deck I just scrambled just to see it work. Very, very cool.

I used an IBM 29 Card Punch.

Had to type accurately, no do-overs.

https://www.ibm.com/ibm/history/exhibits/vintage/vintage_4506VV4002.html

Since we still used cards for some jobs, we still had one hanging around the mainframe shop I worked at in the early 80s.

So, when’s the Punch Card based Looper hitting the market? I hear they are set to replace the hand cranked music box. :rofl: I’m not going to lie, if you posted a video on YouTube that said “Punch card looping cover” of any song, I’m going to click.

2 Likes

:joy::joy::joy: good one!

We used punch cards at Tufts for my undergrade years. Went to BC in 1984 for my MBA and discovered a revolution: the hammer hits the movie screen and Bong! Welcome, my name is McIntosh! I was an assistant professor in my second year MBA and loved to introduce the Mac to freshman. The course was all abiut learning lo learn how to use a computer, the Mac, without assistance, or very little, and just using intuition. Those were fun days! First music software I ever used: midipaint, and then Concertware + midi, Vision, Studio Vision etc…. Everyday was a new discovery as music began to rely on computers for recording and programing synths. When the first samplers came out, I was shocked! How could anyone use a sound that they take from someone else? I thought part of music creativity was making your own sounds programming synths… sort of like Keith Richard trying to find that next lick that would go into a hit and bezt George or Eric to shame :joy: fun…. Fortunately the music is all still there to keep us happy and smiling through harder times even though the technology as evolved so much! Aeros! BB, MM…. Cool stuff. Just wish we wouldn’t be paying to be beta testers for units that are not ready or up to advertised specs when they hit the market… that is something that should really be regulated… next thing we know we will be beta testing washing machines, ovens, cars before they should be allowed to hit the market. I bought SS products as an end user. Not a tester.

Good reading all of your stories and experiences. Cool community!

Update: I’ve been looking at 6x6 files.

It’s becoming clearer why Singular didn’t want to help with this; why they think “documenting” it would take their developers so long. It’s also becoming clearer why they are in such development hell, this file format is an utter mess, I can’t imagine what spaghetti they have hidden away to parse such a monstrosity.

I’d say this to Singular though: “it’s never the crime, it’s the cover up”. We all already know the code is going to be a mess, so hiding it isn’t keeping that secret. You will still help my efforts here even if it’s embarassing to you, and I think that you will look better for it.

Here’s the first track of a 6x6:

0a
.  s  o  n  g  _  9
06 73 6f 6e 67 5f 39
.  .  .  .  B  .  .  .  .  .  .  X  .  p  .  .  .  q
15 00 00 c8 42 1a 04 08 04 10 04 58 18 70 01 80 01 71
.  .  .
90 01 01
.  .  .  .  .  .  .  .  .  .  .  .  .  .
98 01 02 a2 01 06 00 00 00 00 00 00 8a 06
         .  4  .  1  4  .  1  0  8  -  a  e  r  o  s  -  4  .  0  .  2
         14 34 2e 31 34 2e 31 30 38 2d 61 65 72 6f 73 2d 34 2e 30 2e 32
.  .  .
90 06 06
         .  .  .  .   .  .  0  .  q  .  `      R  .  .  .  .  .  .  .  C  H  A  S  P  1  T  1  .  w  a  v  .  .
         9a 06 a2 02  9a 06 30 08 71 18 60     52 14 08 d8 bd 06 12 0c 43 48 41 53 50 31 54 31 2e 77 61 76 18 01
                                               Z  .  .  .  .  .  .  .  C  H  B  S  P  1  T  1  .  w  a  v  .  .
                                               5a 14 08 d8 bd 06 12 0c 43 48 42 53 50 31 54 31 2e 77 61 76 18 01

Here’s the “unusual” observations so far:

  • I’ve previously seen start-of-part tags 9a 06 2f9a 06 60; now I’ve got 9a 06 30 appearing as a start-of-track tag. These tags are therefore context-dependent. Which means a parser can’t just read the next tag to determine what the content is going to be because it can be different depending on where it appears.
  • For the first time in any .meta these two channel records (and only these two in the file) have these strange 18 01 bytes at the end. Maybe that’s special to a 9a 06 30-as-track-tag record? Why are they needed only on this track though and what could they possibly represent?
  • I’ve not confirmed yet, but it seems that the measure counter is a single byte. If that’s so, then there is a hard limit on how long a track can be, and it’s well within human limits (10-20m depending on how it’s encoded, and the BPM)
  • BPM is stored as BPM*2 in byte [3] of the song header (it’s possible some of those zero bytes change my point here). Don’t know if anyone remembers my trying to explain to @BrennanSingularSound why storing times as reciprocals was a bad idea… well this is it. Let’s say you record a track at 100.75 BPM … you’ve tap tempoed it in to make sure you match up with some stuff the rest of the band is gonna do; or you’ve recorded a backing track that isn’t exactly on 0.5 of a BPM. Aeros is incapable of storing that song accurately. Worse, because it’s reciprocal, the error in time units gets bigger as you lower the BPM. For the future then Singular: store the time of a beat as a time, not as a reciprocal. Use more than one byte for it. Use microseconds if you must – bytes are not precious in this application

One that’s got me a bit stumped (brains appreciated on this one) is deciphering the length of channel field. It’s already weird that they’re storing a length for the channel rather than for the track – it means it’s possible to make a file where the two channels within a track have different lengths. But even weirder is that the length of the channel is in bizarre units. The bytes in question are 3,4,5 of the 7 byte channel header.

 Measures      Size   0  1  2     3  4  5     6      [5:3]=S
--------- ---------  -- -- -- -- -- -- -- -- -- -- ---------
 1@100bpm   318,600  52 12 08    d8 bd 06    12      441,816
 2@100bpm   636,120  52 12 08    c8 f8 0c    12      850,120
 3@100bpm   953,640  52 12 08    b8 b3 13    12    1,291,192
 4@100bpm 1,271,160  52 12 08    a8 ee 19    12    1,699,496
 8@100bpm 2,541,240  52 12 08    e8 d9 33    12    3,398,120
16@100bpm 5,081,400  52 12 08    e8 b0 67    12    6,795,496

Those three bytes are pretty clearly 24-bits little-endian, which I’ve expaned to decimal in the last column. I’ve put the size of the data section of the wav file in as the size column and shown the number of measures (all at 100bpm).

If you plot the size coulmn as a function of measures then we get

size = 317520*m + 1080

this is perfect. 317520 is 3 bytes per sample, 44100 samples per second, 60/100 seconds per beat, four beats. 1080 is 360 samples at 3 bytes per sample – exactly what the Aeros pads with.

Now, while there is clearly correlation with the number of measures and the S column, it’s not perfectly linear. A spreadsheet regression gives

S = 424688*m + 11666.66666666

But this is not correct for literally any value of m (+/- 12,000ish), it’s only the line of best fit. That’s leaving me not knowing what this field represents other than it’s clearly related to waveform length.

Unfortunately this is pretty fundamental. I’m at the point where I think I could write the rest of the file out and it would work. While I don’t understand every byte, those that I don’t understand don’t seem to change song-to-song. But this field is, I think, the one that Aeros uses to validate the wav file when it loads. (To be honest, if Singular are storing the size of the wavform in the meta file that is also gonna be a source of bugs for them – the file is was it is, that should be combined with the BPM to say how long the track is in musical units, storing another version of it is just creating ambiguity). My instinct is that this is a bug; but maybe I’m missing something so I’m gonna put it out there to you guys.

So: I’ve heard all your good stories about punched cards. That tells me you guys know about bytes and hex and binary and bit fields and encoding data so it gets nice and small. Find me the relationship between waveform size and this channel meta-field (it does stand out that they are all divisible by 8).

Did you suss out what the bytes are for specifying a locked track? There is nothing else specific to a track or channel that I can think of through empirical examination other than that. And the locked track must also cut across each part or track object in some way. Maybe those extra bits have something to do with that?

I’ve been asked not to make comments on the quality of singular’s code. So I’ll be stopping my commentary here.

We do not accept any criticism that is seen as an attack on our codes or our team. We encourage you all to continue the conversation in a way that is constructive to the company because we intend to use it to help us grow.

It’s the weekend guys, I’m using my free time to tell you:

We have moved forward on this internally, we will have a full official response next week

We do plan on helping @kingofthejaffacakes but I personally cannot give a greenlight and there were some internal questions we had to answer. I cannot move the team right now, it is the weekend.

No, the code is not corrupted and it is not spaghetti

We have a full plan and schedule which is working tightly to get everyone the features they need, it takes time to get away from that to change gears in any way. We apologize if the time it took seemed like we don’t care.

Thank you all for your feedback and most importantly your patience.

1 Like

Hello Brennan

Any full official response on this yet? Its been next week for a while now.

best regards

Sorry forgot to respond here:

We are open to sharing the file that “decodes” the binary format across the forum, but have not done so yet. It is not a priority and it does not really benefit users since we are doing this feature ourselves anyways.

The only reason it reads in binary as of now is not to hide the code but to make it lighter.

This is what the dev told me.

If you would like to have this file, please DM me. Thanks

1 Like