Music

Discussion in 'Project: Sonic Retro (Archive)' started by Phoebius, Nov 9, 2008.

  1. Black Squirrel

    Black Squirrel

    Fifty paces towards the sun, cooking beets. Wiki Sysop
    4,996
    2
    18
    Northumberland, England
    The soil knows all.
    To be honest I think that track by muteKi sounds more like something from the Japanese Sonic CD rather than the American one

    but personally I think it could use a bit more of a in-your-face melody. It currently sounds a bit... unfinished for some reason
     
  2. muteKi

    muteKi

    Fuck it Member
    7,543
    0
    16
    Yeah, the arrangement is a bit spartan. I probably won't go back to it until I've done a couple other things first.
     
  3. Sailu Baru

    Sailu Baru

    Member
    27
    0
    0
    France
    Only Pheonix has given me an answer, so I repost my last messages (with some adds):

    I've studied the Sonics' orchestrations (on Sonic 1 & 2) and I think I got the right style down. Listen to "the Flying Circus" and please tel me what you think about it (I know I still have to change this boring end).
    http://www.everyoneweb.fr/SailuMusic/
    It's just the composition, made with Guitar Pro. I would do this music again with a better software if I was sure almost all of you enjoyed it.
    I could redo it with a software I usually use (listen "Hightech City" for an example) or with a software which emulates Genesis sounds. Do you want a cleaner and modern sound, or a old sonic-like rendering ?
     
  4. Phoenix

    Phoenix

    Has really been far even as decided to use even go Member
    Definitely the former, although you could do certain parts with the Genesis rendering. Like someone a while back in this topic said, it would be great to have the modern sounds alongside the Genesis ones.
     
  5. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    Here are some FL Studio channel presets for VOPM.

    It's mostly bass voices from Sonic 1-S3K. README details where to put them.


    Fun stuff I found when making these:

    The lead voice from Labyrinth is the exact same as the bass voice from Mystic Cave.

    The bass from Marble and Starlight are almost exactly the same (the level of Carrier 2 is altered).

    The bass from Scrap Brain and Emerald Hill are almost exactly the same (the level of Carrier 2 is altered).
     
  6. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    Can you convert these to FXB files so I can use them with programs other than FL Studio? If I get Windows to work, I'll find an old copy of the freeware Cubasis InWired and use it with VOPM. Thanks.
     
  7. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    Can you explain how to use FXB files? I'm still at a loss.

    That being said, I can do .OPMs, if those will work equally well (via VOPM's import/export feature).

    EDIT: Nevermind, OPM's are failing miserably, hang on a bit.
     
  8. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    FXB files are the standard format supported by VST. Most VST hosts use this natively to load/store banks. If FL Studio doesn't support them, I don't know what.

    How is OPM failing?

    PS - I have alternate OPM files ripped from VGZ files of the Sonic music, if you want to test then.
     
  9. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    OPM is failing because of either FLStudio or VOPM, either way, the current settings on VOPM are not being written to the .OPM file, only a default 9 channels, and a bunch of "no Name" to fill the channel list to 127. I dunno.

    I'm going to attempt to write a little program to convert .y12 dumps from Gens KMod to .OPM voice segments.
     
  10. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    Nine channels is all you need; the Genesis sound processor only supports six. Use this awk script to split OPM files into individual settings and drop the no name ones:

    Code (Text):
    1. # splitopm:  split opm file into one per instrument
    2. # pietro gagliardi - 6 january 2009
    3. # usage: splitopm file.opm output-directory
    4.  
    5. BEGIN {
    6.     # Change this if your OS needs it
    7.     DIR_SEPARATOR = "/"
    8.    
    9.     if (ARGC != 3) {
    10.         print "usage: " ARGV[0] " file.opm output-directory"
    11.         exit 1
    12.     }
    13.    
    14.     outdir = ARGV[2]
    15.     ARGV[2] = ""
    16.     ARGC--
    17.    
    18.     RS = ""
    19.     FS = OFS = "\n"
    20. }
    21.  
    22. /^\/\// { next }
    23. !/^@/   { print ARGV[1] ": bad input file"; exit 1 }
    24.  
    25. {
    26.     instrname = substr($1, index($1, " ") + 1)
    27.     if (tolower(instrname) == "no name")
    28.         next
    29.     oldinstrname = instrname
    30.     gsub(/[^A-Za-z0-9_]/,  "", instrname)
    31.     filename = outdir DIR_SEPARATOR instrname ".opm"
    32.     $1 = "@:0 " oldinstrname # convert to bank 0
    33.     print > filename
    34.     close(filename)
    35.     inst++
    36. }
    You may need to change the line

    Code (Text):
    1.     $1 = "@:0 " oldinstrname # convert to bank 0
    to

    Code (Text):
    1.     $1 = "@:1 " oldinstrname # convert to bank 1
    if the script doesn't result in files that can be imported, but I don't know.
     
  11. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    Sorry, I said that wrong, it outputs nine voices, and 118 "no Name" voices to a .OPM file.

    Thanks for the script though. I'm still gonna attempt to write this converter though: Out of practice freshman level C++ powers, activate!
     
  12. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    Well, last night I got through most of Sonic 3 & Knuckles emulated on my computer with the volume off and hummed about an hour and a half of stuff. I'll get Windows up, pick out the best, and give you some tunes soon.
     
  13. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    Alright, here's version -0.1 of the converter.

    It trashes some thing numbers that aren't visible in VOPM, and I don't know what they are, but ditching them isn't hurting anything (yet).

    If anyone encounters any problems, let me know and all that. Also, if anyone knows what they're doing with Windows programming and wants to write a GUI or at least get some sort of drag and drop going, I'd be more than happy to provide the filthy, filthy source for this clunker.

    Converter.exe

    Anyway, this program will convert a .y12 dump provided by Gens KMod to a .OPM file that you can import into VOPM.

    Sadly, I cannot get drag and drop to work, so you folks are stuck running it from a command line for now, like so:

    "converter.exe chan5.y12"

    Sexy.


    For now it works ok, I've done about 15 test runs and haven't had an issue yet, I just worry about those dropped numbers.
     
  14. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    Or, I could help you clean it up :-P
     
  15. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    Help yourself=D

    A lot of the monotonous stuff can be function'd, particularly the printing parts. But I'm wore out:P

    In a codebox because of encoding issues between windows and linux.

    If you're brave the source file itself can be found here.

    [codebox]/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
    /*
    * converter.cpp
    * Copyright © Jake Reed 2009
    *
    * converter.cpp is free software: you can redistribute it and/or modify it
    * under the terms of the GNU General Public License as published by the
    * Free Software Foundation, either version 3 of the License, or
    * (at your option) any later version.
    *
    * converter.cpp is distributed in the hope that it will be useful, but
    * WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    * See the GNU General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License along
    * with this program. If not, see .
    */

    #include
    #include
    #include
    #include

    using namespace std;

    char fixTL(char c)
    {
    // *HACK*
    // The first bit is 1 in the dump.
    // I don't know what it's for, and
    // it works fine if I just drop it.
    // Clarify: The first bit SHOULD
    // NOT be 1.
    // TL is 0-127, 127=7 bits

    unsigned char temp = c;
    temp = (temp << 1);
    temp = (temp >> 1);

    return temp;
    }

    string expandDetMul(char c)
    {
    // First 4 bits = Det
    // Last 4 bits = Mul

    string out;

    char det = (char)0;
    char mul = (char)0;

    unsigned char temp = c;


    for (int I=7; I>=4; I--)
    {
    char bit = ((temp >> I) & 1);
    det = (det << 1 | bit);
    }

    for (int I=3; I>=0; I--)
    {
    char bit = ((temp >> I) & 1);
    mul = (mul << 1 | bit);
    }

    out = det;
    out += mul;
    return out;
    }



    string expandKsAtk(char c)
    {
    // First 2 bits = KS
    // Followed by a 0 bit
    // Last 5 bits = Atk

    string out;

    char KS = (char)0;
    char atk = (char)0;

    unsigned char temp = c;

    for (int I=7; I>=6; I--)
    {
    char bit = ((temp >> I) & 1);
    KS = (KS << 1 | bit);
    }

    for (int I=4; I>=0; I--)
    {
    char bit = ((temp >> I) & 1);
    atk = (atk << 1 | bit);
    }

    out = KS;
    out += atk;
    return out;
    }

    string expandSlRel(char c)
    {
    // First 4 bits = Sus Level
    // Last 4 bits = Rel

    string out;

    char sus = (char)0;
    char rel = (char)0;

    unsigned char temp = c;


    for (int I=7; I>=4; I--)
    {
    char bit = ((temp >> I) & 1);
    sus = (sus << 1 | bit);
    }

    for (int I=3; I>=0; I--)
    {
    char bit = ((temp >> I) & 1);
    rel = (rel << 1 | bit);
    }

    out = sus;
    out += rel;
    return out;
    }

    struct OP
    {
    /*
    *Detune
    *Multiple
    *Total Level
    *Key Scale
    *Attack
    *Decay
    *Sustain (Second Decay)
    *Sus Level
    *Release
    */

    // Single operator attributes
    unsigned char det;
    unsigned char mul;
    unsigned char tLevel;
    unsigned char kScale;
    unsigned char atk;
    unsigned char dec;
    unsigned char sus;
    unsigned char sLevel;
    unsigned char rel;

    // Compressed operator attributes
    unsigned char det_mul;
    unsigned char kS_atk;
    unsigned char sL_rel;
    };

    struct Channel
    {
    char connection;
    char feedback;
    };

    int main(int argc, char* argv[])
    {
    if (argc <= 1)
    {
    cout << "Usage: " << argv[0] << " " << endl;
    exit(1);
    }

    char *pFilename = argv[1];

    //char inFileName[] = "test.y12";
    //char outFileName[] = "test.opm";

    Channel channel;
    OP M1;
    OP M2;
    OP C1;
    OP C2;

    ifstream inFile(pFilename, ios::in | ios::binary);

    char* readBuffer = new char [0];

    /****************************************
    *** READS ***
    ****************************************/

    // Read M1

    inFile.read(readBuffer, 1);
    M1.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Read M2

    inFile.read(readBuffer, 1);
    M2.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Read C1

    inFile.read(readBuffer, 1);
    C1.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Read C2

    inFile.read(readBuffer, 1);
    C2.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Channel

    inFile.read(readBuffer, 1);
    channel.feedback = readBuffer[0];

    inFile.read(readBuffer, 1);
    channel.connection = readBuffer[0];

    inFile.close();

    /****************************************
    *** EXPAND ***
    ****************************************/

    // M1

    string out = expandDetMul(M1.det_mul);

    M1.det = out.at(0);
    M1.mul = out.at(1);

    out = expandKsAtk(M1.kS_atk);

    M1.kScale = out.at(0);
    M1.atk = out.at(1);

    out = expandSlRel(M1.sL_rel);

    M1.sLevel = out.at(0);
    M1.rel = out.at(1);

    char temp = fixTL(M1.tLevel);
    M1.tLevel = temp;

    // M2

    out = expandDetMul(M2.det_mul);

    M2.det = out.at(0);
    M2.mul = out.at(1);

    out = expandKsAtk(M2.kS_atk);

    M2.kScale = out.at(0);
    M2.atk = out.at(1);

    out = expandSlRel(M2.sL_rel);

    M2.sLevel = out.at(0);
    M2.rel = out.at(1);

    temp = fixTL(M2.tLevel);
    M2.tLevel = temp;


    // C1

    out = expandDetMul(C1.det_mul);

    C1.det = out.at(0);
    C1.mul = out.at(1);

    out = expandKsAtk(C1.kS_atk);

    C1.kScale = out.at(0);
    C1.atk = out.at(1);

    out = expandSlRel(C1.sL_rel);

    C1.sLevel = out.at(0);
    C1.rel = out.at(1);

    temp = fixTL(C1.tLevel);
    C1.tLevel = temp;


    // C2

    out = expandDetMul(C2.det_mul);

    C2.det = out.at(0);
    C2.mul = out.at(1);

    out = expandKsAtk(C2.kS_atk);

    C2.kScale = out.at(0);
    C2.atk = out.at(1);

    out = expandSlRel(C2.sL_rel);

    C2.sLevel = out.at(0);
    C2.rel = out.at(1);

    temp = fixTL(C2.tLevel);
    C2.tLevel = temp;


    /****************************************
    *** PRINT ***
    ****************************************/

    fstream outFile("out.OPM", ios::out);

    // Heading
    outFile << "@:0 " << pFilename << "\n";

    outFile << "LFO: 0 0 0 0 0\n";

    outFile << "CH:"
    << setw(4) << "64"
    << setw(4) << (int)channel.connection
    << setw(4) << (int)channel.feedback
    << setw(4) << "0"
    << setw(4) << "0"
    << setw(4) << "120"
    << setw(4) << "0"
    << "\n";

    outFile << "M1:"
    << setw(4) << (int)M1.atk
    << setw(4) << (int)M1.dec
    << setw(4) << (int)M1.sus
    << setw(4) << (int)M1.rel
    << setw(4) << (int)M1.sLevel
    << setw(4) << (int)M1.tLevel
    << setw(4) << (int)M1.kScale
    << setw(4) << (int)M1.mul
    << setw(4) << (int)M1.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile << "C1:"
    << setw(4) << (int)C1.atk
    << setw(4) << (int)C1.dec
    << setw(4) << (int)C1.sus
    << setw(4) << (int)C1.rel
    << setw(4) << (int)C1.sLevel
    << setw(4) << (int)C1.tLevel
    << setw(4) << (int)C1.kScale
    << setw(4) << (int)C1.mul
    << setw(4) << (int)C1.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile << "M2:"
    << setw(4) << (int)M2.atk
    << setw(4) << (int)M2.dec
    << setw(4) << (int)M2.sus
    << setw(4) << (int)M2.rel
    << setw(4) << (int)M2.sLevel
    << setw(4) << (int)M2.tLevel
    << setw(4) << (int)M2.kScale
    << setw(4) << (int)M2.mul
    << setw(4) << (int)M2.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile << "C2:"
    << setw(4) << (int)C2.atk
    << setw(4) << (int)C2.dec
    << setw(4) << (int)C2.sus
    << setw(4) << (int)C2.rel
    << setw(4) << (int)C2.sLevel
    << setw(4) << (int)C2.tLevel
    << setw(4) << (int)C2.kScale
    << setw(4) << (int)C2.mul
    << setw(4) << (int)C2.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile.close();

    return 0;
    }
    [/codebox]

    That's right, it's GPL'd =P

    I started going in anjuta before I got annoyed and whipped out text editor and g++.
     
  16. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    Other than the monotony, this code looks good. Just explain what you are doing in the helper functions and you have a pearl.

    Windows is up. VOPM is up. Cubasis InWired is up. My OPM tracks are all ripped from VGZ files. I have Sonic 3 audio samples ready. Soon!
     
  17. McGuirk

    McGuirk

    The Egg-Man Cometh. Member
    576
    0
    0
    Fort Worth, Texas, USA
    Making a Full-Sized Egg Carrier in Minecraft.
    Fist off, the dumps are compressed.

    I'll explain.

    Here's the values for OP1 channel 3 of the exercise music from Dr. Robotnik's Mean Bean Machine:

    [codebox]
    Detune: 0x03
    Multiple: 0x09
    Total Level: 0x17
    Rate Scaling: 0x00
    Attack Rate: 0x1F
    First Decay: 0x0C
    Second Decay: 0x07
    Sub Level: 0x06
    Release Rate: 0x06
    [/codebox]

    03 09 12 00 1F 0C 07 06 06

    Now, here's the dump from the .y12 file:

    39 17 1F 0C 07 26

    Here's what each of them is:

    (Unless specified otherwise,
    the helper functions take the compressed
    byte as a character for a parameter, then
    returns a std::string of the decompressed
    bytes as 2 characters)

    ----

    39:
    Detune and Multiple grouped.
    1 nybble per value. expandDetMul()
    splits the bits between the two.

    ----

    17:
    Total Level, whole byte.

    NOTE: The value does not include the
    whole byte. TL's value is 0-127,
    so the first bit is ignored.

    I don't know why it's sometimes 1 in the dumps.
    fixTL() takes TL as a char, sets the first
    bit to zero via bit shifts, and returns the
    altered char.

    ----

    1F:
    Rate Scaling and Attack Rate.
    This one is more complex. Of
    the byte, the first two bits
    are the Rate Scaling, followed
    by a 0 bit, followed by the
    Attack rate in the last 5 bits.

    IE: RS0AtkRt
    1F:00011111

    expandKsAtk() splits the bits

    ----

    0C:
    First Decay, whole byte.

    ----

    07:
    Second Decay, whole byte.

    ----

    26:
    Sustain Level and Release rate:
    After more research these two
    values are always equal. They
    are represented by the second
    nybble, I was splitting in two
    before. This means I'll be
    posting a revised source file
    at the bottom of this post.
    The 2 can be dropped.

    ----

    These are followed by 10 bytes
    of 0x00's. Trash for now.
    Repeat for 3 more OP's + 10
    byte buffer between. Next,

    One byte for the channel's
    connection type:
    0x00 - 0x07

    Very next byte is Channel's
    feedback level:
    0x00 - 0x07

    Rest is crap.

    That's the overview.

    The variables should cover
    themselves in the comments
    near them.

    Feel free to ask more detailed
    questions if I left something out.

    Here's the updates source:

    [codebox]
    /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
    /*
    * converter.cpp
    * Copyright &copy; Jake Reed 2009 <[email protected]>
    *
    * converter.cpp is free software: you can redistribute it and/or modify it
    * under the terms of the GNU General Public License as published by the
    * Free Software Foundation, either version 3 of the License, or
    * (at your option) any later version.
    *
    * converter.cpp is distributed in the hope that it will be useful, but
    * WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    * See the GNU General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License along
    * with this program. If not, see <http://www.gnu.org/licenses/>.
    */

    #include <iostream>
    #include <string>
    #include <iomanip>
    #include <fstream>

    using namespace std;

    char fixTL(char c)
    {
    // *HACK*
    // The first bit is 1 in the dump.
    // I don't know what it's for, and
    // it works fine if I just drop it.
    // Clarify: The first bit SHOULD
    // NOT be 1.
    // TL is 0-127, 127=7 bits

    unsigned char temp = c;
    temp = (temp << 1);
    temp = (temp >> 1);

    return temp;
    }

    string expandDetMul(char c)
    {
    // First 4 bits = Det
    // Last 4 bits = Mul

    string out;

    char det = (char)0;
    char mul = (char)0;

    unsigned char temp = c;


    for (int I=7; I>=4; I--)
    {
    char bit = ((temp >> I) & 1);
    det = (det << 1 | bit);
    }

    for (int I=3; I>=0; I--)
    {
    char bit = ((temp >> I) & 1);
    mul = (mul << 1 | bit);
    }

    out = det;
    out += mul;
    return out;
    }



    string expandKsAtk(char c)
    {
    // First 2 bits = KS
    // Followed by a 0 bit
    // Last 5 bits = Atk

    string out;

    char KS = (char)0;
    char atk = (char)0;

    unsigned char temp = c;

    for (int I=7; I>=6; I--)
    {
    char bit = ((temp >> I) & 1);
    KS = (KS << 1 | bit);
    }

    for (int I=4; I>=0; I--)
    {
    char bit = ((temp >> I) & 1);
    atk = (atk << 1 | bit);
    }

    out = KS;
    out += atk;
    return out;
    }

    string expandSlRel(char c)
    {
    // First 4 bits = Crap
    // Last 4 bits = Both Values

    string out;

    char rel = (char)0;

    unsigned char temp = c;

    for (int I=3; I>=0; I--)
    {
    char bit = ((temp >> I) & 1);
    rel = (rel << 1 | bit);
    }

    out = rel;
    out += rel;
    return out;
    }

    struct OP
    {
    /*
    *Detune
    *Multiple
    *Total Level
    *Key Scale
    *Attack
    *Decay
    *Sustain (Second Decay)
    *Sus Level
    *Release
    */

    // Single operator attributes
    unsigned char det;
    unsigned char mul;
    unsigned char tLevel;
    unsigned char kScale;
    unsigned char atk;
    unsigned char dec;
    unsigned char sus;
    unsigned char sLevel;
    unsigned char rel;

    // Compressed operator attributes
    unsigned char det_mul;
    unsigned char kS_atk;
    unsigned char sL_rel;
    };

    struct Channel
    {
    char connection;
    char feedback;
    };

    int main(int argc, char* argv[])
    {
    if (argc <= 1)
    {
    cout << "Usage: " << argv[0] << " <Filename>" << endl;
    exit(1);
    }

    char *pFilename = argv[1];

    //char inFileName[] = "test.y12";
    //char outFileName[] = "test.opm";

    Channel channel;
    OP M1;
    OP M2;
    OP C1;
    OP C2;

    ifstream inFile(pFilename, ios::in | ios::binary);

    char* readBuffer = new char [0];

    /****************************************
    *** READS ***
    ****************************************/

    // Read M1

    inFile.read(readBuffer, 1);
    M1.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    M1.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Read M2

    inFile.read(readBuffer, 1);
    M2.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    M2.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Read C1

    inFile.read(readBuffer, 1);
    C1.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    C1.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Read C2

    inFile.read(readBuffer, 1);
    C2.det_mul = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.tLevel = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.kS_atk = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.dec = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.sus = readBuffer[0];

    inFile.read(readBuffer, 1);
    C2.sL_rel = readBuffer[0];

    for (int I = 1; I <= 10; I++)
    {
    inFile.read(readBuffer, 1);
    }

    // Channel

    inFile.read(readBuffer, 1);
    channel.connection = readBuffer[0];

    inFile.read(readBuffer, 1);
    channel.feedback = readBuffer[0];

    inFile.close();

    /****************************************
    *** EXPAND ***
    ****************************************/

    // M1

    string out = expandDetMul(M1.det_mul);

    M1.det = out.at(0);
    M1.mul = out.at(1);

    out = expandKsAtk(M1.kS_atk);

    M1.kScale = out.at(0);
    M1.atk = out.at(1);

    out = expandSlRel(M1.sL_rel);

    M1.sLevel = out.at(0);
    M1.rel = out.at(1);

    char temp = fixTL(M1.tLevel);
    M1.tLevel = temp;

    // M2

    out = expandDetMul(M2.det_mul);

    M2.det = out.at(0);
    M2.mul = out.at(1);

    out = expandKsAtk(M2.kS_atk);

    M2.kScale = out.at(0);
    M2.atk = out.at(1);

    out = expandSlRel(M2.sL_rel);

    M2.sLevel = out.at(0);
    M2.rel = out.at(1);

    temp = fixTL(M2.tLevel);
    M2.tLevel = temp;


    // C1

    out = expandDetMul(C1.det_mul);

    C1.det = out.at(0);
    C1.mul = out.at(1);

    out = expandKsAtk(C1.kS_atk);

    C1.kScale = out.at(0);
    C1.atk = out.at(1);

    out = expandSlRel(C1.sL_rel);

    C1.sLevel = out.at(0);
    C1.rel = out.at(1);

    temp = fixTL(C1.tLevel);
    C1.tLevel = temp;


    // C2

    out = expandDetMul(C2.det_mul);

    C2.det = out.at(0);
    C2.mul = out.at(1);

    out = expandKsAtk(C2.kS_atk);

    C2.kScale = out.at(0);
    C2.atk = out.at(1);

    out = expandSlRel(C2.sL_rel);

    C2.sLevel = out.at(0);
    C2.rel = out.at(1);

    temp = fixTL(C2.tLevel);
    C2.tLevel = temp;


    /****************************************
    *** PRINT ***
    ****************************************/

    fstream outFile("out.OPM", ios::out);

    // Heading
    outFile << "@:0 " << pFilename << "\n";

    outFile << "LFO: 0 0 0 0 0\n";

    outFile << "CH:"
    << setw(4) << "64"
    << setw(4) << (int)channel.feedback
    << setw(4) << (int)channel.connection
    << setw(4) << "0"
    << setw(4) << "0"
    << setw(4) << "120"
    << setw(4) << "0"
    << "\n";

    outFile << "M1:"
    << setw(4) << (int)M1.atk
    << setw(4) << (int)M1.dec
    << setw(4) << (int)M1.sus
    << setw(4) << (int)M1.rel
    << setw(4) << (int)M1.sLevel
    << setw(4) << (int)M1.tLevel
    << setw(4) << (int)M1.kScale
    << setw(4) << (int)M1.mul
    << setw(4) << (int)M1.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile << "C1:"
    << setw(4) << (int)C1.atk
    << setw(4) << (int)C1.dec
    << setw(4) << (int)C1.sus
    << setw(4) << (int)C1.rel
    << setw(4) << (int)C1.sLevel
    << setw(4) << (int)C1.tLevel
    << setw(4) << (int)C1.kScale
    << setw(4) << (int)C1.mul
    << setw(4) << (int)C1.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile << "M2:"
    << setw(4) << (int)M2.atk
    << setw(4) << (int)M2.dec
    << setw(4) << (int)M2.sus
    << setw(4) << (int)M2.rel
    << setw(4) << (int)M2.sLevel
    << setw(4) << (int)M2.tLevel
    << setw(4) << (int)M2.kScale
    << setw(4) << (int)M2.mul
    << setw(4) << (int)M2.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile << "C2:"
    << setw(4) << (int)C2.atk
    << setw(4) << (int)C2.dec
    << setw(4) << (int)C2.sus
    << setw(4) << (int)C2.rel
    << setw(4) << (int)C2.sLevel
    << setw(4) << (int)C2.tLevel
    << setw(4) << (int)C2.kScale
    << setw(4) << (int)C2.mul
    << setw(4) << (int)C2.det
    << setw(4) << 0
    << setw(4) << 0 << "\n";

    outFile.close();

    return 0;
    }

    [/codebox]
     
  18. XCubed

    XCubed

    Will Someday Own a Rent-A-Center Oldbie

    You motherfucker, I need to make sweet love to you NOW!!! Your directions were a little different from my version of FL Studio, but with some tooling around with the files I was able to get it to work! I LOVE YOU! I want you to have my babies. I can make sweet lovin closer to Genesis sounds that I ever could have before! Sorry for the profanity, but this has made me so damn happy! I don't know how the fuck you did this, but either way you have my love now and forever McGuirk!
     
  19. Andlabs

    Andlabs

    「いっきまーす」 Wiki Sysop
    2,175
    0
    0
    Writing my own MD/Genesis sound driver :D
    Is there a way to emulate the Programmable Sound Generator? I noticed that some songs, such as Lava Reef Act 1, use it alongside the OPM FM channels.
     
  20. muteKi

    muteKi

    Fuck it Member
    7,543
    0
    16
    There must be a decent square wave VST out there somewhere...