Sequence file decoding on Arduino

Maybe I missed something. Are you planning on using the controller to play Vixen Sequences? Like a standalone controller mode or are you just looking to have the Arduino recieve sequence data just like Renard-basd controllers do?

Time to start cracking away at this piece of the puzzle. Question number one is what sequence file to use? I understand that Vixen uses base64 encoding. I found a base64 decoding library for Arduino. Is this the best route to take? Is there another file format that should be used?
 
Last edited:
Sorry, this will be a standalone player.

Although, I suppose another approach would be to have the arduino 'record' a datastream from a player pc and replay that stream along with the audio...
 
Sorry, this will be a standalone player.

Although, I suppose another approach would be to have the arduino 'record' a datastream from a player pc and replay that stream along with the audio...

Sounds cool. Looking forward to seeing it. Do you have a description somewhere of what you are building in terms of the controller? Will it play Audio as well? I believe Greg Bartlett has a similar configuraiton for his Helix stuff.

Kelly
 
Ok, back to work on decoding .vix files.

I made a simple sequence:
gPneO.png


Inside the .vix file you can see the base64 encoding

Code:
<EventValues>/////////////wAAAAAAAAAAAAD/////////////AAAAAAAAAAAAAAAcOFVxjarG4v8AAAAAAAAAAAAA/////////////wAAAAAAAAAAAACAgICAgICAgICAAAAAAAAAAAAAAP////////////8AAAAAAAAAAAAA/////////////wAAAAAAAAAAAAD/////////////AAAAAAAAAAAAAP////////////8AAAAAAAAAAAAApqampqampqampgAAAAAAAAAAAAA=</EventValues>

After decoding base64 to hex, I get the following:

Code:
ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 1c 38 55 71 8d aa c6 e2 ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 80 80 80 80 80 80 80 80 80 80 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 00 00 00 00 00 00 00 00 00 00


So it appears to me that the vixen saves all the data for the first channel, then moves to the next:

Channel1: ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 1c 38 55 71 8d aa c6 e2 ff
Channel2: 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 80 80 80 80 80 80 80 80 80 80 00 00 00 00 00 00 00 00 00 00
Channel3: ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff
Channel4: 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff ff ff ff 00 00 00 00 00 00 00 00 00 00 a6 a6 a6 a6 a6 a6 a6 a6 a6 a6 00 00 00 00 00 00 00 00 00 00
 
Last edited:
Instead of trying to get the the arduino to pull only the information it needs from the vixen file, I think it might be fruitful to just copy/paste the base64 needed for the arduino to read. Then have the track length and event period defined at the beginning of the sketch.

If this is too much work, I'll just figure out how to get the arduino to pull only the info it needs from the vixen file. It's just that the .seek() function really sucks because it will only accept an integer for the location in the file, and that location will always be different based on #of channels, track length, and event period...
 
Here's where I'm at so far with the code:

Code:
/*
 
 The circuit:
 * SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 10
 */

#include <SD.h>
//#include <Base64.h>
const int chipSelect = 10;
File vixlog;

void setup()
{
  Serial.begin(9600);
  Serial.print("Initializing SD card...");
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:

  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    return;
  }
  Serial.println("card initialized.");

  if (SD.exists("vixlog.txt"))
  {
    Serial.print("Deleting old vixlog.txt file...");
    SD.remove("vixlog.txt");
    Serial.println("finished.");
  }


  // open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  Serial.print("Creating new vixlog.txt file...");
  vixlog = SD.open("vixlog.txt", FILE_WRITE);
  vixlog.println("vixlog file initialized.");
  Serial.println("vixlog file initialized.");


  if (SD.exists("1.vix"))
  {
    vixlog.println("1.vix file found. Decoding...");
    Serial.println("1.vix file found. Decoding...");    

  }
  else
  {
    vixlog.println("ERROR - 1.vix - File not found.");
    vixlog.println("Ensure that the first vixen file you wish to play is named 1.vix");
    vixlog.println("Exiting...");
    Serial.println("ERROR - 1.vix - File not found.");
    Serial.println("Ensure that the first vixen file you wish to play is named 1.vix");
    Serial.println("Exiting...");
    vixlog.flush();
    vixlog.close();
    return;
  }

  vixlog.flush();
  vixlog.close();
  File vixen1 = SD.open("1.vix", FILE_READ);
  Serial.println("1.vix opened... ");
  if (vixen1) 
  {
    //note to self: Add 3
    vixen1.seek(102);
    while (vixen1.available()) 
    {
      
      Serial.write(vixen1.read());
    }

    Serial.println("end");
    //vixen1.seek(i);
  }


  //Conversion code goes here


  // vixlog.flush();
  //vixlog.close();
  vixen1.close();
}

void loop()
{
}
 
I believe you stated your intent was to run a Vixen sequence as a stand alone device.

I would suggest not attempting to use the Vixen data as it is currently encoded - you have to decode a complete channel before you get to the next channel - you don't have enough ram.

May I suggest decoding the Vixen bases 64 data on your PC and then recoded that data in a manner that can be placed in rom and read directly for each time slice each channel. That will minimize your ram requirements and speed up your processing.

The more work you can do to the data on the PC before you place it into rom - the better it will be for the micro.

Joe
 
I think you may be right. Perhaps I can convince one of my more proficient coding friends to write a quick app to convert the .vix files into something usable by the arduino.
 
If you can seek to an arbitrary point in the file in a reasonable amount of time, you could avoid the need to store the entire array of event data in RAM. It would take a little bit of arithmetic to figure out what the seek addresses should be, but not a particularly difficult procedure.

My feeling is the opposite about doing stuff on the PC, that it is best to leave the files unaltered, just copying them from one place to another.
 
If you can seek to an arbitrary point in the file in a reasonable amount of time, you could avoid the need to store the entire array of event data in RAM. It would take a little bit of arithmetic to figure out what the seek addresses should be, but not a particularly difficult procedure.

My feeling is the opposite about doing stuff on the PC, that it is best to leave the files unaltered, just copying them from one place to another.

I think if you look at the big picture - you are going to have to go to an intermediate PC step.

Depending on the number of channels and time slots in your sequence - I doubt you will have enough embedded rom to hold the data. Vixen data is not compressed - just base 64 encoded.

Build a PC program to decode Vixen's data - rearrange it so it's in channel time slot order and then perform a compression on that data.

Your PC program could then pack the data pre-formatted in a file ready for your Ardunio assembler/compiler.

In the micro - then all you have to do is un-compress each group of time slot data as required.

Unless you have external rom that can hold a lot of data - that is the only way I can see getting it into rom and then decoding it real time.

Joe
 
Joe beat me to it - I was going to suggest the same thing, except skip the compression.

As I understand it, the Arduino will be reading an SD card (so lots of space!) formatted in FAT32 (FAT16?) via SPI. For 16 channels in .VIX mode you would have to jump back and forth among 16 file pointers within that file (which means also reading and probably caching the FAT, perhaps thrashing the cache on a small processor even if your SD card library hides that detail from you). Then you have to sync up to a base 64 vs 8 bit boundary and start decoding - or keep your own 16 buffers of base64 and/or decoded binary files and append blocks to the end. It could be done and would be an interesting exercise to see what performance you get.

OR you can decode it on the PC and write a simple binary file to the SD card to be read sequentially. Number of channels, length and then all channels sequentially for each timeslot. Arduino loop consists of reading the next 16 bytes from the open file on the SD card and dimming the channels accordingly (8 bit binary data, no encoding).

The latter seems much simpler, but the former might be a more interesting technical challenge. Up to you.

In the latter case, a simple compression like run length encoding might reduce the file size (if you were to encode each channel), but it adds complexity with 16 state machines, etc - and the SD card should have plenty of space for the uncompressed sequences in binary mode so if you opt for re-encoding on the PC, I'd suggest simple naked binary.
 
Perhaps somewhere in the middle.

I think I will try to have the Arduino decode the vixen files and save the decoded data to the SD card as a separate file, say vixen1.avx or something. Then, upon entering the loop, the Arduino can just reference the new file for data. Maybe even make it two separate states.

If vixen1.avx exists, skip to loop. Else, decode vixen1.vix and save to vixen1.avx then reboot.
If I get it working, I'll really tax the Arduino to see what it's limitations are as far as decoding.

EDIT: BTW, cards must be formatted in FAT16
 
Last edited:
I broadened the scope just a bit, and have proposed a file format for the Arduino (BMP Ribbon) - and other micros - to play. I think it would fit this niche pretty well.

You could still do the conversion in the Arduino if you prefer. But I would expect this to become an output plugin for Vixen and others, and/or to have standalone programs to convert files. In fact, I would do that even if nobody used it on a micro, because I think it will be an interesting thing to view. treating the sequence as a color or monochrome image.

If this flies, the Arduino may have the first implementation - but probably not the last.

Have a look.
 
Am I doing this right, or is there a better way?

I'm trying to pick out the word 'Time' in the vixen file.

Code:
while (vixen1.available()) 
    {
      for (int i = 1; i >1000; i++)
      {
        char q;
        vixen1.seek(i);
        q = vixen1.read();
        if (q == 'T')
        {
          i++;
          vixen1.seek(i);
          q = vixen1.read();
          if (q == 'i')
          {
            i++;
            vixen1.seek(i);
            q = vixen1.read();
            if (q == 'm')
            {
              i++;
              vixen1.seek(i);
              q = vixen1.read();
              if (q == 'e')
              {
                //DO STUFF HERE
              }
            }
          }

        }
        i++
      }
 
I take all of that back, it seems that I can just do vixen1.seek('File') as I previously thought that I couldn't. This makes dealing with the vixen file MUCH easier :D
 
Will this work to pull the track length off of the vixen file?

Vixen file contents I'm after: <Time>5000</Time>

Code:
unsigned int trackLength = 0;
while (vixen1.available()) 
    {
      vixen1.seek('<Time>');
      int r = vixen1.position() + 1;

      while (vixen1.read() != '<')
      {
        trackLength = (trackLength * 10) + vixen1.read();
        r++;
      }
    }

EDIT: You're right Zeph, it's not working... back to the if statements...
 
Back
Top