From d2bb4247717d2cc89a8428cae6ae77067d86129d Mon Sep 17 00:00:00 2001 From: norly Date: Sat, 29 Oct 2011 18:59:57 +0100 Subject: [PATCH] Initial commit. Basically the old code from 2006/07, slightly modified to compile on modern GCC/Linux. Changed the tool names. --- .gitignore | 2 + Makefile | 11 ++++ README.md | 57 ++++++++++++++++ ac32spdif.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++ dts2spdif.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 429 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100755 ac32spdif.c create mode 100755 dts2spdif.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c6e429 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +ac32spdif +dts2spdif diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bf64657 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +all: ac32spdif dts2spdif + +ac32spdif: ac32spdif.c + cc -O2 -o ac32spdif ac32spdif.c + +dts2spdif: dts2spdif.c + cc -O2 -o dts2spdif dts2spdif.c + +.PHONY: clean +clean: + rm -f ac32spdif dts2spdif diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed9a663 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +S/PDIF tools +=========== + +These simple programs convert raw AC3 (Dolby Digital, A/52) and DTS streams +into WAV files containing the S/PDIF fake PCM encoding thereof. This means +that if such a .wav file is replayed correctly bit-by-bit via the S/PDIF +output of a device and supplied to a standards compliant decoder, it +will be recognized as a standards compliant AC3/DTS stream, +indistinguishable from a stream generated e.g. by a DVD player. + +This is useful to e.g. author CDs containing compressed multichannel +data (such as DTS encoded CDs that commercially available). +Take care: Playing back the files produced via speakers at high volume +may damage these or your hearing. + + +A note about coding style +------------------------- + +These sources are very old (from around 2006/2007) and show my coding +abilities back then when I started with C. I hope to clean this up +and modernize it at some point in the future. + + +ac32spdif +--------- + +This tool takes a raw .ac3 file and converts it into a .wav file of the +same sample rate containing one AC3 frame plus padding zeros for the +remaining time of that frame's time slot. + + +dts2spdif +--------- + +In a similar fashion, this tool translates a .dts file to a .wav file. +Currently it only supports 16 bit encapsulation, i.e. the data stream +is included in the .wav file 1:1. +The DTS specification also defines a 14 bit format for use with CDs +where there is a possibility that the data will be played back via +speakers in order to reduce the possibility of speaker/hearing damage +when the medium is played back without a DTS decoder. In this case, +only the lower 14 bits of a word would be used, with the high 2 bits +set to zero. This encoding may be added to dts2spdif later on. + + +License +------- + +As usual, this code comes with no warranty whatsoever. I am especially +not responsible if you blow up your speakers or ears using these tools. + +Do whatever you like with this code, but if you use it for your own +application I would appreciate an attribution note in the documentation. +Thanks! + + -- norly diff --git a/ac32spdif.c b/ac32spdif.c new file mode 100755 index 0000000..a1ab79f --- /dev/null +++ b/ac32spdif.c @@ -0,0 +1,182 @@ + +#include +//#include +//#include +#include + +//#include "fs_codes.h" + + +short bitrates[] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, +192, 224, 256, 320, 384, 448, 512, 576, 640 }; + +short fsize44[] = { 70, 88, 105, 122, 140, 175, 209, 244, 279, 349, +418, 488, 558, 697, 836, 976, 1115, 1254, 1394 }; + +unsigned long DecFS(char sratecode, unsigned long fsizecode) +{ + switch (sratecode) + { + case 0: + return (bitrates[fsizecode / 2] * 2); + case 1: + return ((fsizecode % 2) ? fsize44[fsizecode / 2] : fsize44[fsizecode / 2] - 1); + case 2: + return (bitrates[fsizecode / 2] * 3); + default: + return 0; + } + + return 0; +} + + + + +struct WAVEHEADER { + unsigned long ChunkID; + unsigned long ChunkSize; + unsigned long Format; + unsigned long SubChunk1ID; + unsigned long SubChunk1Size; + unsigned short AudioFormat; + unsigned short NumChannels; + unsigned long SampleRate; + unsigned long ByteRate; + unsigned short BlockAlign; + unsigned short BitsPerSample; + unsigned long SubChunk2ID; + unsigned long SubChunk2Size; +}; + + +struct AC3PREAMBLE { + unsigned short sync1; + unsigned short sync2; + unsigned char burst_infoLSB; + unsigned char burst_infoMSB; + unsigned short lengthcode; +}; + +char burst[6144]; + +FILE *infile, *outfile; + +unsigned long bytesread; +unsigned long payloadbytes; +char sampleratecode; +unsigned long framesizecode; + +struct AC3PREAMBLE ac3p = { 0xF872, 0x4E1F, 1, 0, 0x3800 }; +struct WAVEHEADER wavhdr = { 0x46464952, + 0, + 0x45564157, + 0x20746D66, + 16, + 1, + 2, + 0, + 0, + 4, + 16, + 0x61746164, + 0 }; + +unsigned long i; +char temp; + +int main( int argc, char *argv[ ], char *envp[ ] ) +{ + if (argc < 3) + { + printf("Wrong syntax. AC3PACK .\n"); + return 0; + } + + infile = fopen(argv[1], "rb"); + outfile = fopen(argv[2], "wb"); + //fseek(outfile, SEEK_SET, 44); + fwrite (&wavhdr, sizeof(struct WAVEHEADER), 1, outfile); + + + + for(;;) + { + memset (burst, 0, 6144); + bytesread = fread(&burst[8], 1, 6, infile); + if (bytesread < 6) + { + printf ("EOF reached (Frame Header reading)!\nCurrent position in INFILE: %i\n", ftell(infile)); + break; + } + if ((burst[8] != 0x0B) || (burst[9] != 0x77)) + { + printf("ERROR: INVALID SYNCWORD !\nCurrent position in INFILE: %i\n", ftell(infile)); + break; + } + framesizecode = (burst[12] & 63); + sampleratecode = ((burst[12] & 192) / 64); + + if (wavhdr.SampleRate == 0) + { + printf ("First Sampleratecode: %i\n", sampleratecode); + + switch (sampleratecode) + { + case 0: + wavhdr.SampleRate = 48000; + wavhdr.ByteRate = 192000; + break; + case 1: + wavhdr.SampleRate = 44100; + wavhdr.ByteRate = 176000; + break; + case 2: + wavhdr.SampleRate = 32000; + wavhdr.ByteRate = 128000; + break; + default: + wavhdr.SampleRate = 48000; + wavhdr.ByteRate = 192000; + } + } + + payloadbytes = DecFS (sampleratecode, framesizecode); + payloadbytes *= 2; + + bytesread = fread (&burst[14], 1, payloadbytes - 6, infile); + if ((bytesread + 6) < payloadbytes) + { + printf ("EOF reached (Burst Reading)!\nCurrent position in INFILE: %i\n", ftell(infile)); + printf ("Frame size: %i .. Bytes read: %i\n", payloadbytes, bytesread); + break; + } + ac3p.burst_infoMSB = (burst[13] & 7); + ac3p.lengthcode = (short)(payloadbytes * 8); + + for (i = 8; i < (payloadbytes + 8); i += 2) + { + temp = burst[i]; + burst[i] = burst[i + 1]; + burst[i + 1] = temp; + } + + memcpy (burst, &ac3p, sizeof(struct AC3PREAMBLE)); + + fwrite (burst, 1, 6144, outfile); + + } + + printf ("Last Sampleratecode: %i\n", sampleratecode); + + wavhdr.SubChunk2Size = (ftell(outfile) - 44); + wavhdr.ChunkSize = wavhdr.SubChunk2Size + 36; + + fseek (outfile, SEEK_SET, 0); + fwrite (&wavhdr, sizeof(struct WAVEHEADER), 1, outfile); + + fclose (infile); + fclose (outfile); + + return 0; +} diff --git a/dts2spdif.c b/dts2spdif.c new file mode 100755 index 0000000..6aa15bb --- /dev/null +++ b/dts2spdif.c @@ -0,0 +1,177 @@ + +#include +//#include +//#include +#include + +struct WAVEHEADER { + unsigned long ChunkID; + unsigned long ChunkSize; + unsigned long Format; + unsigned long SubChunk1ID; + unsigned long SubChunk1Size; + unsigned short AudioFormat; + unsigned short NumChannels; + unsigned long SampleRate; + unsigned long ByteRate; + unsigned short BlockAlign; + unsigned short BitsPerSample; + unsigned long SubChunk2ID; + unsigned long SubChunk2Size; +}; + + +unsigned char burst[6144]; + +FILE *infile, *outfile; + +unsigned long bytesread; +unsigned long pcmbytes; +unsigned long pcmbytesmultiplier; +char sampleratecode; +unsigned long framesize; + +struct WAVEHEADER wavhdr = { 0x46464952, + 0, + 0x45564157, + 0x20746D66, + 16, + 1, + 2, + 0, + 0, + 4, + 16, + 0x61746164, + 0 }; + +unsigned long i; +char temp; + +int main( int argc, char *argv[ ], char *envp[ ] ) +{ + if (argc < 3) + { + printf("Wrong syntax. dts2spdif .\n"); + return 0; + } + + infile = fopen(argv[1], "rb"); + outfile = fopen(argv[2], "wb"); + //fseek(outfile, SEEK_SET, 44); + fwrite (&wavhdr, sizeof(struct WAVEHEADER), 1, outfile); + + + for(;;) + { + memset (burst, 0, 6144); + bytesread = fread(burst, 1, 9, infile); + if (bytesread < 9) + { + printf ("EOF reached (Frame Header reading)!\nCurrent position in INFILE: %i\n", ftell(infile)); + break; + } + if (((unsigned long*)burst)[0] != 0x0180fe7f) + { + printf("ERROR: INVALID SYNCWORD !\nCurrent position in INFILE: %i\n", ftell(infile)); + break; + } + framesize = (burst[5] & 3); + framesize = framesize * 4096; + framesize = framesize + (burst[6] * 16); + framesize = framesize + ((burst[7] & 240) / 16); + framesize = framesize + 1; + + sampleratecode = ((burst[8] & 60) / 4); + + if (wavhdr.SampleRate == 0) + { + printf ("First Sampleratecode: %i\n", sampleratecode); + + switch (sampleratecode) + { + case 1: + pcmbytesmultiplier = 4; + case 2: + pcmbytesmultiplier = 2; + case 3: + pcmbytesmultiplier = 1; + wavhdr.SampleRate = 32000; + wavhdr.ByteRate = 128000; + break; + case 6: + pcmbytesmultiplier = 4; + case 7: + pcmbytesmultiplier = 2; + case 8: + pcmbytesmultiplier = 1; + wavhdr.SampleRate = 44100; + wavhdr.ByteRate = 176000; + break; + case 11: + pcmbytesmultiplier = 4; + case 12: + pcmbytesmultiplier = 2; + case 13: + pcmbytesmultiplier = 1; + wavhdr.SampleRate = 48000; + wavhdr.ByteRate = 192000; + break; + default: + wavhdr.SampleRate = 0; + wavhdr.ByteRate = 0; + printf ("Invalid Sampleratecode ! Aborting process...\n"); + break; + } + } + + pcmbytes = (burst[4] & 1); + pcmbytes = pcmbytes * 64; + pcmbytes = pcmbytes + ((burst[5] & 252) / 4); + pcmbytes = pcmbytes + 1; + pcmbytes = pcmbytes * 128; + pcmbytes = pcmbytes * pcmbytesmultiplier; + + + bytesread = fread (&burst[9], 1, framesize - 9, infile); + if ((bytesread + 9) < framesize) + { + printf ("EOF reached (Burst Reading)!\nCurrent position in INFILE: %i\n", ftell(infile)); + printf ("Frame size: %i .. Bytes read: %i\n", framesize, bytesread); + break; + } + + for (i = 0; i < framesize; i += 2) + { + temp = burst[i]; + burst[i] = burst[i + 1]; + burst[i + 1] = temp; + } + + + fwrite (burst, 1, framesize, outfile); + if (pcmbytes > framesize) + { + fwrite ("", 1, pcmbytes - framesize, outfile); + } + else + { + printf("Warning: Frame Size > LPCM Frame Size! Buffer underrun may occur/File damaged?\n"); + printf("Frame start at INFILE Offset: %i\n", ftell(infile) - framesize); + } + } + + printf ("Last Sampleratecode: %i\n", sampleratecode); + + wavhdr.SubChunk2Size = (ftell(outfile) - 44); + wavhdr.ChunkSize = wavhdr.SubChunk2Size + 36; + + fseek (outfile, SEEK_SET, 0); + fwrite (&wavhdr, sizeof(struct WAVEHEADER), 1, outfile); + + + fclose (infile); + fclose (outfile); + + return 0; +} -- 2.30.2