Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <fstream>
- #include <stdio.h>
- #include "main.h"
- using namespace std;
- void printStr(char * inputString, unsigned int stringSize, bool newLine);
- //Globals
- int fileSize; //Holds the file size of the xm file
- xmFileStruct xmData = {}; //Holds the xmData after parsing it
- int main(){
- printf("XM PARSE TEST (V1 0308) ODIN / SACIO\n\n");
- const char * fileName = "simple.xm";
- ifstream xmFile(fileName, ios::in | ios::binary | ios::ate); //Load xm file for input operations in binary mode and set pointer at end
- //so we can get file size by calling tellg() later on
- if(!xmFile.is_open()){ //Failed to open file
- printf("ERROR: Failed to open file!\n");
- return -1; //Return error
- }
- fileSize = (int) xmFile.tellg(); //Set fileSize to the current position get-pointer (at the end)
- xmFile.seekg(0, ios::beg); //Set get-pointer to begining of file (no offset)
- //Print filename, size and memory address
- printf("\tFilename:\t\t%s\n\tSize:\t\t\t%d bytes\n\n", fileName, fileSize);
- //Read XM Header
- xmFile.read(xmData.xmHeader.IDText, 17);
- xmFile.read(xmData.xmHeader.moduleName, 20);
- xmFile.read(&xmData.xmHeader.checkByte, 1);
- xmFile.read(xmData.xmHeader.trackerName, 20);
- xmFile.read((char*)&xmData.xmHeader.versionNumber, 2);
- xmFile.read((char*)&xmData.xmHeader.headerSize, 4);
- xmFile.read((char*)&xmData.xmHeader.songLength, 2);
- xmFile.read((char*)&xmData.xmHeader.restartPosition, 2);
- xmFile.read((char*)&xmData.xmHeader.numberOfChannels, 2);
- xmFile.read((char*)&xmData.xmHeader.numberOfPatterns, 2);
- xmFile.read((char*)&xmData.xmHeader.numberOfInstruments, 2);
- xmFile.read((char*)&xmData.xmHeader.flags, 2);
- xmFile.read((char*)&xmData.xmHeader.defaultTempo, 2);
- xmFile.read((char*)&xmData.xmHeader.defaultBPM, 2);
- xmFile.read(xmData.xmHeader.patternOrderTable, 256);
- //Read pattern headers
- xmData.patternHeaders = new xmPatternHeaderStruct[xmData.xmHeader.numberOfPatterns]; //Allocate space for pattern headers
- xmData.patterns = new xmPatternStruct[xmData.xmHeader.numberOfPatterns]; //Allocate space for patterns
- xmFile.seekg(xmData.xmHeader.headerSize+60, ios::beg); //Set pointer at first pattern header (headersize+60)
- for(int i=0; i<xmData.xmHeader.numberOfPatterns; i++){
- //Read header for current pattern
- xmFile.read((char*)&xmData.patternHeaders[i].headerLength, 4);
- xmFile.read(&xmData.patternHeaders[i].packingType, 1);
- xmFile.read((char*)&xmData.patternHeaders[i].numberOfRows, 2);
- xmFile.read((char*)&xmData.patternHeaders[i].patternDataSize, 2);
- if(xmData.patternHeaders[i].patternDataSize<=0){
- //Pattern is empty, set standard values
- xmData.patternHeaders[i].isEmpty = true;
- xmData.patternHeaders[i].headerLength = 9;
- xmData.patternHeaders[i].packingType = 0;
- xmData.patternHeaders[i].numberOfRows = 64;
- xmData.patternHeaders[i].patternDataSize = 64*xmData.xmHeader.numberOfChannels;
- xmData.patternHeaders[i].patternData = new char[xmData.patternHeaders[i].patternDataSize]; //Allocate space for pattern data
- //Fill pattern with 0x80
- for(int x=0; x<xmData.patternHeaders[i].patternDataSize; x++){
- xmData.patternHeaders[i].patternData[x] = 0x80;
- }
- //Set pointer to new offset (xm header + 60 + pattern header (pattern datasize is 0 in file))
- xmFile.seekg(xmData.xmHeader.headerSize+60+xmData.patternHeaders[i].headerLength, ios::beg);
- }else{
- //Start to read pattern data
- xmData.patternHeaders[i].patternData = new char[xmData.patternHeaders[i].patternDataSize]; //Allocate space for pattern data
- xmFile.read(xmData.patternHeaders[i].patternData, xmData.patternHeaders[i].patternDataSize);
- //Set pointer to new offset (xm header + 60 + pattern header + pattern data size)
- xmFile.seekg(xmData.xmHeader.headerSize+60+xmData.patternHeaders[i].headerLength+xmData.patternHeaders[i].patternDataSize, ios::beg);
- }
- //Decompress and store pattern data into pattern structs
- xmData.patterns[i].lines = new xmLineStruct[xmData.patternHeaders[i].numberOfRows]; //Allocate space for lines in pattern
- for(int x=0; x<xmData.patternHeaders[i].numberOfRows; x++){
- xmData.patterns[i].lines[x].notes = new xmNoteStruct[xmData.xmHeader.numberOfChannels]; //Allocate space for notes on line
- }
- bool patternComplete = false; //Decompression complete?
- bool lineComplete = false; //Line complete?
- int currentLine = 0; //Current line in pattern
- int currentNote = 0; //Current note on line
- int dataIndex = 0; //Position in pattern data
- while(!patternComplete){
- while(!lineComplete){
- if(xmData.patternHeaders[i].patternData[dataIndex]&0x80){ //Pattern data is compressed (MSB=1)
- if(xmData.patternHeaders[i].patternData[dataIndex]&0x01){ //Note follows
- xmData.patterns[i].lines[currentLine].notes[currentNote].noteFollows = true;
- }
- if(xmData.patternHeaders[i].patternData[dataIndex]&0x02){ //Instrument follows
- xmData.patterns[i].lines[currentLine].notes[currentNote].instrumentFollows = true;
- }
- if(xmData.patternHeaders[i].patternData[dataIndex]&0x04){ //Volume column byte follows
- xmData.patterns[i].lines[currentLine].notes[currentNote].volumeFollows = true;
- }
- if(xmData.patternHeaders[i].patternData[dataIndex]&0x08){ //Effect type follows
- xmData.patterns[i].lines[currentLine].notes[currentNote].effectTypeFollows = true;
- }
- if(xmData.patternHeaders[i].patternData[dataIndex]&0x10){ //Effect parameter follows
- xmData.patterns[i].lines[currentLine].notes[currentNote].effectParamFollows = true;
- }
- }else{
- }
- if(++currentNote>=xmData.xmHeader.numberOfChannels){ //No more notes on line
- lineComplete = true; //Stop loop
- }
- }
- if(++currentLine>=xmData.patternHeaders[i].numberOfRows){ //No more rows in pattern?
- patternComplete = true; //Stop loop
- }
- }
- for(int x=0; x<xmData.patternHeaders[i].patternDataSize; x+=5){ //Loop pattern data (5 bytes = 1 note)
- //xmData.patterns[i].note[x] = patternHeaders[i].patternData[x];
- }
- //Print pattern data
- printf("Pattern %02d\n"
- "\tLength: %d \n"
- "\tPacktype: %d \n"
- "\tRows: %d \n"
- "\tDatasize: %d \n\n",
- i,
- xmData.patternHeaders[i].headerLength,
- xmData.patternHeaders[i].packingType,
- xmData.patternHeaders[i].numberOfRows,
- xmData.patternHeaders[i].patternDataSize
- );
- }
- //Format and print data
- printStr(xmData.xmHeader.IDText, 17, true);
- printStr(xmData.xmHeader.moduleName, 20, true);
- if(xmData.xmHeader.checkByte==0x1A){ //Is valid XM?
- puts("Checkbyte matches XM specifications");
- }else{
- puts("ERROR: Checkbyte does not match!");
- return -2;
- }
- printStr(xmData.xmHeader.trackerName, 20, true);
- //Print version number. Hi byte = major, lo byte = minor version.
- printf("v%d.%d\n", xmData.xmHeader.versionNumber>>8, xmData.xmHeader.versionNumber&0x00FF);
- printf( "Header size: %d\n"
- "Song length: %d\n"
- "Restart position: %d\n"
- "Number of Channels: %d\n"
- "Number of Patterns: %d\n"
- "Number of Instruments: %d\n",
- xmData.xmHeader.headerSize,
- xmData.xmHeader.songLength,
- xmData.xmHeader.restartPosition,
- xmData.xmHeader.numberOfChannels,
- xmData.xmHeader.numberOfPatterns,
- xmData.xmHeader.numberOfInstruments
- );
- if(xmData.xmHeader.flags&1){
- puts("Linear frequency table");
- }else{
- puts("Amiga frequency table");
- }
- printf("Default tempo: %d\nDefault BPM: %d\n", xmData.xmHeader.defaultTempo, xmData.xmHeader.defaultBPM);
- puts("Pattern Order Table:");
- for(int i=0; i<xmData.xmHeader.songLength; i++){
- printf("%02d ", xmData.xmHeader.patternOrderTable[i]);
- }
- if(!xmFile)
- printf("FILE READ ERROR\n");
- xmFile.close(); //Close xm file
- return 0; //Complete, return from main()
- }
- void printStr(char * inputString, unsigned int stringSize, bool newLine){ //Print unterminated string to stdio (adds null terminator)
- for(unsigned int i=0; i<stringSize; i++){
- putchar(inputString[i]);
- }
- putchar('\0');
- if(newLine)
- putchar('\n');
- return;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement