Skip to content

Instantly share code, notes, and snippets.

@MajsterTynek
Created September 11, 2022 15:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MajsterTynek/7afb88ee52a0e59b1fbcb83025eba198 to your computer and use it in GitHub Desktop.
Save MajsterTynek/7afb88ee52a0e59b1fbcb83025eba198 to your computer and use it in GitHub Desktop.
Program that demonstrates conversion of SNF file into a WAV file. SNF file format comes from Dispel game. Visit our [reddit](https://www.reddit.com/r/DispelRPG/) and [discord](https://discord.gg/Kz23q2qb7c) server!
// PROTOTYPE PROGRAM THAT DEMONSTRATES
// CONVERTING SNF TO WAV FORMAT
#include <string>
#include <fstream>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
typedef unsigned char BYTE; // 1 byte
typedef short WORD; // 2 bytes
typedef int DWORD; // 4 bytes
typedef struct wavformat_tag {
WORD wFormatTag; // audio_format
WORD nChannels; // num_channels
DWORD nSamplesPerSec; // sample_rate
DWORD nAvgBytesPerSec; // byte_rate
WORD nBlockAlign; // block_align
WORD wBitsPerSample; // bits_per_sample
} PCMWAVEFORMAT;
// SNF is just shortened WAV
typedef struct snfformat_tag { // 22 bytes
DWORD sound_bytes; // 4 lenght of sound_data
WORD audio_format; // 2 wFormatTag
WORD num_channels; // 2 nChannels
DWORD sample_rate; // 4 nSamplesPerSec
DWORD byte_rate; // 4 nAvgBytesPerSec
WORD block_align; // 2 nBlockAlign
WORD bits_per_sample; // 2 wBitsPerSample
// "da" // 2 leftover of "data"
// sound_data // n encoded samples
} SNFFORMAT;
// stram read overload
template<typename T>
std::ifstream& operator>>(std::ifstream& str, T& var){
return static_cast<std::ifstream&>(str.read((char*)&(var),sizeof(var)));
}
// simple macros for stream io
#define READ(var) read((char*)&(var),sizeof(var))
#define WRITE(var) write((char*)&(var),sizeof(var))
void load_snf(SNFFORMAT &snd, std::ifstream &s, char *&sound_data)
{
WORD dummy; // for "da" skip
s >> snd.sound_bytes >> snd.audio_format >> snd.num_channels
>> snd.sample_rate >> snd.byte_rate >> snd.block_align
>> snd.bits_per_sample >> dummy;
sound_data = new char[snd.sound_bytes];
s.read( sound_data, snd.sound_bytes );
}
int main(int argc, char* argv[])
{
// we need file to convert
if ( argc != 2 ) return 1;
fs::path path(argv[1]);
// open snf file for conversion
std::ifstream snf( path, std::ios::binary );
if ( !snf.is_open() ) return 2;
SNFFORMAT snd; // load SNF header structure
char* sound_data = nullptr;
load_snf( snd, snf, sound_data );
if ( snf.fail() ) return 3;
snf.close();
PCMWAVEFORMAT wav; // fit in WAV structure
wav.wFormatTag = snd.audio_format;
wav.nChannels = snd.num_channels;
wav.nSamplesPerSec = snd.sample_rate;
wav.nAvgBytesPerSec = snd.byte_rate;
wav.nBlockAlign = snd.block_align;
wav.wBitsPerSample = snd.bits_per_sample;
DWORD res_size = 44 + snd.sound_bytes;
DWORD pcmwav_size = 16;
path.replace_extension( "wav" );
std::ofstream wav_file( path, std::ios::binary | std::ios::trunc );
wav_file.write( "RIFF", 4 ); // build RIFF WAVE file
wav_file.WRITE( res_size ); // size of WAVE resource
wav_file.write( "WAVE", 4 ); // begin WAVE resource
wav_file.write( "fmt ", 4 ); // format of stored sound
wav_file.WRITE( pcmwav_size ); // PCMWAVEFORMAT
wav_file.WRITE( wav.wFormatTag );
wav_file.WRITE( wav.nChannels );
wav_file.WRITE( wav.nSamplesPerSec );
wav_file.WRITE( wav.nAvgBytesPerSec );
wav_file.WRITE( wav.nBlockAlign );
wav_file.WRITE( wav.wBitsPerSample );
wav_file.write( "data", 4 ); // sound samples
wav_file.write( sound_data, snd.sound_bytes );
wav_file.close(); // go listen to it!
delete sound_data;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment