unravel C++ function

I have a C++ function and want to convert it to Max but to do that I need to understand what its doing, I know its creating a special textual file for a piece of hardware.

I need help understand the file writing for want of a better word encoder.

#include "otwriter.h"

const unsigned char header_bytes[] = {0x46,0x4F,0x52,0x4D,0x00,0x00,0x00,0x00,0x44,0x50,0x53,0x31,0x53,0x4D,0x50,0x41};
const unsigned char unknown_bytes[] = {0x00,0x00,0x00,0x00,0x00,0x02,0x00};

OTWriter::OTWriter(const QString fileName, const int sampleRate, const Loop_t loopSetting, const Stretch_t strechSetting, const TrigQuant_t trigQuantSetting, int gain, int tempo)
{
    this->fileName = fileName;
    std::fill_n((char*)&otData, sizeof(otData), 0);
    memcpy(&otData, header_bytes, 16);
    memcpy(&otData.unknown, unknown_bytes, 7);

    this->tempo = tempo;
    this->sampleRate = sampleRate;
    this->gain = gain;
    this->loopSetting = loopSetting;
    this->stretchSetting = strechSetting;
    this->trigQuantSetting = trigQuantSetting;
}

void OTWriter::updateData()
{
    otData.tempo = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(tempo*6) : tempo*6;
    // calculate bars from BPM, sampleRate and audioLength and round off to closest .25
    int bars = ((tempo*totalSampleCount)/(sampleRate*60.0*4)) + 0.5;
    bars *= 25;
    otData.trimLen = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(bars) : bars;
    otData.loopLen = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(bars) : bars;
    otData.loop = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(loopSetting) : loopSetting;
    otData.stretch = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(stretchSetting) : stretchSetting;
    otData.quantize = trigQuantSetting;
    otData.gain = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ushort(gain + 48) : gain + 48;

    if (tempSlices.count() > 1)
    {
        for (int i = 0; i < tempSlices.count(); i++)
        {
            otData.slices[i].startPoint = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(tempSlices[i].startPoint) : tempSlices[i].startPoint;
            otData.slices[i].endPoint = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(tempSlices[i].endPoint) : tempSlices[i].endPoint;
            otData.slices[i].loopPoint = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(tempSlices[i].loopPoint) : tempSlices[i].loopPoint;
        }
        otData.sliceCount = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(tempSlices.count()) : tempSlices.count();
    }
    else
        otData.sliceCount = 0;
    otData.trimEnd = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ulong(totalSampleCount) : totalSampleCount;
    setChecksum();
}

void OTWriter::write(uint32_t totalSamples)
{
    this->totalSampleCount = totalSamples;
    updateData();
    QFile file(fileName);
    file.open(QIODevice::WriteOnly);
    QDataStream outStream(&file);

    outStream.writeRawData((char*)&otData.header, sizeof(otData.header));
    outStream.writeRawData((char*)&otData.unknown, sizeof(otData.unknown));
    outStream.writeRawData((char*)&otData.tempo, sizeof(otData.tempo));
    outStream.writeRawData((char*)&otData.trimLen, sizeof(otData.trimLen));
    outStream.writeRawData((char*)&otData.loopLen, sizeof(otData.loopLen));
    outStream.writeRawData((char*)&otData.stretch, sizeof(otData.stretch));
    outStream.writeRawData((char*)&otData.loop, sizeof(otData.loop));
    outStream.writeRawData((char*)&otData.gain, sizeof(otData.gain));
    outStream.writeRawData((char*)&otData.quantize, sizeof(otData.quantize));
    outStream.writeRawData((char*)&otData.trimStart, sizeof(otData.trimStart));
    outStream.writeRawData((char*)&otData.trimEnd, sizeof(otData.trimEnd));
    outStream.writeRawData((char*)&otData.loopPoint, sizeof(otData.loopPoint));
    outStream.writeRawData((char*)&otData.slices, sizeof(Slice)*64);
    outStream.writeRawData((char*)&otData.sliceCount, sizeof(otData.sliceCount));
    outStream.writeRawData((char*)&otData.checkSum, sizeof(otData.checkSum));
    file.close();
}

void OTWriter::setChecksum()
{
    uint16_t value = 0;
    unsigned char* bytePos = reinterpret_cast<unsigned char*>(&otData);
    for (int i = 16; i < sizeof(otData) - 2; i++)
        value += bytePos[i];

    otData.checkSum = SYSTEM_USE_LITTLE_ENDIAN ? _byteswap_ushort(value) : value;
}

void OTWriter::addSlice(uint32_t start, uint32_t end)
{
    Slice slice;
    slice.loopPoint = 0xFFFFFFFF;
    slice.startPoint = start;
    slice.endPoint = end;
    this->tempSlices.append(slice);
}

'*************************************************************

#ifndef OTWRITER_H
#define OTWRITER_H

#include <QString>
#include <QFile>
#include <QTextStream>
#include <QVector>
#include <stdint.h>
#include <intrin.h>

#define OTFILESIZE 832
#define SYSTEM_USE_LITTLE_ENDIAN 1

enum Loop_t { NoLoop = 0, Loop = 1, PIPO = 2 };
enum Stretch_t { NoStrech = 0, Normal = 2, Beat = 3 };
enum TrigQuant_t { Direct = 0xFF, Pattern = 0,S_1=1,S_2=2,S_3=3,S_4=4,S_6=5,S_8=6,S_12=7,S_16=8,S_24=9,S_32=10,S_48=11,S_64=12,S_96=13,S_128=14,S_192=15,S_256=16};

#pragma pack(push)
#pragma pack(1)
struct Slice
{
    uint32_t startPoint;
    uint32_t endPoint;
    uint32_t loopPoint;
};

struct OTData {
    uint8_t header[16];  // 0x00
    uint8_t unknown[7];  // 0x10 (All blank except 0x15 = 2)
    uint32_t tempo;      // 0x17 (BPM*24)
    uint32_t trimLen;    // 0x1B (value*100)
    uint32_t loopLen;    // 0x1F (value*100)
    uint32_t stretch;    // 0x23 (0ff = 0, Normal = 2, Beat = 3)
    uint32_t loop;       // 0x27 (Off = 0, Normal = 1, PingPong = 2)
    uint16_t gain;       // 0x2B (0x30 = 0, 0x60 = 24 (max), 0x00 = -24 (min))
    uint8_t quantize;    // 0x2D (0x00 = Pattern length, 0xFF = Direct, 1-10 = 1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256)
    uint32_t trimStart;  // 0x2E
    uint32_t trimEnd;    // 0x32
    uint32_t loopPoint;  // 0x36
    Slice slices[64];    // 0x3A - 0x339
    uint32_t sliceCount; // 0x33A
    uint16_t checkSum;   // 0x33E
};
#pragma pack(pop)

class OTWriter {

public:
    OTWriter(const QString fileName, const int sampleRate, const Loop_t loopSetting, const Stretch_t strechSetting, const TrigQuant_t trigQuantSetting, int gain, int tempo);
    void write(uint32_t totalSamples);
    void addSlice(uint32_t start, uint32_t end);
private:
    void updateData();
    void setChecksum();

    uint32_t totalSampleCount;
    QString fileName;
    int sampleRate;
    int tempo;
    int gain;
    Loop_t loopSetting;
    Stretch_t stretchSetting;
    TrigQuant_t trigQuantSetting;
    QVector<Slice> tempSlices;
    OTData otData;
};


#endif // OTWRITER_H

Open in new window

PeterBaileyUkAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

NerdsOfTechTechnology ScientistCommented:
This looks like this has music related functions

Looks like the Write function in particular outputs a music data file of type, tempo, loop segments, and other various attributes of the underlying music.
0
Karrtik IyerSoftware ArchitectCommented:
Hi Peter, Do you want a line by line explanation of code, or is there some particular function in the code pasted above you want us to explain? Along with C++, it is using QT libraries and data types as well for file writing. I have tried explaining each line of the write function below.

void OTWriter::write(uint32_t totalSamples)
{
    this->totalSampleCount = totalSamples; // This set the class member variable totalSampleCount to input passed.
    updateData();// Update the OTDATA which is what is written to your file
    QFile file(fileName);//declaring a QT File variable with file name required
    file.open(QIODevice::WriteOnly); // Open the file in write mode (access)
    QDataStream outStream(&file); // (Create a output stream and associate it to the file so that data written to stream is file sent to file)

    //Below lines of code write all the required member variables of OTDATA to te file by pass the address and size of each variable of OTData
    outStream.writeRawData((char*)&otData.header, sizeof(otData.header));
    outStream.writeRawData((char*)&otData.unknown, sizeof(otData.unknown));
    outStream.writeRawData((char*)&otData.tempo, sizeof(otData.tempo));
    outStream.writeRawData((char*)&otData.trimLen, sizeof(otData.trimLen));
    outStream.writeRawData((char*)&otData.loopLen, sizeof(otData.loopLen));
    outStream.writeRawData((char*)&otData.stretch, sizeof(otData.stretch));
    outStream.writeRawData((char*)&otData.loop, sizeof(otData.loop));
    outStream.writeRawData((char*)&otData.gain, sizeof(otData.gain));
    outStream.writeRawData((char*)&otData.quantize, sizeof(otData.quantize));
    outStream.writeRawData((char*)&otData.trimStart, sizeof(otData.trimStart));
    outStream.writeRawData((char*)&otData.trimEnd, sizeof(otData.trimEnd));
    outStream.writeRawData((char*)&otData.loopPoint, sizeof(otData.loopPoint));
    outStream.writeRawData((char*)&otData.slices, sizeof(Slice)*64);
    outStream.writeRawData((char*)&otData.sliceCount, sizeof(otData.sliceCount));
    outStream.writeRawData((char*)&otData.checkSum, sizeof(otData.checkSum));
    file.close();//Closes the file
}

Open in new window

0
PeterBaileyUkAuthor Commented:
It was more around the nature of the textfile itself so i can replicate what its doing in Cycling74 Max 7.

I know its creating slice point data relating to a .wav.
0
Cloud Class® Course: Amazon Web Services - Basic

Are you thinking about creating an Amazon Web Services account for your business? Not sure where to start? In this course you’ll get an overview of the history of AWS and take a tour of their user interface.

PeterBaileyUkAuthor Commented:
Ive made an waveform editor in Max and want to be able to create that textfile myself but not in C++ as I dont know C++ but yes your correct its creating a complimentary file .OT that goes alongside a sample so when the sampler sees the sample it can set the slice points.
0
Karrtik IyerSoftware ArchitectCommented:
Well, are you in a position to compile and execute this code and run with some sample data, which would in return generate the text file which you can view? Is this possible for you?
0
PeterBaileyUkAuthor Commented:
I have plenty of these files wait i send, normally I do this in my octatrack(this takes too long) but the code i posted joins wav files and then slices them and creates the file (i didnt write that application). This is not the action i want, I want to grab a bunch of wavs and set slice points and create the OT file.

Ive attached a .OT file

this was created by the octatrack.
its 120 BPM and has 16 slices

not sure if that helps, the guy who wrote the c++ app took a file like this, then amended to 8 slices then worked out the slicing algorhytm and then wrote the C++
BS2BassC1C2P35--2-.zip
0
PeterBaileyUkAuthor Commented:
ive linked to the app here, i dont think it breaks any ee rules..

https://drive.google.com/file/d/0B0N9blUzO0wuN0FJd3lMaVg2VEE/view?usp=sharing
0
Karrtik IyerSoftware ArchitectCommented:
Hi peter, I have got to compile and build this code, using the code in your first post (OTWriter.cpp and h), will you be in a position to give the following input values (to the functions below) so that I can generate the file?

1> OTWriter::OTWriter(const QString fileName, const int sampleRate, const Loop_t loopSetting, const Stretch_t strechSetting, const TrigQuant_t trigQuantSetting, int gain, int tempo)
2> void OTWriter::addSlice(uint32_t start, uint32_t end)
3> void OTWriter::write(uint32_t totalSamples)
0
PeterBaileyUkAuthor Commented:
here's a link to a wav file
https://drive.google.com/file/d/0B0N9blUzO0wuRTBubkpQYW5ia1k/view?usp=sharing

its name is as is in this wav
44100 for sample rate
tempo:120
gain:0
loop off i guess thats a 0
Timestretch off
trigquantdirect 0
16 for number of slices
slicemode steps
0
PeterBaileyUkAuthor Commented:
the wav in the link matches the .ot file that i sent earlier
0
Karrtik IyerSoftware ArchitectCommented:
Hi Peter,

Here are the two text files that I generated using the OTWRITER.CPP and H file that you shared, apologies for the delay, I was stuck with some other work. One sample -v1 is with addslice arguments start and end as 0 and 15, while -v2 is with addslice arguments start and end as 1 and 16. Hope they are of some use, I couldn't view any data as text in it, hopefully it is in some format that you can view or make some sense of :-), I am also sharing C++ code that I used to compile using C++ code blocks compiler which is free for use. In case you need the code that I used to generate this file. (https://drive.google.com/folderview?id=0B-PlEmGQASrTdG53dlpCbVUyS00&usp=sharing)

Please let me know if I could be of any further help.
Thanks,
Karrtik
BS2BassC1C2P351_v2.txt
BS2BassC1C2P351_v1.txt
0
PeterBaileyUkAuthor Commented:
I will load the wav and the ot file in the octatrack and I am sure itll be fine, I am almost not quite at a point where I need to understand the function themselves.

did you call the routine from your own main?

maybe I could replicates that first in visual studio? Ive just installed that but not sure how to set that up maybe thats a way for me to go so i can run through each step?
0
PeterBaileyUkAuthor Commented:
the delay is fine other people have their own lives too.
0
Karrtik IyerSoftware ArchitectCommented:
Yes I called from my own main, you can see the code which I have uploaded in google drive.
You can use the same code for a visual studio project as well. Once you have set up, it is pretty easy to use, I can even create a visual studio project for you to directly use and open in visual studio. Which version of visual studio are you targeting?
Thanks,
Karrtik
0
PeterBaileyUkAuthor Commented:
it says community 2015
0
PeterBaileyUkAuthor Commented:
Its starting with this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

Open in new window

0
Karrtik IyerSoftware ArchitectCommented:
What you are trying is a C# (.net)  console app, instead go for new project of C++ console application type.
0
PeterBaileyUkAuthor Commented:
The sampler didnt add any "slices" so I think the way to go is for me to set it up in my visual studio.
0
PeterBaileyUkAuthor Commented:
its starting like this as a console app

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication6
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}
0
PeterBaileyUkAuthor Commented:
here's my choices
ee.PNG
0
Karrtik IyerSoftware ArchitectCommented:
Go for visual C++ on left tree and select console application. Currently you have selected visual c# in left tree.
0
PeterBaileyUkAuthor Commented:
it wants to update stuff and its many gig so will be a while
0
Karrtik IyerSoftware ArchitectCommented:
I have created the same sample in Visual studio 2013 and shared it for you at below location:
https://drive.google.com/open?id=0B-PlEmGQASrTSGtZeVo3bE5MS0U

You should be able to open this directly in Visual studio 2015, Using Open Existing Project menu option. It might (not sure, it might work without conversion wizard as well, I do not know what changes are done in Visual 2015) bring up some conversion wizard, say ok and you should have the code which should work.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.